| ... | ... | @@ -81,6 +81,7 @@ pub const Parser = struct { |
| 81 | 81 | MultiplyExpression: DestPtr, |
| 82 | 82 | BraceSuffixExpression: DestPtr, |
| 83 | 83 | PrefixOpExpression: DestPtr, |
| 84 | AddrOfModifiers: &ast.NodeAddrOfExpr, |
| 84 | 85 | SuffixOpExpression: DestPtr, |
| 85 | 86 | PrimaryExpression: DestPtr, |
| 86 | 87 | TypeExpr: DestPtr, |
| ... | ... | @@ -350,30 +351,51 @@ pub const Parser = struct { |
| 350 | 351 | |
| 351 | 352 | State.PrefixOpExpression => |dest_ptr| { |
| 352 | 353 | const first_token = self.getNextToken(); |
| 353 | | if (first_token.id == Token.Id.Ampersand) { |
| 354 | | const addr_of_expr = %return self.createAttachAddrOfExpr(dest_ptr, first_token); |
| 355 | | var token = self.getNextToken(); |
| 356 | | if (token.id == Token.Id.Keyword_align) { |
| 357 | | @panic("TODO align"); |
| 358 | | } |
| 359 | | if (token.id == Token.Id.Keyword_const) { |
| 354 | switch (first_token.id) { |
| 355 | Token.Id.Ampersand => { |
| 356 | const addr_of_expr = %return self.createAttachAddrOfExpr(dest_ptr, first_token); |
| 357 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; |
| 358 | continue; |
| 359 | }, |
| 360 | else => { |
| 361 | self.putBackToken(first_token); |
| 362 | stack.append(State { .SuffixOpExpression = dest_ptr }) %% unreachable; |
| 363 | continue; |
| 364 | }, |
| 365 | } |
| 366 | }, |
| 367 | |
| 368 | State.AddrOfModifiers => |addr_of_expr| { |
| 369 | var token = self.getNextToken(); |
| 370 | switch (token.id) { |
| 371 | Token.Id.Keyword_align => { |
| 372 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; |
| 373 | if (addr_of_expr.align_expr != null) return self.parseError(token, "multiple align qualifiers"); |
| 374 | _ = %return self.eatToken(Token.Id.LParen); |
| 375 | %return stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 376 | %return stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_expr.align_expr} }); |
| 377 | continue; |
| 378 | }, |
| 379 | Token.Id.Keyword_const => { |
| 380 | if (addr_of_expr.const_token != null) return self.parseError(token, "duplicate qualifier: const"); |
| 360 | 381 | addr_of_expr.const_token = token; |
| 361 | | token = self.getNextToken(); |
| 362 | | } |
| 363 | | if (token.id == Token.Id.Keyword_volatile) { |
| 382 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; |
| 383 | continue; |
| 384 | }, |
| 385 | Token.Id.Keyword_volatile => { |
| 386 | if (addr_of_expr.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile"); |
| 364 | 387 | addr_of_expr.volatile_token = token; |
| 365 | | token = self.getNextToken(); |
| 366 | | } |
| 367 | | self.putBackToken(token); |
| 368 | | stack.append(State { |
| 369 | | .PrefixOpExpression = DestPtr { .Field = &addr_of_expr.op_expr}, |
| 370 | | }) %% unreachable; |
| 371 | | continue; |
| 388 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; |
| 389 | continue; |
| 390 | }, |
| 391 | else => { |
| 392 | self.putBackToken(token); |
| 393 | stack.append(State { |
| 394 | .PrefixOpExpression = DestPtr { .Field = &addr_of_expr.op_expr}, |
| 395 | }) %% unreachable; |
| 396 | continue; |
| 397 | }, |
| 372 | 398 | } |
| 373 | | |
| 374 | | self.putBackToken(first_token); |
| 375 | | stack.append(State { .SuffixOpExpression = dest_ptr }) %% unreachable; |
| 376 | | continue; |
| 377 | 399 | }, |
| 378 | 400 | |
| 379 | 401 | State.SuffixOpExpression => |dest_ptr| { |
| ... | ... | @@ -997,7 +1019,7 @@ pub const Parser = struct { |
| 997 | 1019 | |
| 998 | 1020 | if (addr_of_expr.align_expr) |align_expr| { |
| 999 | 1021 | %return stream.print("align("); |
| 1000 | | %return stack.append(RenderState { .Text = ")"}); |
| 1022 | %return stack.append(RenderState { .Text = ") "}); |
| 1001 | 1023 | %return stack.append(RenderState { .Expression = align_expr}); |
| 1002 | 1024 | } |
| 1003 | 1025 | }, |
| ... | ... | @@ -1189,4 +1211,16 @@ test "zig fmt" { |
| 1189 | 1211 | \\} |
| 1190 | 1212 | \\ |
| 1191 | 1213 | ); |
| 1214 | |
| 1215 | testCanonical( |
| 1216 | \\extern fn f1(s: &align(&u8) u8) -> c_int; |
| 1217 | \\ |
| 1218 | ); |
| 1219 | |
| 1220 | testCanonical( |
| 1221 | \\extern fn f1(s: &&align(1) &const &volatile u8) -> c_int; |
| 1222 | \\extern fn f2(s: &align(1) const &align(1) volatile &const volatile u8) -> c_int; |
| 1223 | \\extern fn f3(s: &align(1) const volatile u8) -> c_int; |
| 1224 | \\ |
| 1225 | ); |
| 1192 | 1226 | } |