commit 8095b097d29a3f0536c9cdf6307a8cc09ec2faab (tree)
parent 63e459fb66fa6e9e9d0d99908b4379083224b080
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Sat, 14 Feb 2026 20:31:22 +0000
parser: add anyframe, labeled switch, fix inline fallthrough
- Implement anyframe and anyframe->T parsing in parseTypeExpr and
parsePrimaryTypeExpr (was failing with unsupported error).
- Add labeled switch support: identifier:switch in parsePrimaryExpr
and parsePrimaryTypeExpr, with main_token = switch_token - 2.
- Fix TOKEN_KEYWORD_INLINE fallthrough into TOKEN_PERIOD case in
parsePrimaryTypeExpr; handle it separately expecting for/while.
Reduces corpus test failures from 20 to 7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
1 file changed, 41 insertions(+), 7 deletions(-)
diff --git a/stage0/parser.c b/stage0/parser.c
@@ -122,7 +122,7 @@ static void parsePtrPayload(Parser*);
static AstNodeIndex parseSingleAssignExpr(Parser*);
static AstNodeIndex parseSuffixExpr(Parser*);
static AstNodeIndex parseSuffixOp(Parser*, AstNodeIndex);
-static AstNodeIndex parseSwitchExpr(Parser*);
+static AstNodeIndex parseSwitchExpr(Parser*, bool is_labeled);
static AstNodeIndex parseSwitchItem(Parser*);
static AstNodeIndex parseSwitchProng(Parser*);
static AstSubRange parseSwitchProngList(Parser*);
@@ -978,7 +978,7 @@ static AstNodeIndex parseLabeledStatement(Parser* p) {
if (loop_stmt != 0)
return loop_stmt;
- const AstNodeIndex switch_expr = parseSwitchExpr(p);
+ const AstNodeIndex switch_expr = parseSwitchExpr(p, false);
if (switch_expr != 0)
return switch_expr;
@@ -1571,7 +1571,20 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
.data = { .lhs = parseTypeExpr(p), .rhs = 0 },
});
case TOKEN_KEYWORD_ANYFRAME:
- fail(p, "unsupported type expression");
+ if (p->token_tags[p->tok_i + 1] == TOKEN_ARROW) {
+ const AstTokenIndex anyframe_tok = nextToken(p);
+ const AstTokenIndex arrow_tok = nextToken(p);
+ const AstNodeIndex return_type = parseTypeExpr(p);
+ if (return_type == 0)
+ fail(p, "expected type expression");
+ return addNode(&p->nodes,
+ (AstNodeItem) {
+ .tag = AST_NODE_ANYFRAME_TYPE,
+ .main_token = anyframe_tok,
+ .data = { .lhs = arrow_tok, .rhs = return_type },
+ });
+ }
+ return parseErrorUnionExpr(p);
case TOKEN_ASTERISK: {
const AstTokenIndex asterisk = nextToken(p);
const PtrModifiers mods = parsePtrModifiers(p);
@@ -1889,6 +1902,9 @@ static AstNodeIndex parsePrimaryExpr(Parser* p) {
case TOKEN_KEYWORD_WHILE:
p->tok_i += 2;
return parseWhileExpr(p);
+ case TOKEN_KEYWORD_SWITCH:
+ p->tok_i += 2;
+ return parseSwitchExpr(p, true);
case TOKEN_L_BRACE:
p->tok_i += 2;
return parseBlock(p);
@@ -2462,7 +2478,12 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
.data = {},
});
case TOKEN_KEYWORD_ANYFRAME:
- fail(p, "unsupported primary type expression");
+ return addNode(&p->nodes,
+ (AstNodeItem) {
+ .tag = AST_NODE_ANYFRAME_LITERAL,
+ .main_token = nextToken(p),
+ .data = {},
+ });
case TOKEN_STRING_LITERAL:
return addNode(&p->nodes,
(AstNodeItem) {
@@ -2477,7 +2498,7 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
case TOKEN_KEYWORD_IF:
return parseIfExpr(p);
case TOKEN_KEYWORD_SWITCH:
- return parseSwitchExpr(p);
+ return parseSwitchExpr(p, false);
case TOKEN_KEYWORD_EXTERN:
case TOKEN_KEYWORD_PACKED:
// extern/packed can precede struct/union/enum
@@ -2527,6 +2548,9 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
return parseLabeledStatement(p);
case TOKEN_KEYWORD_FOR:
return parseLabeledStatement(p);
+ case TOKEN_KEYWORD_SWITCH:
+ p->tok_i += 2;
+ return parseSwitchExpr(p, true);
default:
break;
}
@@ -2542,6 +2566,13 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
case TOKEN_KEYWORD_WHILE:
return parseWhileExpr(p);
case TOKEN_KEYWORD_INLINE:
+ p->tok_i++;
+ if (p->token_tags[p->tok_i] == TOKEN_KEYWORD_FOR)
+ return parseForExpr(p);
+ if (p->token_tags[p->tok_i] == TOKEN_KEYWORD_WHILE)
+ return parseWhileExpr(p);
+ fail(p, "expected 'for' or 'while' after 'inline'");
+ return 0; // tcc
case TOKEN_PERIOD:
switch (p->token_tags[p->tok_i + 1]) {
case TOKEN_IDENTIFIER: {
@@ -2623,11 +2654,14 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
}
}
-static AstNodeIndex parseSwitchExpr(Parser* p) {
+static AstNodeIndex parseSwitchExpr(Parser* p, bool is_labeled) {
const AstTokenIndex switch_token = eatToken(p, TOKEN_KEYWORD_SWITCH);
if (switch_token == null_token)
return null_node;
+ const AstTokenIndex main_token
+ = is_labeled ? switch_token - 2 : switch_token;
+
expectToken(p, TOKEN_L_PAREN);
const AstNodeIndex operand = expectExpr(p);
expectToken(p, TOKEN_R_PAREN);
@@ -2638,7 +2672,7 @@ static AstNodeIndex parseSwitchExpr(Parser* p) {
return addNode(&p->nodes,
(AstNodeItem) {
.tag = comma ? AST_NODE_SWITCH_COMMA : AST_NODE_SWITCH,
- .main_token = switch_token,
+ .main_token = main_token,
.data = {
.lhs = operand,
.rhs = addExtra(p,