diff --git a/Userland/Libraries/LibCpp/AST.cpp b/Userland/Libraries/LibCpp/AST.cpp index 9298d3dafd..1428c2624b 100644 --- a/Userland/Libraries/LibCpp/AST.cpp +++ b/Userland/Libraries/LibCpp/AST.cpp @@ -533,4 +533,36 @@ void CStyleCastExpression::dump(FILE* output, size_t indent) const m_expression->dump(output, indent + 1); } +void Constructor::dump(FILE* output, size_t indent) const +{ + print_indent(output, indent); + outln(output, "C'tor"); + print_indent(output, indent + 1); + outln(output, "("); + for (const auto& arg : m_parameters) { + arg.dump(output, indent + 1); + } + print_indent(output, indent + 1); + outln(output, ")"); + if (!m_definition.is_null()) { + m_definition->dump(output, indent + 1); + } +} + +void Destructor::dump(FILE* output, size_t indent) const +{ + print_indent(output, indent); + outln(output, "D'tor"); + print_indent(output, indent + 1); + outln(output, "("); + for (const auto& arg : m_parameters) { + arg.dump(output, indent + 1); + } + print_indent(output, indent + 1); + outln(output, ")"); + if (!m_definition.is_null()) { + m_definition->dump(output, indent + 1); + } +} + } diff --git a/Userland/Libraries/LibCpp/AST.h b/Userland/Libraries/LibCpp/AST.h index 7532740d7d..d0713808a9 100644 --- a/Userland/Libraries/LibCpp/AST.h +++ b/Userland/Libraries/LibCpp/AST.h @@ -146,6 +146,8 @@ public: virtual const char* class_name() const override { return "FunctionDeclaration"; } virtual void dump(FILE* = stdout, size_t indent = 0) const override; virtual bool is_function() const override { return true; } + virtual bool is_constructor() const { return false; } + virtual bool is_destructor() const { return false; } RefPtr definition() { return m_definition; } FunctionDeclaration(ASTNode* parent, Optional start, Optional end, const String& filename) @@ -721,4 +723,31 @@ public: virtual const char* class_name() const override { return "DummyAstNode"; } virtual void dump(FILE* = stdout, size_t = 0) const override { } }; + +class Constructor : public FunctionDeclaration { +public: + virtual ~Constructor() override = default; + virtual const char* class_name() const override { return "Constructor"; } + virtual void dump(FILE* = stdout, size_t indent = 0) const override; + virtual bool is_constructor() const override { return true; } + + Constructor(ASTNode* parent, Optional start, Optional end, const String& filename) + : FunctionDeclaration(parent, start, end, filename) + { + } +}; + +class Destructor : public FunctionDeclaration { +public: + virtual ~Destructor() override = default; + virtual const char* class_name() const override { return "Destructor"; } + virtual void dump(FILE* = stdout, size_t indent = 0) const override; + virtual bool is_destructor() const override { return true; } + + Destructor(ASTNode* parent, Optional start, Optional end, const String& filename) + : FunctionDeclaration(parent, start, end, filename) + { + } +}; + } diff --git a/Userland/Libraries/LibCpp/Parser.cpp b/Userland/Libraries/LibCpp/Parser.cpp index 419ad2bdbc..0eee97958a 100644 --- a/Userland/Libraries/LibCpp/Parser.cpp +++ b/Userland/Libraries/LibCpp/Parser.cpp @@ -103,6 +103,10 @@ NonnullRefPtr Parser::parse_declaration(ASTNode& parent, Declaratio return parse_class_declaration(parent); case DeclarationType::Namespace: return parse_namespace_declaration(parent); + case DeclarationType::Constructor: + return parse_constructor(parent); + case DeclarationType::Destructor: + return parse_destructor(parent); default: error("unexpected declaration type"); return create_ast_node(parent, position(), position()); @@ -631,7 +635,7 @@ Optional Parser::match_declaration_in_translation_unit( return {}; } -Optional Parser::match_class_member() +Optional Parser::match_class_member(const StringView& class_name) { if (match_function_declaration()) return DeclarationType::Function; @@ -641,6 +645,10 @@ Optional Parser::match_class_member() return DeclarationType::Class; if (match_variable_declaration()) return DeclarationType::Variable; + if (match_constructor(class_name)) + return DeclarationType::Constructor; + if (match_destructor(class_name)) + return DeclarationType::Destructor; return {}; } @@ -1436,13 +1444,15 @@ NonnullRefPtr Parser::parse_braced_init_list(ASTNode& parent) init_list->set_end(position()); return init_list; } -NonnullRefPtrVector Parser::parse_class_members(ASTNode& parent) +NonnullRefPtrVector Parser::parse_class_members(StructOrClassDeclaration& parent) { + auto& class_name = parent.name(); + NonnullRefPtrVector members; while (!eof() && peek().type() != Token::Type::RightCurly) { if (match_access_specifier()) consume_access_specifier(); // FIXME: Do not ignore access specifiers - auto member_type = match_class_member(); + auto member_type = match_class_member(class_name); if (member_type.has_value()) { members.append(parse_declaration(parent, member_type.value())); } else { @@ -1467,4 +1477,100 @@ void Parser::consume_access_specifier() consume(Token::Type::Colon); } +bool Parser::match_constructor(const StringView& class_name) +{ + save_state(); + ScopeGuard state_guard = [this] { load_state(); }; + + auto token = consume(); + if (token.text() != class_name) + return false; + + if (!peek(Token::Type::LeftParen).has_value()) + return false; + consume(); + + while (consume().type() != Token::Type::RightParen && !eof()) { }; + + return (peek(Token::Type::Semicolon).has_value() || peek(Token::Type::LeftCurly).has_value()); +} + +bool Parser::match_destructor(const StringView& class_name) +{ + save_state(); + ScopeGuard state_guard = [this] { load_state(); }; + + if (!match(Token::Type::Tilde)) + return false; + consume(); + + auto token = peek(); + + if (token.text() != class_name) + return false; + consume(); + + if (!peek(Token::Type::LeftParen).has_value()) + return false; + consume(); + + while (consume().type() != Token::Type::RightParen && !eof()) { }; + + return (peek(Token::Type::Semicolon).has_value() || peek(Token::Type::LeftCurly).has_value()); +} + +void Parser::parse_constructor_or_destructor_impl(FunctionDeclaration& func, CtorOrDtor type) +{ + if (type == CtorOrDtor::Dtor) + consume(Token::Type::Tilde); + + auto name_token = consume(); + if (name_token.type() != Token::Type::Identifier && name_token.type() != Token::Type::KnownType) { + error("Unexpected constructor name"); + } + func.m_name = name_token.text(); + + consume(Token::Type::LeftParen); + auto parameters = parse_parameter_list(func); + if (parameters.has_value()) { + if (type == CtorOrDtor::Dtor && !parameters->is_empty()) + error("Destructor declaration that takes parameters"); + else + func.m_parameters = move(parameters.value()); + } + + consume(Token::Type::RightParen); + + // TODO: Parse =default, =delete. + + RefPtr body; + Position ctor_end {}; + if (peek(Token::Type::LeftCurly).has_value()) { + body = parse_function_definition(func); + ctor_end = body->end(); + } else { + ctor_end = position(); + if (match_attribute_specification()) + consume_attribute_specification(); // we don't use the value of __attribute__ + consume(Token::Type::Semicolon); + } + + func.m_definition = move(body); + func.set_end(ctor_end); +} + +NonnullRefPtr Parser::parse_constructor(ASTNode& parent) +{ + auto ctor = create_ast_node(parent, position(), {}); + parse_constructor_or_destructor_impl(*ctor, CtorOrDtor::Ctor); + return ctor; +} + +NonnullRefPtr Parser::parse_destructor(ASTNode& parent) +{ + auto ctor = create_ast_node(parent, position(), {}); + parse_constructor_or_destructor_impl(*ctor, CtorOrDtor::Dtor); + return ctor; +} + } diff --git a/Userland/Libraries/LibCpp/Parser.h b/Userland/Libraries/LibCpp/Parser.h index 509e9d336b..22e294fbf0 100644 --- a/Userland/Libraries/LibCpp/Parser.h +++ b/Userland/Libraries/LibCpp/Parser.h @@ -49,10 +49,13 @@ private: Enum, Class, Namespace, + Constructor, + Destructor, }; Optional match_declaration_in_translation_unit(); - Optional match_class_member(); + Optional match_class_member(const StringView& class_name); + bool match_function_declaration(); bool match_comment(); bool match_preprocessor(); @@ -76,6 +79,8 @@ private: bool match_braced_init_list(); bool match_type(); bool match_access_specifier(); + bool match_constructor(const StringView& class_name); + bool match_destructor(const StringView& class_name); Optional> parse_parameter_list(ASTNode& parent); Optional consume_whitespace(); @@ -113,7 +118,9 @@ 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); + NonnullRefPtrVector parse_class_members(StructOrClassDeclaration& parent); + NonnullRefPtr parse_constructor(ASTNode& parent); + NonnullRefPtr parse_destructor(ASTNode& parent); bool match(Token::Type); Token consume(Token::Type); @@ -170,6 +177,12 @@ private: Vector parse_type_qualifiers(); Vector parse_function_qualifiers(); + enum class CtorOrDtor { + Ctor, + Dtor, + }; + void parse_constructor_or_destructor_impl(FunctionDeclaration&, CtorOrDtor); + Preprocessor::Definitions m_preprocessor_definitions; String m_filename; Vector m_tokens;