Преглед на файлове

LibCpp: Add AST::Name

A Name node is basically an identifier with an optional scope,
e.g Core::File.
Itamar преди 4 години
родител
ревизия
3295609aea

+ 19 - 14
Userland/DevTools/HackStudio/LanguageServers/Cpp/ParserAutoComplete.cpp

@@ -109,8 +109,8 @@ Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(con
     }
 
     if (is_empty_property(document, *node, position)) {
-        VERIFY(node->is_member_expression());
-        return autocomplete_property(document, (MemberExpression&)(*node), "");
+        VERIFY(node->parent()->is_member_expression());
+        return autocomplete_property(document, (MemberExpression&)(*node->parent()), "");
     }
 
     String partial_text = String::empty();
@@ -203,7 +203,7 @@ bool ParserAutoComplete::is_property(const ASTNode& node) const
 
 bool ParserAutoComplete::is_empty_property(const DocumentData& document, const ASTNode& node, const Position& autocomplete_position) const
 {
-    if (!node.is_member_expression())
+    if (!node.parent()->is_member_expression())
         return false;
     auto previous_token = document.parser().token_at(autocomplete_position);
     if (!previous_token.has_value())
@@ -217,7 +217,7 @@ String ParserAutoComplete::type_of_property(const DocumentData& document, const
     auto properties = properties_of_type(document, type_of(document, *parent.m_object));
     for (auto& prop : properties) {
         if (prop.name == identifier.m_name)
-            return prop.type->m_name;
+            return prop.type->m_name->full_name();
     }
     return {};
 }
@@ -230,7 +230,7 @@ String ParserAutoComplete::type_of_variable(const Identifier& identifier) const
             if (decl.is_variable_or_parameter_declaration()) {
                 auto& var_or_param = (VariableOrParameterDeclaration&)decl;
                 if (var_or_param.m_name == identifier.m_name) {
-                    return var_or_param.m_type->m_name;
+                    return var_or_param.m_type->m_name->full_name();
                 }
             }
         }
@@ -247,16 +247,21 @@ String ParserAutoComplete::type_of(const DocumentData& document, const Expressio
             return type_of_property(document, static_cast<const Identifier&>(*member_expression.m_property));
         return {};
     }
-    if (!expression.is_identifier()) {
+
+    const Identifier* identifier { nullptr };
+    if (expression.is_name()) {
+        identifier = static_cast<const Name&>(expression).m_name.ptr();
+    } else if (expression.is_identifier()) {
+        identifier = &static_cast<const Identifier&>(expression);
+    } else {
+        dbgln("expected identifier or name, got: {}", expression.class_name());
         VERIFY_NOT_REACHED(); // TODO
     }
+    VERIFY(identifier);
+    if (is_property(*identifier))
+        return type_of_property(document, *identifier);
 
-    auto& identifier = (const Identifier&)expression;
-
-    if (is_property(identifier))
-        return type_of_property(document, identifier);
-
-    return type_of_variable(identifier);
+    return type_of_variable(*identifier);
 }
 
 Vector<ParserAutoComplete::PropertyInfo> ParserAutoComplete::properties_of_type(const DocumentData& document, const String& type) const
@@ -391,11 +396,11 @@ RefPtr<Declaration> ParserAutoComplete::find_declaration_of(const DocumentData&
                 return decl;
         }
         if (node.is_type() && decl.is_struct_or_class()) {
-            if (((Cpp::StructOrClassDeclaration&)decl).m_name == static_cast<const Type&>(node).m_name)
+            if (((Cpp::StructOrClassDeclaration&)decl).m_name == static_cast<const Type&>(node).m_name->full_name())
                 return decl;
         }
         if (node.is_function_call() && decl.is_function()) {
-            if (((Cpp::FunctionDeclaration&)decl).m_name == static_cast<const FunctionCall&>(node).m_name)
+            if (((Cpp::FunctionDeclaration&)decl).m_name == static_cast<const FunctionCall&>(node).m_name->full_name())
                 return decl;
         }
         if (is_property(node) && decl.is_struct_or_class()) {

+ 20 - 2
Userland/Libraries/LibCpp/AST.cpp

@@ -91,7 +91,7 @@ void Type::dump(size_t indent) const
     String qualifiers_string;
     if (!m_qualifiers.is_empty())
         qualifiers_string = String::formatted("[{}] ", String::join(" ", m_qualifiers));
-    outln("{}{}", qualifiers_string, m_name);
+    outln("{}{}", qualifiers_string, m_name.is_null() ? "" : m_name->full_name());
 }
 
 void Parameter::dump(size_t indent) const
@@ -243,7 +243,7 @@ void FunctionCall::dump(size_t indent) const
 {
     ASTNode::dump(indent);
     print_indent(indent);
-    outln("{}", m_name);
+    outln("{}", m_name->full_name());
     for (const auto& arg : m_arguments) {
         arg.dump(indent + 1);
     }
@@ -462,4 +462,22 @@ void TemplatizedType::dump(size_t indent) const
     outln(">");
 }
 
+void Name::dump(size_t indent) const
+{
+    ASTNode::dump(indent);
+    print_indent(indent);
+    outln("{}", full_name());
+}
+
+String Name::full_name() const
+{
+    StringBuilder builder;
+    if (!m_scope.is_empty()) {
+        for (auto& scope : m_scope) {
+            builder.appendff("{}::", scope.m_name);
+        }
+    }
+    return String::formatted("{}{}", builder.to_string(), m_name.is_null() ? "" : m_name->m_name);
+}
+
 }

+ 22 - 4
Userland/Libraries/LibCpp/AST.h

@@ -43,6 +43,7 @@ class FunctionDefinition;
 class Type;
 class Parameter;
 class Statement;
+class Name;
 
 class ASTNode : public RefCounted<ASTNode> {
 public:
@@ -76,6 +77,7 @@ public:
     virtual bool is_function_call() const { return false; }
     virtual bool is_type() const { return false; }
     virtual bool is_declaration() const { return false; }
+    virtual bool is_name() const {return false;}
 
 protected:
     ASTNode(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
@@ -212,7 +214,6 @@ class Type : public ASTNode {
 public:
     virtual ~Type() override = default;
     virtual const char* class_name() const override { return "Type"; }
-    const StringView& name() const { return m_name; }
     virtual void dump(size_t indent) const override;
     virtual bool is_type() const override { return true; }
     virtual bool is_templatized() const { return false; }
@@ -222,7 +223,7 @@ public:
     {
     }
 
-    StringView m_name;
+    RefPtr<Name> m_name;
     Vector<StringView> m_qualifiers;
 };
 
@@ -341,6 +342,23 @@ public:
     StringView m_name;
 };
 
+class Name : public Expression {
+public:
+    virtual ~Name() override = default;
+    virtual const char* class_name() const override { return "Name"; }
+    virtual void dump(size_t indent) const override;
+    virtual bool is_name() const override {return true;}
+
+    Name(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
+        : Expression(parent, start, end, filename)
+    {
+    }
+    String full_name() const;
+
+    RefPtr<Identifier> m_name;
+    NonnullRefPtrVector<Identifier> m_scope;
+};
+
 class NumericLiteral : public Expression {
 public:
     virtual ~NumericLiteral() override = default;
@@ -453,7 +471,7 @@ public:
     virtual void dump(size_t indent) const override;
     virtual bool is_function_call() const override { return true; }
 
-    StringView m_name;
+    RefPtr<Name> m_name;
     NonnullRefPtrVector<Expression> m_arguments;
 };
 
@@ -577,7 +595,7 @@ public:
     virtual bool is_member_expression() const override { return true; }
 
     RefPtr<Expression> m_object;
-    RefPtr<Identifier> m_property;
+    RefPtr<Expression> m_property;
 };
 
 class ForStatement : public Statement {

+ 42 - 24
Userland/Libraries/LibCpp/Parser.cpp

@@ -258,10 +258,9 @@ Parser::MatchTypeResult Parser::match_type()
 
     parse_type_qualifiers();
 
-    if (!peek(Token::Type::KnownType).has_value() && !peek(Token::Type::Identifier).has_value())
+    if (!match_name())
         return MatchTypeResult::NoMatch;
-
-    consume();
+    parse_name(*m_root_node);
 
     if (peek(Token::Type::Less).has_value()) {
         if (match_template_arguments()) {
@@ -439,19 +438,16 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression(ASTNode& parent)
     if (match_literal()) {
         return parse_literal(parent);
     }
-    switch (peek().type()) {
-    case Token::Type::Identifier: {
+
+    if (match_name()) {
         if (match_function_call())
             return parse_function_call(parent);
-        auto token = consume();
-        return create_ast_node<Identifier>(parent, token.start(), token.end(), text_of_token(token));
-    }
-    default: {
-        error("could not parse primary expression");
-        auto token = consume();
-        return create_ast_node<InvalidExpression>(parent, token.start(), token.end());
-    }
+        return parse_name(parent);
     }
+
+    error("could not parse primary expression");
+    auto token = consume();
+    return create_ast_node<InvalidExpression>(parent, token.start(), token.end());
 }
 
 bool Parser::match_literal()
@@ -557,9 +553,8 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(ASTNode& parent, No
         auto exp = create_ast_node<MemberExpression>(parent, lhs->start(), {});
         lhs->set_parent(*exp);
         exp->m_object = move(lhs);
-        auto property_token = consume(Token::Type::Identifier);
-        exp->m_property = create_ast_node<Identifier>(*exp, property_token.start(), property_token.end(), text_of_token(property_token));
-        exp->set_end(property_token.end());
+        exp->m_property = parse_expression(*exp);
+        exp->set_end(position());
         return exp;
     }
     default: {
@@ -907,9 +902,10 @@ bool Parser::match_function_call()
 {
     save_state();
     ScopeGuard state_guard = [this] { load_state(); };
-    if (!match(Token::Type::Identifier))
+    if (!match_name())
         return false;
-    consume();
+    parse_name(*m_root_node);
+
     return match(Token::Type::LeftParen);
 }
 
@@ -917,8 +913,7 @@ NonnullRefPtr<FunctionCall> Parser::parse_function_call(ASTNode& parent)
 {
     SCOPE_LOGGER();
     auto call = create_ast_node<FunctionCall>(parent, position(), {});
-    auto name_identifier = consume(Token::Type::Identifier);
-    call->m_name = text_of_token(name_identifier);
+    call->m_name = parse_name(*call);
 
     NonnullRefPtrVector<Expression> args;
     consume(Token::Type::LeftParen);
@@ -1115,15 +1110,14 @@ NonnullRefPtr<Type> Parser::parse_type(ASTNode& parent)
     }
 
     auto qualifiers = parse_type_qualifiers();
-    auto type_name_token = consume();
     type->m_qualifiers = move(qualifiers);
-    type->m_name = text_of_token(type_name_token);
 
-    if (type_name_token.type() != Token::Type::KnownType && type_name_token.type() != Token::Type::Identifier) {
+    if (!match_name()) {
         type->set_end(position());
-        error(String::formatted("unexpected type_name_token for type: {}", type_name_token.to_string()));
+        error(String::formatted("expected name instead of: {}", peek().text()));
         return type.release_nonnull();
     }
+    type->m_name = parse_name(*type);
 
     if (is_templatized) {
         static_cast<TemplatizedType&>(*type).m_template_arguments = parse_template_arguments(*type);
@@ -1289,4 +1283,28 @@ NonnullRefPtr<NamespaceDeclaration> Parser::parse_namespace_declaration(ASTNode&
     return namespace_decl;
 }
 
+bool Parser::match_name()
+{
+    auto type = peek().type();
+    return type == Token::Type::Identifier || type == Token::Type::KnownType;
+}
+
+NonnullRefPtr<Name> Parser::parse_name(ASTNode& parent)
+{
+    auto name_node = create_ast_node<Name>(parent, position(), {});
+    while (!eof() && (peek().type() == Token::Type::Identifier || peek().type() == Token::Type::KnownType)) {
+        auto token = consume();
+        name_node->m_scope.append(create_ast_node<Identifier>(*name_node, token.start(), token.end(), token.text()));
+        if (peek().type() == Token::Type::ColonColon)
+            consume();
+        else
+            break;
+    }
+
+    VERIFY(!name_node->m_scope.is_empty());
+    name_node->m_name = name_node->m_scope.take_last();
+    name_node->set_end(position());
+    return name_node;
+}
+
 }

+ 2 - 0
Userland/Libraries/LibCpp/Parser.h

@@ -89,6 +89,7 @@ private:
     bool match_block_statement();
     bool match_namespace_declaration();
     bool match_template_arguments();
+    bool match_name();
 
     enum class MatchTypeResult {
         NoMatch,
@@ -129,6 +130,7 @@ private:
     NonnullRefPtrVector<Declaration> parse_declarations_in_translation_unit(ASTNode& parent);
     RefPtr<Declaration> parse_single_declaration_in_translation_unit(ASTNode& parent);
     NonnullRefPtrVector<Type> parse_template_arguments(ASTNode& parent);
+    NonnullRefPtr<Name> parse_name(ASTNode& parent);
 
     bool match(Token::Type);
     Token consume(Token::Type);