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>
This commit is contained in:
2026-02-14 20:31:22 +00:00
parent 63e459fb66
commit 8095b097d2

View File

@@ -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,