From 1bd1187c92764ff5980fe0566c06d3dd68fad63a Mon Sep 17 00:00:00 2001 From: Dan Klishch Date: Tue, 16 Jan 2024 21:49:33 -0500 Subject: [PATCH] JSSpecCompiler: Push ParseError out of AlgorithmStepList --- .../JSSpecCompiler/Parser/SpecParser.cpp | 74 +++++++++++-------- .../JSSpecCompiler/Parser/SpecParser.h | 4 +- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp index 38cafab777..cc37ebbbc6 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp @@ -48,15 +48,18 @@ Location SpecificationParsingContext::location_from_xml_offset(XML::Offset offse }; } -ParseErrorOr AlgorithmStep::create(XML::Node const* node) +ParseErrorOr AlgorithmStep::create(SpecificationParsingContext& ctx, XML::Node const* node) { VERIFY(node->as_element().name == tag_li); auto [tokens, substeps] = TRY(tokenize_tree(node, true)); AlgorithmStep result { .m_tokens = move(tokens), .m_node = node }; - if (substeps) - result.m_substeps = TRY(AlgorithmStepList::create(substeps->as_element())).m_expression; + if (substeps) { + auto step_list = AlgorithmStepList::create(ctx, substeps); + if (step_list.has_value()) + result.m_substeps = step_list->m_expression; + } result.m_expression = TRY(result.parse()); return result; @@ -72,34 +75,49 @@ ParseErrorOr AlgorithmStep::parse() return parser.parse_step_without_substeps(); } -ParseErrorOr AlgorithmStepList::create(XML::Node::Element const& element) +Optional AlgorithmStepList::create(SpecificationParsingContext& ctx, XML::Node const* element) { - VERIFY(element.name == tag_ol); + VERIFY(element->as_element().name == tag_ol); AlgorithmStepList result; auto& steps = result.m_steps; Vector step_expressions; + bool all_steps_parsed = true; - for (auto const& child : element.children) { - TRY(child->content.visit( - [&](XML::Node::Element const& element) -> ParseErrorOr { - if (element.name != tag_li) - return ParseError::create("
    > :not(
  1. ) should not match any elements"sv, child); - steps.append(TRY(AlgorithmStep::create(child))); - step_expressions.append(steps.last().m_expression); - return {}; + for (auto const& child : element->as_element().children) { + child->content.visit( + [&](XML::Node::Element const& element) { + if (element.name == tag_li) { + auto step_creation_result = AlgorithmStep::create(ctx, child); + if (step_creation_result.is_error()) { + // TODO: Integrate backtracing parser errors better + ctx.diag().error(ctx.location_from_xml_offset(step_creation_result.error()->offset()), + "{}", step_creation_result.error()->to_string()); + all_steps_parsed = false; + } else { + steps.append(step_creation_result.release_value()); + step_expressions.append(steps.last().m_expression); + } + return; + } + + ctx.diag().error(ctx.location_from_xml_offset(child->offset), + "<{}> should not be a child of algorithm step list"sv, element.name); }, - [&](XML::Node::Text const&) -> ParseErrorOr { - if (!contains_empty_text(child)) - return ParseError::create("
      should not have non-empty child text nodes"sv, child); - return {}; + [&](XML::Node::Text const&) { + if (!contains_empty_text(child)) { + ctx.diag().error(ctx.location_from_xml_offset(child->offset), + "non-empty text node should not be a child of algorithm step list"); + } }, - move(ignore_comments))); + [&](auto const&) {}); } - result.m_expression = make_ref_counted(move(step_expressions)); + if (!all_steps_parsed) + return {}; + result.m_expression = make_ref_counted(move(step_expressions)); return result; } @@ -134,18 +152,14 @@ Optional Algorithm::create(SpecificationParsingContext& ctx, XML::Nod return {}; } - auto steps_creation_result = AlgorithmStepList::create(steps_list[0]->as_element()); - if (steps_creation_result.is_error()) { - // TODO: Integrate backtracing parser errors better - ctx.diag().error(ctx.location_from_xml_offset(steps_creation_result.error()->offset()), - "{}", steps_creation_result.error()->to_string()); - return {}; + auto steps_creation_result = AlgorithmStepList::create(ctx, steps_list[0]); + if (steps_creation_result.has_value()) { + Algorithm algorithm; + algorithm.m_steps = steps_creation_result.release_value(); + algorithm.m_tree = algorithm.m_steps.m_expression; + return algorithm; } - - Algorithm algorithm; - algorithm.m_steps = steps_creation_result.release_value(); - algorithm.m_tree = algorithm.m_steps.m_expression; - return algorithm; + return {}; } NonnullOwnPtr SpecificationClause::create(SpecificationParsingContext& ctx, XML::Node const* element) diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h index c53e95dfff..a3fb5b70a2 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h @@ -43,7 +43,7 @@ private: class AlgorithmStepList { public: - static ParseErrorOr create(XML::Node::Element const& element); + static Optional create(SpecificationParsingContext& ctx, XML::Node const* element); Vector m_steps; Tree m_expression = error_tree; @@ -51,7 +51,7 @@ public: class AlgorithmStep { public: - static ParseErrorOr create(XML::Node const* node); + static ParseErrorOr create(SpecificationParsingContext& ctx, XML::Node const* node); ParseErrorOr parse();