| ... | @@ -68,7 +68,12 @@ pub const Parser = struct { | ... | @@ -68,7 +68,12 @@ pub const Parser = struct { |
| 68 | TopLevelExtern: ?Token, | 68 | TopLevelExtern: ?Token, |
| 69 | TopLevelDecl: TopLevelDeclCtx, | 69 | TopLevelDecl: TopLevelDeclCtx, |
| 70 | Expression: DestPtr, | 70 | Expression: DestPtr, |
| 71 | AddrOfModifiers: &ast.NodeAddrOfExpr, | 71 | ExpectOperand, |
| | 72 | Operand: &ast.Node, |
| | 73 | AfterOperand, |
| | 74 | InfixOp: &ast.NodeInfixOp, |
| | 75 | PrefixOp: &ast.NodePrefixOp, |
| | 76 | AddrOfModifiers: &ast.NodePrefixOp.AddrOfInfo, |
| 72 | TypeExpr: DestPtr, | 77 | TypeExpr: DestPtr, |
| 73 | VarDecl: &ast.NodeVarDecl, | 78 | VarDecl: &ast.NodeVarDecl, |
| 74 | VarDeclAlign: &ast.NodeVarDecl, | 79 | VarDeclAlign: &ast.NodeVarDecl, |
| ... | @@ -265,63 +270,140 @@ pub const Parser = struct { | ... | @@ -265,63 +270,140 @@ pub const Parser = struct { |
| 265 | _ = %return self.eatToken(token_id); | 270 | _ = %return self.eatToken(token_id); |
| 266 | continue; | 271 | continue; |
| 267 | }, | 272 | }, |
| | 273 | |
| 268 | State.Expression => |dest_ptr| { | 274 | State.Expression => |dest_ptr| { |
| | 275 | // save the dest_ptr for later |
| | 276 | stack.append(state) %% unreachable; |
| | 277 | %return stack.append(State.ExpectOperand); |
| | 278 | continue; |
| | 279 | }, |
| | 280 | State.ExpectOperand => { |
| | 281 | // we'll either get an operand (like 1 or x), |
| | 282 | // or a prefix operator (like ~ or return). |
| 269 | const token = self.getNextToken(); | 283 | const token = self.getNextToken(); |
| 270 | switch (token.id) { | 284 | switch (token.id) { |
| 271 | Token.Id.Keyword_return => { | 285 | Token.Id.Keyword_return => { |
| 272 | const return_node = %return self.createAttachReturn(dest_ptr, token); | 286 | %return stack.append(State { .PrefixOp = %return self.createPrefixOp(token, |
| 273 | stack.append(State {.Expression = DestPtr {.Field = &return_node.expr} }) %% unreachable; | 287 | ast.NodePrefixOp.PrefixOp.Return) }); |
| | 288 | %return stack.append(State.ExpectOperand); |
| | 289 | continue; |
| | 290 | }, |
| | 291 | Token.Id.Ampersand => { |
| | 292 | const prefix_op = %return self.createPrefixOp(token, ast.NodePrefixOp.PrefixOp{ |
| | 293 | .AddrOf = ast.NodePrefixOp.AddrOfInfo { |
| | 294 | .align_expr = null, |
| | 295 | .bit_offset_start_token = null, |
| | 296 | .bit_offset_end_token = null, |
| | 297 | .const_token = null, |
| | 298 | .volatile_token = null, |
| | 299 | } |
| | 300 | }); |
| | 301 | %return stack.append(State { .PrefixOp = prefix_op }); |
| | 302 | %return stack.append(State.ExpectOperand); |
| | 303 | %return stack.append(State { .AddrOfModifiers = &prefix_op.op.AddrOf }); |
| 274 | continue; | 304 | continue; |
| 275 | }, | 305 | }, |
| 276 | Token.Id.Identifier => { | 306 | Token.Id.Identifier => { |
| 277 | _ = %return self.createAttachIdentifier(dest_ptr, token); | 307 | %return stack.append(State { |
| | 308 | .Operand = &(%return self.createIdentifier(token)).base |
| | 309 | }); |
| | 310 | %return stack.append(State.AfterOperand); |
| 278 | continue; | 311 | continue; |
| 279 | }, | 312 | }, |
| 280 | Token.Id.IntegerLiteral => { | 313 | Token.Id.IntegerLiteral => { |
| 281 | _ = %return self.createAttachIntegerLiteral(dest_ptr, token); | 314 | %return stack.append(State { |
| | 315 | .Operand = &(%return self.createIntegerLiteral(token)).base |
| | 316 | }); |
| | 317 | %return stack.append(State.AfterOperand); |
| 282 | continue; | 318 | continue; |
| 283 | }, | 319 | }, |
| 284 | Token.Id.FloatLiteral => { | 320 | Token.Id.FloatLiteral => { |
| 285 | _ = %return self.createAttachFloatLiteral(dest_ptr, token); | 321 | %return stack.append(State { |
| | 322 | .Operand = &(%return self.createFloatLiteral(token)).base |
| | 323 | }); |
| | 324 | %return stack.append(State.AfterOperand); |
| 286 | continue; | 325 | continue; |
| 287 | }, | 326 | }, |
| 288 | Token.Id.Ampersand => { | 327 | else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)), |
| 289 | const addr_of_expr = %return self.createAttachAddrOfExpr(dest_ptr, token); | 328 | } |
| 290 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; | 329 | }, |
| | 330 | |
| | 331 | State.AfterOperand => { |
| | 332 | // we'll either get an infix operator (like != or ^), |
| | 333 | // or a postfix operator (like () or {}), |
| | 334 | // otherwise this expression is done (like on a ; or else). |
| | 335 | var token = self.getNextToken(); |
| | 336 | switch (token.id) { |
| | 337 | Token.Id.EqualEqual => { |
| | 338 | %return stack.append(State { |
| | 339 | .InfixOp = %return self.createInfixOp(token, ast.NodeInfixOp.InfixOp.EqualEqual) |
| | 340 | }); |
| | 341 | %return stack.append(State.ExpectOperand); |
| | 342 | continue; |
| | 343 | }, |
| | 344 | Token.Id.BangEqual => { |
| | 345 | %return stack.append(State { |
| | 346 | .InfixOp = %return self.createInfixOp(token, ast.NodeInfixOp.InfixOp.BangEqual) |
| | 347 | }); |
| | 348 | %return stack.append(State.ExpectOperand); |
| | 349 | continue; |
| | 350 | }, |
| | 351 | else => { |
| | 352 | // no postfix/infix operator after this operand. |
| | 353 | self.putBackToken(token); |
| | 354 | // reduce the stack |
| | 355 | var expression: &ast.Node = stack.pop().Operand; |
| | 356 | while (true) { |
| | 357 | switch (stack.pop()) { |
| | 358 | State.Expression => |dest_ptr| { |
| | 359 | // we're done |
| | 360 | %return dest_ptr.store(expression); |
| | 361 | break; |
| | 362 | }, |
| | 363 | State.InfixOp => |infix_op| { |
| | 364 | infix_op.rhs = expression; |
| | 365 | infix_op.lhs = stack.pop().Operand; |
| | 366 | expression = &infix_op.base; |
| | 367 | continue; |
| | 368 | }, |
| | 369 | State.PrefixOp => |prefix_op| { |
| | 370 | prefix_op.rhs = expression; |
| | 371 | expression = &prefix_op.base; |
| | 372 | continue; |
| | 373 | }, |
| | 374 | else => unreachable, |
| | 375 | } |
| | 376 | } |
| 291 | continue; | 377 | continue; |
| 292 | }, | 378 | }, |
| 293 | else => return self.parseError(token, "expected primary expression, found {}", @tagName(token.id)), | | |
| 294 | } | 379 | } |
| 295 | }, | 380 | }, |
| 296 | | 381 | |
| 297 | State.AddrOfModifiers => |addr_of_expr| { | 382 | State.AddrOfModifiers => |addr_of_info| { |
| 298 | var token = self.getNextToken(); | 383 | var token = self.getNextToken(); |
| 299 | switch (token.id) { | 384 | switch (token.id) { |
| 300 | Token.Id.Keyword_align => { | 385 | Token.Id.Keyword_align => { |
| 301 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; | 386 | stack.append(state) %% unreachable; |
| 302 | if (addr_of_expr.align_expr != null) return self.parseError(token, "multiple align qualifiers"); | 387 | if (addr_of_info.align_expr != null) return self.parseError(token, "multiple align qualifiers"); |
| 303 | _ = %return self.eatToken(Token.Id.LParen); | 388 | _ = %return self.eatToken(Token.Id.LParen); |
| 304 | %return stack.append(State { .ExpectToken = Token.Id.RParen }); | 389 | %return stack.append(State { .ExpectToken = Token.Id.RParen }); |
| 305 | %return stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_expr.align_expr} }); | 390 | %return stack.append(State { .Expression = DestPtr{.NullableField = &addr_of_info.align_expr} }); |
| 306 | continue; | 391 | continue; |
| 307 | }, | 392 | }, |
| 308 | Token.Id.Keyword_const => { | 393 | Token.Id.Keyword_const => { |
| 309 | if (addr_of_expr.const_token != null) return self.parseError(token, "duplicate qualifier: const"); | 394 | stack.append(state) %% unreachable; |
| 310 | addr_of_expr.const_token = token; | 395 | if (addr_of_info.const_token != null) return self.parseError(token, "duplicate qualifier: const"); |
| 311 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; | 396 | addr_of_info.const_token = token; |
| 312 | continue; | 397 | continue; |
| 313 | }, | 398 | }, |
| 314 | Token.Id.Keyword_volatile => { | 399 | Token.Id.Keyword_volatile => { |
| 315 | if (addr_of_expr.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile"); | 400 | stack.append(state) %% unreachable; |
| 316 | addr_of_expr.volatile_token = token; | 401 | if (addr_of_info.volatile_token != null) return self.parseError(token, "duplicate qualifier: volatile"); |
| 317 | stack.append(State { .AddrOfModifiers = addr_of_expr }) %% unreachable; | 402 | addr_of_info.volatile_token = token; |
| 318 | continue; | 403 | continue; |
| 319 | }, | 404 | }, |
| 320 | else => { | 405 | else => { |
| 321 | self.putBackToken(token); | 406 | self.putBackToken(token); |
| 322 | stack.append(State { | | |
| 323 | .Expression = DestPtr { .Field = &addr_of_expr.op_expr}, | | |
| 324 | }) %% unreachable; | | |
| 325 | continue; | 407 | continue; |
| 326 | }, | 408 | }, |
| 327 | } | 409 | } |
| ... | @@ -482,8 +564,14 @@ pub const Parser = struct { | ... | @@ -482,8 +564,14 @@ pub const Parser = struct { |
| 482 | %return stack.append(State { .Expression = DestPtr{.List = &block.statements} }); | 564 | %return stack.append(State { .Expression = DestPtr{.List = &block.statements} }); |
| 483 | continue; | 565 | continue; |
| 484 | }, | 566 | }, |
| | 567 | |
| | 568 | // These are data, not control flow. |
| | 569 | State.InfixOp => unreachable, |
| | 570 | State.PrefixOp => unreachable, |
| | 571 | State.Operand => unreachable, |
| 485 | } | 572 | } |
| 486 | unreachable; | 573 | @import("std").debug.panic("{}", @tagName(state)); |
| | 574 | //unreachable; |
| 487 | } | 575 | } |
| 488 | } | 576 | } |
| 489 | | 577 | |
| ... | @@ -560,23 +648,6 @@ pub const Parser = struct { | ... | @@ -560,23 +648,6 @@ pub const Parser = struct { |
| 560 | return node; | 648 | return node; |
| 561 | } | 649 | } |
| 562 | | 650 | |
| 563 | fn createAddrOfExpr(self: &Parser, op_token: &const Token) -> %&ast.NodeAddrOfExpr { | | |
| 564 | const node = %return self.allocator.create(ast.NodeAddrOfExpr); | | |
| 565 | %defer self.allocator.destroy(node); | | |
| 566 | | | |
| 567 | *node = ast.NodeAddrOfExpr { | | |
| 568 | .base = ast.Node {.id = ast.Node.Id.AddrOfExpr}, | | |
| 569 | .align_expr = null, | | |
| 570 | .op_token = *op_token, | | |
| 571 | .bit_offset_start_token = null, | | |
| 572 | .bit_offset_end_token = null, | | |
| 573 | .const_token = null, | | |
| 574 | .volatile_token = null, | | |
| 575 | .op_expr = undefined, | | |
| 576 | }; | | |
| 577 | return node; | | |
| 578 | } | | |
| 579 | | | |
| 580 | fn createBlock(self: &Parser, begin_token: &const Token) -> %&ast.NodeBlock { | 651 | fn createBlock(self: &Parser, begin_token: &const Token) -> %&ast.NodeBlock { |
| 581 | const node = %return self.allocator.create(ast.NodeBlock); | 652 | const node = %return self.allocator.create(ast.NodeBlock); |
| 582 | %defer self.allocator.destroy(node); | 653 | %defer self.allocator.destroy(node); |
| ... | @@ -590,14 +661,29 @@ pub const Parser = struct { | ... | @@ -590,14 +661,29 @@ pub const Parser = struct { |
| 590 | return node; | 661 | return node; |
| 591 | } | 662 | } |
| 592 | | 663 | |
| 593 | fn createReturn(self: &Parser, return_token: &const Token) -> %&ast.NodeReturn { | 664 | fn createInfixOp(self: &Parser, op_token: &const Token, op: &const ast.NodeInfixOp.InfixOp) -> %&ast.NodeInfixOp { |
| 594 | const node = %return self.allocator.create(ast.NodeReturn); | 665 | const node = %return self.allocator.create(ast.NodeInfixOp); |
| | 666 | %defer self.allocator.destroy(node); |
| | 667 | |
| | 668 | *node = ast.NodeInfixOp { |
| | 669 | .base = ast.Node {.id = ast.Node.Id.InfixOp}, |
| | 670 | .op_token = *op_token, |
| | 671 | .lhs = undefined, |
| | 672 | .op = *op, |
| | 673 | .rhs = undefined, |
| | 674 | }; |
| | 675 | return node; |
| | 676 | } |
| | 677 | |
| | 678 | fn createPrefixOp(self: &Parser, op_token: &const Token, op: &const ast.NodePrefixOp.PrefixOp) -> %&ast.NodePrefixOp { |
| | 679 | const node = %return self.allocator.create(ast.NodePrefixOp); |
| 595 | %defer self.allocator.destroy(node); | 680 | %defer self.allocator.destroy(node); |
| 596 | | 681 | |
| 597 | *node = ast.NodeReturn { | 682 | *node = ast.NodePrefixOp { |
| 598 | .base = ast.Node {.id = ast.Node.Id.Return}, | 683 | .base = ast.Node {.id = ast.Node.Id.PrefixOp}, |
| 599 | .return_token = *return_token, | 684 | .op_token = *op_token, |
| 600 | .expr = undefined, | 685 | .op = *op, |
| | 686 | .rhs = undefined, |
| 601 | }; | 687 | }; |
| 602 | return node; | 688 | return node; |
| 603 | } | 689 | } |
| ... | @@ -635,20 +721,6 @@ pub const Parser = struct { | ... | @@ -635,20 +721,6 @@ pub const Parser = struct { |
| 635 | return node; | 721 | return node; |
| 636 | } | 722 | } |
| 637 | | 723 | |
| 638 | fn createAttachFloatLiteral(self: &Parser, dest_ptr: &const DestPtr, token: &const Token) -> %&ast.NodeFloatLiteral { | | |
| 639 | const node = %return self.createFloatLiteral(token); | | |
| 640 | %defer self.allocator.destroy(node); | | |
| 641 | %return dest_ptr.store(&node.base); | | |
| 642 | return node; | | |
| 643 | } | | |
| 644 | | | |
| 645 | fn createAttachIntegerLiteral(self: &Parser, dest_ptr: &const DestPtr, token: &const Token) -> %&ast.NodeIntegerLiteral { | | |
| 646 | const node = %return self.createIntegerLiteral(token); | | |
| 647 | %defer self.allocator.destroy(node); | | |
| 648 | %return dest_ptr.store(&node.base); | | |
| 649 | return node; | | |
| 650 | } | | |
| 651 | | | |
| 652 | fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) -> %&ast.NodeIdentifier { | 724 | fn createAttachIdentifier(self: &Parser, dest_ptr: &const DestPtr, name_token: &const Token) -> %&ast.NodeIdentifier { |
| 653 | const node = %return self.createIdentifier(name_token); | 725 | const node = %return self.createIdentifier(name_token); |
| 654 | %defer self.allocator.destroy(node); | 726 | %defer self.allocator.destroy(node); |
| ... | @@ -656,20 +728,6 @@ pub const Parser = struct { | ... | @@ -656,20 +728,6 @@ pub const Parser = struct { |
| 656 | return node; | 728 | return node; |
| 657 | } | 729 | } |
| 658 | | 730 | |
| 659 | fn createAttachReturn(self: &Parser, dest_ptr: &const DestPtr, return_token: &const Token) -> %&ast.NodeReturn { | | |
| 660 | const node = %return self.createReturn(return_token); | | |
| 661 | %defer self.allocator.destroy(node); | | |
| 662 | %return dest_ptr.store(&node.base); | | |
| 663 | return node; | | |
| 664 | } | | |
| 665 | | | |
| 666 | fn createAttachAddrOfExpr(self: &Parser, dest_ptr: &const DestPtr, op_token: &const Token) -> %&ast.NodeAddrOfExpr { | | |
| 667 | const node = %return self.createAddrOfExpr(op_token); | | |
| 668 | %defer self.allocator.destroy(node); | | |
| 669 | %return dest_ptr.store(&node.base); | | |
| 670 | return node; | | |
| 671 | } | | |
| 672 | | | |
| 673 | fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) -> %&ast.NodeParamDecl { | 731 | fn createAttachParamDecl(self: &Parser, list: &ArrayList(&ast.Node)) -> %&ast.NodeParamDecl { |
| 674 | const node = %return self.createParamDecl(); | 732 | const node = %return self.createParamDecl(); |
| 675 | %defer self.allocator.destroy(node); | 733 | %defer self.allocator.destroy(node); |
| ... | @@ -783,7 +841,6 @@ pub const Parser = struct { | ... | @@ -783,7 +841,6 @@ pub const Parser = struct { |
| 783 | ParamDecl: &ast.Node, | 841 | ParamDecl: &ast.Node, |
| 784 | Text: []const u8, | 842 | Text: []const u8, |
| 785 | Expression: &ast.Node, | 843 | Expression: &ast.Node, |
| 786 | AddrOfExprBit: &ast.NodeAddrOfExpr, | | |
| 787 | VarDecl: &ast.NodeVarDecl, | 844 | VarDecl: &ast.NodeVarDecl, |
| 788 | Statement: &ast.Node, | 845 | Statement: &ast.Node, |
| 789 | PrintIndent, | 846 | PrintIndent, |
| ... | @@ -912,17 +969,6 @@ pub const Parser = struct { | ... | @@ -912,17 +969,6 @@ pub const Parser = struct { |
| 912 | const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base); | 969 | const identifier = @fieldParentPtr(ast.NodeIdentifier, "base", base); |
| 913 | %return stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token)); | 970 | %return stream.print("{}", self.tokenizer.getTokenSlice(identifier.name_token)); |
| 914 | }, | 971 | }, |
| 915 | ast.Node.Id.AddrOfExpr => { | | |
| 916 | const addr_of_expr = @fieldParentPtr(ast.NodeAddrOfExpr, "base", base); | | |
| 917 | %return stream.print("{}", self.tokenizer.getTokenSlice(addr_of_expr.op_token)); | | |
| 918 | %return stack.append(RenderState { .AddrOfExprBit = addr_of_expr}); | | |
| 919 | | | |
| 920 | if (addr_of_expr.align_expr) |align_expr| { | | |
| 921 | %return stream.print("align("); | | |
| 922 | %return stack.append(RenderState { .Text = ") "}); | | |
| 923 | %return stack.append(RenderState { .Expression = align_expr}); | | |
| 924 | } | | |
| 925 | }, | | |
| 926 | ast.Node.Id.Block => { | 972 | ast.Node.Id.Block => { |
| 927 | const block = @fieldParentPtr(ast.NodeBlock, "base", base); | 973 | const block = @fieldParentPtr(ast.NodeBlock, "base", base); |
| 928 | %return stream.write("{"); | 974 | %return stream.write("{"); |
| ... | @@ -940,10 +986,43 @@ pub const Parser = struct { | ... | @@ -940,10 +986,43 @@ pub const Parser = struct { |
| 940 | %return stack.append(RenderState { .Text = "\n" }); | 986 | %return stack.append(RenderState { .Text = "\n" }); |
| 941 | } | 987 | } |
| 942 | }, | 988 | }, |
| 943 | ast.Node.Id.Return => { | 989 | ast.Node.Id.InfixOp => { |
| 944 | const return_node = @fieldParentPtr(ast.NodeReturn, "base", base); | 990 | const prefix_op_node = @fieldParentPtr(ast.NodeInfixOp, "base", base); |
| 945 | %return stream.write("return "); | 991 | %return stack.append(RenderState { .Expression = prefix_op_node.rhs }); |
| 946 | %return stack.append(RenderState { .Expression = return_node.expr }); | 992 | switch (prefix_op_node.op) { |
| | 993 | ast.NodeInfixOp.InfixOp.EqualEqual => { |
| | 994 | %return stack.append(RenderState { .Text = " == "}); |
| | 995 | }, |
| | 996 | ast.NodeInfixOp.InfixOp.BangEqual => { |
| | 997 | %return stack.append(RenderState { .Text = " != "}); |
| | 998 | }, |
| | 999 | else => unreachable, |
| | 1000 | } |
| | 1001 | %return stack.append(RenderState { .Expression = prefix_op_node.lhs }); |
| | 1002 | }, |
| | 1003 | ast.Node.Id.PrefixOp => { |
| | 1004 | const prefix_op_node = @fieldParentPtr(ast.NodePrefixOp, "base", base); |
| | 1005 | %return stack.append(RenderState { .Expression = prefix_op_node.rhs }); |
| | 1006 | switch (prefix_op_node.op) { |
| | 1007 | ast.NodePrefixOp.PrefixOp.Return => { |
| | 1008 | %return stream.write("return "); |
| | 1009 | }, |
| | 1010 | ast.NodePrefixOp.PrefixOp.AddrOf => |addr_of_info| { |
| | 1011 | %return stream.write("&"); |
| | 1012 | if (addr_of_info.volatile_token != null) { |
| | 1013 | %return stack.append(RenderState { .Text = "volatile "}); |
| | 1014 | } |
| | 1015 | if (addr_of_info.const_token != null) { |
| | 1016 | %return stack.append(RenderState { .Text = "const "}); |
| | 1017 | } |
| | 1018 | if (addr_of_info.align_expr) |align_expr| { |
| | 1019 | %return stream.print("align("); |
| | 1020 | %return stack.append(RenderState { .Text = ") "}); |
| | 1021 | %return stack.append(RenderState { .Expression = align_expr}); |
| | 1022 | } |
| | 1023 | }, |
| | 1024 | else => unreachable, |
| | 1025 | } |
| 947 | }, | 1026 | }, |
| 948 | ast.Node.Id.IntegerLiteral => { | 1027 | ast.Node.Id.IntegerLiteral => { |
| 949 | const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base); | 1028 | const integer_literal = @fieldParentPtr(ast.NodeIntegerLiteral, "base", base); |
| ... | @@ -955,21 +1034,6 @@ pub const Parser = struct { | ... | @@ -955,21 +1034,6 @@ pub const Parser = struct { |
| 955 | }, | 1034 | }, |
| 956 | else => unreachable, | 1035 | else => unreachable, |
| 957 | }, | 1036 | }, |
| 958 | RenderState.AddrOfExprBit => |addr_of_expr| { | | |
| 959 | if (addr_of_expr.bit_offset_start_token) |bit_offset_start_token| { | | |
| 960 | %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_start_token)); | | |
| 961 | } | | |
| 962 | if (addr_of_expr.bit_offset_end_token) |bit_offset_end_token| { | | |
| 963 | %return stream.print("{} ", self.tokenizer.getTokenSlice(bit_offset_end_token)); | | |
| 964 | } | | |
| 965 | if (addr_of_expr.const_token) |const_token| { | | |
| 966 | %return stream.print("{} ", self.tokenizer.getTokenSlice(const_token)); | | |
| 967 | } | | |
| 968 | if (addr_of_expr.volatile_token) |volatile_token| { | | |
| 969 | %return stream.print("{} ", self.tokenizer.getTokenSlice(volatile_token)); | | |
| 970 | } | | |
| 971 | %return stack.append(RenderState { .Expression = addr_of_expr.op_expr}); | | |
| 972 | }, | | |
| 973 | RenderState.FnProtoRParen => |fn_proto| { | 1037 | RenderState.FnProtoRParen => |fn_proto| { |
| 974 | %return stream.print(")"); | 1038 | %return stream.print(")"); |
| 975 | if (fn_proto.align_expr != null) { | 1039 | if (fn_proto.align_expr != null) { |
| ... | @@ -1128,4 +1192,12 @@ test "zig fmt" { | ... | @@ -1128,4 +1192,12 @@ test "zig fmt" { |
| 1128 | \\extern fn f3(s: &align(1) const volatile u8) -> c_int; | 1192 | \\extern fn f3(s: &align(1) const volatile u8) -> c_int; |
| 1129 | \\ | 1193 | \\ |
| 1130 | ); | 1194 | ); |
| | 1195 | |
| | 1196 | testCanonical( |
| | 1197 | \\fn f1(a: bool, b: bool) -> bool { |
| | 1198 | \\ a != b; |
| | 1199 | \\ return a == b; |
| | 1200 | \\} |
| | 1201 | \\ |
| | 1202 | ); |
| 1131 | } | 1203 | } |