Selaa lähdekoodia

JSSpecCompiler: Parse accessor property headers

Dan Klishch 1 vuosi sitten
vanhempi
commit
d1fc84c638

+ 26 - 18
Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecParser.cpp

@@ -239,7 +239,7 @@ NonnullOwnPtr<SpecificationClause> SpecificationClause::create(SpecificationPars
             [&](AK::Empty const&) {
                 result = make<SpecificationClause>(move(specification_clause));
             },
-            [&](ClauseHeader::FunctionDefinition const&) {
+            [&](OneOf<ClauseHeader::AbstractOperation, ClauseHeader::Accessor> auto const&) {
                 result = make<SpecFunction>(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<ClauseHeader::FunctionDefinition>();
-    m_arguments = arguments;
-
-    if (m_name != function_name) {
-        ctx.diag().warn(ctx.location_from_xml_offset(element->offset),
-            "function name in header and <emu-clause>[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 <emu-clause>[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<XML::Node const*> algorithm_nodes;
 
@@ -399,12 +407,12 @@ void SpecFunction::do_collect(TranslationUnitRef translation_unit)
     translation_unit->adopt_function(make_ref_counted<FunctionDefinition>(m_name, m_algorithm.tree(), move(m_arguments)));
 }
 
-Specification Specification::create(SpecificationParsingContext& ctx, XML::Node const* element)
+NonnullOwnPtr<Specification> 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>();
+    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);
 }
 }

+ 4 - 3
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<FunctionArgument> m_arguments;
     Algorithm m_algorithm;
@@ -142,7 +141,7 @@ private:
 
 class Specification {
 public:
-    static Specification create(SpecificationParsingContext& ctx, XML::Node const* element);
+    static NonnullOwnPtr<Specification> create(SpecificationParsingContext& ctx, XML::Node const* element);
 
     void collect_into(TranslationUnitRef translation_unit);
 
@@ -161,6 +160,8 @@ public:
 
 private:
     OwnPtr<XML::Document> m_document;
+    OwnPtr<Specification> m_specification;
+
     ByteBuffer m_input;
 };
 

+ 62 - 13
Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.cpp

@@ -599,34 +599,83 @@ TextParseErrorOr<Tree> TextParser::parse_step_with_substeps(Tree substeps)
     return TextParseError {};
 }
 
-TextParseErrorOr<ClauseHeader> TextParser::parse_clause_header()
+// <qualified_name> :== <word> (. <word>)*
+TextParseErrorOr<Vector<StringView>> 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<StringView> 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);
+    }
+}
 
+// <function_arguments> :== '(' (<word> (, <word>)*)? ')'
+TextParseErrorOr<Vector<FunctionArgument>> TextParser::parse_function_arguments_in_declaration()
+{
+    Vector<FunctionArgument> 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;
+}
+
+// <ao_declaration> :== <word> <function_arguments> $
+TextParseErrorOr<ClauseHeader::AbstractOperation> 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;
+}
+
+// <accessor_declaration> :== get <qualified_name> $
+TextParseErrorOr<ClauseHeader::Accessor> 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;
+}
+
+// <clause_header> :== <section_number> <ao_declaration> | <accessor_declaration>
+TextParseErrorOr<ClauseHeader> 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;
 }

+ 11 - 2
Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/TextParser.h

@@ -13,13 +13,17 @@
 namespace JSSpecCompiler {
 
 struct ClauseHeader {
-    struct FunctionDefinition {
+    struct AbstractOperation {
         StringView name;
         Vector<FunctionArgument> arguments;
     };
 
+    struct Accessor {
+        Vector<StringView> qualified_name;
+    };
+
     StringView section_number;
-    Variant<AK::Empty, FunctionDefinition> header;
+    Variant<AK::Empty, AbstractOperation, Accessor> header;
 };
 
 struct TextParseError { };
@@ -86,6 +90,11 @@ private:
     TextParseErrorOr<Tree> parse_if(Tree then_branch);
     TextParseErrorOr<Tree> parse_else(Tree else_branch);
 
+    TextParseErrorOr<Vector<StringView>> parse_qualified_name();
+    TextParseErrorOr<Vector<FunctionArgument>> parse_function_arguments_in_declaration();
+    TextParseErrorOr<ClauseHeader::AbstractOperation> parse_abstract_operation_declaration();
+    TextParseErrorOr<ClauseHeader::Accessor> parse_accessor_declaration();
+
     SpecificationParsingContext& m_ctx;
     Vector<Token> const& m_tokens;
     size_t m_next_token_index = 0;