mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-24 10:22:05 -05:00
LibCpp: Add AST::Name
A Name node is basically an identifier with an optional scope, e.g Core::File.
This commit is contained in:
parent
29b6915db9
commit
3295609aea
5 changed files with 105 additions and 44 deletions
|
@ -109,8 +109,8 @@ Vector<GUI::AutocompleteProvider::Entry> ParserAutoComplete::get_suggestions(con
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_empty_property(document, *node, position)) {
|
if (is_empty_property(document, *node, position)) {
|
||||||
VERIFY(node->is_member_expression());
|
VERIFY(node->parent()->is_member_expression());
|
||||||
return autocomplete_property(document, (MemberExpression&)(*node), "");
|
return autocomplete_property(document, (MemberExpression&)(*node->parent()), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
String partial_text = String::empty();
|
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
|
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;
|
return false;
|
||||||
auto previous_token = document.parser().token_at(autocomplete_position);
|
auto previous_token = document.parser().token_at(autocomplete_position);
|
||||||
if (!previous_token.has_value())
|
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));
|
auto properties = properties_of_type(document, type_of(document, *parent.m_object));
|
||||||
for (auto& prop : properties) {
|
for (auto& prop : properties) {
|
||||||
if (prop.name == identifier.m_name)
|
if (prop.name == identifier.m_name)
|
||||||
return prop.type->m_name;
|
return prop.type->m_name->full_name();
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ String ParserAutoComplete::type_of_variable(const Identifier& identifier) const
|
||||||
if (decl.is_variable_or_parameter_declaration()) {
|
if (decl.is_variable_or_parameter_declaration()) {
|
||||||
auto& var_or_param = (VariableOrParameterDeclaration&)decl;
|
auto& var_or_param = (VariableOrParameterDeclaration&)decl;
|
||||||
if (var_or_param.m_name == identifier.m_name) {
|
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 type_of_property(document, static_cast<const Identifier&>(*member_expression.m_property));
|
||||||
return {};
|
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_NOT_REACHED(); // TODO
|
||||||
}
|
}
|
||||||
|
VERIFY(identifier);
|
||||||
|
if (is_property(*identifier))
|
||||||
|
return type_of_property(document, *identifier);
|
||||||
|
|
||||||
auto& identifier = (const Identifier&)expression;
|
return type_of_variable(*identifier);
|
||||||
|
|
||||||
if (is_property(identifier))
|
|
||||||
return type_of_property(document, identifier);
|
|
||||||
|
|
||||||
return type_of_variable(identifier);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<ParserAutoComplete::PropertyInfo> ParserAutoComplete::properties_of_type(const DocumentData& document, const String& type) const
|
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;
|
return decl;
|
||||||
}
|
}
|
||||||
if (node.is_type() && decl.is_struct_or_class()) {
|
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;
|
return decl;
|
||||||
}
|
}
|
||||||
if (node.is_function_call() && decl.is_function()) {
|
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;
|
return decl;
|
||||||
}
|
}
|
||||||
if (is_property(node) && decl.is_struct_or_class()) {
|
if (is_property(node) && decl.is_struct_or_class()) {
|
||||||
|
|
|
@ -91,7 +91,7 @@ void Type::dump(size_t indent) const
|
||||||
String qualifiers_string;
|
String qualifiers_string;
|
||||||
if (!m_qualifiers.is_empty())
|
if (!m_qualifiers.is_empty())
|
||||||
qualifiers_string = String::formatted("[{}] ", String::join(" ", m_qualifiers));
|
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
|
void Parameter::dump(size_t indent) const
|
||||||
|
@ -243,7 +243,7 @@ void FunctionCall::dump(size_t indent) const
|
||||||
{
|
{
|
||||||
ASTNode::dump(indent);
|
ASTNode::dump(indent);
|
||||||
print_indent(indent);
|
print_indent(indent);
|
||||||
outln("{}", m_name);
|
outln("{}", m_name->full_name());
|
||||||
for (const auto& arg : m_arguments) {
|
for (const auto& arg : m_arguments) {
|
||||||
arg.dump(indent + 1);
|
arg.dump(indent + 1);
|
||||||
}
|
}
|
||||||
|
@ -462,4 +462,22 @@ void TemplatizedType::dump(size_t indent) const
|
||||||
outln(">");
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ class FunctionDefinition;
|
||||||
class Type;
|
class Type;
|
||||||
class Parameter;
|
class Parameter;
|
||||||
class Statement;
|
class Statement;
|
||||||
|
class Name;
|
||||||
|
|
||||||
class ASTNode : public RefCounted<ASTNode> {
|
class ASTNode : public RefCounted<ASTNode> {
|
||||||
public:
|
public:
|
||||||
|
@ -76,6 +77,7 @@ public:
|
||||||
virtual bool is_function_call() const { return false; }
|
virtual bool is_function_call() const { return false; }
|
||||||
virtual bool is_type() const { return false; }
|
virtual bool is_type() const { return false; }
|
||||||
virtual bool is_declaration() const { return false; }
|
virtual bool is_declaration() const { return false; }
|
||||||
|
virtual bool is_name() const {return false;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ASTNode(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
|
ASTNode(ASTNode* parent, Optional<Position> start, Optional<Position> end, const String& filename)
|
||||||
|
@ -212,7 +214,6 @@ class Type : public ASTNode {
|
||||||
public:
|
public:
|
||||||
virtual ~Type() override = default;
|
virtual ~Type() override = default;
|
||||||
virtual const char* class_name() const override { return "Type"; }
|
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 void dump(size_t indent) const override;
|
||||||
virtual bool is_type() const override { return true; }
|
virtual bool is_type() const override { return true; }
|
||||||
virtual bool is_templatized() const { return false; }
|
virtual bool is_templatized() const { return false; }
|
||||||
|
@ -222,7 +223,7 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView m_name;
|
RefPtr<Name> m_name;
|
||||||
Vector<StringView> m_qualifiers;
|
Vector<StringView> m_qualifiers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -341,6 +342,23 @@ public:
|
||||||
StringView m_name;
|
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 {
|
class NumericLiteral : public Expression {
|
||||||
public:
|
public:
|
||||||
virtual ~NumericLiteral() override = default;
|
virtual ~NumericLiteral() override = default;
|
||||||
|
@ -453,7 +471,7 @@ public:
|
||||||
virtual void dump(size_t indent) const override;
|
virtual void dump(size_t indent) const override;
|
||||||
virtual bool is_function_call() const override { return true; }
|
virtual bool is_function_call() const override { return true; }
|
||||||
|
|
||||||
StringView m_name;
|
RefPtr<Name> m_name;
|
||||||
NonnullRefPtrVector<Expression> m_arguments;
|
NonnullRefPtrVector<Expression> m_arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -577,7 +595,7 @@ public:
|
||||||
virtual bool is_member_expression() const override { return true; }
|
virtual bool is_member_expression() const override { return true; }
|
||||||
|
|
||||||
RefPtr<Expression> m_object;
|
RefPtr<Expression> m_object;
|
||||||
RefPtr<Identifier> m_property;
|
RefPtr<Expression> m_property;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ForStatement : public Statement {
|
class ForStatement : public Statement {
|
||||||
|
|
|
@ -258,10 +258,9 @@ Parser::MatchTypeResult Parser::match_type()
|
||||||
|
|
||||||
parse_type_qualifiers();
|
parse_type_qualifiers();
|
||||||
|
|
||||||
if (!peek(Token::Type::KnownType).has_value() && !peek(Token::Type::Identifier).has_value())
|
if (!match_name())
|
||||||
return MatchTypeResult::NoMatch;
|
return MatchTypeResult::NoMatch;
|
||||||
|
parse_name(*m_root_node);
|
||||||
consume();
|
|
||||||
|
|
||||||
if (peek(Token::Type::Less).has_value()) {
|
if (peek(Token::Type::Less).has_value()) {
|
||||||
if (match_template_arguments()) {
|
if (match_template_arguments()) {
|
||||||
|
@ -439,19 +438,16 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression(ASTNode& parent)
|
||||||
if (match_literal()) {
|
if (match_literal()) {
|
||||||
return parse_literal(parent);
|
return parse_literal(parent);
|
||||||
}
|
}
|
||||||
switch (peek().type()) {
|
|
||||||
case Token::Type::Identifier: {
|
if (match_name()) {
|
||||||
if (match_function_call())
|
if (match_function_call())
|
||||||
return parse_function_call(parent);
|
return parse_function_call(parent);
|
||||||
auto token = consume();
|
return parse_name(parent);
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error("could not parse primary expression");
|
||||||
|
auto token = consume();
|
||||||
|
return create_ast_node<InvalidExpression>(parent, token.start(), token.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Parser::match_literal()
|
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(), {});
|
auto exp = create_ast_node<MemberExpression>(parent, lhs->start(), {});
|
||||||
lhs->set_parent(*exp);
|
lhs->set_parent(*exp);
|
||||||
exp->m_object = move(lhs);
|
exp->m_object = move(lhs);
|
||||||
auto property_token = consume(Token::Type::Identifier);
|
exp->m_property = parse_expression(*exp);
|
||||||
exp->m_property = create_ast_node<Identifier>(*exp, property_token.start(), property_token.end(), text_of_token(property_token));
|
exp->set_end(position());
|
||||||
exp->set_end(property_token.end());
|
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -907,9 +902,10 @@ bool Parser::match_function_call()
|
||||||
{
|
{
|
||||||
save_state();
|
save_state();
|
||||||
ScopeGuard state_guard = [this] { load_state(); };
|
ScopeGuard state_guard = [this] { load_state(); };
|
||||||
if (!match(Token::Type::Identifier))
|
if (!match_name())
|
||||||
return false;
|
return false;
|
||||||
consume();
|
parse_name(*m_root_node);
|
||||||
|
|
||||||
return match(Token::Type::LeftParen);
|
return match(Token::Type::LeftParen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -917,8 +913,7 @@ NonnullRefPtr<FunctionCall> Parser::parse_function_call(ASTNode& parent)
|
||||||
{
|
{
|
||||||
SCOPE_LOGGER();
|
SCOPE_LOGGER();
|
||||||
auto call = create_ast_node<FunctionCall>(parent, position(), {});
|
auto call = create_ast_node<FunctionCall>(parent, position(), {});
|
||||||
auto name_identifier = consume(Token::Type::Identifier);
|
call->m_name = parse_name(*call);
|
||||||
call->m_name = text_of_token(name_identifier);
|
|
||||||
|
|
||||||
NonnullRefPtrVector<Expression> args;
|
NonnullRefPtrVector<Expression> args;
|
||||||
consume(Token::Type::LeftParen);
|
consume(Token::Type::LeftParen);
|
||||||
|
@ -1115,15 +1110,14 @@ NonnullRefPtr<Type> Parser::parse_type(ASTNode& parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
auto qualifiers = parse_type_qualifiers();
|
auto qualifiers = parse_type_qualifiers();
|
||||||
auto type_name_token = consume();
|
|
||||||
type->m_qualifiers = move(qualifiers);
|
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());
|
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();
|
return type.release_nonnull();
|
||||||
}
|
}
|
||||||
|
type->m_name = parse_name(*type);
|
||||||
|
|
||||||
if (is_templatized) {
|
if (is_templatized) {
|
||||||
static_cast<TemplatizedType&>(*type).m_template_arguments = parse_template_arguments(*type);
|
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;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ private:
|
||||||
bool match_block_statement();
|
bool match_block_statement();
|
||||||
bool match_namespace_declaration();
|
bool match_namespace_declaration();
|
||||||
bool match_template_arguments();
|
bool match_template_arguments();
|
||||||
|
bool match_name();
|
||||||
|
|
||||||
enum class MatchTypeResult {
|
enum class MatchTypeResult {
|
||||||
NoMatch,
|
NoMatch,
|
||||||
|
@ -129,6 +130,7 @@ private:
|
||||||
NonnullRefPtrVector<Declaration> parse_declarations_in_translation_unit(ASTNode& parent);
|
NonnullRefPtrVector<Declaration> parse_declarations_in_translation_unit(ASTNode& parent);
|
||||||
RefPtr<Declaration> parse_single_declaration_in_translation_unit(ASTNode& parent);
|
RefPtr<Declaration> parse_single_declaration_in_translation_unit(ASTNode& parent);
|
||||||
NonnullRefPtrVector<Type> parse_template_arguments(ASTNode& parent);
|
NonnullRefPtrVector<Type> parse_template_arguments(ASTNode& parent);
|
||||||
|
NonnullRefPtr<Name> parse_name(ASTNode& parent);
|
||||||
|
|
||||||
bool match(Token::Type);
|
bool match(Token::Type);
|
||||||
Token consume(Token::Type);
|
Token consume(Token::Type);
|
||||||
|
|
Loading…
Add table
Reference in a new issue