SpecificationClause.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. /*
  2. * Copyright (c) 2023-2024, Dan Klishch <danilklishch@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "Parser/Lexer.h"
  7. #include "Parser/SpecificationParsing.h"
  8. #include "Parser/XMLUtils.h"
  9. namespace JSSpecCompiler {
  10. NonnullOwnPtr<SpecificationClause> SpecificationClause::create(SpecificationParsingContext& ctx, XML::Node const* element)
  11. {
  12. return ctx.with_new_logical_scope([&] {
  13. VERIFY(element->as_element().name == tag_emu_clause);
  14. SpecificationClause specification_clause(ctx);
  15. specification_clause.parse(element);
  16. OwnPtr<SpecificationClause> result;
  17. specification_clause.m_header.header.visit(
  18. [&](AK::Empty const&) {
  19. result = make<SpecificationClause>(move(specification_clause));
  20. },
  21. [&](OneOf<ClauseHeader::AbstractOperation, ClauseHeader::Accessor, ClauseHeader::Method> auto const&) {
  22. result = make<SpecificationFunction>(move(specification_clause));
  23. });
  24. if (!result->post_initialize(element))
  25. result = make<SpecificationClause>(move(*result));
  26. return result.release_nonnull();
  27. });
  28. }
  29. void SpecificationClause::collect_into(TranslationUnitRef translation_unit)
  30. {
  31. do_collect(translation_unit);
  32. for (auto& subclause : m_subclauses)
  33. subclause->collect_into(translation_unit);
  34. }
  35. Optional<FailedTextParseDiagnostic> SpecificationClause::parse_header(XML::Node const* element)
  36. {
  37. auto& ctx = *m_ctx_pointer;
  38. VERIFY(element->as_element().name == tag_h1);
  39. auto maybe_tokens = tokenize_header(ctx, element);
  40. if (!maybe_tokens.has_value())
  41. return {};
  42. auto const& tokens = maybe_tokens.release_value();
  43. TextParser parser(ctx, tokens, element);
  44. auto parse_result = parser.parse_clause_header(m_clause_has_aoid_attribute);
  45. if (parse_result.is_error()) {
  46. // Still try to at least scavenge section number.
  47. if (tokens.size() && tokens[0].type == TokenType::SectionNumber)
  48. ctx.current_logical_scope().section = MUST(String::from_utf8(tokens[0].data));
  49. return parser.get_diagnostic();
  50. }
  51. m_header = parse_result.release_value();
  52. ctx.current_logical_scope().section = MUST(String::from_utf8(m_header.section_number));
  53. return {};
  54. }
  55. void SpecificationClause::parse(XML::Node const* element)
  56. {
  57. auto& ctx = context();
  58. u32 child_index = 0;
  59. bool node_ignored_warning_issued = false;
  60. Optional<FailedTextParseDiagnostic> header_parse_error;
  61. m_clause_has_aoid_attribute = element->as_element().attributes.get("aoid").has_value()
  62. ? TextParser::ClauseHasAoidAttribute::Yes
  63. : TextParser::ClauseHasAoidAttribute::No;
  64. for (auto const& child : element->as_element().children) {
  65. child->content.visit(
  66. [&](XML::Node::Element const& element) {
  67. if (child_index == 0) {
  68. if (element.name != tag_h1) {
  69. ctx.diag().error(ctx.location_from_xml_offset(child->offset),
  70. "<h1> must be the first child of <emu-clause>");
  71. return;
  72. }
  73. header_parse_error = parse_header(child);
  74. } else {
  75. if (element.name == tag_h1) {
  76. ctx.diag().error(ctx.location_from_xml_offset(child->offset),
  77. "<h1> can only be the first child of <emu-clause>");
  78. return;
  79. }
  80. if (element.name == tag_emu_clause) {
  81. m_subclauses.append(create(ctx, child));
  82. return;
  83. }
  84. if (!node_ignored_warning_issued && m_header.header.has<AK::Empty>()) {
  85. node_ignored_warning_issued = true;
  86. ctx.diag().warn(ctx.location_from_xml_offset(child->offset),
  87. "node content will be ignored since section header was not parsed successfully");
  88. if (header_parse_error.has_value())
  89. ctx.diag().note(header_parse_error->location, "{}", header_parse_error->message);
  90. }
  91. }
  92. ++child_index;
  93. },
  94. [&](XML::Node::Text const&) {
  95. if (!contains_empty_text(child)) {
  96. ctx.diag().error(ctx.location_from_xml_offset(child->offset),
  97. "non-empty text node should not be a child of <emu-clause>");
  98. }
  99. },
  100. [&](auto) {});
  101. }
  102. }
  103. }