diff --git a/parser.c b/parser.c index d1f858b026..1f96dee260 100644 --- a/parser.c +++ b/parser.c @@ -839,10 +839,25 @@ static AstNodeIndex parseTypeExpr(Parser* p) { .data = { .lhs = 0, .rhs = child_type }, }); } - case TOKEN_ASTERISK_ASTERISK: - fprintf(stderr, "parseTypeExpr not supported for %s\n", - tokenizerGetTagString(tok)); - exit(1); + case TOKEN_ASTERISK_ASTERISK: { + // ** is two nested pointer types sharing the same token + 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 + return addNode(&p->nodes, + (AstNodeItem) { + .tag = AST_NODE_PTR_TYPE_ALIGNED, + .main_token = asterisk, + .data = { .lhs = 0, .rhs = inner }, + }); + } case TOKEN_L_BRACKET: { const AstTokenIndex lbracket = nextToken(p); if (p->token_tags[p->tok_i] == TOKEN_ASTERISK) { diff --git a/parser_test.zig b/parser_test.zig index 90a0544cd7..3f1e2fefd8 100644 --- a/parser_test.zig +++ b/parser_test.zig @@ -1812,3 +1812,10 @@ test "zig fmt: top-level bare asterisk+identifier" { \\ ); } + +test "zig fmt: top-level bare asterisk+asterisk+identifier" { + try testCanonical( + \\**x + \\ + ); +}