From dcdb0c7035d78ca8dedfe33372a6b39e63660028 Mon Sep 17 00:00:00 2001 From: Itamar Date: Sat, 5 Jun 2021 17:57:13 +0300 Subject: [PATCH] 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. --- .../Cpp/CppComprehensionEngine.cpp | 6 +- Userland/Libraries/LibCpp/AST.cpp | 11 --- Userland/Libraries/LibCpp/AST.h | 18 +--- Userland/Libraries/LibCpp/Parser.cpp | 98 +++++++++++-------- Userland/Libraries/LibCpp/Parser.h | 9 +- Userland/Libraries/LibCpp/Tests/struct.ast | 6 +- 6 files changed, 71 insertions(+), 77 deletions(-) diff --git a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp index 04fb565436..acfab18d8e 100644 --- a/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp +++ b/Userland/DevTools/HackStudio/LanguageServers/Cpp/CppComprehensionEngine.cpp @@ -293,7 +293,9 @@ Vector CppComprehensionEngine::properties_ Vector 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 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) { diff --git a/Userland/Libraries/LibCpp/AST.cpp b/Userland/Libraries/LibCpp/AST.cpp index 344858d7e0..9298d3dafd 100644 --- a/Userland/Libraries/LibCpp/AST.cpp +++ b/Userland/Libraries/LibCpp/AST.cpp @@ -308,17 +308,6 @@ NonnullRefPtrVector 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); diff --git a/Userland/Libraries/LibCpp/AST.h b/Userland/Libraries/LibCpp/AST.h index bd77a2a343..7532740d7d 100644 --- a/Userland/Libraries/LibCpp/AST.h +++ b/Userland/Libraries/LibCpp/AST.h @@ -506,22 +506,6 @@ public: Vector 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 start, Optional end, const String& filename) - : Declaration(parent, start, end, filename) - { - } - - RefPtr m_type; - RefPtr m_initial_value; -}; - class StructOrClassDeclaration : public Declaration { public: virtual ~StructOrClassDeclaration() override = default; @@ -544,7 +528,7 @@ public: } StructOrClassDeclaration::Type m_type; - NonnullRefPtrVector m_members; + NonnullRefPtrVector m_members; }; enum class UnaryOp { diff --git a/Userland/Libraries/LibCpp/Parser.cpp b/Userland/Libraries/LibCpp/Parser.cpp index d93b977dca..0b7c5c4483 100644 --- a/Userland/Libraries/LibCpp/Parser.cpp +++ b/Userland/Libraries/LibCpp/Parser.cpp @@ -100,9 +100,7 @@ NonnullRefPtr 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 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::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::match_declaration_in_translation_unit( return {}; } +Optional 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 Parser::parse_struct_or_class_declaration(ASTNode& parent, StructOrClassDeclaration::Type type) +NonnullRefPtr Parser::parse_class_declaration(ASTNode& parent) { ScopeLogger 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(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 Parser::parse_struct_or_class_declaratio return decl; } -NonnullRefPtr Parser::parse_member_declaration(ASTNode& parent) -{ - ScopeLogger logger; - auto member_decl = create_ast_node(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 Parser::parse_boolean_literal(ASTNode& parent) { ScopeLogger logger; @@ -1429,5 +1435,19 @@ NonnullRefPtr Parser::parse_braced_init_list(ASTNode& parent) init_list->set_end(position()); return init_list; } +NonnullRefPtrVector Parser::parse_class_members(ASTNode& parent) +{ + NonnullRefPtrVector 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; +} } diff --git a/Userland/Libraries/LibCpp/Parser.h b/Userland/Libraries/LibCpp/Parser.h index 6296722946..a99d965452 100644 --- a/Userland/Libraries/LibCpp/Parser.h +++ b/Userland/Libraries/LibCpp/Parser.h @@ -47,12 +47,12 @@ private: Function, Variable, Enum, - Struct, - Namespace, Class, + Namespace, }; Optional match_declaration_in_translation_unit(); + Optional 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 parse_string_literal(ASTNode& parent); NonnullRefPtr parse_return_statement(ASTNode& parent); NonnullRefPtr parse_enum_declaration(ASTNode& parent); - NonnullRefPtr parse_struct_or_class_declaration(ASTNode& parent, StructOrClassDeclaration::Type); - NonnullRefPtr parse_member_declaration(ASTNode& parent); + NonnullRefPtr parse_class_declaration(ASTNode& parent); NonnullRefPtr parse_literal(ASTNode& parent); NonnullRefPtr parse_unary_expression(ASTNode& parent); NonnullRefPtr parse_boolean_literal(ASTNode& parent); @@ -114,6 +112,7 @@ private: NonnullRefPtr parse_sizeof_expression(ASTNode& parent); NonnullRefPtr parse_braced_init_list(ASTNode& parent); NonnullRefPtr parse_c_style_cast_expression(ASTNode& parent); + NonnullRefPtrVector parse_class_members(ASTNode& parent); bool match(Token::Type); Token consume(Token::Type); diff --git a/Userland/Libraries/LibCpp/Tests/struct.ast b/Userland/Libraries/LibCpp/Tests/struct.ast index 437686b344..7a90400743 100644 --- a/Userland/Libraries/LibCpp/Tests/struct.ast +++ b/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