From b6d9a0c32e64fd4ce4d3350fca9a671d5daac126 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 13:16:55 +0100 Subject: Manually implement tail-recursion for `parse_if_stmt` --- src/parser.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'src/parser.cpp') diff --git a/src/parser.cpp b/src/parser.cpp index 6461c9dd0..1a45c4ea5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4532,12 +4532,10 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { return ast_bad_stmt(f, f->curr_token, f->curr_token); } - if (f->recursion_depth_else_if > 256) { - syntax_error(f->curr_token, "if-else chain recursion depth limit hit. Consider using a 'switch' statement instead or refactor the code to not require a large if-else chain"); - f->recursion_depth_else_if = 0; - return ast_bad_stmt(f, f->curr_token, f->curr_token); - } + Ast *top_if_stmt = nullptr; + Ast *prev_if_stmt = nullptr; +if_else_chain:; Token token = expect_token(f, Token_if); Ast *init = nullptr; Ast *cond = nullptr; @@ -4579,14 +4577,24 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { ignore_strict_style = true; } skip_possible_newline_for_literal(f, ignore_strict_style); + + Ast *curr_if_stmt = ast_if_stmt(f, token, init, cond, body, nullptr); + if (top_if_stmt == nullptr) { + top_if_stmt = curr_if_stmt; + } + if (prev_if_stmt != nullptr) { + prev_if_stmt->IfStmt.else_stmt = curr_if_stmt; + } + if (f->curr_token.kind == Token_else) { Token else_token = expect_token(f, Token_else); switch (f->curr_token.kind) { case Token_if: - f->recursion_depth_else_if += 1; - else_stmt = parse_if_stmt(f); - f->recursion_depth_else_if -= 1; - break; + // NOTE(bill): Instead of relying on recursive descent for an if-else chain + // we can just inline the tail-recursion manually with a simple loop like + // construct using a `goto` + prev_if_stmt = curr_if_stmt; + goto if_else_chain; case Token_OpenBrace: else_stmt = parse_block_stmt(f, false); break; @@ -4601,7 +4609,9 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { } } - return ast_if_stmt(f, token, init, cond, body, else_stmt); + curr_if_stmt->IfStmt.else_stmt = else_stmt; + + return top_if_stmt; } gb_internal Ast *parse_when_stmt(AstFile *f) { -- cgit v1.2.3