diff --git a/Userland/Libraries/LibCpp/AST.cpp b/Userland/Libraries/LibCpp/AST.cpp index 8c41c596d5..6e5a5e7c87 100644 --- a/Userland/Libraries/LibCpp/AST.cpp +++ b/Userland/Libraries/LibCpp/AST.cpp @@ -43,7 +43,7 @@ void ASTNode::dump(size_t indent) const void TranslationUnit::dump(size_t indent) const { ASTNode::dump(indent); - for (const auto& child : m_children) { + for (const auto& child : m_declarations) { child.dump(indent + 1); } } @@ -413,4 +413,14 @@ NonnullRefPtrVector IfStatement::declarations() const declarations.append(m_else->declarations()); return declarations; } + +void NamespaceDeclaration::dump(size_t indent) const +{ + ASTNode::dump(indent); + print_indent(indent + 1); + outln("{}", m_name); + for (auto& decl : m_declarations) + decl.dump(indent + 1); +} + } diff --git a/Userland/Libraries/LibCpp/AST.h b/Userland/Libraries/LibCpp/AST.h index 1dce0550a3..498ca566cb 100644 --- a/Userland/Libraries/LibCpp/AST.h +++ b/Userland/Libraries/LibCpp/AST.h @@ -96,23 +96,16 @@ class TranslationUnit : public ASTNode { public: virtual ~TranslationUnit() override = default; - const NonnullRefPtrVector& children() const { return m_children; } virtual const char* class_name() const override { return "TranslationUnit"; } virtual void dump(size_t indent) const override; - void append(NonnullRefPtr child) - { - m_children.append(move(child)); - } - virtual NonnullRefPtrVector declarations() const override { return m_children; } + virtual NonnullRefPtrVector declarations() const override { return m_declarations; } -public: TranslationUnit(ASTNode* parent, Optional start, Optional end, const String& filename) : ASTNode(parent, start, end, filename) { } -private: - NonnullRefPtrVector m_children; + NonnullRefPtrVector m_declarations; }; class Statement : public ASTNode { @@ -140,6 +133,7 @@ public: virtual bool is_struct() const { return false; } virtual bool is_class() const { return false; } virtual bool is_function() const { return false; } + virtual bool is_namespace() const { return false; } const StringView& name() const { return m_name; } StringView m_name; @@ -618,4 +612,22 @@ public: RefPtr m_else; }; +class NamespaceDeclaration : public Declaration { +public: + virtual ~NamespaceDeclaration() override = default; + virtual const char* class_name() const override { return "NamespaceDeclaration"; } + virtual void dump(size_t indent) const override; + virtual bool is_namespace() const override { return true; } + + NamespaceDeclaration(ASTNode* parent, Optional start, Optional end, const String& filename) + : Declaration(parent, start, end, filename) + { + } + + virtual NonnullRefPtrVector declarations() const override { return m_declarations; } + + StringView m_name; + NonnullRefPtrVector m_declarations; +}; + } diff --git a/Userland/Libraries/LibCpp/Parser.cpp b/Userland/Libraries/LibCpp/Parser.cpp index f968686c46..aebdc829c3 100644 --- a/Userland/Libraries/LibCpp/Parser.cpp +++ b/Userland/Libraries/LibCpp/Parser.cpp @@ -78,7 +78,28 @@ NonnullRefPtr Parser::parse() if (m_tokens.is_empty()) return create_root_ast_node({}, {}); auto unit = create_root_ast_node(m_tokens.first().start(), m_tokens.last().end()); - while (!done()) { + unit->m_declarations = parse_declarations_in_translation_unit(*unit); + return unit; +} + +NonnullRefPtrVector Parser::parse_declarations_in_translation_unit(ASTNode& parent) +{ + NonnullRefPtrVector declarations; + while (!eof()) { + auto declaration = parse_single_declaration_in_translation_unit(parent); + if (declaration) { + declarations.append(declaration.release_nonnull()); + } else { + error("unexpected token"); + consume(); + } + } + return declarations; +} + +RefPtr Parser::parse_single_declaration_in_translation_unit(ASTNode& parent) +{ + while (!eof()) { if (match_comment()) { consume(Token::Type::Comment); continue; @@ -89,29 +110,13 @@ NonnullRefPtr Parser::parse() continue; } - auto declaration = match_declaration(); + auto declaration = match_declaration_in_translation_unit(); if (declaration.has_value()) { - unit->append(parse_declaration(*unit, declaration.value())); - continue; + return parse_declaration(parent, declaration.value()); } - - error("unexpected token"); - consume(); - } - return unit; -} - -Optional Parser::match_declaration() -{ - switch (m_state.context) { - case Context::InTranslationUnit: - return match_declaration_in_translation_unit(); - case Context::InFunctionDefinition: - return match_declaration_in_function_definition(); - default: - error("unexpected context"); return {}; } + return {}; } NonnullRefPtr Parser::parse_declaration(ASTNode& parent, DeclarationType declaration_type) @@ -125,6 +130,8 @@ NonnullRefPtr Parser::parse_declaration(ASTNode& parent, Declaratio return parse_enum_declaration(parent); case DeclarationType::Struct: return parse_struct_or_class_declaration(parent, StructOrClassDeclaration::Type::Struct); + case DeclarationType::Namespace: + return parse_namespace_declaration(parent); default: error("unexpected declaration type"); return create_ast_node(parent, position(), position()); @@ -233,7 +240,7 @@ NonnullRefPtr Parser::parse_block_statement(ASTNode& parent) SCOPE_LOGGER(); auto block_statement = create_ast_node(parent, position(), {}); consume(Token::Type::LeftCurly); - while (peek().type() != Token::Type::RightCurly) { + while (!eof() && peek().type() != Token::Type::RightCurly) { block_statement->m_statements.append(parse_statement(*block_statement)); } consume(Token::Type::RightCurly); @@ -524,17 +531,24 @@ Optional Parser::match_declaration_in_translation_unit( return DeclarationType::Enum; if (match_struct_declaration()) return DeclarationType::Struct; + if (match_namespace_declaration()) + return DeclarationType::Namespace; return {}; } bool Parser::match_enum_declaration() { - return peek().type() == Token::Type::Keyword && text_of_token(peek()) == "enum"; + return match_keyword("enum"); } bool Parser::match_struct_declaration() { - return peek().type() == Token::Type::Keyword && text_of_token(peek()) == "struct"; + return match_keyword("struct"); +} + +bool Parser::match_namespace_declaration() +{ + return match_keyword("namespace"); } bool Parser::match_function_declaration() @@ -687,16 +701,6 @@ void Parser::load_state() m_state = m_saved_states.take_last(); } -Optional Parser::match_declaration_in_function_definition() -{ - VERIFY_NOT_REACHED(); -} - -bool Parser::done() -{ - return m_state.token_index == m_tokens.size(); -} - StringView Parser::text_of_token(const Cpp::Token& token) const { return token.text(); @@ -906,7 +910,7 @@ NonnullRefPtr Parser::parse_enum_declaration(ASTNode& parent) auto name_token = consume(Token::Type::Identifier); enum_decl->m_name = text_of_token(name_token); consume(Token::Type::LeftCurly); - while (peek().type() != Token::Type::RightCurly && !eof()) { + while (!eof() && peek().type() != Token::Type::RightCurly) { enum_decl->m_entries.append(text_of_token(consume(Token::Type::Identifier))); if (peek().type() != Token::Type::Comma) { break; @@ -962,7 +966,7 @@ NonnullRefPtr Parser::parse_struct_or_class_declaratio consume(Token::Type::LeftCurly); - while (peek().type() != Token::Type::RightCurly && !eof()) { + while (!eof() && peek().type() != Token::Type::RightCurly) { decl->m_members.append(parse_member_declaration(*decl)); } @@ -1073,7 +1077,7 @@ Vector Parser::parse_type_qualifiers() { SCOPE_LOGGER(); Vector qualifiers; - while (!done()) { + while (!eof()) { auto token = peek(); if (token.type() != Token::Type::Keyword) break; @@ -1096,7 +1100,7 @@ void Parser::consume_attribute_specification() consume(); // __attribute__ consume(Token::Type::LeftParen); size_t left_count = 1; - while (!done()) { + while (!eof()) { auto token = consume(); if (token.type() == Token::Type::LeftParen) { ++left_count; @@ -1129,4 +1133,36 @@ void Parser::add_tokens_for_preprocessor(Token& replaced_token, Preprocessor::De } } +NonnullRefPtr Parser::parse_namespace_declaration(ASTNode& parent, bool is_nested_namespace) +{ + auto namespace_decl = create_ast_node(parent, position(), {}); + + if (!is_nested_namespace) + consume(Token::Type::Keyword); + + auto name_token = consume(Token::Type::Identifier); + namespace_decl->m_name = name_token.text(); + + if (peek().type() == Token::Type::ColonColon) { + consume(Token::Type::ColonColon); + namespace_decl->m_declarations.append(parse_namespace_declaration(*namespace_decl, true)); + namespace_decl->set_end(position()); + return namespace_decl; + } + + consume(Token::Type::LeftCurly); + while (!eof() && peek().type() != Token::Type::RightCurly) { + auto declaration = parse_single_declaration_in_translation_unit(*namespace_decl); + if (declaration) { + namespace_decl->m_declarations.append(declaration.release_nonnull()); + } else { + error("unexpected token"); + consume(); + } + } + consume(Token::Type::RightCurly); + namespace_decl->set_end(position()); + return namespace_decl; +} + } diff --git a/Userland/Libraries/LibCpp/Parser.h b/Userland/Libraries/LibCpp/Parser.h index bab5f28045..4511e09bda 100644 --- a/Userland/Libraries/LibCpp/Parser.h +++ b/Userland/Libraries/LibCpp/Parser.h @@ -68,13 +68,10 @@ private: Variable, Enum, Struct, + Namespace, }; - bool done(); - - Optional match_declaration(); Optional match_declaration_in_translation_unit(); - Optional match_declaration_in_function_definition(); bool match_function_declaration(); bool match_comment(); bool match_preprocessor(); @@ -90,6 +87,7 @@ private: bool match_boolean_literal(); bool match_keyword(const String&); bool match_block_statement(); + bool match_namespace_declaration(); Optional> parse_parameter_list(ASTNode& parent); Optional consume_whitespace(); @@ -119,6 +117,10 @@ private: NonnullRefPtr parse_block_statement(ASTNode& parent); NonnullRefPtr parse_comment(ASTNode& parent); NonnullRefPtr parse_if_statement(ASTNode& parent); + NonnullRefPtr parse_namespace_declaration(ASTNode& parent, bool is_nested_namespace = false); + NonnullRefPtrVector parse_declarations_in_translation_unit(ASTNode& parent); + RefPtr parse_single_declaration_in_translation_unit(ASTNode& parent); + bool match(Token::Type); Token consume(Token::Type); @@ -132,13 +134,7 @@ private: void save_state(); void load_state(); - enum class Context { - InTranslationUnit, - InFunctionDefinition, - }; - struct State { - Context context { Context::InTranslationUnit }; size_t token_index { 0 }; };