From e52629cd53782dbc8207616c3d3b643c8f329cb9 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 4 Feb 2025 18:47:10 +0100 Subject: [PATCH 1/4] Reduce backtracking when parsing nested name specifiers Signed-off-by: Roberto Raggi --- src/parser/cxx/parser.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 2d1fe33c..bc671b43 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -1565,6 +1565,14 @@ auto Parser::parse_nested_name_specifier(NestedNameSpecifierAST*& yyast) auto lookat_decltype_nested_name_specifier = [&] { LookaheadParser lookahead{this}; + SourceLocation decltypeLoc; + if (!match(TokenKind::T_DECLTYPE, decltypeLoc)) return false; + if (!lookat(TokenKind::T_LPAREN)) return false; + if (!parse_skip_balanced()) return false; + if (!lookat(TokenKind::T_COLON_COLON)) return false; + + rewind(decltypeLoc); + DecltypeSpecifierAST* decltypeSpecifier = nullptr; if (!parse_decltype_specifier(decltypeSpecifier)) return false; From dcdb1c6ac9e7c87490522f450d4097472eb4221b Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 4 Feb 2025 19:04:31 +0100 Subject: [PATCH 2/4] Reduce backtracking while parsing for statements Signed-off-by: Roberto Raggi --- src/parser/cxx/parser.cc | 61 +++++++++++++++++----------------------- src/parser/cxx/parser.h | 1 - 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index bc671b43..747856ae 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -4180,9 +4180,7 @@ auto Parser::parse_do_statement(StatementAST*& yyast) -> bool { return true; } -auto Parser::parse_for_range_statement(StatementAST*& yyast) -> bool { - LookaheadParser lookahead{this}; - +auto Parser::parse_for_statement(StatementAST*& yyast) -> bool { SourceLocation forLoc; if (!match(TokenKind::T_FOR, forLoc)) return false; @@ -4190,63 +4188,56 @@ auto Parser::parse_for_range_statement(StatementAST*& yyast) -> bool { auto parentScope = scope_; auto blockSymbol = control_->newBlockSymbol(scope_, forLoc); + parentScope->addSymbol(blockSymbol); + setScope(blockSymbol); SourceLocation lparenLoc; - if (!match(TokenKind::T_LPAREN, lparenLoc)) return false; + expect(TokenKind::T_LPAREN, lparenLoc); StatementAST* initializer = nullptr; parse_init_statement(initializer); DeclarationAST* rangeDeclaration = nullptr; - if (!parse_for_range_declaration(rangeDeclaration)) return false; - SourceLocation colonLoc; - if (!match(TokenKind::T_COLON, colonLoc)) return false; - lookahead.commit(); - - parentScope->addSymbol(blockSymbol); + auto lookat_for_range_declaration = [&] { + LookaheadParser lookahead{this}; - auto ast = make_node(pool_); - yyast = ast; + if (!parse_for_range_declaration(rangeDeclaration)) return false; - ast->forLoc = forLoc; - ast->rangeDeclaration = rangeDeclaration; - ast->lparenLoc = lparenLoc; - ast->initializer = initializer; - ast->colonLoc = colonLoc; - - parse_for_range_initializer(ast->rangeInitializer); + if (!match(TokenKind::T_COLON, colonLoc)) return false; - expect(TokenKind::T_RPAREN, ast->rparenLoc); + lookahead.commit(); - parse_statement(ast->statement); + return true; + }; - return true; -} + if (lookat_for_range_declaration()) { + auto ast = make_node(pool_); + yyast = ast; -auto Parser::parse_for_statement(StatementAST*& yyast) -> bool { - if (parse_for_range_statement(yyast)) return true; + ast->forLoc = forLoc; + ast->rangeDeclaration = rangeDeclaration; + ast->lparenLoc = lparenLoc; + ast->initializer = initializer; + ast->colonLoc = colonLoc; - SourceLocation forLoc; + parse_for_range_initializer(ast->rangeInitializer); - if (!match(TokenKind::T_FOR, forLoc)) return false; + expect(TokenKind::T_RPAREN, ast->rparenLoc); - ScopeGuard scopeGuard{this}; + parse_statement(ast->statement); - auto blockSymbol = control_->newBlockSymbol(scope_, forLoc); - scope_->addSymbol(blockSymbol); - setScope(blockSymbol); + return true; + } auto ast = make_node(pool_); yyast = ast; ast->forLoc = forLoc; - - expect(TokenKind::T_LPAREN, ast->lparenLoc); - - parse_init_statement(ast->initializer); + ast->lparenLoc = lparenLoc; + ast->initializer = initializer; if (!match(TokenKind::T_SEMICOLON, ast->semicolonLoc)) { parse_condition(ast->condition, ExprContext{}); diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index 84d66f47..dce0cbe0 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -342,7 +342,6 @@ class Parser final { [[nodiscard]] auto parse_switch_statement(StatementAST*& yyast) -> bool; [[nodiscard]] auto parse_while_statement(StatementAST*& yyast) -> bool; [[nodiscard]] auto parse_do_statement(StatementAST*& yyast) -> bool; - [[nodiscard]] auto parse_for_range_statement(StatementAST*& yyast) -> bool; [[nodiscard]] auto parse_for_statement(StatementAST*& yyast) -> bool; [[nodiscard]] auto parse_for_range_declaration(DeclarationAST*& yyast) -> bool; From dfe11d12ff5133963237695e0323952aa5b60ed4 Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 4 Feb 2025 19:13:30 +0100 Subject: [PATCH 3/4] Remove cache of already parsed cast expressions Signed-off-by: Roberto Raggi --- src/parser/cxx/parser.cc | 17 ++--------------- src/parser/cxx/parser.h | 1 - 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 747856ae..73ac1952 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -3245,13 +3245,6 @@ auto Parser::parse_cast_expression(ExpressionAST*& yyast, const ExprContext& ctx) -> bool { const auto start = currentLocation(); - if (auto it = cast_expressions_.get(start)) { - auto [endLoc, ast, parsed, hit] = *it; - rewind(endLoc); - yyast = ast; - return parsed; - } - auto lookat_cast_expression = [&] { LookaheadParser lookahead{this}; if (!parse_cast_expression_helper(yyast, ctx)) return false; @@ -3259,15 +3252,9 @@ auto Parser::parse_cast_expression(ExpressionAST*& yyast, return true; }; - auto parsed = lookat_cast_expression(); + if (lookat_cast_expression()) return true; - if (!parsed) { - parsed = parse_unary_expression(yyast, ctx); - } - - cast_expressions_.set(start, currentLocation(), yyast, parsed); - - return parsed; + return parse_unary_expression(yyast, ctx); } auto Parser::parse_cast_expression_helper(ExpressionAST*& yyast, diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index dce0cbe0..af80fc39 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -972,7 +972,6 @@ class Parser final { std::deque queue_; }; - CachedAST cast_expressions_; CachedAST nested_name_specifiers_; CachedAST parameter_declaration_clauses_; CachedAST template_arguments_; From a2b26eff4e7492be93b6198a94d6ccb273334c3e Mon Sep 17 00:00:00 2001 From: Roberto Raggi Date: Tue, 4 Feb 2025 19:15:37 +0100 Subject: [PATCH 4/4] Remove caching for nested name specifiers Signed-off-by: Roberto Raggi --- src/parser/cxx/parser.cc | 11 ----------- src/parser/cxx/parser.h | 1 - 2 files changed, 12 deletions(-) diff --git a/src/parser/cxx/parser.cc b/src/parser/cxx/parser.cc index 73ac1952..5d3cd1e6 100644 --- a/src/parser/cxx/parser.cc +++ b/src/parser/cxx/parser.cc @@ -1650,15 +1650,6 @@ auto Parser::parse_nested_name_specifier(NestedNameSpecifierAST*& yyast) return true; }; - const auto start = currentLocation(); - - if (auto entry = nested_name_specifiers_.get(start)) { - auto [cursor, ast, parsed, hit] = *entry; - rewind(cursor); - yyast = ast; - return parsed; - } - yyast = nullptr; if (SourceLocation scopeLoc; match(TokenKind::T_COLON_COLON, scopeLoc)) { @@ -1680,8 +1671,6 @@ auto Parser::parse_nested_name_specifier(NestedNameSpecifierAST*& yyast) const auto parsed = yyast != nullptr; - nested_name_specifiers_.set(start, currentLocation(), yyast, parsed); - return parsed; } diff --git a/src/parser/cxx/parser.h b/src/parser/cxx/parser.h index af80fc39..2ae49c58 100644 --- a/src/parser/cxx/parser.h +++ b/src/parser/cxx/parser.h @@ -972,7 +972,6 @@ class Parser final { std::deque queue_; }; - CachedAST nested_name_specifiers_; CachedAST parameter_declaration_clauses_; CachedAST template_arguments_;