/* * Copyright (c) 2023-2024, Dan Klishch * * SPDX-License-Identifier: BSD-2-Clause */ #include "Parser/Lexer.h" #include "Parser/SpecificationParsing.h" #include "Parser/XMLUtils.h" namespace JSSpecCompiler { NonnullOwnPtr SpecificationClause::create(SpecificationParsingContext& ctx, XML::Node const* element) { return ctx.with_new_logical_scope([&] { VERIFY(element->as_element().name == tag_emu_clause); SpecificationClause specification_clause(ctx); specification_clause.parse(element); OwnPtr result; specification_clause.m_header.header.visit( [&](AK::Empty const&) { result = make(move(specification_clause)); }, [&](OneOf auto const&) { result = make(move(specification_clause)); }); if (!result->post_initialize(element)) result = make(move(*result)); return result.release_nonnull(); }); } void SpecificationClause::collect_into(TranslationUnitRef translation_unit) { do_collect(translation_unit); for (auto& subclause : m_subclauses) subclause->collect_into(translation_unit); } Optional SpecificationClause::parse_header(XML::Node const* element) { auto& ctx = *m_ctx_pointer; VERIFY(element->as_element().name == tag_h1); auto maybe_tokens = tokenize_header(ctx, element); if (!maybe_tokens.has_value()) return {}; auto const& tokens = maybe_tokens.release_value(); TextParser parser(ctx, tokens, element); auto parse_result = parser.parse_clause_header(m_clause_has_aoid_attribute); if (parse_result.is_error()) { // Still try to at least scavenge section number. if (tokens.size() && tokens[0].type == TokenType::SectionNumber) ctx.current_logical_scope().section = MUST(String::from_utf8(tokens[0].data)); return parser.get_diagnostic(); } m_header = parse_result.release_value(); ctx.current_logical_scope().section = MUST(String::from_utf8(m_header.section_number)); return {}; } void SpecificationClause::parse(XML::Node const* element) { auto& ctx = context(); u32 child_index = 0; bool node_ignored_warning_issued = false; Optional header_parse_error; m_clause_has_aoid_attribute = element->as_element().attributes.get("aoid").has_value() ? TextParser::ClauseHasAoidAttribute::Yes : TextParser::ClauseHasAoidAttribute::No; for (auto const& child : element->as_element().children) { child->content.visit( [&](XML::Node::Element const& element) { if (child_index == 0) { if (element.name != tag_h1) { ctx.diag().error(ctx.location_from_xml_offset(child->offset), "

must be the first child of "); return; } header_parse_error = parse_header(child); } else { if (element.name == tag_h1) { ctx.diag().error(ctx.location_from_xml_offset(child->offset), "

can only be the first child of "); return; } if (element.name == tag_emu_clause) { m_subclauses.append(create(ctx, child)); return; } if (!node_ignored_warning_issued && m_header.header.has()) { node_ignored_warning_issued = true; ctx.diag().warn(ctx.location_from_xml_offset(child->offset), "node content will be ignored since section header was not parsed successfully"); if (header_parse_error.has_value()) ctx.diag().note(header_parse_error->location, "{}", header_parse_error->message); } } ++child_index; }, [&](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 "); } }, [&](auto) {}); } } }