From 646aaa111ba2a09627be6127fcb79040191da2a7 Mon Sep 17 00:00:00 2001 From: Itamar Date: Wed, 31 Mar 2021 18:19:58 +0300 Subject: [PATCH] LibCpp: Support parsing templatized function calls --- Userland/Libraries/LibCpp/AST.cpp | 21 +++++++++++ Userland/Libraries/LibCpp/AST.h | 20 +++++++++- Userland/Libraries/LibCpp/Parser.cpp | 56 +++++++++++++++++++++------- Userland/Libraries/LibCpp/Parser.h | 6 +-- 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/Userland/Libraries/LibCpp/AST.cpp b/Userland/Libraries/LibCpp/AST.cpp index 65e78567b8..399905f056 100644 --- a/Userland/Libraries/LibCpp/AST.cpp +++ b/Userland/Libraries/LibCpp/AST.cpp @@ -483,4 +483,25 @@ String Name::full_name() const return String::formatted("{}{}", builder.to_string(), m_name.is_null() ? "" : m_name->m_name); } +void TemplatizedFunctionCall::dump(size_t indent) const +{ + ASTNode::dump(indent); + + print_indent(indent); + outln("{}", m_name->full_name()); + + print_indent(indent + 1); + outln("<"); + for (auto& arg : m_template_arguments) { + arg.dump(indent + 1); + } + print_indent(indent + 1); + outln(">"); + + for (const auto& arg : m_arguments) { + arg.dump(indent + 1); + } + +} + } diff --git a/Userland/Libraries/LibCpp/AST.h b/Userland/Libraries/LibCpp/AST.h index 2fd1353451..9f0140c5ce 100644 --- a/Userland/Libraries/LibCpp/AST.h +++ b/Userland/Libraries/LibCpp/AST.h @@ -460,22 +460,38 @@ public: RefPtr m_rhs; }; -class FunctionCall final : public Expression { +class FunctionCall : public Expression { public: FunctionCall(ASTNode* parent, Optional start, Optional end, const String& filename) : Expression(parent, start, end, filename) { } - ~FunctionCall() override = default; + virtual ~FunctionCall() override = default; virtual const char* class_name() const override { return "FunctionCall"; } virtual void dump(size_t indent) const override; virtual bool is_function_call() const override { return true; } + virtual bool is_templatized() const { return false; } RefPtr m_name; NonnullRefPtrVector m_arguments; }; +class TemplatizedFunctionCall final : public FunctionCall { +public: + TemplatizedFunctionCall(ASTNode* parent, Optional start, Optional end, const String& filename) + : FunctionCall(parent, start, end, filename) + { + } + + ~TemplatizedFunctionCall() override = default; + virtual const char* class_name() const override { return "TemplatizedFunctionCall"; } + virtual void dump(size_t indent) const override; + virtual bool is_templatized() const override { return true; } + + NonnullRefPtrVector m_template_arguments; +}; + class StringLiteral final : public Expression { public: StringLiteral(ASTNode* parent, Optional start, Optional end, const String& filename) diff --git a/Userland/Libraries/LibCpp/Parser.cpp b/Userland/Libraries/LibCpp/Parser.cpp index 224d876506..96b84f54d0 100644 --- a/Userland/Libraries/LibCpp/Parser.cpp +++ b/Userland/Libraries/LibCpp/Parser.cpp @@ -251,7 +251,7 @@ NonnullRefPtr Parser::parse_block_statement(ASTNode& parent) return block_statement; } -Parser::MatchTypeResult Parser::match_type() +Parser::TemplatizedMatchResult Parser::match_type() { save_state(); ScopeGuard state_guard = [this] { load_state(); }; @@ -259,17 +259,17 @@ Parser::MatchTypeResult Parser::match_type() parse_type_qualifiers(); if (!match_name()) - return MatchTypeResult::NoMatch; + return TemplatizedMatchResult::NoMatch; parse_name(*m_root_node); if (peek(Token::Type::Less).has_value()) { if (match_template_arguments()) { - return MatchTypeResult::Templatized; + return TemplatizedMatchResult::Templatized; } - return MatchTypeResult::NoMatch; + return TemplatizedMatchResult::NoMatch; } - return MatchTypeResult::Regular; + return TemplatizedMatchResult::Regular; } bool Parser::match_template_arguments() @@ -282,7 +282,7 @@ bool Parser::match_template_arguments() consume(); while (!eof() && peek().type() != Token::Type::Greater) { - if (match_type() == MatchTypeResult::NoMatch) + if (match_type() == TemplatizedMatchResult::NoMatch) return false; parse_type(*m_root_node); } @@ -312,7 +312,7 @@ bool Parser::match_variable_declaration() save_state(); ScopeGuard state_guard = [this] { load_state(); }; - if (match_type() == MatchTypeResult::NoMatch) { + if (match_type() == TemplatizedMatchResult::NoMatch) { return false; } @@ -441,7 +441,7 @@ NonnullRefPtr Parser::parse_primary_expression(ASTNode& parent) } if (match_name()) { - if (match_function_call()) + if (match_function_call() != TemplatizedMatchResult::NoMatch) return parse_function_call(parent); return parse_name(parent); } @@ -634,7 +634,7 @@ bool Parser::match_function_declaration() parse_function_qualifiers(); - if (match_type() == MatchTypeResult::NoMatch) + if (match_type() == TemplatizedMatchResult::NoMatch) return false; VERIFY(m_root_node); parse_type(*m_root_node); @@ -904,22 +904,49 @@ void Parser::print_tokens() const } } -bool Parser::match_function_call() +Parser::TemplatizedMatchResult Parser::match_function_call() { save_state(); ScopeGuard state_guard = [this] { load_state(); }; if (!match_name()) - return false; + return TemplatizedMatchResult::NoMatch; parse_name(*m_root_node); - return match(Token::Type::LeftParen); + bool is_templatized = false; + if (match_template_arguments()) { + is_templatized = true; + parse_template_arguments(*m_root_node); + } + + if (!match(Token::Type::LeftParen)) + return TemplatizedMatchResult::NoMatch; + + return is_templatized ? TemplatizedMatchResult::Templatized : TemplatizedMatchResult::Regular; } NonnullRefPtr Parser::parse_function_call(ASTNode& parent) { SCOPE_LOGGER(); - auto call = create_ast_node(parent, position(), {}); + + auto match_result = match_type(); + if (match_result == TemplatizedMatchResult::NoMatch) { + error("expected type"); + return create_ast_node(parent, position(), position()); + } + + bool is_templatized = match_result == TemplatizedMatchResult::Templatized; + + RefPtr call; + if (is_templatized) { + call = create_ast_node(parent, position(), {}); + } else { + call = create_ast_node(parent, position(), {}); + } + call->m_name = parse_name(*call); + if (is_templatized) { + static_cast(*call).m_template_arguments = parse_template_arguments(*call); + } NonnullRefPtrVector args; consume(Token::Type::LeftParen); @@ -931,7 +958,8 @@ NonnullRefPtr Parser::parse_function_call(ASTNode& parent) consume(Token::Type::RightParen); call->m_arguments = move(args); call->set_end(position()); - return call; + + return call.release_nonnull(); } NonnullRefPtr Parser::parse_string_literal(ASTNode& parent) diff --git a/Userland/Libraries/LibCpp/Parser.h b/Userland/Libraries/LibCpp/Parser.h index e496cc94eb..d59b81b44d 100644 --- a/Userland/Libraries/LibCpp/Parser.h +++ b/Userland/Libraries/LibCpp/Parser.h @@ -78,7 +78,6 @@ private: bool match_whitespace(); bool match_variable_declaration(); bool match_expression(); - bool match_function_call(); bool match_secondary_expression(); bool match_enum_declaration(); bool match_struct_declaration(); @@ -91,12 +90,13 @@ private: bool match_template_arguments(); bool match_name(); - enum class MatchTypeResult { + enum class TemplatizedMatchResult { NoMatch, Regular, Templatized, }; - MatchTypeResult match_type(); + TemplatizedMatchResult match_type(); + TemplatizedMatchResult match_function_call(); Optional> parse_parameter_list(ASTNode& parent); Optional consume_whitespace();