Browse Source

LibCpp: Support non-field class members

Previously, we had a special ASTNode for class members,
"MemberDeclaration", which only represented fields.

This commit removes MemberDeclaration and instead uses regular
Declaration nodes for representing the members of a class.

This means that we can now also parse methods, inner-classes, and other
declarations that appear inside of a class.
Itamar 4 years ago
parent
commit
dcdb0c7035

+ 4 - 2
Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp

@@ -293,7 +293,9 @@ Vector<CppComprehensionEngine::PropertyInfo> CppComprehensionEngine::properties_
 
     Vector<PropertyInfo> properties;
     for (auto& member : struct_or_class.m_members) {
-        properties.append({ member.m_name, member.m_type });
+        if (!member.is_variable_declaration())
+            continue;
+        properties.append({ member.m_name, ((VariableDeclaration&)member).m_type });
     }
     return properties;
 }
@@ -453,7 +455,7 @@ RefPtr<Declaration> CppComprehensionEngine::find_declaration_of(const DocumentDa
         bool match_function = target_decl.value().type == TargetDeclaration::Function && symbol.declaration->is_function();
         bool match_variable = target_decl.value().type == TargetDeclaration::Variable && symbol.declaration->is_variable_declaration();
         bool match_type = target_decl.value().type == TargetDeclaration::Type && symbol.declaration->is_struct_or_class();
-        bool match_property = target_decl.value().type == TargetDeclaration::Property && symbol.declaration->is_member();
+        bool match_property = target_decl.value().type == TargetDeclaration::Property && symbol.declaration->parent()->is_declaration() && ((Declaration*)symbol.declaration->parent())->is_struct_or_class();
         bool match_parameter = target_decl.value().type == TargetDeclaration::Variable && symbol.declaration->is_parameter();
 
         if (match_property) {

+ 0 - 11
Userland/Libraries/LibCpp/AST.cpp

@@ -308,17 +308,6 @@ NonnullRefPtrVector<Declaration> StructOrClassDeclaration::declarations() const
     return declarations;
 }
 
-void MemberDeclaration::dump(FILE* output, size_t indent) const
-{
-    ASTNode::dump(output, indent);
-    m_type->dump(output, indent + 1);
-    print_indent(output, indent + 1);
-    outln(output, "{}", m_name);
-    if (m_initial_value) {
-        m_initial_value->dump(output, indent + 2);
-    }
-}
-
 void UnaryExpression::dump(FILE* output, size_t indent) const
 {
     ASTNode::dump(output, indent);

+ 1 - 17
Userland/Libraries/LibCpp/AST.h

@@ -506,22 +506,6 @@ public:
     Vector<StringView> m_entries;
 };
 
-class MemberDeclaration : public Declaration {
-public:
-    virtual ~MemberDeclaration() override = default;
-    virtual const char* class_name() const override { return "MemberDeclaration"; }
-    virtual void dump(FILE* = stdout, size_t indent = 0) const override;
-    virtual bool is_member() const override { return true; }
-
-    MemberDeclaration(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
-        : Declaration(parent, start, end, filename)
-    {
-    }
-
-    RefPtr<Type> m_type;
-    RefPtr<Expression> m_initial_value;
-};
-
 class StructOrClassDeclaration : public Declaration {
 public:
     virtual ~StructOrClassDeclaration() override = default;
@@ -544,7 +528,7 @@ public:
     }
 
     StructOrClassDeclaration::Type m_type;
-    NonnullRefPtrVector<MemberDeclaration> m_members;
+    NonnullRefPtrVector<Declaration> m_members;
 };
 
 enum class UnaryOp {

+ 59 - 39
Userland/Libraries/LibCpp/Parser.cpp

@@ -100,9 +100,7 @@ NonnullRefPtr<Declaration> Parser::parse_declaration(ASTNode& parent, Declaratio
     case DeclarationType::Enum:
         return parse_enum_declaration(parent);
     case DeclarationType::Class:
-        return parse_struct_or_class_declaration(parent, StructOrClassDeclaration::Type::Class);
-    case DeclarationType::Struct:
-        return parse_struct_or_class_declaration(parent, StructOrClassDeclaration::Type::Struct);
+        return parse_class_declaration(parent);
     case DeclarationType::Namespace:
         return parse_namespace_declaration(parent);
     default:
@@ -306,6 +304,9 @@ bool Parser::match_variable_declaration()
         return true;
     }
 
+    if (match_braced_init_list())
+        parse_braced_init_list(get_dummy_node());
+
     return match(Token::Type::Semicolon);
 }
 
@@ -327,6 +328,10 @@ NonnullRefPtr<VariableDeclaration> Parser::parse_variable_declaration(ASTNode& p
         initial_value = parse_expression(var);
     }
 
+    if (match_braced_init_list()) {
+        initial_value = parse_braced_init_list(var);
+    }
+
     if (expect_semicolon)
         consume(Token::Type::Semicolon);
 
@@ -619,8 +624,6 @@ Optional<Parser::DeclarationType> Parser::match_declaration_in_translation_unit(
         return DeclarationType::Enum;
     if (match_class_declaration())
         return DeclarationType::Class;
-    if (match_struct_declaration())
-        return DeclarationType::Struct;
     if (match_namespace_declaration())
         return DeclarationType::Namespace;
     if (match_variable_declaration())
@@ -628,6 +631,19 @@ Optional<Parser::DeclarationType> Parser::match_declaration_in_translation_unit(
     return {};
 }
 
+Optional<Parser::DeclarationType> Parser::match_class_member()
+{
+    if (match_function_declaration())
+        return DeclarationType::Function;
+    if (match_enum_declaration())
+        return DeclarationType::Enum;
+    if (match_class_declaration())
+        return DeclarationType::Class;
+    if (match_variable_declaration())
+        return DeclarationType::Variable;
+    return {};
+}
+
 bool Parser::match_enum_declaration()
 {
     return match_keyword("enum");
@@ -635,12 +651,19 @@ bool Parser::match_enum_declaration()
 
 bool Parser::match_class_declaration()
 {
-    return match_keyword("class");
-}
+    save_state();
+    ScopeGuard state_guard = [this] { load_state(); };
 
-bool Parser::match_struct_declaration()
-{
-    return match_keyword("struct");
+    if (!match_keyword("struct") && !match_keyword("class"))
+        return false;
+    consume(Token::Type::Keyword);
+
+    if (!match(Token::Type::Identifier))
+        return false;
+
+    consume(Token::Type::Identifier);
+
+    return match(Token::Type::LeftCurly);
 }
 
 bool Parser::match_namespace_declaration()
@@ -1023,25 +1046,27 @@ bool Parser::match_keyword(const String& keyword)
     return true;
 }
 
-NonnullRefPtr<StructOrClassDeclaration> Parser::parse_struct_or_class_declaration(ASTNode& parent, StructOrClassDeclaration::Type type)
+NonnullRefPtr<StructOrClassDeclaration> Parser::parse_class_declaration(ASTNode& parent)
 {
     ScopeLogger<CPP_DEBUG> logger;
+
+    auto type_token = consume(Token::Type::Keyword);
+    StructOrClassDeclaration::Type type {};
+
+    if (type_token.text() == "struct")
+        type = StructOrClassDeclaration::Type::Struct;
+    if (type_token.text() == "class")
+        type = StructOrClassDeclaration::Type::Class;
+
     auto decl = create_ast_node<StructOrClassDeclaration>(parent, position(), {}, type);
-    switch (type) {
-    case StructOrClassDeclaration::Type::Struct:
-        consume_keyword("struct");
-        break;
-    case StructOrClassDeclaration::Type::Class:
-        consume_keyword("class");
-        break;
-    }
+
     auto name_token = consume(Token::Type::Identifier);
     decl->m_name = text_of_token(name_token);
 
     consume(Token::Type::LeftCurly);
 
     while (!eof() && peek().type() != Token::Type::RightCurly) {
-        decl->m_members.append(parse_member_declaration(*decl));
+        decl->m_members = parse_class_members(*decl);
     }
 
     consume(Token::Type::RightCurly);
@@ -1050,25 +1075,6 @@ NonnullRefPtr<StructOrClassDeclaration> Parser::parse_struct_or_class_declaratio
     return decl;
 }
 
-NonnullRefPtr<MemberDeclaration> Parser::parse_member_declaration(ASTNode& parent)
-{
-    ScopeLogger<CPP_DEBUG> logger;
-    auto member_decl = create_ast_node<MemberDeclaration>(parent, position(), {});
-    member_decl->m_type = parse_type(*member_decl);
-
-    auto identifier_token = consume(Token::Type::Identifier);
-    member_decl->m_name = text_of_token(identifier_token);
-
-    if (match_braced_init_list()) {
-        member_decl->m_initial_value = parse_braced_init_list(*member_decl);
-    }
-
-    consume(Token::Type::Semicolon);
-    member_decl->set_end(position());
-
-    return member_decl;
-}
-
 NonnullRefPtr<BooleanLiteral> Parser::parse_boolean_literal(ASTNode& parent)
 {
     ScopeLogger<CPP_DEBUG> logger;
@@ -1429,5 +1435,19 @@ NonnullRefPtr<BracedInitList> Parser::parse_braced_init_list(ASTNode& parent)
     init_list->set_end(position());
     return init_list;
 }
+NonnullRefPtrVector<Declaration> Parser::parse_class_members(ASTNode& parent)
+{
+    NonnullRefPtrVector<Declaration> members;
+    while (!eof() && peek().type() != Token::Type::RightCurly) {
+        auto member_type = match_class_member();
+        if (member_type.has_value()) {
+            members.append(parse_declaration(parent, member_type.value()));
+        } else {
+            error("Expected class member");
+            consume();
+        }
+    }
+    return members;
+}
 
 }

+ 4 - 5
Userland/Libraries/LibCpp/Parser.h

@@ -47,12 +47,12 @@ private:
         Function,
         Variable,
         Enum,
-        Struct,
-        Namespace,
         Class,
+        Namespace,
     };
 
     Optional<DeclarationType> match_declaration_in_translation_unit();
+    Optional<Parser::DeclarationType> match_class_member();
     bool match_function_declaration();
     bool match_comment();
     bool match_preprocessor();
@@ -62,7 +62,6 @@ private:
     bool match_secondary_expression();
     bool match_enum_declaration();
     bool match_class_declaration();
-    bool match_struct_declaration();
     bool match_literal();
     bool match_unary_expression();
     bool match_boolean_literal();
@@ -93,8 +92,7 @@ private:
     NonnullRefPtr<StringLiteral> parse_string_literal(ASTNode& parent);
     NonnullRefPtr<ReturnStatement> parse_return_statement(ASTNode& parent);
     NonnullRefPtr<EnumDeclaration> parse_enum_declaration(ASTNode& parent);
-    NonnullRefPtr<StructOrClassDeclaration> parse_struct_or_class_declaration(ASTNode& parent, StructOrClassDeclaration::Type);
-    NonnullRefPtr<MemberDeclaration> parse_member_declaration(ASTNode& parent);
+    NonnullRefPtr<StructOrClassDeclaration> parse_class_declaration(ASTNode& parent);
     NonnullRefPtr<Expression> parse_literal(ASTNode& parent);
     NonnullRefPtr<UnaryExpression> parse_unary_expression(ASTNode& parent);
     NonnullRefPtr<BooleanLiteral> parse_boolean_literal(ASTNode& parent);
@@ -114,6 +112,7 @@ private:
     NonnullRefPtr<SizeofExpression> parse_sizeof_expression(ASTNode& parent);
     NonnullRefPtr<BracedInitList> parse_braced_init_list(ASTNode& parent);
     NonnullRefPtr<CStyleCastExpression> parse_c_style_cast_expression(ASTNode& parent);
+    NonnullRefPtrVector<Declaration> parse_class_members(ASTNode& parent);
 
     bool match(Token::Type);
     Token consume(Token::Type);

+ 3 - 3
Userland/Libraries/LibCpp/Tests/struct.ast

@@ -1,11 +1,11 @@
 TranslationUnit[1:0->12:0]
-  StructOrClassDeclaration[1:0->7:0]
+  StructOrClassDeclaration[1:7->7:0]
   MyStruct
-    MemberDeclaration[3:4->4:4]
+    VariableDeclaration[3:4->4:4]
       Type[3:4->3:8]
         int
       x
-    MemberDeclaration[4:4->5:0]
+    VariableDeclaration[4:4->5:0]
       Pointer[4:12->4:14]
         Type[4:4->4:12]
           s