From 57e033e4b3df0afeb2b13ef84c44c622d0c066f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Wed, 11 Feb 2026 13:48:45 +0000 Subject: [PATCH] parser: align function names with upstream Parse.zig Rename assignOpTag to assignOpNode to match upstream. Extract inlined code into separate functions to match upstream's structure: expectTestDecl, expectIfStatement, expectParamDecl, parseSwitchProngList. Add parseSingleAssignExpr for upstream API surface alignment. Co-Authored-By: Claude Opus 4.6 --- parser.c | 234 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 125 insertions(+), 109 deletions(-) diff --git a/parser.c b/parser.c index a2d643126c..3284335c81 100644 --- a/parser.c +++ b/parser.c @@ -50,7 +50,7 @@ typedef struct { static AstNodeIndex addExtra(Parser*, const AstNodeIndex*, uint32_t); static AstNodeIndex addNode(AstNodeList*, AstNodeItem); -static AstNodeTag assignOpTag(TokenizerTag); +static AstNodeTag assignOpNode(TokenizerTag); static AstTokenIndex assertToken(Parser*, TokenizerTag); static void astNodeListEnsureCapacity(AstNodeList*, uint32_t); static void cleanupScratch(CleanupScratch*); @@ -59,8 +59,11 @@ static AstTokenIndex eatToken(Parser*, TokenizerTag); static AstNodeIndex expectBlockExprStatement(Parser*); static AstNodeIndex expectContainerField(Parser*); static AstNodeIndex expectExpr(Parser*); +static AstNodeIndex expectIfStatement(Parser*); +static AstNodeIndex expectParamDecl(Parser*); static AstNodeIndex expectSemicolon(Parser*); static AstNodeIndex expectStatement(Parser*, bool); +static AstNodeIndex expectTestDecl(Parser*); static AstTokenIndex expectToken(Parser*, TokenizerTag); static AstNodeIndex expectTopLevelDecl(Parser*); static AstNodeIndex expectVarDeclExprStatement(Parser*, AstTokenIndex); @@ -107,11 +110,13 @@ static AstNodeIndex parsePrimaryExpr(Parser*); static AstNodeIndex parsePrimaryTypeExpr(Parser*); static PtrModifiers parsePtrModifiers(Parser*); static void parsePtrPayload(Parser*); +static AstNodeIndex parseSingleAssignExpr(Parser*); static AstNodeIndex parseSuffixExpr(Parser*); static AstNodeIndex parseSuffixOp(Parser*, AstNodeIndex); static AstNodeIndex parseSwitchExpr(Parser*); static AstNodeIndex parseSwitchItem(Parser*); static AstNodeIndex parseSwitchProng(Parser*); +static AstSubRange parseSwitchProngList(Parser*); static AstNodeIndex parseTypeExpr(Parser*); static AstNodeIndex parseVarDeclProto(Parser*); static AstNodeIndex parseWhileContinueExpr(Parser*); @@ -1220,6 +1225,18 @@ static AstNodeIndex parseTypeExpr(Parser* p) { return 0; // tcc } +static AstNodeIndex expectParamDecl(Parser* p) { + eatDocComments(p); + eatToken(p, TOKEN_KEYWORD_COMPTIME); + eatToken(p, TOKEN_KEYWORD_NOALIAS); + if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER + && p->token_tags[p->tok_i + 1] == TOKEN_COLON) + p->tok_i += 2; + if (eatToken(p, TOKEN_KEYWORD_ANYTYPE) != null_token) + return 0; + return parseTypeExpr(p); +} + static SmallSpan parseParamDeclList(Parser* p) { expectToken(p, TOKEN_L_PAREN); @@ -1235,18 +1252,7 @@ static SmallSpan parseParamDeclList(Parser* p) { if (varargs == 1) varargs = 2; - eatDocComments(p); - - // Check for comptime or noalias - eatToken(p, TOKEN_KEYWORD_COMPTIME); - eatToken(p, TOKEN_KEYWORD_NOALIAS); - - // Check for name: type or just type - if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER - && p->token_tags[p->tok_i + 1] == TOKEN_COLON) { - p->tok_i += 2; // consume name and colon - } else if (p->token_tags[p->tok_i] == TOKEN_ELLIPSIS3) { - // varargs (...) + if (p->token_tags[p->tok_i] == TOKEN_ELLIPSIS3) { p->tok_i++; if (varargs == 0) varargs = 1; @@ -1256,17 +1262,7 @@ static SmallSpan parseParamDeclList(Parser* p) { continue; } - // anytype params are omitted from the AST - if (eatToken(p, TOKEN_KEYWORD_ANYTYPE) != null_token) { - if (p->token_tags[p->tok_i] == TOKEN_COMMA) { - p->tok_i++; - continue; - } - expectToken(p, TOKEN_R_PAREN); - break; - } - - const AstNodeIndex type_expr = parseTypeExpr(p); + const AstNodeIndex type_expr = expectParamDecl(p); if (type_expr != 0) SLICE_APPEND(AstNodeIndex, &p->scratch, type_expr); @@ -2442,19 +2438,9 @@ static AstNodeIndex parseSwitchProng(Parser* p) { return case_node; } -static AstNodeIndex parseSwitchExpr(Parser* p) { - const AstTokenIndex switch_token = eatToken(p, TOKEN_KEYWORD_SWITCH); - if (switch_token == null_token) - return null_node; - - expectToken(p, TOKEN_L_PAREN); - const AstNodeIndex operand = expectExpr(p); - expectToken(p, TOKEN_R_PAREN); - expectToken(p, TOKEN_L_BRACE); - +static AstSubRange parseSwitchProngList(Parser* p) { CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) = initCleanupScratch(p); - while (true) { if (eatToken(p, TOKEN_R_BRACE) != null_token) break; @@ -2466,11 +2452,22 @@ static AstNodeIndex parseSwitchExpr(Parser* p) { if (p->token_tags[p->tok_i] == TOKEN_COMMA) p->tok_i++; } - - const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; const uint32_t cases_len = p->scratch.len - scratch_top.old_len; - const AstSubRange span - = listToSpan(p, &p->scratch.arr[scratch_top.old_len], cases_len); + return listToSpan(p, &p->scratch.arr[scratch_top.old_len], cases_len); +} + +static AstNodeIndex parseSwitchExpr(Parser* p) { + const AstTokenIndex switch_token = eatToken(p, TOKEN_KEYWORD_SWITCH); + if (switch_token == null_token) + return null_node; + + expectToken(p, TOKEN_L_PAREN); + const AstNodeIndex operand = expectExpr(p); + expectToken(p, TOKEN_R_PAREN); + expectToken(p, TOKEN_L_BRACE); + + const AstSubRange span = parseSwitchProngList(p); + const bool comma = p->token_tags[p->tok_i - 2] == TOKEN_COMMA; return addNode(&p->nodes, (AstNodeItem) { .tag = comma ? AST_NODE_SWITCH_COMMA : AST_NODE_SWITCH, @@ -2682,7 +2679,7 @@ static AstNodeIndex parsePrefixExpr(Parser* p) { }); } -static AstNodeTag assignOpTag(TokenizerTag tok) { +static AstNodeTag assignOpNode(TokenizerTag tok) { switch (tok) { case TOKEN_EQUAL: return AST_NODE_ASSIGN; @@ -2726,7 +2723,7 @@ static AstNodeTag assignOpTag(TokenizerTag tok) { } static AstNodeIndex finishAssignExpr(Parser* p, AstNodeIndex lhs) { - const AstNodeTag assign_tag = assignOpTag(p->token_tags[p->tok_i]); + const AstNodeTag assign_tag = assignOpNode(p->token_tags[p->tok_i]); if (assign_tag == AST_NODE_ROOT) return lhs; @@ -2747,6 +2744,23 @@ static AstNodeIndex parseAssignExpr(Parser* p) { return finishAssignExpr(p, expr); } +static AstNodeIndex parseSingleAssignExpr(Parser* p) { + const AstNodeIndex expr = parseExpr(p); + if (expr == 0) + return null_node; + const AstNodeTag tag = assignOpNode(p->token_tags[p->tok_i]); + if (tag == AST_NODE_ROOT) + return expr; + const AstTokenIndex op_token = nextToken(p); + const AstNodeIndex rhs = expectExpr(p); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = tag, + .main_token = op_token, + .data = { .lhs = expr, .rhs = rhs }, + }); +} + static AstNodeIndex parseBlockExpr(Parser* p) { if (p->token_tags[p->tok_i] == TOKEN_L_BRACE) return parseBlock(p); @@ -2869,6 +2883,54 @@ static AstNodeIndex expectVarDeclExprStatement( }); } +static AstNodeIndex expectIfStatement(Parser* p) { + const AstTokenIndex if_token = assertToken(p, TOKEN_KEYWORD_IF); + expectToken(p, TOKEN_L_PAREN); + const AstNodeIndex condition = expectExpr(p); + expectToken(p, TOKEN_R_PAREN); + parsePtrPayload(p); + bool else_required = false; + AstNodeIndex then_body; + const AstNodeIndex block2 = parseBlockExpr(p); + if (block2 != 0) { + then_body = block2; + } else { + then_body = parseAssignExpr(p); + if (then_body == 0) + fail(p, "expected block or assignment"); + if (eatToken(p, TOKEN_SEMICOLON) != null_token) + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_IF_SIMPLE, + .main_token = if_token, + .data = { .lhs = condition, .rhs = then_body }, + }); + else_required = true; + } + if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { + if (else_required) + fail(p, "expected_semi_or_else"); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_IF_SIMPLE, + .main_token = if_token, + .data = { .lhs = condition, .rhs = then_body }, + }); + } + parsePayload(p); + const AstNodeIndex else_body = expectStatement(p, false); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_IF, + .main_token = if_token, + .data = { + .lhs = condition, + .rhs = addExtra(p, + (AstNodeIndex[]) { then_body, else_body }, 2), + }, + }); +} + static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) { const AstTokenIndex comptime_token = eatToken(p, TOKEN_KEYWORD_COMPTIME); if (comptime_token != null_token) { @@ -2950,55 +3012,8 @@ static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) { .rhs = 0, }, }); - case TOKEN_KEYWORD_IF: { - const AstTokenIndex if_token = nextToken(p); - expectToken(p, TOKEN_L_PAREN); - const AstNodeIndex condition = expectExpr(p); - expectToken(p, TOKEN_R_PAREN); - parsePtrPayload(p); - bool else_required = false; - AstNodeIndex then_body; - const AstNodeIndex block2 = parseBlockExpr(p); - if (block2 != 0) { - then_body = block2; - } else { - then_body = parseAssignExpr(p); - if (then_body == 0) { - fail(p, "expected block or assignment"); - } - if (eatToken(p, TOKEN_SEMICOLON) != null_token) - return addNode(&p->nodes, - (AstNodeItem) { - .tag = AST_NODE_IF_SIMPLE, - .main_token = if_token, - .data = { .lhs = condition, .rhs = then_body }, - }); - else_required = true; - } - if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) { - if (else_required) { - fail(p, "expected_semi_or_else"); - } - return addNode(&p->nodes, - (AstNodeItem) { - .tag = AST_NODE_IF_SIMPLE, - .main_token = if_token, - .data = { .lhs = condition, .rhs = then_body }, - }); - } - parsePayload(p); - const AstNodeIndex else_body = expectStatement(p, false); - return addNode(&p->nodes, - (AstNodeItem) { - .tag = AST_NODE_IF, - .main_token = if_token, - .data = { - .lhs = condition, - .rhs = addExtra(p, - (AstNodeIndex[]) { then_body, else_body }, 2), - }, - }); - } + case TOKEN_KEYWORD_IF: + return expectIfStatement(p); case TOKEN_KEYWORD_ENUM: case TOKEN_KEYWORD_STRUCT: case TOKEN_KEYWORD_UNION:; @@ -3235,6 +3250,24 @@ static void findNextContainerMember(Parser* p) { } } +static AstNodeIndex expectTestDecl(Parser* p) { + const AstTokenIndex test_token = assertToken(p, TOKEN_KEYWORD_TEST); + const AstTokenIndex test_name + = (p->token_tags[p->tok_i] == TOKEN_STRING_LITERAL + || p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) + ? nextToken(p) + : null_token; + const AstNodeIndex body = parseBlock(p); + if (body == 0) + fail(p, "expected block after test"); + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_TEST_DECL, + .main_token = test_token, + .data = { .lhs = test_name, .rhs = body }, + }); +} + static Members parseContainerMembers(Parser* p) { CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) = initCleanupScratch(p); @@ -3248,26 +3281,9 @@ static Members parseContainerMembers(Parser* p) { const AstTokenIndex doc_comment = eatDocComments(p); switch (p->token_tags[p->tok_i]) { case TOKEN_KEYWORD_TEST: { - if (doc_comment != null_token) { + if (doc_comment != null_token) fail(p, "test_doc_comment"); - } - const AstTokenIndex test_token = nextToken(p); - // test name can be a string literal or identifier, or omitted - const AstTokenIndex test_name - = (p->token_tags[p->tok_i] == TOKEN_STRING_LITERAL - || p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) - ? nextToken(p) - : null_token; - const AstNodeIndex body = parseBlock(p); - if (body == 0) { - fail(p, "expected block after test"); - } - const AstNodeIndex test_decl = addNode(&p->nodes, - (AstNodeItem) { - .tag = AST_NODE_TEST_DECL, - .main_token = test_token, - .data = { .lhs = test_name, .rhs = body }, - }); + const AstNodeIndex test_decl = expectTestDecl(p); SLICE_APPEND(AstNodeIndex, &p->scratch, test_decl); trailing = p->token_tags[p->tok_i - 1] == TOKEN_R_BRACE; break;