parser: add function, comptime, var declaration tests
Port tests from upstream parser_test.zig: - "respect line breaks before functions" - "simple top level comptime block" - "two spaced line comments before decl" - "respect line breaks after var declarations" Implement in parser.c: - parseSuffixOp: array access (a[i]), field access (a.b), deref (a.*), unwrap optional (a.?) - Multiline string literal parsing - Slice types ([]T, [:s]T) and array types ([N]T, [N:s]T) - Fix comptime block main_token in parseContainerMembers Fix zigData mapping in parser_test.zig: - field_access, unwrap_optional use node_and_token (not node_and_node) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
61
parser.c
61
parser.c
@@ -533,16 +533,67 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
|
||||
}
|
||||
|
||||
static AstNodeIndex parseSuffixOp(Parser* p, AstNodeIndex lhs) {
|
||||
(void)lhs;
|
||||
const TokenizerTag tok = p->token_tags[p->tok_i];
|
||||
switch (tok) {
|
||||
case TOKEN_L_BRACKET:
|
||||
case TOKEN_L_BRACKET: {
|
||||
const AstTokenIndex lbracket = nextToken(p);
|
||||
const AstNodeIndex index_expr = expectExpr(p);
|
||||
switch (p->token_tags[p->tok_i]) {
|
||||
case TOKEN_R_BRACKET:
|
||||
p->tok_i++;
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_ARRAY_ACCESS,
|
||||
.main_token = lbracket,
|
||||
.data = { .lhs = lhs, .rhs = index_expr },
|
||||
});
|
||||
case TOKEN_ELLIPSIS2:
|
||||
fprintf(stderr, "parseSuffixOp: slicing not implemented\n");
|
||||
exit(1);
|
||||
default:
|
||||
fprintf(
|
||||
stderr, "parseSuffixOp: expected ] or .. after index expr\n");
|
||||
exit(1);
|
||||
}
|
||||
return 0; // tcc
|
||||
}
|
||||
case TOKEN_PERIOD_ASTERISK:
|
||||
case TOKEN_INVALID_PERIODASTERISKS:
|
||||
case TOKEN_PERIOD:
|
||||
fprintf(stderr, "parseSuffixOp does not support %s\n",
|
||||
tokenizerGetTagString(tok));
|
||||
exit(1);
|
||||
case TOKEN_PERIOD:
|
||||
if (p->token_tags[p->tok_i + 1] == TOKEN_IDENTIFIER) {
|
||||
const AstTokenIndex dot = nextToken(p);
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_FIELD_ACCESS,
|
||||
.main_token = dot,
|
||||
.data = { .lhs = lhs, .rhs = nextToken(p) },
|
||||
});
|
||||
}
|
||||
if (p->token_tags[p->tok_i + 1] == TOKEN_ASTERISK) {
|
||||
const AstTokenIndex dot = nextToken(p);
|
||||
nextToken(p); // consume the *
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_DEREF,
|
||||
.main_token = dot,
|
||||
.data = { .lhs = lhs, .rhs = 0 },
|
||||
});
|
||||
}
|
||||
if (p->token_tags[p->tok_i + 1] == TOKEN_QUESTION_MARK) {
|
||||
const AstTokenIndex dot = nextToken(p);
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_UNWRAP_OPTIONAL,
|
||||
.main_token = dot,
|
||||
.data = { .lhs = lhs, .rhs = nextToken(p) },
|
||||
});
|
||||
}
|
||||
fprintf(stderr, "parseSuffixOp: unsupported period suffix\n");
|
||||
exit(1);
|
||||
return 0; // tcc
|
||||
default:
|
||||
return null_node;
|
||||
}
|
||||
@@ -1521,13 +1572,13 @@ static Members parseContainerMembers(Parser* p) {
|
||||
// block/decl. Check if it's followed by a block (comptime { ...
|
||||
// }).
|
||||
if (p->token_tags[p->tok_i + 1] == TOKEN_L_BRACE) {
|
||||
p->tok_i++;
|
||||
const AstTokenIndex comptime_token = nextToken(p);
|
||||
const AstNodeIndex block_node = parseBlock(p);
|
||||
SLICE_APPEND(AstNodeIndex, &p->scratch,
|
||||
addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_COMPTIME,
|
||||
.main_token = p->tok_i - 1,
|
||||
.main_token = comptime_token,
|
||||
.data = { .lhs = block_node, .rhs = 0 },
|
||||
}));
|
||||
trailing = p->token_tags[p->tok_i - 1] == TOKEN_R_BRACE;
|
||||
|
||||
@@ -234,8 +234,6 @@ fn zigData(tag: Ast.Node.Tag, lhs: u32, rhs: u32) Ast.Node.Data {
|
||||
.container_field_align,
|
||||
.error_union,
|
||||
.@"catch",
|
||||
.field_access,
|
||||
.unwrap_optional,
|
||||
.equal_equal,
|
||||
.bang_equal,
|
||||
.less_than,
|
||||
@@ -378,6 +376,8 @@ fn zigData(tag: Ast.Node.Tag, lhs: u32, rhs: u32) Ast.Node.Data {
|
||||
// .node_and_token
|
||||
.grouped_expression,
|
||||
.asm_input,
|
||||
.field_access,
|
||||
.unwrap_optional,
|
||||
=> .{ .node_and_token = .{ toIndex(lhs), rhs } },
|
||||
|
||||
// .opt_node_and_token
|
||||
@@ -599,3 +599,53 @@ test "zig fmt: respect line breaks in struct field value declaration" {
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: respect line breaks before functions" {
|
||||
try testCanonical(
|
||||
\\const std = @import("std");
|
||||
\\
|
||||
\\inline fn foo() void {}
|
||||
\\
|
||||
\\noinline fn foo() void {}
|
||||
\\
|
||||
\\export fn foo() void {}
|
||||
\\
|
||||
\\extern fn foo() void;
|
||||
\\
|
||||
\\extern "foo" fn foo() void;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: simple top level comptime block" {
|
||||
try testCanonical(
|
||||
\\// line comment
|
||||
\\comptime {}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: two spaced line comments before decl" {
|
||||
try testCanonical(
|
||||
\\// line comment
|
||||
\\
|
||||
\\// another
|
||||
\\comptime {}
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: respect line breaks after var declarations" {
|
||||
try testCanonical(
|
||||
\\const crc =
|
||||
\\ lookup_tables[0][p[7]] ^
|
||||
\\ lookup_tables[1][p[6]] ^
|
||||
\\ lookup_tables[2][p[5]] ^
|
||||
\\ lookup_tables[3][p[4]] ^
|
||||
\\ lookup_tables[4][@as(u8, self.crc >> 24)] ^
|
||||
\\ lookup_tables[5][@as(u8, self.crc >> 16)] ^
|
||||
\\ lookup_tables[6][@as(u8, self.crc >> 8)] ^
|
||||
\\ lookup_tables[7][@as(u8, self.crc >> 0)];
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user