commit f5d0a7d8e94dedfae1ac2933fc6572b028b2aa6d (tree)
parent aed96d0ff98c061241bd144fab2a7ef8440ebc72
Author: Motiejus Jakštys <motiejus.jakstys@chronosphere.io>
Date: Tue, 10 Feb 2026 15:05:41 +0000
parser: port test "c pointer type"
Implement [*], [*c], and [*:s] pointer type parsing in parseTypeExpr.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/parser.c b/parser.c
@@ -862,9 +862,71 @@ static AstNodeIndex parseTypeExpr(Parser* p) {
case TOKEN_L_BRACKET: {
const AstTokenIndex lbracket = nextToken(p);
if (p->token_tags[p->tok_i] == TOKEN_ASTERISK) {
- fprintf(
- stderr, "parseTypeExpr: [*] pointer types not implemented\n");
- exit(1);
+ // [*] many-item pointer, [*c] C pointer, [*:s] sentinel
+ p->tok_i++; // consume *
+ AstNodeIndex sentinel = 0;
+ if (p->token_tags[p->tok_i] == TOKEN_IDENTIFIER) {
+ // Check for 'c' modifier: [*c]
+ // The 'c' is a regular identifier token
+ const char c = p->source[p->token_starts[p->tok_i]];
+ if (c == 'c'
+ && p->token_starts[p->tok_i + 1]
+ - p->token_starts[p->tok_i]
+ <= 2) {
+ p->tok_i++; // consume 'c'
+ }
+ } else if (eatToken(p, TOKEN_COLON) != null_token) {
+ sentinel = expectExpr(p);
+ }
+ expectToken(p, TOKEN_R_BRACKET);
+ // const/volatile/allowzero pointer modifiers
+ 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 align_expr = parseByteAlign(p);
+ const AstNodeIndex addrspace_expr = parseAddrSpace(p);
+ // const/volatile/allowzero again (can appear before or after
+ // align)
+ 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);
+ if (sentinel != 0) {
+ if (addrspace_expr != 0) {
+ fprintf(stderr,
+ "parseTypeExpr: [*:s] with addrspace not "
+ "implemented\n");
+ exit(1);
+ }
+ return addNode(&p->nodes,
+ (AstNodeItem) {
+ .tag = AST_NODE_PTR_TYPE_SENTINEL,
+ .main_token = lbracket,
+ .data = { .lhs = sentinel, .rhs = elem_type },
+ });
+ }
+ if (addrspace_expr != 0) {
+ return addNode(&p->nodes,
+ (AstNodeItem) {
+ .tag = AST_NODE_PTR_TYPE,
+ .main_token = lbracket,
+ .data = {
+ .lhs = addExtra(p,
+ (AstNodeIndex[]) {
+ 0, align_expr, addrspace_expr },
+ 3),
+ .rhs = elem_type,
+ },
+ });
+ }
+ return addNode(&p->nodes,
+ (AstNodeItem) {
+ .tag = AST_NODE_PTR_TYPE_ALIGNED,
+ .main_token = lbracket,
+ .data = { .lhs = align_expr, .rhs = elem_type },
+ });
}
const AstNodeIndex len_expr = parseExpr(p);
const AstNodeIndex sentinel
diff --git a/parser_test.zig b/parser_test.zig
@@ -1810,6 +1810,13 @@ test "zig fmt: nosuspend block" {
);
}
+test "zig fmt: c pointer type" {
+ try testCanonical(
+ \\pub extern fn repro() [*c]const u8;
+ \\
+ );
+}
+
test "zig fmt: top-level tuple function call type" {
try testCanonical(
\\foo()