parser: port pointer/slice attributes tests
Port tests: - "pointer attributes" - "slice attributes" Fix ** pointer type to parse modifiers per upstream (no sentinel, modifiers on inner pointer only). Fix ptr_type selection when both sentinel and align are present (use ptr_type with extra data instead of ptr_type_sentinel which can't store alignment). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
93
parser.c
93
parser.c
@@ -897,7 +897,7 @@ static AstNodeIndex parsePtrModifiersAndType(
|
||||
},
|
||||
});
|
||||
}
|
||||
if (addrspace_expr != 0) {
|
||||
if (addrspace_expr != 0 || (sentinel != 0 && align_expr != 0)) {
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE,
|
||||
@@ -905,7 +905,7 @@ static AstNodeIndex parsePtrModifiersAndType(
|
||||
.data = {
|
||||
.lhs = addExtra(p,
|
||||
(AstNodeIndex[]) { OPT(sentinel), OPT(align_expr),
|
||||
addrspace_expr },
|
||||
OPT(addrspace_expr) },
|
||||
3),
|
||||
.rhs = child_type,
|
||||
},
|
||||
@@ -946,17 +946,74 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
|
||||
return parsePtrModifiersAndType(p, asterisk);
|
||||
}
|
||||
case TOKEN_ASTERISK_ASTERISK: {
|
||||
// ** is two nested pointer types sharing the same token
|
||||
// ** is two nested pointer types sharing the same token.
|
||||
// Inner pointer gets modifiers, outer wraps it with none.
|
||||
// (Matches upstream Parse.zig asterisk_asterisk case)
|
||||
const AstTokenIndex asterisk = nextToken(p);
|
||||
// Inner pointer: parse modifiers and child type
|
||||
const AstNodeIndex inner_child = parseTypeExpr(p);
|
||||
const AstNodeIndex inner = addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE_ALIGNED,
|
||||
.main_token = asterisk,
|
||||
.data = { .lhs = 0, .rhs = inner_child },
|
||||
});
|
||||
// Outer pointer wraps the inner
|
||||
|
||||
// Parse inner pointer modifiers (no sentinel for **)
|
||||
while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST
|
||||
|| p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE
|
||||
|| p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO)
|
||||
p->tok_i++;
|
||||
AstNodeIndex align_expr = 0;
|
||||
AstNodeIndex bit_range_start = 0;
|
||||
AstNodeIndex bit_range_end = 0;
|
||||
if (eatToken(p, TOKEN_KEYWORD_ALIGN) != null_token) {
|
||||
expectToken(p, TOKEN_L_PAREN);
|
||||
align_expr = expectExpr(p);
|
||||
if (eatToken(p, TOKEN_COLON) != null_token) {
|
||||
bit_range_start = expectExpr(p);
|
||||
expectToken(p, TOKEN_COLON);
|
||||
bit_range_end = expectExpr(p);
|
||||
}
|
||||
expectToken(p, TOKEN_R_PAREN);
|
||||
}
|
||||
const AstNodeIndex addrspace_expr = parseAddrSpace(p);
|
||||
while (p->token_tags[p->tok_i] == TOKEN_KEYWORD_CONST
|
||||
|| p->token_tags[p->tok_i] == TOKEN_KEYWORD_VOLATILE
|
||||
|| p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO)
|
||||
p->tok_i++;
|
||||
const AstNodeIndex elem_type = parseTypeExpr(p);
|
||||
assert(elem_type != 0);
|
||||
|
||||
AstNodeIndex inner;
|
||||
if (bit_range_start != 0) {
|
||||
inner = addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE_BIT_RANGE,
|
||||
.main_token = asterisk,
|
||||
.data = {
|
||||
.lhs = addExtra(p,
|
||||
(AstNodeIndex[]) { OPT(0), align_expr,
|
||||
OPT(addrspace_expr), bit_range_start,
|
||||
bit_range_end },
|
||||
5),
|
||||
.rhs = elem_type,
|
||||
},
|
||||
});
|
||||
} else if (addrspace_expr != 0) {
|
||||
inner = addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE,
|
||||
.main_token = asterisk,
|
||||
.data = {
|
||||
.lhs = addExtra(p,
|
||||
(AstNodeIndex[]) { OPT(0), OPT(align_expr),
|
||||
addrspace_expr },
|
||||
3),
|
||||
.rhs = elem_type,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
inner = addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE_ALIGNED,
|
||||
.main_token = asterisk,
|
||||
.data = { .lhs = align_expr, .rhs = elem_type },
|
||||
});
|
||||
}
|
||||
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE_ALIGNED,
|
||||
@@ -1034,7 +1091,7 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
|
||||
},
|
||||
});
|
||||
}
|
||||
if (addrspace_expr != 0) {
|
||||
if (addrspace_expr != 0 || (sentinel != 0 && align_expr != 0)) {
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE,
|
||||
@@ -1042,7 +1099,8 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
|
||||
.data = {
|
||||
.lhs = addExtra(p,
|
||||
(AstNodeIndex[]) { OPT(sentinel),
|
||||
OPT(align_expr), addrspace_expr },
|
||||
OPT(align_expr),
|
||||
OPT(addrspace_expr) },
|
||||
3),
|
||||
.rhs = elem_type,
|
||||
},
|
||||
@@ -1081,7 +1139,7 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
|
||||
|| p->token_tags[p->tok_i] == TOKEN_KEYWORD_ALLOWZERO)
|
||||
p->tok_i++;
|
||||
const AstNodeIndex elem_type = parseTypeExpr(p);
|
||||
if (addrspace_expr != 0) {
|
||||
if (addrspace_expr != 0 || (sentinel != 0 && align_expr != 0)) {
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE,
|
||||
@@ -1089,13 +1147,14 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
|
||||
.data = {
|
||||
.lhs = addExtra(p,
|
||||
(AstNodeIndex[]) { OPT(sentinel),
|
||||
OPT(align_expr), addrspace_expr },
|
||||
OPT(align_expr),
|
||||
OPT(addrspace_expr) },
|
||||
3),
|
||||
.rhs = elem_type,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (sentinel != 0 && align_expr == 0) {
|
||||
if (sentinel != 0) {
|
||||
return addNode(&p->nodes,
|
||||
(AstNodeItem) {
|
||||
.tag = AST_NODE_PTR_TYPE_SENTINEL,
|
||||
|
||||
@@ -2850,6 +2850,28 @@ test "zig fmt: nested pointers with ** tokens" {
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: pointer attributes" {
|
||||
try testCanonical(
|
||||
\\extern fn f1(s: *align(*u8) u8) c_int;
|
||||
\\extern fn f2(s: **align(1) *const *volatile u8) c_int;
|
||||
\\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int;
|
||||
\\extern fn f4(s: *align(1) const volatile u8) c_int;
|
||||
\\extern fn f5(s: [*:0]align(1) const volatile u8) c_int;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: slice attributes" {
|
||||
try testCanonical(
|
||||
\\extern fn f1(s: []align(*u8) u8) c_int;
|
||||
\\extern fn f2(s: []align(1) []const []volatile u8) c_int;
|
||||
\\extern fn f3(s: []align(1) const [:0]align(1) volatile []const volatile u8) c_int;
|
||||
\\extern fn f4(s: []align(1) const volatile u8) c_int;
|
||||
\\extern fn f5(s: [:0]align(1) const volatile u8) c_int;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: test declaration" {
|
||||
try testCanonical(
|
||||
\\test "test name" {
|
||||
@@ -5550,5 +5572,3 @@ fn zigAst(gpa: Allocator, c_ast: c.Ast) !Ast {
|
||||
.errors = errors,
|
||||
};
|
||||
}
|
||||
|
||||
// copy-past from parser_test.zig
|
||||
|
||||
Reference in New Issue
Block a user