diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp index 6c008966a0816c6b58e8e7f848c6a7cced016424..5fc673f493c50ac34aab94f5e80ceb8d9ed04140 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp @@ -239,7 +239,7 @@ NonnullOwnPtr SpecificationClause::create(SpecificationPars [&](AK::Empty const&) { result = make(move(specification_clause)); }, - [&](ClauseHeader::FunctionDefinition const&) { + [&](OneOf auto const&) { result = make(move(specification_clause)); }); @@ -346,18 +346,26 @@ bool SpecFunction::post_initialize(XML::Node const* element) m_id = maybe_id.value(); } - auto maybe_abstract_operation_id = get_attribute_by_name(element, attribute_aoid); - if (maybe_abstract_operation_id.has_value()) - m_name = maybe_abstract_operation_id.value(); - - m_section_number = m_header.section_number; - auto const& [function_name, arguments] = m_header.header.get(); - m_arguments = arguments; - - if (m_name != function_name) { - ctx.diag().warn(ctx.location_from_xml_offset(element->offset), - "function name in header and [aoid] do not match"); - } + m_header.header.visit( + [&](ClauseHeader::AbstractOperation const& abstract_operation) { + auto maybe_abstract_operation_id = get_attribute_by_name(element, attribute_aoid); + if (maybe_abstract_operation_id.has_value()) + m_name = MUST(String::from_utf8(maybe_abstract_operation_id.value())); + + auto const& [function_name, arguments] = abstract_operation; + m_arguments = arguments; + + if (m_name != function_name) { + ctx.diag().warn(ctx.location_from_xml_offset(element->offset), + "function name in header and [aoid] do not match"); + } + }, + [&](ClauseHeader::Accessor const& accessor) { + m_name = MUST(String::formatted("%get {}%", MUST(String::join("."sv, accessor.qualified_name)))); + }, + [&](auto const&) { + VERIFY_NOT_REACHED(); + }); Vector algorithm_nodes; @@ -399,12 +407,12 @@ void SpecFunction::do_collect(TranslationUnitRef translation_unit) translation_unit->adopt_function(make_ref_counted(m_name, m_algorithm.tree(), move(m_arguments))); } -Specification Specification::create(SpecificationParsingContext& ctx, XML::Node const* element) +NonnullOwnPtr Specification::create(SpecificationParsingContext& ctx, XML::Node const* element) { VERIFY(element->as_element().name == tag_specification); - Specification specification; - specification.parse(ctx, element); + auto specification = make(); + specification->parse(ctx, element); return specification; } @@ -486,7 +494,7 @@ void SpecParsingStep::run(TranslationUnitRef translation_unit) return; } - auto specification = Specification::create(ctx, &root); - specification.collect_into(translation_unit); + m_specification = Specification::create(ctx, &root); + m_specification->collect_into(translation_unit); } } diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h index 26cd33a70706a49d3fb73279a02b162509c0fa0f..cc471c2aefe9a608d2ce49c656bd38f198f15d89 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.h @@ -132,9 +132,8 @@ protected: void do_collect(TranslationUnitRef translation_unit) override; private: - StringView m_section_number; StringView m_id; - StringView m_name; + String m_name; Vector m_arguments; Algorithm m_algorithm; @@ -142,7 +141,7 @@ private: class Specification { public: - static Specification create(SpecificationParsingContext& ctx, XML::Node const* element); + static NonnullOwnPtr create(SpecificationParsingContext& ctx, XML::Node const* element); void collect_into(TranslationUnitRef translation_unit); @@ -161,6 +160,8 @@ public: private: OwnPtr m_document; + OwnPtr m_specification; + ByteBuffer m_input; }; diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp index 1330cf0ff11dc23377327f050d9be6e365dd7970..6e637e000fa9ca91aa98c0c4ca4c55802c805335 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp @@ -599,34 +599,83 @@ TextParseErrorOr TextParser::parse_step_with_substeps(Tree substeps) return TextParseError {}; } -TextParseErrorOr TextParser::parse_clause_header() +// :== (. )* +TextParseErrorOr> TextParser::parse_qualified_name() { - ClauseHeader result; - - auto section_number_token = TRY(consume_token_with_type(TokenType::SectionNumber)); - result.section_number = section_number_token.data; - - ClauseHeader::FunctionDefinition function_definition; - - function_definition.name = TRY(consume_token_with_type(TokenType::Word)).data; + Vector qualified_name; + qualified_name.append(TRY(consume_token_with_type(TokenType::Word)).data); + while (true) { + auto token_or_error = consume_token_with_type(TokenType::MemberAccess); + if (token_or_error.is_error()) + return qualified_name; + qualified_name.append(TRY(consume_token_with_type(TokenType::Word)).data); + } +} +// :== '(' ( (, )*)? ')' +TextParseErrorOr> TextParser::parse_function_arguments_in_declaration() +{ + Vector arguments; TRY(consume_token_with_type(TokenType::ParenOpen)); while (true) { - if (function_definition.arguments.is_empty()) { + if (arguments.is_empty()) { auto argument = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Identifier })); if (argument.type == TokenType::ParenClose) break; - function_definition.arguments.append({ argument.data }); + arguments.append({ argument.data }); } else { - function_definition.arguments.append({ TRY(consume_token_with_type(TokenType::Identifier)).data }); + arguments.append({ TRY(consume_token_with_type(TokenType::Identifier)).data }); } auto next_token = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Comma })); if (next_token.type == TokenType::ParenClose) break; } + return arguments; +} + +// :== $ +TextParseErrorOr TextParser::parse_abstract_operation_declaration() +{ + auto rollback = rollback_point(); + + ClauseHeader::AbstractOperation function_definition; + function_definition.name = TRY(consume_token_with_type(TokenType::Word)).data; + function_definition.arguments = TRY(parse_function_arguments_in_declaration()); + TRY(expect_eof()); + + rollback.disarm(); + return function_definition; +} + +// :== get $ +TextParseErrorOr TextParser::parse_accessor_declaration() +{ + auto rollback = rollback_point(); + + TRY(consume_word("get"sv)); + ClauseHeader::Accessor accessor; + accessor.qualified_name = TRY(parse_qualified_name()); TRY(expect_eof()); - result.header = function_definition; + rollback.disarm(); + return accessor; +} + +// :== | +TextParseErrorOr TextParser::parse_clause_header() +{ + ClauseHeader result; + + auto section_number_token = TRY(consume_token_with_type(TokenType::SectionNumber)); + result.section_number = section_number_token.data; + + if (auto ao_declaration = parse_abstract_operation_declaration(); !ao_declaration.is_error()) { + result.header = ao_declaration.release_value(); + } else if (auto accessor = parse_accessor_declaration(); !accessor.is_error()) { + result.header = accessor.release_value(); + } else { + return TextParseError {}; + } return result; } diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h index c1a6655525270c4d7bced03df4a90c4f6ab4f13f..7142c1521baa5d987a5b9755f20ebd1dbc3bcd94 100644 --- a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h @@ -13,13 +13,17 @@ namespace JSSpecCompiler { struct ClauseHeader { - struct FunctionDefinition { + struct AbstractOperation { StringView name; Vector arguments; }; + struct Accessor { + Vector qualified_name; + }; + StringView section_number; - Variant header; + Variant header; }; struct TextParseError { }; @@ -86,6 +90,11 @@ private: TextParseErrorOr parse_if(Tree then_branch); TextParseErrorOr parse_else(Tree else_branch); + TextParseErrorOr> parse_qualified_name(); + TextParseErrorOr> parse_function_arguments_in_declaration(); + TextParseErrorOr parse_abstract_operation_declaration(); + TextParseErrorOr parse_accessor_declaration(); + SpecificationParsingContext& m_ctx; Vector const& m_tokens; size_t m_next_token_index = 0;