parser: implement while loops, port while test
Implement in parser.c: - parseWhileExpr: while (cond) body, with optional payload, continue expression, and else clause - while_simple, while_cont, while AST nodes Port test "while else err prong with no block". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
67
parser.c
67
parser.c
@@ -33,6 +33,10 @@ static AstNodeIndex parseFnProto(Parser*);
|
||||
static Members parseContainerMembers(Parser*);
|
||||
static AstNodeIndex parseInitList(Parser*, AstNodeIndex, AstTokenIndex);
|
||||
static AstNodeIndex expectBlockExprStatement(Parser*);
|
||||
static AstNodeIndex parseWhileExpr(Parser*);
|
||||
static AstNodeIndex parseAssignExpr(Parser*);
|
||||
static void parsePtrPayload(Parser*);
|
||||
static void parsePayload(Parser*);
|
||||
|
||||
typedef struct {
|
||||
enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag;
|
||||
@@ -1277,14 +1281,64 @@ static AstNodeIndex parseForStatement(Parser* p) {
|
||||
return 0; // tcc
|
||||
}
|
||||
|
||||
static AstNodeIndex parseWhileStatement(Parser* p) {
|
||||
const AstNodeIndex while_token = eatToken(p, TOKEN_KEYWORD_WHILE);
|
||||
static AstNodeIndex parseWhileExpr(Parser* p) {
|
||||
const AstTokenIndex while_token = eatToken(p, TOKEN_KEYWORD_WHILE);
|
||||
if (while_token == null_token)
|
||||
return null_node;
|
||||
|
||||
(void)while_token;
|
||||
fprintf(stderr, "parseWhileStatement cannot parse while statements\n");
|
||||
return 0; // tcc
|
||||
expectToken(p, TOKEN_L_PAREN);
|
||||
const AstNodeIndex condition = expectExpr(p);
|
||||
expectToken(p, TOKEN_R_PAREN);
|
||||
parsePtrPayload(p);
|
||||
|
||||
// Continue expression: : (expr)
|
||||
AstNodeIndex cont_expr = 0;
|
||||
if (eatToken(p, TOKEN_COLON) != null_token) {
|
||||
expectToken(p, TOKEN_L_PAREN);
|
||||
cont_expr = parseAssignExpr(p);
|
||||
expectToken(p, TOKEN_R_PAREN);
|
||||
}
|
||||
|
||||
const AstNodeIndex body = expectExpr(p);
|
||||
|
||||
if (eatToken(p, TOKEN_KEYWORD_ELSE) == null_token) {
|
||||
if (cont_expr != 0) {
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_WHILE_CONT,
|
||||
.main_token = while_token,
|
||||
.data = {
|
||||
.lhs = condition,
|
||||
.rhs = addExtra(p,
|
||||
(AstNodeIndex[]) { cont_expr, body }, 2),
|
||||
},
|
||||
});
|
||||
}
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_WHILE_SIMPLE,
|
||||
.main_token = while_token,
|
||||
.data = { .lhs = condition, .rhs = body },
|
||||
});
|
||||
}
|
||||
|
||||
parsePayload(p);
|
||||
const AstNodeIndex else_expr = expectExpr(p);
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_WHILE,
|
||||
.main_token = while_token,
|
||||
.data = {
|
||||
.lhs = condition,
|
||||
.rhs = addExtra(p,
|
||||
(AstNodeIndex[]) { OPT(cont_expr), body, else_expr },
|
||||
3),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static AstNodeIndex parseWhileStatement(Parser* p) {
|
||||
return parseWhileExpr(p);
|
||||
}
|
||||
|
||||
static AstNodeIndex parseLoopStatement(Parser* p) {
|
||||
@@ -1851,9 +1905,10 @@ static AstNodeIndex parsePrimaryExpr(Parser* p) {
|
||||
} else {
|
||||
return parseCurlySuffixExpr(p);
|
||||
}
|
||||
case TOKEN_KEYWORD_WHILE:
|
||||
return parseWhileExpr(p);
|
||||
case TOKEN_KEYWORD_INLINE:
|
||||
case TOKEN_KEYWORD_FOR:
|
||||
case TOKEN_KEYWORD_WHILE:
|
||||
fprintf(stderr, "parsePrimaryExpr does not implement %s\n", tok);
|
||||
exit(1);
|
||||
return 0; // tcc
|
||||
|
||||
@@ -1517,6 +1517,18 @@ test "zig fmt: whitespace fixes" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: while else err prong with no block" {
|
||||
try testCanonical(
|
||||
\\test "" {
|
||||
\\ const result = while (returnError()) |value| {
|
||||
\\ break value;
|
||||
\\ } else |err| @as(i32, 2);
|
||||
\\ try expect(result == 2);
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: tagged union with enum values" {
|
||||
try testCanonical(
|
||||
\\const MultipleChoice2 = union(enum(u32)) {
|
||||
|
||||
Reference in New Issue
Block a user