@@ -808,7 +808,6 @@ fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
808
808
// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)?
809
809
fn parseCompareExpr (arena : * Allocator , it : * TokenIterator , tree : * Tree ) ! ? * Node {
810
810
return parseBinOpExpr (arena , it , tree , parseCompareOp , parseBitwiseExpr , .Once );
811
- // TODO: stage1 supplies BinOpChainInf, not Once, but grammar uses `?`
812
811
}
813
812
814
813
// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)*
@@ -849,8 +848,6 @@ fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
849
848
// / Block
850
849
// / CurlySuffixExpr
851
850
fn parsePrimaryExpr (arena : * Allocator , it : * TokenIterator , tree : * Tree ) ! ? * Node {
852
- // TODO: enum literal not represented in grammar: https://github.com/ziglang/zig/issues/2235
853
- if (try parseEnumLiteral (arena , it , tree )) | node | return node ;
854
851
if (try parseAsmExpr (arena , it , tree )) | node | return node ;
855
852
if (try parseIfExpr (arena , it , tree )) | node | return node ;
856
853
@@ -1213,6 +1210,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1213
1210
// <- BUILTINIDENTIFIER FnCallArguments
1214
1211
// / CHAR_LITERAL
1215
1212
// / ContainerDecl
1213
+ // / DOT IDENTIFIER
1216
1214
// / ErrorSetDecl
1217
1215
// / FLOAT
1218
1216
// / FnProto
@@ -1243,6 +1241,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1243
1241
return & node .base ;
1244
1242
}
1245
1243
if (try parseContainerDecl (arena , it , tree )) | node | return node ;
1244
+ if (try parseEnumLiteral (arena , it , tree )) | node | return node ;
1246
1245
if (try parseErrorSetDecl (arena , it , tree )) | node | return node ;
1247
1246
if (try parseFloatLiteral (arena , it , tree )) | node | return node ;
1248
1247
if (try parseFnProto (arena , it , tree )) | node | return node ;
@@ -1318,7 +1317,7 @@ fn parseContainerDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
1318
1317
fn parseErrorSetDecl (arena : * Allocator , it : * TokenIterator , tree : * Tree ) ! ? * Node {
1319
1318
const error_token = eatToken (it , .Keyword_error ) orelse return null ;
1320
1319
if (eatToken (it , .LBrace ) == null ) {
1321
- // TODO: Check the order of choices that leads to this not being "expectToken"
1320
+ // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error
1322
1321
_ = prevToken (it );
1323
1322
return null ;
1324
1323
}
@@ -1381,8 +1380,11 @@ fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1381
1380
}
1382
1381
1383
1382
if (label != null ) {
1384
- _ = prevToken (it ); // rewind IDENTIFIER
1385
- _ = prevToken (it ); // rewind ":"
1383
+ // If we saw a label, there should have been a block next
1384
+ try tree .errors .push (AstError {
1385
+ .ExpectedLBrace = AstError.ExpectedLBrace { .token = it .index },
1386
+ });
1387
+ return Error .UnexpectedToken ;
1386
1388
}
1387
1389
return null ;
1388
1390
}
@@ -1519,11 +1521,10 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1519
1521
return & node .base ;
1520
1522
}
1521
1523
1522
- // TODO: enum literal not represented in grammar: https://github.com/ziglang/zig/issues/2235
1524
+ // DOT IDENTIFIER
1523
1525
fn parseEnumLiteral (arena : * Allocator , it : * TokenIterator , tree : * Tree ) ! ? * Node {
1524
1526
const dot = eatToken (it , .Period ) orelse return null ;
1525
1527
const name = try expectToken (it , tree , .Identifier );
1526
-
1527
1528
const node = try arena .create (Node .EnumLiteral );
1528
1529
node .* = Node.EnumLiteral {
1529
1530
.base = Node { .id = .EnumLiteral },
@@ -1646,7 +1647,12 @@ fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) ?TokenInd
1646
1647
fn parseFieldInit (arena : * Allocator , it : * TokenIterator , tree : * Tree ) ! ? * Node {
1647
1648
const period_token = eatToken (it , .Period ) orelse return null ;
1648
1649
const name_token = try expectToken (it , tree , .Identifier );
1649
- const eq_token = try expectToken (it , tree , .Equal );
1650
+ const eq_token = eatToken (it , .Equal ) orelse {
1651
+ // `.Name` may also be an enum literal, which is a later rule.
1652
+ _ = prevToken (it ); // rewind IDENTIFIER
1653
+ _ = prevToken (it ); // rewind DOT
1654
+ return null ;
1655
+ };
1650
1656
const expr_node = try expectNode (arena , it , tree , parseExpr , AstError {
1651
1657
.ExpectedExpr = AstError.ExpectedExpr { .token = it .index },
1652
1658
});
@@ -2204,10 +2210,8 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2204
2210
return & node .base ;
2205
2211
}
2206
2212
2207
- // TODO: last choice allows for `*const volatile volatile const`, `*align(4) align(8) align(4)` etc.
2208
2213
// TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on
2209
- // pointers. (Note: does align(x) work for arrays as well as slices/pointers? Does volatile?)
2210
- // Maybe it would be better to have two separate rules?
2214
+ // pointers. Consider updating this rule:
2211
2215
// ...
2212
2216
// / ArrayTypeStart
2213
2217
// / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
@@ -2255,23 +2259,48 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2255
2259
switch (node .cast (Node .PrefixOp ).? .op ) {
2256
2260
.ArrayType = > {},
2257
2261
.SliceType = > | * slice_type | {
2262
+ // Collect pointer qualifiers in any order, but disallow duplicates
2258
2263
while (true ) {
2259
2264
if (try parseByteAlign (arena , it , tree )) | align_expr | {
2265
+ if (slice_type .align_info != null ) {
2266
+ try tree .errors .push (AstError {
2267
+ .ExtraAlignQualifier = AstError.ExtraAlignQualifier { .token = it .index },
2268
+ });
2269
+ return Error .UnexpectedToken ;
2270
+ }
2260
2271
slice_type .align_info = Node.PrefixOp.PtrInfo.Align {
2261
2272
.node = align_expr ,
2262
2273
.bit_range = null ,
2263
2274
};
2264
2275
continue ;
2265
2276
}
2266
2277
if (eatToken (it , .Keyword_const )) | const_token | {
2278
+ if (slice_type .const_token != null ) {
2279
+ try tree .errors .push (AstError {
2280
+ .ExtraConstQualifier = AstError.ExtraConstQualifier { .token = it .index },
2281
+ });
2282
+ return Error .UnexpectedToken ;
2283
+ }
2267
2284
slice_type .const_token = const_token ;
2268
2285
continue ;
2269
2286
}
2270
2287
if (eatToken (it , .Keyword_volatile )) | volatile_token | {
2288
+ if (slice_type .volatile_token != null ) {
2289
+ try tree .errors .push (AstError {
2290
+ .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier { .token = it .index },
2291
+ });
2292
+ return Error .UnexpectedToken ;
2293
+ }
2271
2294
slice_type .volatile_token = volatile_token ;
2272
2295
continue ;
2273
2296
}
2274
2297
if (eatToken (it , .Keyword_allowzero )) | allowzero_token | {
2298
+ if (slice_type .allowzero_token != null ) {
2299
+ try tree .errors .push (AstError {
2300
+ .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier { .token = it .index },
2301
+ });
2302
+ return Error .UnexpectedToken ;
2303
+ }
2275
2304
slice_type .allowzero_token = allowzero_token ;
2276
2305
continue ;
2277
2306
}
0 commit comments