SpecParser.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /*
  2. * Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/NonnullOwnPtr.h>
  7. #include "Parser/Lexer.h"
  8. #include "Parser/SpecParser.h"
  9. #include "Parser/TextParser.h"
  10. #include "Parser/XMLUtils.h"
  11. namespace JSSpecCompiler {
  12. ParseErrorOr<AlgorithmStep> AlgorithmStep::create(XML::Node const* node)
  13. {
  14. VERIFY(node->as_element().name == tag_li);
  15. auto [tokens, substeps] = TRY(tokenize_tree(node, true));
  16. AlgorithmStep result { .m_tokens = move(tokens), .m_node = node };
  17. if (substeps)
  18. result.m_substeps = TRY(AlgorithmStepList::create(substeps->as_element())).m_expression;
  19. result.m_expression = TRY(result.parse());
  20. return result;
  21. }
  22. ParseErrorOr<Tree> AlgorithmStep::parse()
  23. {
  24. TextParser parser(m_tokens, m_node);
  25. if (m_substeps)
  26. return parser.parse_step_with_substeps(RefPtr(m_substeps).release_nonnull());
  27. else
  28. return parser.parse_step_without_substeps();
  29. }
  30. ParseErrorOr<AlgorithmStepList> AlgorithmStepList::create(XML::Node::Element const& element)
  31. {
  32. VERIFY(element.name == tag_ol);
  33. AlgorithmStepList result;
  34. auto& steps = result.m_steps;
  35. Vector<Tree> step_expressions;
  36. for (auto const& child : element.children) {
  37. TRY(child->content.visit(
  38. [&](XML::Node::Element const& element) -> ParseErrorOr<void> {
  39. if (element.name != tag_li)
  40. return ParseError::create("<emu-alg> <ol> > :not(<li>) should not match any elements"sv, child);
  41. steps.append(TRY(AlgorithmStep::create(child)));
  42. step_expressions.append(steps.last().m_expression);
  43. return {};
  44. },
  45. [&](XML::Node::Text const&) -> ParseErrorOr<void> {
  46. if (!contains_empty_text(child))
  47. return ParseError::create("<emu-alg> <ol> should not have non-empty child text nodes"sv, child);
  48. return {};
  49. },
  50. move(ignore_comments)));
  51. }
  52. result.m_expression = make_ref_counted<TreeList>(move(step_expressions));
  53. return result;
  54. }
  55. ParseErrorOr<Algorithm> Algorithm::create(XML::Node const* node)
  56. {
  57. VERIFY(node->as_element().name == tag_emu_alg);
  58. XML::Node::Element const* steps_list = nullptr;
  59. for (auto const& child : node->as_element().children) {
  60. TRY(child->content.visit(
  61. [&](XML::Node::Element const& element) -> ParseErrorOr<void> {
  62. if (element.name == tag_ol) {
  63. if (steps_list != nullptr)
  64. return ParseError::create("<emu-alg> should have exactly one <ol> child"sv, child);
  65. steps_list = &element;
  66. return {};
  67. } else {
  68. return ParseError::create("<emu-alg> should not have children other than <ol>"sv, child);
  69. }
  70. },
  71. [&](XML::Node::Text const&) -> ParseErrorOr<void> {
  72. if (!contains_empty_text(child))
  73. return ParseError::create("<emu-alg> should not have non-empty child text nodes"sv, child);
  74. return {};
  75. },
  76. move(ignore_comments)));
  77. }
  78. if (steps_list == nullptr)
  79. return ParseError::create("<emu-alg> should have exactly one <ol> child"sv, node);
  80. Algorithm algorithm;
  81. algorithm.m_steps = TRY(AlgorithmStepList::create(*steps_list));
  82. algorithm.m_tree = algorithm.m_steps.m_expression;
  83. return algorithm;
  84. }
  85. ParseErrorOr<SpecFunction> SpecFunction::create(XML::Node const* element)
  86. {
  87. VERIFY(element->as_element().name == tag_emu_clause);
  88. SpecFunction result;
  89. result.m_id = TRY(get_attribute_by_name(element, attribute_id));
  90. result.m_name = TRY(get_attribute_by_name(element, attribute_aoid));
  91. u32 children_count = 0;
  92. bool has_definition = false;
  93. XML::Node const* algorithm_node = nullptr;
  94. XML::Node const* prose_node = nullptr;
  95. for (auto const& child : element->as_element().children) {
  96. TRY(child->content.visit(
  97. [&](XML::Node::Element const& element) -> ParseErrorOr<void> {
  98. ++children_count;
  99. if (element.name == tag_h1) {
  100. if (children_count != 1)
  101. return ParseError::create("<h1> should be the first child of a <emu-clause>"sv, child);
  102. TRY(result.parse_definition(child));
  103. has_definition = true;
  104. } else if (element.name == tag_p) {
  105. if (prose_node == nullptr)
  106. prose_node = child;
  107. } else if (element.name == tag_emu_alg) {
  108. algorithm_node = child;
  109. } else {
  110. return ParseError::create("Unknown child of <emu-clause>"sv, child);
  111. }
  112. return {};
  113. },
  114. [&](XML::Node::Text const&) -> ParseErrorOr<void> {
  115. if (!contains_empty_text(child)) {
  116. return ParseError::create("<emu-clause> should not have non-empty child text nodes"sv, child);
  117. }
  118. return {};
  119. },
  120. move(ignore_comments)));
  121. }
  122. if (algorithm_node == nullptr)
  123. return ParseError::create("No <emu-alg>"sv, element);
  124. if (prose_node == nullptr)
  125. return ParseError::create("No prose element"sv, element);
  126. if (!has_definition)
  127. return ParseError::create("Definition was not found"sv, element);
  128. result.m_algorithm = TRY(Algorithm::create(algorithm_node));
  129. return result;
  130. }
  131. ParseErrorOr<void> SpecFunction::parse_definition(XML::Node const* element)
  132. {
  133. auto tokens = TRY(tokenize_tree(element));
  134. TextParser parser(tokens.tokens, element);
  135. auto [section_number, function_name, arguments] = TRY(parser.parse_definition());
  136. if (function_name != m_name)
  137. return ParseError::create("Function name in definition differs from <emu-clause>[aoid]"sv, element);
  138. m_section_number = section_number;
  139. for (auto const& argument : arguments)
  140. m_arguments.append({ argument });
  141. return {};
  142. }
  143. }