authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-23 23:05:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-23 23:05:26-07:00
logaac6e8c4182b5d70de27b1f325151ac4233ed912
treec745097fb669f9b7f8c21f0bdc264a7d20656d7a
parentb4d383a47876b794b3f0950151c7cdcd5eddfc7a

self-hosted: AST flattening, astgen improvements, result locations, and more

* AST: flatten ControlFlowExpression into Continue, Break, and Return. * AST: unify identifiers and literals into the same AST type: OneToken * AST: ControlFlowExpression uses TrailerFlags to optimize storage space. * astgen: support `var` as well as `const` locals, and support explicitly typed locals. Corresponding Module and codegen code is not implemented yet. * astgen: support result locations. * ZIR: add the following instructions (see the corresponding doc comments for explanations of semantics): - alloc - alloc_inferred - bitcast_result_ptr - coerce_result_block_ptr - coerce_result_ptr - coerce_to_ptr_elem - ensure_result_used - ensure_result_non_error - ret_ptr - ret_type - store - param_type * the skeleton structure for result locations is set up. It's looking pretty clean so far. * add compile error for unused result and compile error for discarding errors. * astgen: split builtin calls up to implemented manually, and implement `@as`, `@bitCast` (and others) with respect to result locations. * add CLI support for hex and raw object formats. They are not supported by the self-hosted compiler yet, and emit errors. * rename `--c` CLI to `-ofmt=[objectformat]` which can be any of the object formats. Only ELF and C are supported so far. Also added missing help to the help text. * Remove hard tabs from C backend test cases. Shame on you Noam, you are grounded, you should know better, etc. Bad boy. * Delete C backend code and test case that relied on comptime_int incorrectly making it all the way to codegen.

12 files changed, 1177 insertions(+), 765 deletions(-)

lib/std/target.zig+2
...@@ -436,6 +436,8 @@ pub const Target = struct {...@@ -436,6 +436,8 @@ pub const Target = struct {
436 macho,436 macho,
437 wasm,437 wasm,
438 c,438 c,
439 hex,
440 raw,
439 };441 };
440442
441 pub const SubSystem = enum {443 pub const SubSystem = enum {
lib/std/zig/ast.zig+85-217
...@@ -495,8 +495,10 @@ pub const Node = struct {...@@ -495,8 +495,10 @@ pub const Node = struct {
495 While,495 While,
496 For,496 For,
497 If,497 If,
498 ControlFlowExpression,
499 Suspend,498 Suspend,
499 Continue,
500 Break,
501 Return,
500502
501 // Type expressions503 // Type expressions
502 AnyType,504 AnyType,
...@@ -601,6 +603,24 @@ pub const Node = struct {...@@ -601,6 +603,24 @@ pub const Node = struct {
601 .Try,603 .Try,
602 => SimplePrefixOp,604 => SimplePrefixOp,
603605
606 .Identifier,
607 .BoolLiteral,
608 .NullLiteral,
609 .UndefinedLiteral,
610 .Unreachable,
611 .AnyType,
612 .ErrorType,
613 .IntegerLiteral,
614 .FloatLiteral,
615 .StringLiteral,
616 .CharLiteral,
617 => OneToken,
618
619 .Continue,
620 .Break,
621 .Return,
622 => ControlFlowExpression,
623
604 .ArrayType => ArrayType,624 .ArrayType => ArrayType,
605 .ArrayTypeSentinel => ArrayTypeSentinel,625 .ArrayTypeSentinel => ArrayTypeSentinel,
606626
...@@ -621,23 +641,11 @@ pub const Node = struct {...@@ -621,23 +641,11 @@ pub const Node = struct {
621 .While => While,641 .While => While,
622 .For => For,642 .For => For,
623 .If => If,643 .If => If,
624 .ControlFlowExpression => ControlFlowExpression,
625 .Suspend => Suspend,644 .Suspend => Suspend,
626 .AnyType => AnyType,
627 .ErrorType => ErrorType,
628 .FnProto => FnProto,645 .FnProto => FnProto,
629 .AnyFrameType => AnyFrameType,646 .AnyFrameType => AnyFrameType,
630 .IntegerLiteral => IntegerLiteral,
631 .FloatLiteral => FloatLiteral,
632 .EnumLiteral => EnumLiteral,647 .EnumLiteral => EnumLiteral,
633 .StringLiteral => StringLiteral,
634 .MultilineStringLiteral => MultilineStringLiteral,648 .MultilineStringLiteral => MultilineStringLiteral,
635 .CharLiteral => CharLiteral,
636 .BoolLiteral => BoolLiteral,
637 .NullLiteral => NullLiteral,
638 .UndefinedLiteral => UndefinedLiteral,
639 .Unreachable => Unreachable,
640 .Identifier => Identifier,
641 .GroupedExpression => GroupedExpression,649 .GroupedExpression => GroupedExpression,
642 .BuiltinCall => BuiltinCall,650 .BuiltinCall => BuiltinCall,
643 .ErrorSetDecl => ErrorSetDecl,651 .ErrorSetDecl => ErrorSetDecl,
...@@ -1182,19 +1190,19 @@ pub const Node = struct {...@@ -1182,19 +1190,19 @@ pub const Node = struct {
1182 }1190 }
1183 };1191 };
11841192
1185 pub const Identifier = struct {1193 pub const OneToken = struct {
1186 base: Node = Node{ .tag = .Identifier },1194 base: Node,
1187 token: TokenIndex,1195 token: TokenIndex,
11881196
1189 pub fn iterate(self: *const Identifier, index: usize) ?*Node {1197 pub fn iterate(self: *const OneToken, index: usize) ?*Node {
1190 return null;1198 return null;
1191 }1199 }
11921200
1193 pub fn firstToken(self: *const Identifier) TokenIndex {1201 pub fn firstToken(self: *const OneToken) TokenIndex {
1194 return self.token;1202 return self.token;
1195 }1203 }
11961204
1197 pub fn lastToken(self: *const Identifier) TokenIndex {1205 pub fn lastToken(self: *const OneToken) TokenIndex {
1198 return self.token;1206 return self.token;
1199 }1207 }
1200 };1208 };
...@@ -2569,34 +2577,65 @@ pub const Node = struct {...@@ -2569,34 +2577,65 @@ pub const Node = struct {
2569 }2577 }
2570 };2578 };
25712579
2572 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.2580 /// Trailed in memory by possibly many things, with each optional thing
2573 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.2581 /// determined by a bit in `trailer_flags`.
2582 /// Can be: return, break, continue
2574 pub const ControlFlowExpression = struct {2583 pub const ControlFlowExpression = struct {
2575 base: Node = Node{ .tag = .ControlFlowExpression },2584 base: Node,
2585 trailer_flags: TrailerFlags,
2576 ltoken: TokenIndex,2586 ltoken: TokenIndex,
2577 kind: Kind,
2578 rhs: ?*Node,
25792587
2580 pub const Kind = union(enum) {2588 pub const TrailerFlags = std.meta.TrailerFlags(struct {
2581 Break: ?*Node,2589 rhs: *Node,
2582 Continue: ?*Node,2590 label: TokenIndex,
2583 Return,2591 });
2592
2593 pub const RequiredFields = struct {
2594 tag: Tag,
2595 ltoken: TokenIndex,
2584 };2596 };
25852597
2598 pub fn getRHS(self: *const ControlFlowExpression) ?*Node {
2599 return self.getTrailer("rhs");
2600 }
2601
2602 pub fn getLabel(self: *const ControlFlowExpression) ?TokenIndex {
2603 return self.getTrailer("label");
2604 }
2605
2606 pub fn getTrailer(self: *const ControlFlowExpression, comptime name: []const u8) ?TrailerFlags.Field(name) {
2607 const trailers_start = @ptrCast([*]const u8, self) + @sizeOf(ControlFlowExpression);
2608 return self.trailer_flags.get(trailers_start, name);
2609 }
2610
2611 pub fn setTrailer(self: *ControlFlowExpression, comptime name: []const u8, value: TrailerFlags.Field(name)) void {
2612 const trailers_start = @ptrCast([*]u8, self) + @sizeOf(ControlFlowExpression);
2613 self.trailer_flags.set(trailers_start, name, value);
2614 }
2615
2616 pub fn create(allocator: *mem.Allocator, required: RequiredFields, trailers: anytype) !*ControlFlowExpression {
2617 const trailer_flags = TrailerFlags.init(trailers);
2618 const bytes = try allocator.alignedAlloc(u8, @alignOf(ControlFlowExpression), sizeInBytes(trailer_flags));
2619 const ctrl_flow_expr = @ptrCast(*ControlFlowExpression, bytes.ptr);
2620 ctrl_flow_expr.* = .{
2621 .base = .{ .tag = required.tag },
2622 .trailer_flags = trailer_flags,
2623 .ltoken = required.ltoken,
2624 };
2625 const trailers_start = bytes.ptr + @sizeOf(ControlFlowExpression);
2626 trailer_flags.setMany(trailers_start, trailers);
2627 return ctrl_flow_expr;
2628 }
2629
2630 pub fn destroy(self: *ControlFlowExpression, allocator: *mem.Allocator) void {
2631 const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.trailer_flags)];
2632 allocator.free(bytes);
2633 }
2634
2586 pub fn iterate(self: *const ControlFlowExpression, index: usize) ?*Node {2635 pub fn iterate(self: *const ControlFlowExpression, index: usize) ?*Node {
2587 var i = index;2636 var i = index;
25882637
2589 switch (self.kind) {2638 if (self.getRHS()) |rhs| {
2590 .Break, .Continue => |maybe_label| {
2591 if (maybe_label) |label| {
2592 if (i < 1) return label;
2593 i -= 1;
2594 }
2595 },
2596 .Return => {},
2597 }
2598
2599 if (self.rhs) |rhs| {
2600 if (i < 1) return rhs;2639 if (i < 1) return rhs;
2601 i -= 1;2640 i -= 1;
2602 }2641 }
...@@ -2609,21 +2648,20 @@ pub const Node = struct {...@@ -2609,21 +2648,20 @@ pub const Node = struct {
2609 }2648 }
26102649
2611 pub fn lastToken(self: *const ControlFlowExpression) TokenIndex {2650 pub fn lastToken(self: *const ControlFlowExpression) TokenIndex {
2612 if (self.rhs) |rhs| {2651 if (self.getRHS()) |rhs| {
2613 return rhs.lastToken();2652 return rhs.lastToken();
2614 }2653 }
26152654
2616 switch (self.kind) {2655 if (self.getLabel()) |label| {
2617 .Break, .Continue => |maybe_label| {2656 return label;
2618 if (maybe_label) |label| {
2619 return label.lastToken();
2620 }
2621 },
2622 .Return => return self.ltoken,
2623 }2657 }
26242658
2625 return self.ltoken;2659 return self.ltoken;
2626 }2660 }
2661
2662 fn sizeInBytes(trailer_flags: TrailerFlags) usize {
2663 return @sizeOf(ControlFlowExpression) + trailer_flags.sizeInBytes();
2664 }
2627 };2665 };
26282666
2629 pub const Suspend = struct {2667 pub const Suspend = struct {
...@@ -2655,23 +2693,6 @@ pub const Node = struct {...@@ -2655,23 +2693,6 @@ pub const Node = struct {
2655 }2693 }
2656 };2694 };
26572695
2658 pub const IntegerLiteral = struct {
2659 base: Node = Node{ .tag = .IntegerLiteral },
2660 token: TokenIndex,
2661
2662 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {
2663 return null;
2664 }
2665
2666 pub fn firstToken(self: *const IntegerLiteral) TokenIndex {
2667 return self.token;
2668 }
2669
2670 pub fn lastToken(self: *const IntegerLiteral) TokenIndex {
2671 return self.token;
2672 }
2673 };
2674
2675 pub const EnumLiteral = struct {2696 pub const EnumLiteral = struct {
2676 base: Node = Node{ .tag = .EnumLiteral },2697 base: Node = Node{ .tag = .EnumLiteral },
2677 dot: TokenIndex,2698 dot: TokenIndex,
...@@ -2690,23 +2711,6 @@ pub const Node = struct {...@@ -2690,23 +2711,6 @@ pub const Node = struct {
2690 }2711 }
2691 };2712 };
26922713
2693 pub const FloatLiteral = struct {
2694 base: Node = Node{ .tag = .FloatLiteral },
2695 token: TokenIndex,
2696
2697 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {
2698 return null;
2699 }
2700
2701 pub fn firstToken(self: *const FloatLiteral) TokenIndex {
2702 return self.token;
2703 }
2704
2705 pub fn lastToken(self: *const FloatLiteral) TokenIndex {
2706 return self.token;
2707 }
2708 };
2709
2710 /// Parameters are in memory following BuiltinCall.2714 /// Parameters are in memory following BuiltinCall.
2711 pub const BuiltinCall = struct {2715 pub const BuiltinCall = struct {
2712 base: Node = Node{ .tag = .BuiltinCall },2716 base: Node = Node{ .tag = .BuiltinCall },
...@@ -2757,23 +2761,6 @@ pub const Node = struct {...@@ -2757,23 +2761,6 @@ pub const Node = struct {
2757 }2761 }
2758 };2762 };
27592763
2760 pub const StringLiteral = struct {
2761 base: Node = Node{ .tag = .StringLiteral },
2762 token: TokenIndex,
2763
2764 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {
2765 return null;
2766 }
2767
2768 pub fn firstToken(self: *const StringLiteral) TokenIndex {
2769 return self.token;
2770 }
2771
2772 pub fn lastToken(self: *const StringLiteral) TokenIndex {
2773 return self.token;
2774 }
2775 };
2776
2777 /// The string literal tokens appear directly in memory after MultilineStringLiteral.2764 /// The string literal tokens appear directly in memory after MultilineStringLiteral.
2778 pub const MultilineStringLiteral = struct {2765 pub const MultilineStringLiteral = struct {
2779 base: Node = Node{ .tag = .MultilineStringLiteral },2766 base: Node = Node{ .tag = .MultilineStringLiteral },
...@@ -2817,74 +2804,6 @@ pub const Node = struct {...@@ -2817,74 +2804,6 @@ pub const Node = struct {
2817 }2804 }
2818 };2805 };
28192806
2820 pub const CharLiteral = struct {
2821 base: Node = Node{ .tag = .CharLiteral },
2822 token: TokenIndex,
2823
2824 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {
2825 return null;
2826 }
2827
2828 pub fn firstToken(self: *const CharLiteral) TokenIndex {
2829 return self.token;
2830 }
2831
2832 pub fn lastToken(self: *const CharLiteral) TokenIndex {
2833 return self.token;
2834 }
2835 };
2836
2837 pub const BoolLiteral = struct {
2838 base: Node = Node{ .tag = .BoolLiteral },
2839 token: TokenIndex,
2840
2841 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {
2842 return null;
2843 }
2844
2845 pub fn firstToken(self: *const BoolLiteral) TokenIndex {
2846 return self.token;
2847 }
2848
2849 pub fn lastToken(self: *const BoolLiteral) TokenIndex {
2850 return self.token;
2851 }
2852 };
2853
2854 pub const NullLiteral = struct {
2855 base: Node = Node{ .tag = .NullLiteral },
2856 token: TokenIndex,
2857
2858 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {
2859 return null;
2860 }
2861
2862 pub fn firstToken(self: *const NullLiteral) TokenIndex {
2863 return self.token;
2864 }
2865
2866 pub fn lastToken(self: *const NullLiteral) TokenIndex {
2867 return self.token;
2868 }
2869 };
2870
2871 pub const UndefinedLiteral = struct {
2872 base: Node = Node{ .tag = .UndefinedLiteral },
2873 token: TokenIndex,
2874
2875 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {
2876 return null;
2877 }
2878
2879 pub fn firstToken(self: *const UndefinedLiteral) TokenIndex {
2880 return self.token;
2881 }
2882
2883 pub fn lastToken(self: *const UndefinedLiteral) TokenIndex {
2884 return self.token;
2885 }
2886 };
2887
2888 pub const Asm = struct {2807 pub const Asm = struct {
2889 base: Node = Node{ .tag = .Asm },2808 base: Node = Node{ .tag = .Asm },
2890 asm_token: TokenIndex,2809 asm_token: TokenIndex,
...@@ -2904,7 +2823,7 @@ pub const Node = struct {...@@ -2904,7 +2823,7 @@ pub const Node = struct {
2904 rparen: TokenIndex,2823 rparen: TokenIndex,
29052824
2906 pub const Kind = union(enum) {2825 pub const Kind = union(enum) {
2907 Variable: *Identifier,2826 Variable: *OneToken,
2908 Return: *Node,2827 Return: *Node,
2909 };2828 };
29102829
...@@ -3005,57 +2924,6 @@ pub const Node = struct {...@@ -3005,57 +2924,6 @@ pub const Node = struct {
3005 }2924 }
3006 };2925 };
30072926
3008 pub const Unreachable = struct {
3009 base: Node = Node{ .tag = .Unreachable },
3010 token: TokenIndex,
3011
3012 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {
3013 return null;
3014 }
3015
3016 pub fn firstToken(self: *const Unreachable) TokenIndex {
3017 return self.token;
3018 }
3019
3020 pub fn lastToken(self: *const Unreachable) TokenIndex {
3021 return self.token;
3022 }
3023 };
3024
3025 pub const ErrorType = struct {
3026 base: Node = Node{ .tag = .ErrorType },
3027 token: TokenIndex,
3028
3029 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {
3030 return null;
3031 }
3032
3033 pub fn firstToken(self: *const ErrorType) TokenIndex {
3034 return self.token;
3035 }
3036
3037 pub fn lastToken(self: *const ErrorType) TokenIndex {
3038 return self.token;
3039 }
3040 };
3041
3042 pub const AnyType = struct {
3043 base: Node = Node{ .tag = .AnyType },
3044 token: TokenIndex,
3045
3046 pub fn iterate(self: *const AnyType, index: usize) ?*Node {
3047 return null;
3048 }
3049
3050 pub fn firstToken(self: *const AnyType) TokenIndex {
3051 return self.token;
3052 }
3053
3054 pub fn lastToken(self: *const AnyType) TokenIndex {
3055 return self.token;
3056 }
3057 };
3058
3059 /// TODO remove from the Node base struct2927 /// TODO remove from the Node base struct
3060 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()2928 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
3061 /// and forwards to find same-line doc comments.2929 /// and forwards to find same-line doc comments.
lib/std/zig/parse.zig+47-35
...@@ -628,8 +628,11 @@ const Parser = struct {...@@ -628,8 +628,11 @@ const Parser = struct {
628 var type_expr: ?*Node = null;628 var type_expr: ?*Node = null;
629 if (p.eatToken(.Colon)) |_| {629 if (p.eatToken(.Colon)) |_| {
630 if (p.eatToken(.Keyword_anytype) orelse p.eatToken(.Keyword_var)) |anytype_tok| {630 if (p.eatToken(.Keyword_anytype) orelse p.eatToken(.Keyword_var)) |anytype_tok| {
631 const node = try p.arena.allocator.create(Node.AnyType);631 const node = try p.arena.allocator.create(Node.OneToken);
632 node.* = .{ .token = anytype_tok };632 node.* = .{
633 .base = .{ .tag = .AnyType },
634 .token = anytype_tok,
635 };
633 type_expr = &node.base;636 type_expr = &node.base;
634 } else {637 } else {
635 type_expr = try p.expectNode(parseTypeExpr, .{638 type_expr = try p.expectNode(parseTypeExpr, .{
...@@ -1079,12 +1082,13 @@ const Parser = struct {...@@ -1079,12 +1082,13 @@ const Parser = struct {
1079 if (p.eatToken(.Keyword_break)) |token| {1082 if (p.eatToken(.Keyword_break)) |token| {
1080 const label = try p.parseBreakLabel();1083 const label = try p.parseBreakLabel();
1081 const expr_node = try p.parseExpr();1084 const expr_node = try p.parseExpr();
1082 const node = try p.arena.allocator.create(Node.ControlFlowExpression);1085 const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
1083 node.* = .{1086 .tag = .Break,
1084 .ltoken = token,1087 .ltoken = token,
1085 .kind = .{ .Break = label },1088 }, .{
1089 .label = label,
1086 .rhs = expr_node,1090 .rhs = expr_node,
1087 };1091 });
1088 return &node.base;1092 return &node.base;
1089 }1093 }
10901094
...@@ -1115,12 +1119,13 @@ const Parser = struct {...@@ -1115,12 +1119,13 @@ const Parser = struct {
11151119
1116 if (p.eatToken(.Keyword_continue)) |token| {1120 if (p.eatToken(.Keyword_continue)) |token| {
1117 const label = try p.parseBreakLabel();1121 const label = try p.parseBreakLabel();
1118 const node = try p.arena.allocator.create(Node.ControlFlowExpression);1122 const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
1119 node.* = .{1123 .tag = .Continue,
1120 .ltoken = token,1124 .ltoken = token,
1121 .kind = .{ .Continue = label },1125 }, .{
1126 .label = label,
1122 .rhs = null,1127 .rhs = null,
1123 };1128 });
1124 return &node.base;1129 return &node.base;
1125 }1130 }
11261131
...@@ -1139,12 +1144,12 @@ const Parser = struct {...@@ -1139,12 +1144,12 @@ const Parser = struct {
11391144
1140 if (p.eatToken(.Keyword_return)) |token| {1145 if (p.eatToken(.Keyword_return)) |token| {
1141 const expr_node = try p.parseExpr();1146 const expr_node = try p.parseExpr();
1142 const node = try p.arena.allocator.create(Node.ControlFlowExpression);1147 const node = try Node.ControlFlowExpression.create(&p.arena.allocator, .{
1143 node.* = .{1148 .tag = .Return,
1144 .ltoken = token,1149 .ltoken = token,
1145 .kind = .Return,1150 }, .{
1146 .rhs = expr_node,1151 .rhs = expr_node,
1147 };1152 });
1148 return &node.base;1153 return &node.base;
1149 }1154 }
11501155
...@@ -1516,8 +1521,9 @@ const Parser = struct {...@@ -1516,8 +1521,9 @@ const Parser = struct {
1516 fn parsePrimaryTypeExpr(p: *Parser) !?*Node {1521 fn parsePrimaryTypeExpr(p: *Parser) !?*Node {
1517 if (try p.parseBuiltinCall()) |node| return node;1522 if (try p.parseBuiltinCall()) |node| return node;
1518 if (p.eatToken(.CharLiteral)) |token| {1523 if (p.eatToken(.CharLiteral)) |token| {
1519 const node = try p.arena.allocator.create(Node.CharLiteral);1524 const node = try p.arena.allocator.create(Node.OneToken);
1520 node.* = .{1525 node.* = .{
1526 .base = .{ .tag = .CharLiteral },
1521 .token = token,1527 .token = token,
1522 };1528 };
1523 return &node.base;1529 return &node.base;
...@@ -1547,7 +1553,7 @@ const Parser = struct {...@@ -1547,7 +1553,7 @@ const Parser = struct {
1547 const identifier = try p.expectNodeRecoverable(parseIdentifier, .{1553 const identifier = try p.expectNodeRecoverable(parseIdentifier, .{
1548 .ExpectedIdentifier = .{ .token = p.tok_i },1554 .ExpectedIdentifier = .{ .token = p.tok_i },
1549 });1555 });
1550 const global_error_set = try p.createLiteral(Node.ErrorType, token);1556 const global_error_set = try p.createLiteral(.ErrorType, token);
1551 if (period == null or identifier == null) return global_error_set;1557 if (period == null or identifier == null) return global_error_set;
15521558
1553 const node = try p.arena.allocator.create(Node.SimpleInfixOp);1559 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
...@@ -1559,8 +1565,8 @@ const Parser = struct {...@@ -1559,8 +1565,8 @@ const Parser = struct {
1559 };1565 };
1560 return &node.base;1566 return &node.base;
1561 }1567 }
1562 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(Node.BoolLiteral, token);1568 if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(.BoolLiteral, token);
1563 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(Node.NullLiteral, token);1569 if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(.NullLiteral, token);
1564 if (p.eatToken(.Keyword_anyframe)) |token| {1570 if (p.eatToken(.Keyword_anyframe)) |token| {
1565 const node = try p.arena.allocator.create(Node.AnyFrameType);1571 const node = try p.arena.allocator.create(Node.AnyFrameType);
1566 node.* = .{1572 node.* = .{
...@@ -1569,9 +1575,9 @@ const Parser = struct {...@@ -1569,9 +1575,9 @@ const Parser = struct {
1569 };1575 };
1570 return &node.base;1576 return &node.base;
1571 }1577 }
1572 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(Node.BoolLiteral, token);1578 if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(.BoolLiteral, token);
1573 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(Node.UndefinedLiteral, token);1579 if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(.UndefinedLiteral, token);
1574 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(Node.Unreachable, token);1580 if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(.Unreachable, token);
1575 if (try p.parseStringLiteral()) |node| return node;1581 if (try p.parseStringLiteral()) |node| return node;
1576 if (try p.parseSwitchExpr()) |node| return node;1582 if (try p.parseSwitchExpr()) |node| return node;
15771583
...@@ -1865,7 +1871,7 @@ const Parser = struct {...@@ -1865,7 +1871,7 @@ const Parser = struct {
1865 const variable = try p.expectNode(parseIdentifier, .{1871 const variable = try p.expectNode(parseIdentifier, .{
1866 .ExpectedIdentifier = .{ .token = p.tok_i },1872 .ExpectedIdentifier = .{ .token = p.tok_i },
1867 });1873 });
1868 break :blk .{ .Variable = variable.cast(Node.Identifier).? };1874 break :blk .{ .Variable = variable.castTag(.Identifier).? };
1869 };1875 };
1870 const rparen = try p.expectToken(.RParen);1876 const rparen = try p.expectToken(.RParen);
18711877
...@@ -1906,11 +1912,10 @@ const Parser = struct {...@@ -1906,11 +1912,10 @@ const Parser = struct {
1906 }1912 }
19071913
1908 /// BreakLabel <- COLON IDENTIFIER1914 /// BreakLabel <- COLON IDENTIFIER
1909 fn parseBreakLabel(p: *Parser) !?*Node {1915 fn parseBreakLabel(p: *Parser) !?TokenIndex {
1910 _ = p.eatToken(.Colon) orelse return null;1916 _ = p.eatToken(.Colon) orelse return null;
1911 return try p.expectNode(parseIdentifier, .{1917 const ident = try p.expectToken(.Identifier);
1912 .ExpectedIdentifier = .{ .token = p.tok_i },1918 return ident;
1913 });
1914 }1919 }
19151920
1916 /// BlockLabel <- IDENTIFIER COLON1921 /// BlockLabel <- IDENTIFIER COLON
...@@ -3022,8 +3027,9 @@ const Parser = struct {...@@ -3022,8 +3027,9 @@ const Parser = struct {
3022 });3027 });
30233028
3024 // lets pretend this was an identifier so we can continue parsing3029 // lets pretend this was an identifier so we can continue parsing
3025 const node = try p.arena.allocator.create(Node.Identifier);3030 const node = try p.arena.allocator.create(Node.OneToken);
3026 node.* = .{3031 node.* = .{
3032 .base = .{ .tag = .Identifier },
3027 .token = token,3033 .token = token,
3028 };3034 };
3029 return &node.base;3035 return &node.base;
...@@ -3054,8 +3060,9 @@ const Parser = struct {...@@ -3054,8 +3060,9 @@ const Parser = struct {
30543060
3055 fn parseIdentifier(p: *Parser) !?*Node {3061 fn parseIdentifier(p: *Parser) !?*Node {
3056 const token = p.eatToken(.Identifier) orelse return null;3062 const token = p.eatToken(.Identifier) orelse return null;
3057 const node = try p.arena.allocator.create(Node.Identifier);3063 const node = try p.arena.allocator.create(Node.OneToken);
3058 node.* = .{3064 node.* = .{
3065 .base = .{ .tag = .Identifier },
3059 .token = token,3066 .token = token,
3060 };3067 };
3061 return &node.base;3068 return &node.base;
...@@ -3064,16 +3071,18 @@ const Parser = struct {...@@ -3064,16 +3071,18 @@ const Parser = struct {
3064 fn parseAnyType(p: *Parser) !?*Node {3071 fn parseAnyType(p: *Parser) !?*Node {
3065 const token = p.eatToken(.Keyword_anytype) orelse3072 const token = p.eatToken(.Keyword_anytype) orelse
3066 p.eatToken(.Keyword_var) orelse return null; // TODO remove in next release cycle3073 p.eatToken(.Keyword_var) orelse return null; // TODO remove in next release cycle
3067 const node = try p.arena.allocator.create(Node.AnyType);3074 const node = try p.arena.allocator.create(Node.OneToken);
3068 node.* = .{3075 node.* = .{
3076 .base = .{ .tag = .AnyType },
3069 .token = token,3077 .token = token,
3070 };3078 };
3071 return &node.base;3079 return &node.base;
3072 }3080 }
30733081
3074 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {3082 fn createLiteral(p: *Parser, tag: ast.Node.Tag, token: TokenIndex) !*Node {
3075 const result = try p.arena.allocator.create(T);3083 const result = try p.arena.allocator.create(Node.OneToken);
3076 result.* = T{3084 result.* = .{
3085 .base = .{ .tag = tag },
3077 .token = token,3086 .token = token,
3078 };3087 };
3079 return &result.base;3088 return &result.base;
...@@ -3081,8 +3090,9 @@ const Parser = struct {...@@ -3081,8 +3090,9 @@ const Parser = struct {
30813090
3082 fn parseStringLiteralSingle(p: *Parser) !?*Node {3091 fn parseStringLiteralSingle(p: *Parser) !?*Node {
3083 if (p.eatToken(.StringLiteral)) |token| {3092 if (p.eatToken(.StringLiteral)) |token| {
3084 const node = try p.arena.allocator.create(Node.StringLiteral);3093 const node = try p.arena.allocator.create(Node.OneToken);
3085 node.* = .{3094 node.* = .{
3095 .base = .{ .tag = .StringLiteral },
3086 .token = token,3096 .token = token,
3087 };3097 };
3088 return &node.base;3098 return &node.base;
...@@ -3131,8 +3141,9 @@ const Parser = struct {...@@ -3131,8 +3141,9 @@ const Parser = struct {
31313141
3132 fn parseIntegerLiteral(p: *Parser) !?*Node {3142 fn parseIntegerLiteral(p: *Parser) !?*Node {
3133 const token = p.eatToken(.IntegerLiteral) orelse return null;3143 const token = p.eatToken(.IntegerLiteral) orelse return null;
3134 const node = try p.arena.allocator.create(Node.IntegerLiteral);3144 const node = try p.arena.allocator.create(Node.OneToken);
3135 node.* = .{3145 node.* = .{
3146 .base = .{ .tag = .IntegerLiteral },
3136 .token = token,3147 .token = token,
3137 };3148 };
3138 return &node.base;3149 return &node.base;
...@@ -3140,8 +3151,9 @@ const Parser = struct {...@@ -3140,8 +3151,9 @@ const Parser = struct {
31403151
3141 fn parseFloatLiteral(p: *Parser) !?*Node {3152 fn parseFloatLiteral(p: *Parser) !?*Node {
3142 const token = p.eatToken(.FloatLiteral) orelse return null;3153 const token = p.eatToken(.FloatLiteral) orelse return null;
3143 const node = try p.arena.allocator.create(Node.FloatLiteral);3154 const node = try p.arena.allocator.create(Node.OneToken);
3144 node.* = .{3155 node.* = .{
3156 .base = .{ .tag = .FloatLiteral },
3145 .token = token,3157 .token = token,
3146 };3158 };
3147 return &node.base;3159 return &node.base;
lib/std/zig/render.zig+62-87
...@@ -366,10 +366,32 @@ fn renderExpression(...@@ -366,10 +366,32 @@ fn renderExpression(
366 space: Space,366 space: Space,
367) (@TypeOf(stream).Error || Error)!void {367) (@TypeOf(stream).Error || Error)!void {
368 switch (base.tag) {368 switch (base.tag) {
369 .Identifier => {369 .Identifier,
370 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);370 .IntegerLiteral,
371 return renderToken(tree, stream, identifier.token, indent, start_col, space);371 .FloatLiteral,
372 .StringLiteral,
373 .CharLiteral,
374 .BoolLiteral,
375 .NullLiteral,
376 .Unreachable,
377 .ErrorType,
378 .UndefinedLiteral,
379 => {
380 const casted_node = base.cast(ast.Node.OneToken).?;
381 return renderToken(tree, stream, casted_node.token, indent, start_col, space);
372 },382 },
383
384 .AnyType => {
385 const any_type = base.castTag(.AnyType).?;
386 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
387 // TODO remove in next release cycle
388 try stream.writeAll("anytype");
389 if (space == .Comma) try stream.writeAll(",\n");
390 return;
391 }
392 return renderToken(tree, stream, any_type.token, indent, start_col, space);
393 },
394
373 .Block => {395 .Block => {
374 const block = @fieldParentPtr(ast.Node.Block, "base", base);396 const block = @fieldParentPtr(ast.Node.Block, "base", base);
375397
...@@ -399,6 +421,7 @@ fn renderExpression(...@@ -399,6 +421,7 @@ fn renderExpression(
399 return renderToken(tree, stream, block.rbrace, indent, start_col, space);421 return renderToken(tree, stream, block.rbrace, indent, start_col, space);
400 }422 }
401 },423 },
424
402 .Defer => {425 .Defer => {
403 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);426 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
404427
...@@ -1107,50 +1130,48 @@ fn renderExpression(...@@ -1107,50 +1130,48 @@ fn renderExpression(
1107 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?1130 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
1108 },1131 },
11091132
1110 .ControlFlowExpression => {1133 .Break => {
1111 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);1134 const flow_expr = base.castTag(.Break).?;
1135 const maybe_rhs = flow_expr.getRHS();
1136 const maybe_label = flow_expr.getLabel();
11121137
1113 switch (flow_expr.kind) {1138 if (maybe_label == null and maybe_rhs == null) {
1114 .Break => |maybe_label| {1139 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break
1115 if (maybe_label == null and flow_expr.rhs == null) {1140 }
1116 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // break
1117 }
1118
1119 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break
1120 if (maybe_label) |label| {
1121 const colon = tree.nextToken(flow_expr.ltoken);
1122 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1123
1124 if (flow_expr.rhs == null) {
1125 return renderExpression(allocator, stream, tree, indent, start_col, label, space); // label
1126 }
1127 try renderExpression(allocator, stream, tree, indent, start_col, label, Space.Space); // label
1128 }
1129 },
1130 .Continue => |maybe_label| {
1131 assert(flow_expr.rhs == null);
11321141
1133 if (maybe_label == null and flow_expr.rhs == null) {1142 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // break
1134 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue1143 if (maybe_label) |label| {
1135 }1144 const colon = tree.nextToken(flow_expr.ltoken);
1145 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
11361146
1137 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue1147 if (maybe_rhs == null) {
1138 if (maybe_label) |label| {1148 return renderToken(tree, stream, label, indent, start_col, space); // label
1139 const colon = tree.nextToken(flow_expr.ltoken);1149 }
1140 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :1150 try renderToken(tree, stream, label, indent, start_col, Space.Space); // label
1151 }
1152 return renderExpression(allocator, stream, tree, indent, start_col, maybe_rhs.?, space);
1153 },
11411154
1142 return renderExpression(allocator, stream, tree, indent, start_col, label, space);1155 .Continue => {
1143 }1156 const flow_expr = base.castTag(.Continue).?;
1144 },1157 if (flow_expr.getLabel()) |label| {
1145 .Return => {1158 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space); // continue
1146 if (flow_expr.rhs == null) {1159 const colon = tree.nextToken(flow_expr.ltoken);
1147 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);1160 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1148 }1161 return renderToken(tree, stream, label, indent, start_col, space); // label
1149 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);1162 } else {
1150 },1163 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space); // continue
1151 }1164 }
1165 },
11521166
1153 return renderExpression(allocator, stream, tree, indent, start_col, flow_expr.rhs.?, space);1167 .Return => {
1168 const flow_expr = base.castTag(.Return).?;
1169 if (flow_expr.getRHS()) |rhs| {
1170 try renderToken(tree, stream, flow_expr.ltoken, indent, start_col, Space.Space);
1171 return renderExpression(allocator, stream, tree, indent, start_col, rhs, space);
1172 } else {
1173 return renderToken(tree, stream, flow_expr.ltoken, indent, start_col, space);
1174 }
1154 },1175 },
11551176
1156 .Payload => {1177 .Payload => {
...@@ -1208,48 +1229,6 @@ fn renderExpression(...@@ -1208,48 +1229,6 @@ fn renderExpression(
1208 return renderExpression(allocator, stream, tree, indent, start_col, field_init.expr, space);1229 return renderExpression(allocator, stream, tree, indent, start_col, field_init.expr, space);
1209 },1230 },
12101231
1211 .IntegerLiteral => {
1212 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
1213 return renderToken(tree, stream, integer_literal.token, indent, start_col, space);
1214 },
1215 .FloatLiteral => {
1216 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
1217 return renderToken(tree, stream, float_literal.token, indent, start_col, space);
1218 },
1219 .StringLiteral => {
1220 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
1221 return renderToken(tree, stream, string_literal.token, indent, start_col, space);
1222 },
1223 .CharLiteral => {
1224 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
1225 return renderToken(tree, stream, char_literal.token, indent, start_col, space);
1226 },
1227 .BoolLiteral => {
1228 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
1229 return renderToken(tree, stream, bool_literal.token, indent, start_col, space);
1230 },
1231 .NullLiteral => {
1232 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
1233 return renderToken(tree, stream, null_literal.token, indent, start_col, space);
1234 },
1235 .Unreachable => {
1236 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
1237 return renderToken(tree, stream, unreachable_node.token, indent, start_col, space);
1238 },
1239 .ErrorType => {
1240 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
1241 return renderToken(tree, stream, error_type.token, indent, start_col, space);
1242 },
1243 .AnyType => {
1244 const any_type = @fieldParentPtr(ast.Node.AnyType, "base", base);
1245 if (mem.eql(u8, tree.tokenSlice(any_type.token), "var")) {
1246 // TODO remove in next release cycle
1247 try stream.writeAll("anytype");
1248 if (space == .Comma) try stream.writeAll(",\n");
1249 return;
1250 }
1251 return renderToken(tree, stream, any_type.token, indent, start_col, space);
1252 },
1253 .ContainerDecl => {1232 .ContainerDecl => {
1254 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);1233 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
12551234
...@@ -1468,10 +1447,6 @@ fn renderExpression(...@@ -1468,10 +1447,6 @@ fn renderExpression(
1468 }1447 }
1469 try stream.writeByteNTimes(' ', indent);1448 try stream.writeByteNTimes(' ', indent);
1470 },1449 },
1471 .UndefinedLiteral => {
1472 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
1473 return renderToken(tree, stream, undefined_literal.token, indent, start_col, space);
1474 },
14751450
1476 .BuiltinCall => {1451 .BuiltinCall => {
1477 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);1452 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
src-self-hosted/Module.zig+185-45
...@@ -212,7 +212,8 @@ pub const Decl = struct {...@@ -212,7 +212,8 @@ pub const Decl = struct {
212 },212 },
213 .block => unreachable,213 .block => unreachable,
214 .gen_zir => unreachable,214 .gen_zir => unreachable,
215 .local_var => unreachable,215 .local_val => unreachable,
216 .local_ptr => unreachable,
216 .decl => unreachable,217 .decl => unreachable,
217 }218 }
218 }219 }
...@@ -308,7 +309,8 @@ pub const Scope = struct {...@@ -308,7 +309,8 @@ pub const Scope = struct {
308 .block => return self.cast(Block).?.arena,309 .block => return self.cast(Block).?.arena,
309 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,310 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
310 .gen_zir => return self.cast(GenZIR).?.arena,311 .gen_zir => return self.cast(GenZIR).?.arena,
311 .local_var => return self.cast(LocalVar).?.gen_zir.arena,312 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
313 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
312 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,314 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
313 .file => unreachable,315 .file => unreachable,
314 }316 }
...@@ -320,7 +322,8 @@ pub const Scope = struct {...@@ -320,7 +322,8 @@ pub const Scope = struct {
320 return switch (self.tag) {322 return switch (self.tag) {
321 .block => self.cast(Block).?.decl,323 .block => self.cast(Block).?.decl,
322 .gen_zir => self.cast(GenZIR).?.decl,324 .gen_zir => self.cast(GenZIR).?.decl,
323 .local_var => return self.cast(LocalVar).?.gen_zir.decl,325 .local_val => return self.cast(LocalVal).?.gen_zir.decl,
326 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl,
324 .decl => self.cast(DeclAnalysis).?.decl,327 .decl => self.cast(DeclAnalysis).?.decl,
325 .zir_module => null,328 .zir_module => null,
326 .file => null,329 .file => null,
...@@ -333,7 +336,8 @@ pub const Scope = struct {...@@ -333,7 +336,8 @@ pub const Scope = struct {
333 switch (self.tag) {336 switch (self.tag) {
334 .block => return self.cast(Block).?.decl.scope,337 .block => return self.cast(Block).?.decl.scope,
335 .gen_zir => return self.cast(GenZIR).?.decl.scope,338 .gen_zir => return self.cast(GenZIR).?.decl.scope,
336 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope,339 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
340 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
337 .decl => return self.cast(DeclAnalysis).?.decl.scope,341 .decl => return self.cast(DeclAnalysis).?.decl.scope,
338 .zir_module, .file => return self,342 .zir_module, .file => return self,
339 }343 }
...@@ -346,7 +350,8 @@ pub const Scope = struct {...@@ -346,7 +350,8 @@ pub const Scope = struct {
346 switch (self.tag) {350 switch (self.tag) {
347 .block => unreachable,351 .block => unreachable,
348 .gen_zir => unreachable,352 .gen_zir => unreachable,
349 .local_var => unreachable,353 .local_val => unreachable,
354 .local_ptr => unreachable,
350 .decl => unreachable,355 .decl => unreachable,
351 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),356 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
352 .file => return self.cast(File).?.fullyQualifiedNameHash(name),357 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
...@@ -361,7 +366,8 @@ pub const Scope = struct {...@@ -361,7 +366,8 @@ pub const Scope = struct {
361 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,366 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
362 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,367 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
363 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,368 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,
364 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope.cast(File).?.contents.tree,369 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(File).?.contents.tree,
370 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(File).?.contents.tree,
365 }371 }
366 }372 }
367373
...@@ -370,7 +376,8 @@ pub const Scope = struct {...@@ -370,7 +376,8 @@ pub const Scope = struct {
370 return switch (self.tag) {376 return switch (self.tag) {
371 .block => unreachable,377 .block => unreachable,
372 .gen_zir => self.cast(GenZIR).?,378 .gen_zir => self.cast(GenZIR).?,
373 .local_var => return self.cast(LocalVar).?.gen_zir,379 .local_val => return self.cast(LocalVal).?.gen_zir,
380 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
374 .decl => unreachable,381 .decl => unreachable,
375 .zir_module => unreachable,382 .zir_module => unreachable,
376 .file => unreachable,383 .file => unreachable,
...@@ -397,7 +404,8 @@ pub const Scope = struct {...@@ -397,7 +404,8 @@ pub const Scope = struct {
397 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,404 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
398 .block => unreachable,405 .block => unreachable,
399 .gen_zir => unreachable,406 .gen_zir => unreachable,
400 .local_var => unreachable,407 .local_val => unreachable,
408 .local_ptr => unreachable,
401 .decl => unreachable,409 .decl => unreachable,
402 }410 }
403 }411 }
...@@ -408,7 +416,8 @@ pub const Scope = struct {...@@ -408,7 +416,8 @@ pub const Scope = struct {
408 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),416 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
409 .block => unreachable,417 .block => unreachable,
410 .gen_zir => unreachable,418 .gen_zir => unreachable,
411 .local_var => unreachable,419 .local_val => unreachable,
420 .local_ptr => unreachable,
412 .decl => unreachable,421 .decl => unreachable,
413 }422 }
414 }423 }
...@@ -418,7 +427,8 @@ pub const Scope = struct {...@@ -418,7 +427,8 @@ pub const Scope = struct {
418 .file => return @fieldParentPtr(File, "base", base).getSource(module),427 .file => return @fieldParentPtr(File, "base", base).getSource(module),
419 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),428 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
420 .gen_zir => unreachable,429 .gen_zir => unreachable,
421 .local_var => unreachable,430 .local_val => unreachable,
431 .local_ptr => unreachable,
422 .block => unreachable,432 .block => unreachable,
423 .decl => unreachable,433 .decl => unreachable,
424 }434 }
...@@ -431,7 +441,8 @@ pub const Scope = struct {...@@ -431,7 +441,8 @@ pub const Scope = struct {
431 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),441 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
432 .block => unreachable,442 .block => unreachable,
433 .gen_zir => unreachable,443 .gen_zir => unreachable,
434 .local_var => unreachable,444 .local_val => unreachable,
445 .local_ptr => unreachable,
435 .decl => unreachable,446 .decl => unreachable,
436 }447 }
437 }448 }
...@@ -451,7 +462,8 @@ pub const Scope = struct {...@@ -451,7 +462,8 @@ pub const Scope = struct {
451 },462 },
452 .block => unreachable,463 .block => unreachable,
453 .gen_zir => unreachable,464 .gen_zir => unreachable,
454 .local_var => unreachable,465 .local_val => unreachable,
466 .local_ptr => unreachable,
455 .decl => unreachable,467 .decl => unreachable,
456 }468 }
457 }469 }
...@@ -472,7 +484,8 @@ pub const Scope = struct {...@@ -472,7 +484,8 @@ pub const Scope = struct {
472 block,484 block,
473 decl,485 decl,
474 gen_zir,486 gen_zir,
475 local_var,487 local_val,
488 local_ptr,
476 };489 };
477490
478 pub const File = struct {491 pub const File = struct {
...@@ -708,17 +721,31 @@ pub const Scope = struct {...@@ -708,17 +721,31 @@ pub const Scope = struct {
708 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},721 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
709 };722 };
710723
724 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
711 /// This structure lives as long as the AST generation of the Block725 /// This structure lives as long as the AST generation of the Block
712 /// node that contains the variable.726 /// node that contains the variable.
713 pub const LocalVar = struct {727 pub const LocalVal = struct {
714 pub const base_tag: Tag = .local_var;728 pub const base_tag: Tag = .local_val;
715 base: Scope = Scope{ .tag = base_tag },729 base: Scope = Scope{ .tag = base_tag },
716 /// Parents can be: `LocalVar`, `GenZIR`.730 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
717 parent: *Scope,731 parent: *Scope,
718 gen_zir: *GenZIR,732 gen_zir: *GenZIR,
719 name: []const u8,733 name: []const u8,
720 inst: *zir.Inst,734 inst: *zir.Inst,
721 };735 };
736
737 /// This could be a `const` or `var` local. It has a pointer instead of a value.
738 /// This structure lives as long as the AST generation of the Block
739 /// node that contains the variable.
740 pub const LocalPtr = struct {
741 pub const base_tag: Tag = .local_ptr;
742 base: Scope = Scope{ .tag = base_tag },
743 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
744 parent: *Scope,
745 gen_zir: *GenZIR,
746 name: []const u8,
747 ptr: *zir.Inst,
748 };
722};749};
723750
724pub const AllErrors = struct {751pub const AllErrors = struct {
...@@ -1176,12 +1203,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1176,12 +1203,19 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11761203
1177 const param_decls = fn_proto.params();1204 const param_decls = fn_proto.params();
1178 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);1205 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);
1206
1207 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1208 const type_type = try self.addZIRInstConst(&fn_type_scope.base, fn_src, .{
1209 .ty = Type.initTag(.type),
1210 .val = Value.initTag(.type_type),
1211 });
1212 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
1179 for (param_decls) |param_decl, i| {1213 for (param_decls) |param_decl, i| {
1180 const param_type_node = switch (param_decl.param_type) {1214 const param_type_node = switch (param_decl.param_type) {
1181 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),1215 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
1182 .type_expr => |node| node,1216 .type_expr => |node| node,
1183 };1217 };
1184 param_types[i] = try astgen.expr(self, &fn_type_scope.base, param_type_node);1218 param_types[i] = try astgen.expr(self, &fn_type_scope.base, type_type_rl, param_type_node);
1185 }1219 }
1186 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {1220 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1187 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});1221 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
...@@ -1209,8 +1243,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1209,8 +1243,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1209 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),1243 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
1210 };1244 };
12111245
1212 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, return_type_expr);1246 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, type_type_rl, return_type_expr);
1213 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1214 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{1247 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1215 .return_type = return_type_inst,1248 .return_type = return_type_inst,
1216 .param_types = param_types,1249 .param_types = param_types,
...@@ -1266,7 +1299,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1266,7 +1299,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1266 .kw_args = .{},1299 .kw_args = .{},
1267 };1300 };
1268 gen_scope.instructions.items[i] = &arg.base;1301 gen_scope.instructions.items[i] = &arg.base;
1269 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVar);1302 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVal);
1270 sub_scope.* = .{1303 sub_scope.* = .{
1271 .parent = params_scope,1304 .parent = params_scope,
1272 .gen_zir = &gen_scope,1305 .gen_zir = &gen_scope,
...@@ -1829,6 +1862,7 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -1829,6 +1862,7 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
1829 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);1862 return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src);
1830}1863}
18311864
1865/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
1832fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {1866fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
1833 return scope.cast(Scope.Block) orelse1867 return scope.cast(Scope.Block) orelse
1834 return self.fail(scope, src, "instruction illegal outside function body", .{});1868 return self.fail(scope, src, "instruction illegal outside function body", .{});
...@@ -2098,12 +2132,7 @@ pub fn addZIRInstSpecial(...@@ -2098,12 +2132,7 @@ pub fn addZIRInstSpecial(
2098 return inst;2132 return inst;
2099}2133}
21002134
2101pub fn addZIRNoOp(2135pub fn addZIRNoOpT(self: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst.NoOp {
2102 self: *Module,
2103 scope: *Scope,
2104 src: usize,
2105 tag: zir.Inst.Tag,
2106) !*zir.Inst {
2107 const gen_zir = scope.getGenZIR();2136 const gen_zir = scope.getGenZIR();
2108 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);2137 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);
2109 const inst = try gen_zir.arena.create(zir.Inst.NoOp);2138 const inst = try gen_zir.arena.create(zir.Inst.NoOp);
...@@ -2116,6 +2145,11 @@ pub fn addZIRNoOp(...@@ -2116,6 +2145,11 @@ pub fn addZIRNoOp(
2116 .kw_args = .{},2145 .kw_args = .{},
2117 };2146 };
2118 gen_zir.instructions.appendAssumeCapacity(&inst.base);2147 gen_zir.instructions.appendAssumeCapacity(&inst.base);
2148 return inst;
2149}
2150
2151pub fn addZIRNoOp(self: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst {
2152 const inst = try self.addZIRNoOpT(scope, src, tag);
2119 return &inst.base;2153 return &inst.base;
2120}2154}
21212155
...@@ -2320,24 +2354,36 @@ fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) I...@@ -2320,24 +2354,36 @@ fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) I
23202354
2321fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {2355fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
2322 switch (old_inst.tag) {2356 switch (old_inst.tag) {
2357 .alloc => return self.analyzeInstAlloc(scope, old_inst.castTag(.alloc).?),
2358 .alloc_inferred => return self.analyzeInstAllocInferred(scope, old_inst.castTag(.alloc_inferred).?),
2323 .arg => return self.analyzeInstArg(scope, old_inst.castTag(.arg).?),2359 .arg => return self.analyzeInstArg(scope, old_inst.castTag(.arg).?),
2360 .bitcast_result_ptr => return self.analyzeInstBitCastResultPtr(scope, old_inst.castTag(.bitcast_result_ptr).?),
2324 .block => return self.analyzeInstBlock(scope, old_inst.castTag(.block).?),2361 .block => return self.analyzeInstBlock(scope, old_inst.castTag(.block).?),
2325 .@"break" => return self.analyzeInstBreak(scope, old_inst.castTag(.@"break").?),2362 .@"break" => return self.analyzeInstBreak(scope, old_inst.castTag(.@"break").?),
2326 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.castTag(.breakpoint).?),2363 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.castTag(.breakpoint).?),
2327 .breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.castTag(.breakvoid).?),2364 .breakvoid => return self.analyzeInstBreakVoid(scope, old_inst.castTag(.breakvoid).?),
2328 .call => return self.analyzeInstCall(scope, old_inst.castTag(.call).?),2365 .call => return self.analyzeInstCall(scope, old_inst.castTag(.call).?),
2366 .coerce_result_block_ptr => return self.analyzeInstCoerceResultBlockPtr(scope, old_inst.castTag(.coerce_result_block_ptr).?),
2367 .coerce_result_ptr => return self.analyzeInstCoerceResultPtr(scope, old_inst.castTag(.coerce_result_ptr).?),
2368 .coerce_to_ptr_elem => return self.analyzeInstCoerceToPtrElem(scope, old_inst.castTag(.coerce_to_ptr_elem).?),
2329 .compileerror => return self.analyzeInstCompileError(scope, old_inst.castTag(.compileerror).?),2369 .compileerror => return self.analyzeInstCompileError(scope, old_inst.castTag(.compileerror).?),
2330 .@"const" => return self.analyzeInstConst(scope, old_inst.castTag(.@"const").?),2370 .@"const" => return self.analyzeInstConst(scope, old_inst.castTag(.@"const").?),
2331 .declref => return self.analyzeInstDeclRef(scope, old_inst.castTag(.declref).?),2371 .declref => return self.analyzeInstDeclRef(scope, old_inst.castTag(.declref).?),
2332 .declref_str => return self.analyzeInstDeclRefStr(scope, old_inst.castTag(.declref_str).?),2372 .declref_str => return self.analyzeInstDeclRefStr(scope, old_inst.castTag(.declref_str).?),
2333 .declval => return self.analyzeInstDeclVal(scope, old_inst.castTag(.declval).?),2373 .declval => return self.analyzeInstDeclVal(scope, old_inst.castTag(.declval).?),
2334 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.castTag(.declval_in_module).?),2374 .declval_in_module => return self.analyzeInstDeclValInModule(scope, old_inst.castTag(.declval_in_module).?),
2375 .ensure_result_used => return self.analyzeInstEnsureResultUsed(scope, old_inst.castTag(.ensure_result_used).?),
2376 .ensure_result_non_error => return self.analyzeInstEnsureResultNonError(scope, old_inst.castTag(.ensure_result_non_error).?),
2377 .ret_ptr => return self.analyzeInstRetPtr(scope, old_inst.castTag(.ret_ptr).?),
2378 .ret_type => return self.analyzeInstRetType(scope, old_inst.castTag(.ret_type).?),
2379 .store => return self.analyzeInstStore(scope, old_inst.castTag(.store).?),
2335 .str => return self.analyzeInstStr(scope, old_inst.castTag(.str).?),2380 .str => return self.analyzeInstStr(scope, old_inst.castTag(.str).?),
2336 .int => {2381 .int => {
2337 const big_int = old_inst.castTag(.int).?.positionals.int;2382 const big_int = old_inst.castTag(.int).?.positionals.int;
2338 return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int);2383 return self.constIntBig(scope, old_inst.src, Type.initTag(.comptime_int), big_int);
2339 },2384 },
2340 .inttype => return self.analyzeInstIntType(scope, old_inst.castTag(.inttype).?),2385 .inttype => return self.analyzeInstIntType(scope, old_inst.castTag(.inttype).?),
2386 .param_type => return self.analyzeInstParamType(scope, old_inst.castTag(.param_type).?),
2341 .ptrtoint => return self.analyzeInstPtrToInt(scope, old_inst.castTag(.ptrtoint).?),2387 .ptrtoint => return self.analyzeInstPtrToInt(scope, old_inst.castTag(.ptrtoint).?),
2342 .fieldptr => return self.analyzeInstFieldPtr(scope, old_inst.castTag(.fieldptr).?),2388 .fieldptr => return self.analyzeInstFieldPtr(scope, old_inst.castTag(.fieldptr).?),
2343 .deref => return self.analyzeInstDeref(scope, old_inst.castTag(.deref).?),2389 .deref => return self.analyzeInstDeref(scope, old_inst.castTag(.deref).?),
...@@ -2369,6 +2415,94 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In...@@ -2369,6 +2415,94 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
2369 }2415 }
2370}2416}
23712417
2418fn analyzeInstCoerceResultBlockPtr(
2419 self: *Module,
2420 scope: *Scope,
2421 inst: *zir.Inst.CoerceResultBlockPtr,
2422) InnerError!*Inst {
2423 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
2424}
2425
2426fn analyzeInstBitCastResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2427 return self.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastResultPtr", .{});
2428}
2429
2430fn analyzeInstCoerceResultPtr(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2431 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultPtr", .{});
2432}
2433
2434fn analyzeInstCoerceToPtrElem(self: *Module, scope: *Scope, inst: *zir.Inst.CoerceToPtrElem) InnerError!*Inst {
2435 return self.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceToPtrElem", .{});
2436}
2437
2438fn analyzeInstRetPtr(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2439 return self.fail(scope, inst.base.src, "TODO implement analyzeInstRetPtr", .{});
2440}
2441
2442fn analyzeInstRetType(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2443 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2444 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
2445 const ret_type = fn_ty.fnReturnType();
2446 return self.constType(scope, inst.base.src, ret_type);
2447}
2448
2449fn analyzeInstEnsureResultUsed(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2450 const operand = try self.resolveInst(scope, inst.positionals.operand);
2451 switch (operand.ty.zigTypeTag()) {
2452 .Void, .NoReturn => return self.constVoid(scope, operand.src),
2453 else => return self.fail(scope, operand.src, "expression value is ignored", .{}),
2454 }
2455}
2456
2457fn analyzeInstEnsureResultNonError(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2458 const operand = try self.resolveInst(scope, inst.positionals.operand);
2459 switch (operand.ty.zigTypeTag()) {
2460 .ErrorSet, .ErrorUnion => return self.fail(scope, operand.src, "error is discarded", .{}),
2461 else => return self.constVoid(scope, operand.src),
2462 }
2463}
2464
2465fn analyzeInstAlloc(self: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2466 return self.fail(scope, inst.base.src, "TODO implement analyzeInstAlloc", .{});
2467}
2468
2469fn analyzeInstAllocInferred(self: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2470 return self.fail(scope, inst.base.src, "TODO implement analyzeInstAllocInferred", .{});
2471}
2472
2473fn analyzeInstStore(self: *Module, scope: *Scope, inst: *zir.Inst.Store) InnerError!*Inst {
2474 return self.fail(scope, inst.base.src, "TODO implement analyzeInstStore", .{});
2475}
2476
2477fn analyzeInstParamType(self: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerError!*Inst {
2478 const fn_inst = try self.resolveInst(scope, inst.positionals.func);
2479 const arg_index = inst.positionals.arg_index;
2480
2481 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
2482 .Fn => fn_inst.ty,
2483 .BoundFn => {
2484 return self.fail(scope, fn_inst.src, "TODO implement analyzeInstParamType for method call syntax", .{});
2485 },
2486 else => {
2487 return self.fail(scope, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
2488 },
2489 };
2490
2491 // TODO support C-style var args
2492 const param_count = fn_ty.fnParamLen();
2493 if (arg_index >= param_count) {
2494 return self.fail(scope, inst.base.src, "arg index {} out of bounds; '{}' has {} arguments", .{
2495 arg_index,
2496 fn_ty,
2497 param_count,
2498 });
2499 }
2500
2501 // TODO support generic functions
2502 const param_type = fn_ty.fnParamType(arg_index);
2503 return self.constType(scope, inst.base.src, param_type);
2504}
2505
2372fn analyzeInstStr(self: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst {2506fn analyzeInstStr(self: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst {
2373 // The bytes references memory inside the ZIR module, which can get deallocated2507 // The bytes references memory inside the ZIR module, which can get deallocated
2374 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.2508 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
...@@ -2746,13 +2880,13 @@ fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primi...@@ -2746,13 +2880,13 @@ fn analyzeInstPrimitive(self: *Module, scope: *Scope, primitive: *zir.Inst.Primi
2746 return self.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue());2880 return self.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue());
2747}2881}
27482882
2749fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.As) InnerError!*Inst {2883fn analyzeInstAs(self: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*Inst {
2750 const dest_type = try self.resolveType(scope, as.positionals.dest_type);2884 const dest_type = try self.resolveType(scope, as.positionals.lhs);
2751 const new_inst = try self.resolveInst(scope, as.positionals.value);2885 const new_inst = try self.resolveInst(scope, as.positionals.rhs);
2752 return self.coerce(scope, dest_type, new_inst);2886 return self.coerce(scope, dest_type, new_inst);
2753}2887}
27542888
2755fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.PtrToInt) InnerError!*Inst {2889fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) InnerError!*Inst {
2756 const ptr = try self.resolveInst(scope, ptrtoint.positionals.operand);2890 const ptr = try self.resolveInst(scope, ptrtoint.positionals.operand);
2757 if (ptr.ty.zigTypeTag() != .Pointer) {2891 if (ptr.ty.zigTypeTag() != .Pointer) {
2758 return self.fail(scope, ptrtoint.positionals.operand.src, "expected pointer, found '{}'", .{ptr.ty});2892 return self.fail(scope, ptrtoint.positionals.operand.src, "expected pointer, found '{}'", .{ptr.ty});
...@@ -2797,16 +2931,16 @@ fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPt...@@ -2797,16 +2931,16 @@ fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPt
2797 }2931 }
2798}2932}
27992933
2800fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) InnerError!*Inst {2934fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2801 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);2935 const dest_type = try self.resolveType(scope, inst.positionals.lhs);
2802 const operand = try self.resolveInst(scope, inst.positionals.operand);2936 const operand = try self.resolveInst(scope, inst.positionals.rhs);
28032937
2804 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {2938 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
2805 .ComptimeInt => true,2939 .ComptimeInt => true,
2806 .Int => false,2940 .Int => false,
2807 else => return self.fail(2941 else => return self.fail(
2808 scope,2942 scope,
2809 inst.positionals.dest_type.src,2943 inst.positionals.lhs.src,
2810 "expected integer type, found '{}'",2944 "expected integer type, found '{}'",
2811 .{2945 .{
2812 dest_type,2946 dest_type,
...@@ -2818,7 +2952,7 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) Inn...@@ -2818,7 +2952,7 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) Inn
2818 .ComptimeInt, .Int => {},2952 .ComptimeInt, .Int => {},
2819 else => return self.fail(2953 else => return self.fail(
2820 scope,2954 scope,
2821 inst.positionals.operand.src,2955 inst.positionals.rhs.src,
2822 "expected integer type, found '{}'",2956 "expected integer type, found '{}'",
2823 .{operand.ty},2957 .{operand.ty},
2824 ),2958 ),
...@@ -2833,22 +2967,22 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) Inn...@@ -2833,22 +2967,22 @@ fn analyzeInstIntCast(self: *Module, scope: *Scope, inst: *zir.Inst.IntCast) Inn
2833 return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{});2967 return self.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{});
2834}2968}
28352969
2836fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BitCast) InnerError!*Inst {2970fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2837 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);2971 const dest_type = try self.resolveType(scope, inst.positionals.lhs);
2838 const operand = try self.resolveInst(scope, inst.positionals.operand);2972 const operand = try self.resolveInst(scope, inst.positionals.rhs);
2839 return self.bitcast(scope, dest_type, operand);2973 return self.bitcast(scope, dest_type, operand);
2840}2974}
28412975
2842fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast) InnerError!*Inst {2976fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2843 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);2977 const dest_type = try self.resolveType(scope, inst.positionals.lhs);
2844 const operand = try self.resolveInst(scope, inst.positionals.operand);2978 const operand = try self.resolveInst(scope, inst.positionals.rhs);
28452979
2846 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {2980 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
2847 .ComptimeFloat => true,2981 .ComptimeFloat => true,
2848 .Float => false,2982 .Float => false,
2849 else => return self.fail(2983 else => return self.fail(
2850 scope,2984 scope,
2851 inst.positionals.dest_type.src,2985 inst.positionals.lhs.src,
2852 "expected float type, found '{}'",2986 "expected float type, found '{}'",
2853 .{2987 .{
2854 dest_type,2988 dest_type,
...@@ -2860,7 +2994,7 @@ fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast)...@@ -2860,7 +2994,7 @@ fn analyzeInstFloatCast(self: *Module, scope: *Scope, inst: *zir.Inst.FloatCast)
2860 .ComptimeFloat, .Float, .ComptimeInt => {},2994 .ComptimeFloat, .Float, .ComptimeInt => {},
2861 else => return self.fail(2995 else => return self.fail(
2862 scope,2996 scope,
2863 inst.positionals.operand.src,2997 inst.positionals.rhs.src,
2864 "expected float type, found '{}'",2998 "expected float type, found '{}'",
2865 .{operand.ty},2999 .{operand.ty},
2866 ),3000 ),
...@@ -3560,8 +3694,14 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err...@@ -3560,8 +3694,14 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
3560 gen_zir.decl.generation = self.generation;3694 gen_zir.decl.generation = self.generation;
3561 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3695 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3562 },3696 },
3563 .local_var => {3697 .local_val => {
3564 const gen_zir = scope.cast(Scope.LocalVar).?.gen_zir;3698 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
3699 gen_zir.decl.analysis = .sema_failure;
3700 gen_zir.decl.generation = self.generation;
3701 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3702 },
3703 .local_ptr => {
3704 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
3565 gen_zir.decl.analysis = .sema_failure;3705 gen_zir.decl.analysis = .sema_failure;
3566 gen_zir.decl.generation = self.generation;3706 gen_zir.decl.generation = self.generation;
3567 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3707 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
src-self-hosted/astgen.zig+457-153
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const Allocator = std.mem.Allocator;
3const Value = @import("value.zig").Value;4const Value = @import("value.zig").Value;
4const Type = @import("type.zig").Type;5const Type = @import("type.zig").Type;
5const TypedValue = @import("TypedValue.zig");6const TypedValue = @import("TypedValue.zig");
...@@ -11,35 +12,67 @@ const trace = @import("tracy.zig").trace;...@@ -11,35 +12,67 @@ const trace = @import("tracy.zig").trace;
11const Scope = Module.Scope;12const Scope = Module.Scope;
12const InnerError = Module.InnerError;13const InnerError = Module.InnerError;
1314
15pub const ResultLoc = union(enum) {
16 /// The expression is the right-hand side of assignment to `_`.
17 discard,
18 /// The expression has an inferred type, and it will be evaluated as an rvalue.
19 none,
20 /// The expression will be type coerced into this type, but it will be evaluated as an rvalue.
21 ty: *zir.Inst,
22 /// The expression must store its result into this typed pointer.
23 ptr: *zir.Inst,
24 /// The expression must store its result into this allocation, which has an inferred type.
25 inferred_ptr: *zir.Inst.Tag.alloc_inferred.Type(),
26 /// The expression must store its result into this pointer, which is a typed pointer that
27 /// has been bitcasted to whatever the expression's type is.
28 bitcasted_ptr: *zir.Inst.UnOp,
29 /// There is a pointer for the expression to store its result into, however, its type
30 /// is inferred based on peer type resolution for a `zir.Inst.Block`.
31 block_ptr: *zir.Inst.Block,
32};
33
34pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*zir.Inst {
35 const type_src = scope.tree().token_locs[type_node.firstToken()].start;
36 const type_type = try mod.addZIRInstConst(scope, type_src, .{
37 .ty = Type.initTag(.type),
38 .val = Value.initTag(.type_type),
39 });
40 const type_rl: ResultLoc = .{ .ty = type_type };
41 return expr(mod, scope, type_rl, type_node);
42}
43
14/// Turn Zig AST into untyped ZIR istructions.44/// Turn Zig AST into untyped ZIR istructions.
15pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {45pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst {
16 switch (node.tag) {46 switch (node.tag) {
17 .VarDecl => unreachable, // Handled in `blockExpr`.47 .VarDecl => unreachable, // Handled in `blockExpr`.
1848 .Assign => unreachable, // Handled in `blockExpr`.
19 .Add => return simpleInfixOp(mod, scope, node.castTag(.Add).?, .add),49
20 .Sub => return simpleInfixOp(mod, scope, node.castTag(.Sub).?, .sub),50 .Add => return arithmetic(mod, scope, rl, node.castTag(.Add).?, .add),
21 .BangEqual => return simpleInfixOp(mod, scope, node.castTag(.BangEqual).?, .cmp_neq),51 .Sub => return arithmetic(mod, scope, rl, node.castTag(.Sub).?, .sub),
22 .EqualEqual => return simpleInfixOp(mod, scope, node.castTag(.EqualEqual).?, .cmp_eq),52
23 .GreaterThan => return simpleInfixOp(mod, scope, node.castTag(.GreaterThan).?, .cmp_gt),53 .BangEqual => return cmp(mod, scope, rl, node.castTag(.BangEqual).?, .cmp_neq),
24 .GreaterOrEqual => return simpleInfixOp(mod, scope, node.castTag(.GreaterOrEqual).?, .cmp_gte),54 .EqualEqual => return cmp(mod, scope, rl, node.castTag(.EqualEqual).?, .cmp_eq),
25 .LessThan => return simpleInfixOp(mod, scope, node.castTag(.LessThan).?, .cmp_lt),55 .GreaterThan => return cmp(mod, scope, rl, node.castTag(.GreaterThan).?, .cmp_gt),
26 .LessOrEqual => return simpleInfixOp(mod, scope, node.castTag(.LessOrEqual).?, .cmp_lte),56 .GreaterOrEqual => return cmp(mod, scope, rl, node.castTag(.GreaterOrEqual).?, .cmp_gte),
2757 .LessThan => return cmp(mod, scope, rl, node.castTag(.LessThan).?, .cmp_lt),
28 .Identifier => return identifier(mod, scope, node.castTag(.Identifier).?),58 .LessOrEqual => return cmp(mod, scope, rl, node.castTag(.LessOrEqual).?, .cmp_lte),
29 .Asm => return assembly(mod, scope, node.castTag(.Asm).?),59
30 .StringLiteral => return stringLiteral(mod, scope, node.castTag(.StringLiteral).?),60 .Identifier => return rlWrap(mod, scope, rl, try identifier(mod, scope, node.castTag(.Identifier).?)),
31 .IntegerLiteral => return integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?),61 .Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
32 .BuiltinCall => return builtinCall(mod, scope, node.castTag(.BuiltinCall).?),62 .StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)),
33 .Call => return callExpr(mod, scope, node.castTag(.Call).?),63 .IntegerLiteral => return rlWrap(mod, scope, rl, try integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?)),
64 .BuiltinCall => return builtinCall(mod, scope, rl, node.castTag(.BuiltinCall).?),
65 .Call => return callExpr(mod, scope, rl, node.castTag(.Call).?),
34 .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?),66 .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?),
35 .ControlFlowExpression => return controlFlowExpr(mod, scope, node.castTag(.ControlFlowExpression).?),67 .Return => return ret(mod, scope, node.castTag(.Return).?),
36 .If => return ifExpr(mod, scope, node.castTag(.If).?),68 .If => return ifExpr(mod, scope, rl, node.castTag(.If).?),
37 .Assign => return assign(mod, scope, node.castTag(.Assign).?),69 .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),
38 .Period => return field(mod, scope, node.castTag(.Period).?),70 .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),
39 .Deref => return deref(mod, scope, node.castTag(.Deref).?),71 .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)),
40 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),72 .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)),
41 .FloatLiteral => return floatLiteral(mod, scope, node.castTag(.FloatLiteral).?),73 .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),
42 .UndefinedLiteral, .BoolLiteral, .NullLiteral => return primitiveLiteral(mod, scope, node),74 .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)),
75 .NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)),
43 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),76 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
44 }77 }
45}78}
...@@ -59,17 +92,28 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block...@@ -59,17 +92,28 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block
59 for (block_node.statements()) |statement| {92 for (block_node.statements()) |statement| {
60 switch (statement.tag) {93 switch (statement.tag) {
61 .VarDecl => {94 .VarDecl => {
62 const sub_scope = try block_arena.allocator.create(Scope.LocalVar);95 const var_decl_node = statement.castTag(.VarDecl).?;
63 const var_decl_node = @fieldParentPtr(ast.Node.VarDecl, "base", statement);96 scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator);
64 sub_scope.* = try varDecl(mod, scope, var_decl_node);97 },
65 scope = &sub_scope.base;98 .Assign => {
99 const ass = statement.castTag(.Assign).?;
100 try assign(mod, scope, ass);
101 },
102 else => {
103 const possibly_unused_result = try expr(mod, scope, .none, statement);
104 const src = scope.tree().token_locs[statement.firstToken()].start;
105 _ = try mod.addZIRUnOp(scope, src, .ensure_result_used, possibly_unused_result);
66 },106 },
67 else => _ = try expr(mod, scope, statement),
68 }107 }
69 }108 }
70}109}
71110
72fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scope.LocalVar {111fn varDecl(
112 mod: *Module,
113 scope: *Scope,
114 node: *ast.Node.VarDecl,
115 block_arena: *Allocator,
116) InnerError!*Scope {
73 // TODO implement detection of shadowing117 // TODO implement detection of shadowing
74 if (node.getTrailer("comptime_token")) |comptime_token| {118 if (node.getTrailer("comptime_token")) |comptime_token| {
75 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});119 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
...@@ -78,48 +122,96 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop...@@ -78,48 +122,96 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop
78 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});122 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
79 }123 }
80 const tree = scope.tree();124 const tree = scope.tree();
125 const name_src = tree.token_locs[node.name_token].start;
126 const ident_name = try identifierTokenString(mod, scope, node.name_token);
127 const init_node = node.getTrailer("init_node").?;
81 switch (tree.token_ids[node.mut_token]) {128 switch (tree.token_ids[node.mut_token]) {
82 .Keyword_const => {129 .Keyword_const => {
83 if (node.getTrailer("type_node")) |type_node| {
84 return mod.failNode(scope, type_node, "TODO implement typed const locals", .{});
85 }
86 // Depending on the type of AST the initialization expression is, we may need an lvalue130 // Depending on the type of AST the initialization expression is, we may need an lvalue
87 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as131 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
88 // the variable, no memory location needed.132 // the variable, no memory location needed.
89 const init_node = node.getTrailer("init_node").?;
90 if (nodeMayNeedMemoryLocation(init_node)) {133 if (nodeMayNeedMemoryLocation(init_node)) {
91 return mod.failNode(scope, init_node, "TODO implement result locations", .{});134 if (node.getTrailer("type_node")) |type_node| {
135 const type_inst = try typeExpr(mod, scope, type_node);
136 const alloc = try mod.addZIRUnOp(scope, name_src, .alloc, type_inst);
137 const result_loc: ResultLoc = .{ .ptr = alloc };
138 const init_inst = try expr(mod, scope, result_loc, init_node);
139 const sub_scope = try block_arena.create(Scope.LocalVal);
140 sub_scope.* = .{
141 .parent = scope,
142 .gen_zir = scope.getGenZIR(),
143 .name = ident_name,
144 .inst = init_inst,
145 };
146 return &sub_scope.base;
147 } else {
148 const alloc = try mod.addZIRNoOpT(scope, name_src, .alloc_inferred);
149 const result_loc: ResultLoc = .{ .inferred_ptr = alloc };
150 const init_inst = try expr(mod, scope, result_loc, init_node);
151 const sub_scope = try block_arena.create(Scope.LocalVal);
152 sub_scope.* = .{
153 .parent = scope,
154 .gen_zir = scope.getGenZIR(),
155 .name = ident_name,
156 .inst = init_inst,
157 };
158 return &sub_scope.base;
159 }
160 } else {
161 const result_loc: ResultLoc = if (node.getTrailer("type_node")) |type_node|
162 .{ .ty = try typeExpr(mod, scope, type_node) }
163 else
164 .none;
165 const init_inst = try expr(mod, scope, result_loc, init_node);
166 const sub_scope = try block_arena.create(Scope.LocalVal);
167 sub_scope.* = .{
168 .parent = scope,
169 .gen_zir = scope.getGenZIR(),
170 .name = ident_name,
171 .inst = init_inst,
172 };
173 return &sub_scope.base;
92 }174 }
93 const init_inst = try expr(mod, scope, init_node);
94 const ident_name = try identifierTokenString(mod, scope, node.name_token);
95 return Scope.LocalVar{
96 .parent = scope,
97 .gen_zir = scope.getGenZIR(),
98 .name = ident_name,
99 .inst = init_inst,
100 };
101 },175 },
102 .Keyword_var => {176 .Keyword_var => {
103 return mod.failNode(scope, &node.base, "TODO implement local vars", .{});177 if (node.getTrailer("type_node")) |type_node| {
178 const type_inst = try typeExpr(mod, scope, type_node);
179 const alloc = try mod.addZIRUnOp(scope, name_src, .alloc, type_inst);
180 const result_loc: ResultLoc = .{ .ptr = alloc };
181 const init_inst = try expr(mod, scope, result_loc, init_node);
182 const sub_scope = try block_arena.create(Scope.LocalPtr);
183 sub_scope.* = .{
184 .parent = scope,
185 .gen_zir = scope.getGenZIR(),
186 .name = ident_name,
187 .ptr = alloc,
188 };
189 return &sub_scope.base;
190 } else {
191 const alloc = try mod.addZIRNoOp(scope, name_src, .alloc_inferred);
192 const result_loc = .{ .inferred_ptr = alloc.castTag(.alloc_inferred).? };
193 const init_inst = try expr(mod, scope, result_loc, init_node);
194 const sub_scope = try block_arena.create(Scope.LocalPtr);
195 sub_scope.* = .{
196 .parent = scope,
197 .gen_zir = scope.getGenZIR(),
198 .name = ident_name,
199 .ptr = alloc,
200 };
201 return &sub_scope.base;
202 }
104 },203 },
105 else => unreachable,204 else => unreachable,
106 }205 }
107}206}
108207
109fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {208fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void {
110 const operand = try expr(mod, scope, node.rhs);209 if (infix_node.lhs.castTag(.Identifier)) |ident| {
111 const tree = scope.tree();
112 const src = tree.token_locs[node.op_token].start;
113 return mod.addZIRUnOp(scope, src, .boolnot, operand);
114}
115
116fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
117 if (infix_node.lhs.tag == .Identifier) {
118 const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs);
119 const tree = scope.tree();210 const tree = scope.tree();
120 const ident_name = try identifierTokenString(mod, scope, ident.token);211 const ident_name = try identifierTokenString(mod, scope, ident.token);
121 if (std.mem.eql(u8, ident_name, "_")) {212 if (std.mem.eql(u8, ident_name, "_")) {
122 return expr(mod, scope, infix_node.rhs);213 _ = try expr(mod, scope, .discard, infix_node.rhs);
214 return;
123 } else {215 } else {
124 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});216 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
125 }217 }
...@@ -128,6 +220,17 @@ fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) Inne...@@ -128,6 +220,17 @@ fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) Inne
128 }220 }
129}221}
130222
223fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
224 const tree = scope.tree();
225 const src = tree.token_locs[node.op_token].start;
226 const bool_type = try mod.addZIRInstConst(scope, src, .{
227 .ty = Type.initTag(.type),
228 .val = Value.initTag(.bool_type),
229 });
230 const operand = try expr(mod, scope, .{ .ty = bool_type }, node.rhs);
231 return mod.addZIRUnOp(scope, src, .boolnot, operand);
232}
233
131/// Identifier token -> String (allocated in scope.arena())234/// Identifier token -> String (allocated in scope.arena())
132pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {235pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
133 const tree = scope.tree();236 const tree = scope.tree();
...@@ -148,7 +251,7 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)...@@ -148,7 +251,7 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
148 return ident_name;251 return ident_name;
149}252}
150253
151pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.Identifier) InnerError!*zir.Inst {254pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
152 const tree = scope.tree();255 const tree = scope.tree();
153 const src = tree.token_locs[node.token].start;256 const src = tree.token_locs[node.token].start;
154257
...@@ -158,10 +261,11 @@ pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.Identif...@@ -158,10 +261,11 @@ pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.Identif
158}261}
159262
160fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {263fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
264 // TODO introduce lvalues
161 const tree = scope.tree();265 const tree = scope.tree();
162 const src = tree.token_locs[node.op_token].start;266 const src = tree.token_locs[node.op_token].start;
163267
164 const lhs = try expr(mod, scope, node.lhs);268 const lhs = try expr(mod, scope, .none, node.lhs);
165 const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);269 const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
166270
167 const pointer = try mod.addZIRInst(scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{});271 const pointer = try mod.addZIRInst(scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{});
...@@ -171,26 +275,44 @@ fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!...@@ -171,26 +275,44 @@ fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!
171fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {275fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
172 const tree = scope.tree();276 const tree = scope.tree();
173 const src = tree.token_locs[node.rtoken].start;277 const src = tree.token_locs[node.rtoken].start;
174 const lhs = try expr(mod, scope, node.lhs);278 const lhs = try expr(mod, scope, .none, node.lhs);
175 return mod.addZIRUnOp(scope, src, .deref, lhs);279 return mod.addZIRUnOp(scope, src, .deref, lhs);
176}280}
177281
178fn simpleInfixOp(282fn cmp(
283 mod: *Module,
284 scope: *Scope,
285 rl: ResultLoc,
286 infix_node: *ast.Node.SimpleInfixOp,
287 cmp_inst_tag: zir.Inst.Tag,
288) InnerError!*zir.Inst {
289 const tree = scope.tree();
290 const src = tree.token_locs[infix_node.op_token].start;
291
292 const lhs = try expr(mod, scope, .none, infix_node.lhs);
293 const rhs = try expr(mod, scope, .none, infix_node.rhs);
294 const result = try mod.addZIRBinOp(scope, src, cmp_inst_tag, lhs, rhs);
295 return rlWrap(mod, scope, rl, result);
296}
297
298fn arithmetic(
179 mod: *Module,299 mod: *Module,
180 scope: *Scope,300 scope: *Scope,
301 rl: ResultLoc,
181 infix_node: *ast.Node.SimpleInfixOp,302 infix_node: *ast.Node.SimpleInfixOp,
182 op_inst_tag: zir.Inst.Tag,303 op_inst_tag: zir.Inst.Tag,
183) InnerError!*zir.Inst {304) InnerError!*zir.Inst {
184 const lhs = try expr(mod, scope, infix_node.lhs);305 const lhs = try expr(mod, scope, .none, infix_node.lhs);
185 const rhs = try expr(mod, scope, infix_node.rhs);306 const rhs = try expr(mod, scope, .none, infix_node.rhs);
186307
187 const tree = scope.tree();308 const tree = scope.tree();
188 const src = tree.token_locs[infix_node.op_token].start;309 const src = tree.token_locs[infix_node.op_token].start;
189310
190 return mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);311 const result = try mod.addZIRBinOp(scope, src, op_inst_tag, lhs, rhs);
312 return rlWrap(mod, scope, rl, result);
191}313}
192314
193fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst {315fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
194 if (if_node.payload) |payload| {316 if (if_node.payload) |payload| {
195 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});317 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});
196 }318 }
...@@ -207,10 +329,14 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In...@@ -207,10 +329,14 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
207 };329 };
208 defer block_scope.instructions.deinit(mod.gpa);330 defer block_scope.instructions.deinit(mod.gpa);
209331
210 const cond = try expr(mod, &block_scope.base, if_node.condition);
211
212 const tree = scope.tree();332 const tree = scope.tree();
213 const if_src = tree.token_locs[if_node.if_token].start;333 const if_src = tree.token_locs[if_node.if_token].start;
334 const bool_type = try mod.addZIRInstConst(scope, if_src, .{
335 .ty = Type.initTag(.type),
336 .val = Value.initTag(.bool_type),
337 });
338 const cond = try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_node.condition);
339
214 const condbr = try mod.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{340 const condbr = try mod.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{
215 .condition = cond,341 .condition = cond,
216 .then_body = undefined, // populated below342 .then_body = undefined, // populated below
...@@ -228,7 +354,16 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In...@@ -228,7 +354,16 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
228 };354 };
229 defer then_scope.instructions.deinit(mod.gpa);355 defer then_scope.instructions.deinit(mod.gpa);
230356
231 const then_result = try expr(mod, &then_scope.base, if_node.body);357 // Most result location types can be forwarded directly; however
358 // if we need to write to a pointer which has an inferred type,
359 // proper type inference requires peer type resolution on the if's
360 // branches.
361 const branch_rl: ResultLoc = switch (rl) {
362 .discard, .none, .ty, .ptr => rl,
363 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
364 };
365
366 const then_result = try expr(mod, &then_scope.base, branch_rl, if_node.body);
232 if (!then_result.tag.isNoReturn()) {367 if (!then_result.tag.isNoReturn()) {
233 const then_src = tree.token_locs[if_node.body.lastToken()].start;368 const then_src = tree.token_locs[if_node.body.lastToken()].start;
234 _ = try mod.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{369 _ = try mod.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{
...@@ -249,7 +384,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In...@@ -249,7 +384,7 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
249 defer else_scope.instructions.deinit(mod.gpa);384 defer else_scope.instructions.deinit(mod.gpa);
250385
251 if (if_node.@"else") |else_node| {386 if (if_node.@"else") |else_node| {
252 const else_result = try expr(mod, &else_scope.base, else_node.body);387 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
253 if (!else_result.tag.isNoReturn()) {388 if (!else_result.tag.isNoReturn()) {
254 const else_src = tree.token_locs[else_node.body.lastToken()].start;389 const else_src = tree.token_locs[else_node.body.lastToken()].start;
255 _ = try mod.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{390 _ = try mod.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{
...@@ -272,27 +407,25 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In...@@ -272,27 +407,25 @@ fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.In
272 return &block.base;407 return &block.base;
273}408}
274409
275fn controlFlowExpr(410fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {
276 mod: *Module,
277 scope: *Scope,
278 cfe: *ast.Node.ControlFlowExpression,
279) InnerError!*zir.Inst {
280 switch (cfe.kind) {
281 .Break => return mod.failNode(scope, &cfe.base, "TODO implement astgen.Expr for Break", .{}),
282 .Continue => return mod.failNode(scope, &cfe.base, "TODO implement astgen.Expr for Continue", .{}),
283 .Return => {},
284 }
285 const tree = scope.tree();411 const tree = scope.tree();
286 const src = tree.token_locs[cfe.ltoken].start;412 const src = tree.token_locs[cfe.ltoken].start;
287 if (cfe.rhs) |rhs_node| {413 if (cfe.getRHS()) |rhs_node| {
288 const operand = try expr(mod, scope, rhs_node);414 if (nodeMayNeedMemoryLocation(rhs_node)) {
289 return mod.addZIRUnOp(scope, src, .@"return", operand);415 const ret_ptr = try mod.addZIRNoOp(scope, src, .ret_ptr);
416 const operand = try expr(mod, scope, .{ .ptr = ret_ptr }, rhs_node);
417 return mod.addZIRUnOp(scope, src, .@"return", operand);
418 } else {
419 const fn_ret_ty = try mod.addZIRNoOp(scope, src, .ret_type);
420 const operand = try expr(mod, scope, .{ .ty = fn_ret_ty }, rhs_node);
421 return mod.addZIRUnOp(scope, src, .@"return", operand);
422 }
290 } else {423 } else {
291 return mod.addZIRNoOp(scope, src, .returnvoid);424 return mod.addZIRNoOp(scope, src, .returnvoid);
292 }425 }
293}426}
294427
295fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {428fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.OneToken) InnerError!*zir.Inst {
296 const tracy = trace(@src());429 const tracy = trace(@src());
297 defer tracy.end();430 defer tracy.end();
298431
...@@ -345,12 +478,19 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr...@@ -345,12 +478,19 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr
345 {478 {
346 var s = scope;479 var s = scope;
347 while (true) switch (s.tag) {480 while (true) switch (s.tag) {
348 .local_var => {481 .local_val => {
349 const local_var = s.cast(Scope.LocalVar).?;482 const local_val = s.cast(Scope.LocalVal).?;
350 if (mem.eql(u8, local_var.name, ident_name)) {483 if (mem.eql(u8, local_val.name, ident_name)) {
351 return local_var.inst;484 return local_val.inst;
485 }
486 s = local_val.parent;
487 },
488 .local_ptr => {
489 const local_ptr = s.cast(Scope.LocalPtr).?;
490 if (mem.eql(u8, local_ptr.name, ident_name)) {
491 return try mod.addZIRUnOp(scope, src, .deref, local_ptr.ptr);
352 }492 }
353 s = local_var.parent;493 s = local_ptr.parent;
354 },494 },
355 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,495 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,
356 else => break,496 else => break,
...@@ -364,7 +504,7 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr...@@ -364,7 +504,7 @@ fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerErr
364 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});504 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});
365}505}
366506
367fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {507fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
368 const tree = scope.tree();508 const tree = scope.tree();
369 const unparsed_bytes = tree.tokenSlice(str_lit.token);509 const unparsed_bytes = tree.tokenSlice(str_lit.token);
370 const arena = scope.arena();510 const arena = scope.arena();
...@@ -383,7 +523,7 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral)...@@ -383,7 +523,7 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral)
383 return mod.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});523 return mod.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
384}524}
385525
386fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {526fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
387 const arena = scope.arena();527 const arena = scope.arena();
388 const tree = scope.tree();528 const tree = scope.tree();
389 const prefixed_bytes = tree.tokenSlice(int_lit.token);529 const prefixed_bytes = tree.tokenSlice(int_lit.token);
...@@ -414,7 +554,7 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral...@@ -414,7 +554,7 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral
414 }554 }
415}555}
416556
417fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.FloatLiteral) InnerError!*zir.Inst {557fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) InnerError!*zir.Inst {
418 const arena = scope.arena();558 const arena = scope.arena();
419 const tree = scope.tree();559 const tree = scope.tree();
420 const bytes = tree.tokenSlice(float_lit.token);560 const bytes = tree.tokenSlice(float_lit.token);
...@@ -434,30 +574,38 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.FloatLiteral)...@@ -434,30 +574,38 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.FloatLiteral)
434 });574 });
435}575}
436576
437fn primitiveLiteral(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {577fn undefLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
438 const arena = scope.arena();578 const arena = scope.arena();
439 const tree = scope.tree();579 const tree = scope.tree();
440 const src = tree.token_locs[node.firstToken()].start;580 const src = tree.token_locs[node.token].start;
581 return mod.addZIRInstConst(scope, src, .{
582 .ty = Type.initTag(.@"undefined"),
583 .val = Value.initTag(.undef),
584 });
585}
441586
442 if (node.cast(ast.Node.BoolLiteral)) |bool_node| {587fn boolLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
443 return mod.addZIRInstConst(scope, src, .{588 const arena = scope.arena();
444 .ty = Type.initTag(.bool),589 const tree = scope.tree();
445 .val = if (tree.token_ids[bool_node.token] == .Keyword_true)590 const src = tree.token_locs[node.token].start;
446 Value.initTag(.bool_true)591 return mod.addZIRInstConst(scope, src, .{
447 else592 .ty = Type.initTag(.bool),
448 Value.initTag(.bool_false),593 .val = switch (tree.token_ids[node.token]) {
449 });594 .Keyword_true => Value.initTag(.bool_true),
450 } else if (node.tag == .UndefinedLiteral) {595 .Keyword_false => Value.initTag(.bool_false),
451 return mod.addZIRInstConst(scope, src, .{596 else => unreachable,
452 .ty = Type.initTag(.@"undefined"),597 },
453 .val = Value.initTag(.undef),598 });
454 });599}
455 } else if (node.tag == .NullLiteral) {600
456 return mod.addZIRInstConst(scope, src, .{601fn nullLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
457 .ty = Type.initTag(.@"null"),602 const arena = scope.arena();
458 .val = Value.initTag(.null_value),603 const tree = scope.tree();
459 });604 const src = tree.token_locs[node.token].start;
460 } else unreachable;605 return mod.addZIRInstConst(scope, src, .{
606 .ty = Type.initTag(.@"null"),
607 .val = Value.initTag(.null_value),
608 });
461}609}
462610
463fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {611fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
...@@ -470,19 +618,26 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi...@@ -470,19 +618,26 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi
470 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);618 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);
471 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);619 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);
472620
621 const src = tree.token_locs[asm_node.asm_token].start;
622
623 const str_type = try mod.addZIRInstConst(scope, src, .{
624 .ty = Type.initTag(.type),
625 .val = Value.initTag(.const_slice_u8_type),
626 });
627 const str_type_rl: ResultLoc = .{ .ty = str_type };
628
473 for (asm_node.inputs) |input, i| {629 for (asm_node.inputs) |input, i| {
474 // TODO semantically analyze constraints630 // TODO semantically analyze constraints
475 inputs[i] = try expr(mod, scope, input.constraint);631 inputs[i] = try expr(mod, scope, str_type_rl, input.constraint);
476 args[i] = try expr(mod, scope, input.expr);632 args[i] = try expr(mod, scope, .none, input.expr);
477 }633 }
478634
479 const src = tree.token_locs[asm_node.asm_token].start;
480 const return_type = try mod.addZIRInstConst(scope, src, .{635 const return_type = try mod.addZIRInstConst(scope, src, .{
481 .ty = Type.initTag(.type),636 .ty = Type.initTag(.type),
482 .val = Value.initTag(.void_type),637 .val = Value.initTag(.void_type),
483 });638 });
484 const asm_inst = try mod.addZIRInst(scope, src, zir.Inst.Asm, .{639 const asm_inst = try mod.addZIRInst(scope, src, zir.Inst.Asm, .{
485 .asm_source = try expr(mod, scope, asm_node.template),640 .asm_source = try expr(mod, scope, str_type_rl, asm_node.template),
486 .return_type = return_type,641 .return_type = return_type,
487 }, .{642 }, .{
488 .@"volatile" = asm_node.volatile_token != null,643 .@"volatile" = asm_node.volatile_token != null,
...@@ -493,63 +648,174 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi...@@ -493,63 +648,174 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi
493 return asm_inst;648 return asm_inst;
494}649}
495650
496fn builtinCall(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {651fn ensureBuiltinParamCount(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall, count: u32) !void {
652 if (call.params_len == count)
653 return;
654
655 const s = if (count == 1) "" else "s";
656 return mod.failTok(scope, call.builtin_token, "expected {} parameter{}, found {}", .{ count, s, call.params_len });
657}
658
659fn simpleCast(
660 mod: *Module,
661 scope: *Scope,
662 rl: ResultLoc,
663 call: *ast.Node.BuiltinCall,
664 inst_tag: zir.Inst.Tag,
665) InnerError!*zir.Inst {
666 try ensureBuiltinParamCount(mod, scope, call, 2);
497 const tree = scope.tree();667 const tree = scope.tree();
498 const builtin_name = tree.tokenSlice(call.builtin_token);
499 const src = tree.token_locs[call.builtin_token].start;668 const src = tree.token_locs[call.builtin_token].start;
669 const type_type = try mod.addZIRInstConst(scope, src, .{
670 .ty = Type.initTag(.type),
671 .val = Value.initTag(.type_type),
672 });
673 const params = call.params();
674 const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
675 const rhs = try expr(mod, scope, .none, params[1]);
676 const result = try mod.addZIRBinOp(scope, src, inst_tag, dest_type, rhs);
677 return rlWrap(mod, scope, rl, result);
678}
500679
501 inline for (std.meta.declarations(zir.Inst)) |inst| {680fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
502 if (inst.data != .Type) continue;681 try ensureBuiltinParamCount(mod, scope, call, 1);
503 const T = inst.data.Type;682 const operand = try expr(mod, scope, .none, call.params()[0]);
504 if (!@hasDecl(T, "builtin_name")) continue;683 const tree = scope.tree();
505 if (std.mem.eql(u8, builtin_name, T.builtin_name)) {684 const src = tree.token_locs[call.builtin_token].start;
506 var value: T = undefined;685 return mod.addZIRUnOp(scope, src, .ptrtoint, operand);
507 const positionals = @typeInfo(std.meta.fieldInfo(T, "positionals").field_type).Struct;686}
508 if (positionals.fields.len == 0) {
509 return mod.addZIRInst(scope, src, T, value.positionals, value.kw_args);
510 }
511 const arg_count: ?usize = if (positionals.fields[0].field_type == []*zir.Inst) null else positionals.fields.len;
512 if (arg_count) |some| {
513 if (call.params_len != some) {
514 return mod.failTok(
515 scope,
516 call.builtin_token,
517 "expected {} parameter{}, found {}",
518 .{ some, if (some == 1) "" else "s", call.params_len },
519 );
520 }
521 const params = call.params();
522 inline for (positionals.fields) |p, i| {
523 @field(value.positionals, p.name) = try expr(mod, scope, params[i]);
524 }
525 } else {
526 return mod.failTok(scope, call.builtin_token, "TODO var args builtin '{}'", .{builtin_name});
527 }
528687
529 return mod.addZIRInst(scope, src, T, value.positionals, .{});688fn as(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
530 }689 try ensureBuiltinParamCount(mod, scope, call, 2);
690 const tree = scope.tree();
691 const src = tree.token_locs[call.builtin_token].start;
692 const params = call.params();
693 const dest_type = try typeExpr(mod, scope, params[0]);
694 switch (rl) {
695 .none => return try expr(mod, scope, .{ .ty = dest_type }, params[1]),
696 .discard => {
697 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
698 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
699 return result;
700 },
701 .ty => |result_ty| {
702 const result = try expr(mod, scope, .{ .ty = dest_type }, params[1]);
703 return mod.addZIRBinOp(scope, src, .as, result_ty, result);
704 },
705 .ptr => |result_ptr| {
706 const casted_result_ptr = try mod.addZIRBinOp(scope, src, .coerce_result_ptr, dest_type, result_ptr);
707 return expr(mod, scope, .{ .ptr = casted_result_ptr }, params[1]);
708 },
709 .bitcasted_ptr => |bitcasted_ptr| {
710 // TODO here we should be able to resolve the inference; we now have a type for the result.
711 return mod.failTok(scope, call.builtin_token, "TODO implement @as with result location @bitCast", .{});
712 },
713 .inferred_ptr => |result_alloc| {
714 // TODO here we should be able to resolve the inference; we now have a type for the result.
715 return mod.failTok(scope, call.builtin_token, "TODO implement @as with inferred-type result location pointer", .{});
716 },
717 .block_ptr => |block_ptr| {
718 const casted_block_ptr = try mod.addZIRInst(scope, src, zir.Inst.CoerceResultBlockPtr, .{
719 .dest_type = dest_type,
720 .block = block_ptr,
721 }, .{});
722 return expr(mod, scope, .{ .ptr = casted_block_ptr }, params[1]);
723 },
724 }
725}
726
727fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
728 try ensureBuiltinParamCount(mod, scope, call, 2);
729 const tree = scope.tree();
730 const src = tree.token_locs[call.builtin_token].start;
731 const type_type = try mod.addZIRInstConst(scope, src, .{
732 .ty = Type.initTag(.type),
733 .val = Value.initTag(.type_type),
734 });
735 const params = call.params();
736 const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
737 switch (rl) {
738 .none => {
739 const operand = try expr(mod, scope, .none, params[1]);
740 return mod.addZIRBinOp(scope, src, .bitcast, dest_type, operand);
741 },
742 .discard => {
743 const operand = try expr(mod, scope, .none, params[1]);
744 const result = try mod.addZIRBinOp(scope, src, .bitcast, dest_type, operand);
745 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
746 return result;
747 },
748 .ty => |result_ty| {
749 const result = try expr(mod, scope, .none, params[1]);
750 const bitcasted = try mod.addZIRBinOp(scope, src, .bitcast, dest_type, result);
751 return mod.addZIRBinOp(scope, src, .as, result_ty, bitcasted);
752 },
753 .ptr => |result_ptr| {
754 const casted_result_ptr = try mod.addZIRUnOp(scope, src, .bitcast_result_ptr, result_ptr);
755 return expr(mod, scope, .{ .bitcasted_ptr = casted_result_ptr.castTag(.bitcast_result_ptr).? }, params[1]);
756 },
757 .bitcasted_ptr => |bitcasted_ptr| {
758 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location another @bitCast", .{});
759 },
760 .block_ptr => |block_ptr| {
761 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with result location inferred peer types", .{});
762 },
763 .inferred_ptr => |result_alloc| {
764 // TODO here we should be able to resolve the inference; we now have a type for the result.
765 return mod.failTok(scope, call.builtin_token, "TODO implement @bitCast with inferred-type result location pointer", .{});
766 },
531 }767 }
532 return mod.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
533}768}
534769
535fn callExpr(mod: *Module, scope: *Scope, node: *ast.Node.Call) InnerError!*zir.Inst {770fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
536 const tree = scope.tree();771 const tree = scope.tree();
537 const lhs = try expr(mod, scope, node.lhs);772 const builtin_name = tree.tokenSlice(call.builtin_token);
773
774 // We handle the different builtins manually because they have different semantics depending
775 // on the function. For example, `@as` and others participate in result location semantics,
776 // and `@cImport` creates a special scope that collects a .c source code text buffer.
777 // Also, some builtins have a variable number of parameters.
778
779 if (mem.eql(u8, builtin_name, "@ptrToInt")) {
780 return rlWrap(mod, scope, rl, try ptrToInt(mod, scope, call));
781 } else if (mem.eql(u8, builtin_name, "@as")) {
782 return as(mod, scope, rl, call);
783 } else if (mem.eql(u8, builtin_name, "@floatCast")) {
784 return simpleCast(mod, scope, rl, call, .floatcast);
785 } else if (mem.eql(u8, builtin_name, "@intCast")) {
786 return simpleCast(mod, scope, rl, call, .intcast);
787 } else if (mem.eql(u8, builtin_name, "@bitCast")) {
788 return bitCast(mod, scope, rl, call);
789 } else {
790 return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{}'", .{builtin_name});
791 }
792}
793
794fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) InnerError!*zir.Inst {
795 const tree = scope.tree();
796 const lhs = try expr(mod, scope, .none, node.lhs);
538797
539 const param_nodes = node.params();798 const param_nodes = node.params();
540 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len);799 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len);
541 for (param_nodes) |param_node, i| {800 for (param_nodes) |param_node, i| {
542 args[i] = try expr(mod, scope, param_node);801 const param_src = tree.token_locs[param_node.firstToken()].start;
802 const param_type = try mod.addZIRInst(scope, param_src, zir.Inst.ParamType, .{
803 .func = lhs,
804 .arg_index = i,
805 }, .{});
806 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);
543 }807 }
544808
545 const src = tree.token_locs[node.lhs.firstToken()].start;809 const src = tree.token_locs[node.lhs.firstToken()].start;
546 return mod.addZIRInst(scope, src, zir.Inst.Call, .{810 const result = try mod.addZIRInst(scope, src, zir.Inst.Call, .{
547 .func = lhs,811 .func = lhs,
548 .args = args,812 .args = args,
549 }, .{});813 }, .{});
814 // TODO function call with result location
815 return rlWrap(mod, scope, rl, result);
550}816}
551817
552fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {818fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst {
553 const tree = scope.tree();819 const tree = scope.tree();
554 const src = tree.token_locs[unreach_node.token].start;820 const src = tree.token_locs[unreach_node.token].start;
555 return mod.addZIRNoOp(scope, src, .@"unreachable");821 return mod.addZIRNoOp(scope, src, .@"unreachable");
...@@ -611,7 +877,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {...@@ -611,7 +877,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
611 .FieldInitializer,877 .FieldInitializer,
612 => unreachable,878 => unreachable,
613879
614 .ControlFlowExpression,880 .Return,
881 .Break,
882 .Continue,
615 .BitNot,883 .BitNot,
616 .BoolNot,884 .BoolNot,
617 .VarDecl,885 .VarDecl,
...@@ -722,3 +990,39 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {...@@ -722,3 +990,39 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
722 }990 }
723 }991 }
724}992}
993
994/// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of
995/// result locations must call this function on their result.
996/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
997/// If the `ResultLoc` is `ty`, it will coerce the result to the type.
998fn rlWrap(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerError!*zir.Inst {
999 switch (rl) {
1000 .none => return result,
1001 .discard => {
1002 // Emit a compile error for discarding error values.
1003 _ = try mod.addZIRUnOp(scope, result.src, .ensure_result_non_error, result);
1004 return result;
1005 },
1006 .ty => |ty_inst| return mod.addZIRBinOp(scope, result.src, .as, ty_inst, result),
1007 .ptr => |ptr_inst| {
1008 const casted_result = try mod.addZIRInst(scope, result.src, zir.Inst.CoerceToPtrElem, .{
1009 .ptr = ptr_inst,
1010 .value = result,
1011 }, .{});
1012 _ = try mod.addZIRInst(scope, result.src, zir.Inst.Store, .{
1013 .ptr = ptr_inst,
1014 .value = casted_result,
1015 }, .{});
1016 return casted_result;
1017 },
1018 .bitcasted_ptr => |bitcasted_ptr| {
1019 return mod.fail(scope, result.src, "TODO implement rlWrap .bitcasted_ptr", .{});
1020 },
1021 .inferred_ptr => |alloc| {
1022 return mod.fail(scope, result.src, "TODO implement rlWrap .inferred_ptr", .{});
1023 },
1024 .block_ptr => |block_ptr| {
1025 return mod.fail(scope, result.src, "TODO implement rlWrap .block_ptr", .{});
1026 },
1027 }
1028}
src-self-hosted/codegen/c.zig+3-17
...@@ -90,7 +90,7 @@ fn genFn(file: *C, decl: *Decl) !void {...@@ -90,7 +90,7 @@ fn genFn(file: *C, decl: *Decl) !void {
90 const instructions = func.analysis.success.instructions;90 const instructions = func.analysis.success.instructions;
91 if (instructions.len > 0) {91 if (instructions.len > 0) {
92 for (instructions) |inst| {92 for (instructions) |inst| {
93 try writer.writeAll("\n\t");93 try writer.writeAll("\n ");
94 switch (inst.tag) {94 switch (inst.tag) {
95 .assembly => try genAsm(file, inst.castTag(.assembly).?, decl),95 .assembly => try genAsm(file, inst.castTag(.assembly).?, decl),
96 .call => try genCall(file, inst.castTag(.call).?, decl),96 .call => try genCall(file, inst.castTag(.call).?, decl),
...@@ -106,21 +106,7 @@ fn genFn(file: *C, decl: *Decl) !void {...@@ -106,21 +106,7 @@ fn genFn(file: *C, decl: *Decl) !void {
106}106}
107107
108fn genRet(file: *C, inst: *Inst.UnOp, decl: *Decl, expected_return_type: Type) !void {108fn genRet(file: *C, inst: *Inst.UnOp, decl: *Decl, expected_return_type: Type) !void {
109 const writer = file.main.writer();109 return file.fail(decl.src(), "TODO return {}", .{expected_return_type});
110 const ret_value = inst.operand;
111 const value = ret_value.value().?;
112 if (expected_return_type.eql(ret_value.ty))
113 return file.fail(decl.src(), "TODO return {}", .{expected_return_type})
114 else if (expected_return_type.isInt() and ret_value.ty.tag() == .comptime_int)
115 if (value.intFitsInType(expected_return_type, file.options.target))
116 if (expected_return_type.intInfo(file.options.target).bits <= 64)
117 try writer.print("return {};", .{value.toUnsignedInt()})
118 else
119 return file.fail(decl.src(), "TODO return ints > 64 bits", .{})
120 else
121 return file.fail(decl.src(), "comptime int {} does not fit in {}", .{ value.toUnsignedInt(), expected_return_type })
122 else
123 return file.fail(decl.src(), "return type mismatch: expected {}, found {}", .{ expected_return_type, ret_value.ty });
124}110}
125111
126fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {112fn genCall(file: *C, inst: *Inst.Call, decl: *Decl) !void {
...@@ -162,7 +148,7 @@ fn genAsm(file: *C, as: *Inst.Assembly, decl: *Decl) !void {...@@ -162,7 +148,7 @@ fn genAsm(file: *C, as: *Inst.Assembly, decl: *Decl) !void {
162 if (c.val.tag() == .int_u64) {148 if (c.val.tag() == .int_u64) {
163 try writer.writeAll("register ");149 try writer.writeAll("register ");
164 try renderType(file, writer, arg.ty, decl.src());150 try renderType(file, writer, arg.ty, decl.src());
165 try writer.print(" {}_constant __asm__(\"{}\") = {};\n\t", .{ reg, reg, c.val.toUnsignedInt() });151 try writer.print(" {}_constant __asm__(\"{}\") = {};\n ", .{ reg, reg, c.val.toUnsignedInt() });
166 } else {152 } else {
167 return file.fail(decl.src(), "TODO inline asm {} args", .{c.val.tag()});153 return file.fail(decl.src(), "TODO inline asm {} args", .{c.val.tag()});
168 }154 }
src-self-hosted/link.zig+4
...@@ -1579,6 +1579,8 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !Fi...@@ -1579,6 +1579,8 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !Fi
1579 .elf => {},1579 .elf => {},
1580 .macho => return error.TODOImplementWritingMachO,1580 .macho => return error.TODOImplementWritingMachO,
1581 .wasm => return error.TODOImplementWritingWasmObjects,1581 .wasm => return error.TODOImplementWritingWasmObjects,
1582 .hex => return error.TODOImplementWritingHex,
1583 .raw => return error.TODOImplementWritingRaw,
1582 }1584 }
15831585
1584 var self: File.Elf = .{1586 var self: File.Elf = .{
...@@ -1638,6 +1640,8 @@ fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !Fil...@@ -1638,6 +1640,8 @@ fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !Fil
1638 .elf => {},1640 .elf => {},
1639 .macho => return error.IncrFailed,1641 .macho => return error.IncrFailed,
1640 .wasm => return error.IncrFailed,1642 .wasm => return error.IncrFailed,
1643 .hex => return error.IncrFailed,
1644 .raw => return error.IncrFailed,
1641 }1645 }
1642 var self: File.Elf = .{1646 var self: File.Elf = .{
1643 .allocator = allocator,1647 .allocator = allocator,
src-self-hosted/main.zig+38-10
...@@ -141,11 +141,19 @@ const usage_build_generic =...@@ -141,11 +141,19 @@ const usage_build_generic =
141 \\ --name [name] Override output name141 \\ --name [name] Override output name
142 \\ --mode [mode] Set the build mode142 \\ --mode [mode] Set the build mode
143 \\ Debug (default) optimizations off, safety on143 \\ Debug (default) optimizations off, safety on
144 \\ ReleaseFast optimizations on, safety off144 \\ ReleaseFast Optimizations on, safety off
145 \\ ReleaseSafe optimizations on, safety on145 \\ ReleaseSafe Optimizations on, safety on
146 \\ ReleaseSmall optimize for small binary, safety off146 \\ ReleaseSmall Optimize for small binary, safety off
147 \\ --dynamic Force output to be dynamically linked147 \\ --dynamic Force output to be dynamically linked
148 \\ --strip Exclude debug symbols148 \\ --strip Exclude debug symbols
149 \\ -ofmt=[mode] Override target object format
150 \\ elf Executable and Linking Format
151 \\ c Compile to C source code
152 \\ coff (planned) Common Object File Format (Windows)
153 \\ pe (planned) Portable Executable (Windows)
154 \\ macho (planned) macOS relocatables
155 \\ hex (planned) Intel IHEX
156 \\ raw (planned) Dump machine code directly
149 \\157 \\
150 \\Link Options:158 \\Link Options:
151 \\ -l[lib], --library [lib] Link against system library159 \\ -l[lib], --library [lib] Link against system library
...@@ -195,7 +203,7 @@ fn buildOutputType(...@@ -195,7 +203,7 @@ fn buildOutputType(
195 var target_arch_os_abi: []const u8 = "native";203 var target_arch_os_abi: []const u8 = "native";
196 var target_mcpu: ?[]const u8 = null;204 var target_mcpu: ?[]const u8 = null;
197 var target_dynamic_linker: ?[]const u8 = null;205 var target_dynamic_linker: ?[]const u8 = null;
198 var object_format: ?std.builtin.ObjectFormat = null;206 var target_ofmt: ?[]const u8 = null;
199207
200 var system_libs = std.ArrayList([]const u8).init(gpa);208 var system_libs = std.ArrayList([]const u8).init(gpa);
201 defer system_libs.deinit();209 defer system_libs.deinit();
...@@ -282,12 +290,8 @@ fn buildOutputType(...@@ -282,12 +290,8 @@ fn buildOutputType(
282 }290 }
283 i += 1;291 i += 1;
284 target_mcpu = args[i];292 target_mcpu = args[i];
285 } else if (mem.eql(u8, arg, "--c")) {293 } else if (mem.startsWith(u8, arg, "-ofmt=")) {
286 if (object_format) |old| {294 target_ofmt = arg["-ofmt=".len..];
287 std.debug.print("attempted to override object format {} with C\n", .{old});
288 process.exit(1);
289 }
290 object_format = .c;
291 } else if (mem.startsWith(u8, arg, "-mcpu=")) {295 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
292 target_mcpu = arg["-mcpu=".len..];296 target_mcpu = arg["-mcpu=".len..];
293 } else if (mem.eql(u8, arg, "--dynamic-linker")) {297 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
...@@ -434,6 +438,30 @@ fn buildOutputType(...@@ -434,6 +438,30 @@ fn buildOutputType(
434 process.exit(1);438 process.exit(1);
435 };439 };
436440
441 const object_format: ?std.Target.ObjectFormat = blk: {
442 const ofmt = target_ofmt orelse break :blk null;
443 if (mem.eql(u8, ofmt, "elf")) {
444 break :blk .elf;
445 } else if (mem.eql(u8, ofmt, "c")) {
446 break :blk .c;
447 } else if (mem.eql(u8, ofmt, "coff")) {
448 break :blk .coff;
449 } else if (mem.eql(u8, ofmt, "pe")) {
450 break :blk .coff;
451 } else if (mem.eql(u8, ofmt, "macho")) {
452 break :blk .macho;
453 } else if (mem.eql(u8, ofmt, "wasm")) {
454 break :blk .wasm;
455 } else if (mem.eql(u8, ofmt, "hex")) {
456 break :blk .hex;
457 } else if (mem.eql(u8, ofmt, "raw")) {
458 break :blk .raw;
459 } else {
460 std.debug.print("unsupported object format: {}", .{ofmt});
461 process.exit(1);
462 }
463 };
464
437 const bin_path = switch (emit_bin) {465 const bin_path = switch (emit_bin) {
438 .no => {466 .no => {
439 std.debug.print("-fno-emit-bin not supported yet", .{});467 std.debug.print("-fno-emit-bin not supported yet", .{});
src-self-hosted/translate_c.zig+165-91
...@@ -1308,8 +1308,7 @@ fn transBinaryOperator(...@@ -1308,8 +1308,7 @@ fn transBinaryOperator(
1308 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);1308 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
1309 if (expr) {1309 if (expr) {
1310 _ = try appendToken(rp.c, .Semicolon, ";");1310 _ = try appendToken(rp.c, .Semicolon, ";");
1311 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);1311 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, rhs);
1312 break_node.rhs = rhs;
1313 try block_scope.statements.append(&break_node.base);1312 try block_scope.statements.append(&break_node.base);
1314 const block_node = try block_scope.complete(rp.c);1313 const block_node = try block_scope.complete(rp.c);
1315 const rparen = try appendToken(rp.c, .RParen, ")");1314 const rparen = try appendToken(rp.c, .RParen, ")");
...@@ -1881,12 +1880,19 @@ fn transReturnStmt(...@@ -1881,12 +1880,19 @@ fn transReturnStmt(
1881 scope: *Scope,1880 scope: *Scope,
1882 expr: *const ZigClangReturnStmt,1881 expr: *const ZigClangReturnStmt,
1883) TransError!*ast.Node {1882) TransError!*ast.Node {
1884 const node = try transCreateNodeReturnExpr(rp.c);1883 const return_kw = try appendToken(rp.c, .Keyword_return, "return");
1885 if (ZigClangReturnStmt_getRetValue(expr)) |val_expr| {1884 const rhs: ?*ast.Node = if (ZigClangReturnStmt_getRetValue(expr)) |val_expr|
1886 node.rhs = try transExprCoercing(rp, scope, val_expr, .used, .r_value);1885 try transExprCoercing(rp, scope, val_expr, .used, .r_value)
1887 }1886 else
1887 null;
1888 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
1889 .ltoken = return_kw,
1890 .tag = .Return,
1891 }, .{
1892 .rhs = rhs,
1893 });
1888 _ = try appendToken(rp.c, .Semicolon, ";");1894 _ = try appendToken(rp.c, .Semicolon, ";");
1889 return &node.base;1895 return &return_expr.base;
1890}1896}
18911897
1892fn transStringLiteral(1898fn transStringLiteral(
...@@ -1912,8 +1918,9 @@ fn transStringLiteral(...@@ -1912,8 +1918,9 @@ fn transStringLiteral(
1912 buf[buf.len - 1] = '"';1918 buf[buf.len - 1] = '"';
19131919
1914 const token = try appendToken(rp.c, .StringLiteral, buf);1920 const token = try appendToken(rp.c, .StringLiteral, buf);
1915 const node = try rp.c.arena.create(ast.Node.StringLiteral);1921 const node = try rp.c.arena.create(ast.Node.OneToken);
1916 node.* = .{1922 node.* = .{
1923 .base = .{ .tag = .StringLiteral },
1917 .token = token,1924 .token = token,
1918 };1925 };
1919 return maybeSuppressResult(rp, scope, result_used, &node.base);1926 return maybeSuppressResult(rp, scope, result_used, &node.base);
...@@ -2518,7 +2525,7 @@ fn transDoWhileLoop(...@@ -2518,7 +2525,7 @@ fn transDoWhileLoop(
2518 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);2525 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true);
2519 _ = try appendToken(rp.c, .RParen, ")");2526 _ = try appendToken(rp.c, .RParen, ")");
2520 if_node.condition = &prefix_op.base;2527 if_node.condition = &prefix_op.base;
2521 if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;2528 if_node.body = &(try transCreateNodeBreak(rp.c, null, null)).base;
2522 _ = try appendToken(rp.c, .Semicolon, ";");2529 _ = try appendToken(rp.c, .Semicolon, ";");
25232530
2524 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {2531 const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
...@@ -2688,7 +2695,7 @@ fn transSwitch(...@@ -2688,7 +2695,7 @@ fn transSwitch(
2688 _ = try appendToken(rp.c, .Colon, ":");2695 _ = try appendToken(rp.c, .Colon, ":");
2689 if (!switch_scope.has_default) {2696 if (!switch_scope.has_default) {
2690 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));2697 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2691 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base;2698 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch", null)).base;
2692 _ = try appendToken(rp.c, .Comma, ",");2699 _ = try appendToken(rp.c, .Comma, ",");
26932700
2694 if (switch_scope.case_index >= switch_scope.cases.len)2701 if (switch_scope.case_index >= switch_scope.cases.len)
...@@ -2732,7 +2739,7 @@ fn transCase(...@@ -2732,7 +2739,7 @@ fn transCase(
2732 try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);2739 try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);
27332740
2734 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);2741 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
2735 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;2742 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base;
2736 _ = try appendToken(rp.c, .Comma, ",");2743 _ = try appendToken(rp.c, .Comma, ",");
27372744
2738 if (switch_scope.case_index >= switch_scope.cases.len)2745 if (switch_scope.case_index >= switch_scope.cases.len)
...@@ -2768,7 +2775,7 @@ fn transDefault(...@@ -2768,7 +2775,7 @@ fn transDefault(
2768 _ = try appendToken(rp.c, .Semicolon, ";");2775 _ = try appendToken(rp.c, .Semicolon, ";");
27692776
2770 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));2777 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2771 else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base;2778 else_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base;
2772 _ = try appendToken(rp.c, .Comma, ",");2779 _ = try appendToken(rp.c, .Comma, ",");
27732780
2774 if (switch_scope.case_index >= switch_scope.cases.len)2781 if (switch_scope.case_index >= switch_scope.cases.len)
...@@ -2843,8 +2850,9 @@ fn transCharLiteral(...@@ -2843,8 +2850,9 @@ fn transCharLiteral(
2843 }2850 }
2844 var char_buf: [4]u8 = undefined;2851 var char_buf: [4]u8 = undefined;
2845 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});2852 const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)});
2846 const node = try rp.c.arena.create(ast.Node.CharLiteral);2853 const node = try rp.c.arena.create(ast.Node.OneToken);
2847 node.* = .{2854 node.* = .{
2855 .base = .{ .tag = .CharLiteral },
2848 .token = token,2856 .token = token,
2849 };2857 };
2850 break :blk &node.base;2858 break :blk &node.base;
...@@ -2889,8 +2897,11 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,...@@ -2889,8 +2897,11 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
2889 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);2897 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
2890 try block_scope.statements.append(result);2898 try block_scope.statements.append(result);
2891 }2899 }
2892 const break_node = try transCreateNodeBreak(rp.c, "blk");2900 const break_node = blk: {
2893 break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);2901 var tmp = try CtrlFlow.init(rp.c, .Break, "blk");
2902 const rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
2903 break :blk try tmp.finish(rhs);
2904 };
2894 _ = try appendToken(rp.c, .Semicolon, ";");2905 _ = try appendToken(rp.c, .Semicolon, ";");
2895 try block_scope.statements.append(&break_node.base);2906 try block_scope.statements.append(&break_node.base);
2896 const block_node = try block_scope.complete(rp.c);2907 const block_node = try block_scope.complete(rp.c);
...@@ -3205,8 +3216,7 @@ fn transCreatePreCrement(...@@ -3205,8 +3216,7 @@ fn transCreatePreCrement(
3205 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);3216 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
3206 try block_scope.statements.append(assign);3217 try block_scope.statements.append(assign);
32073218
3208 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);3219 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node);
3209 break_node.rhs = ref_node;
3210 try block_scope.statements.append(&break_node.base);3220 try block_scope.statements.append(&break_node.base);
3211 const block_node = try block_scope.complete(rp.c);3221 const block_node = try block_scope.complete(rp.c);
3212 // semicolon must immediately follow rbrace because it is the last token in a block3222 // semicolon must immediately follow rbrace because it is the last token in a block
...@@ -3297,8 +3307,11 @@ fn transCreatePostCrement(...@@ -3297,8 +3307,11 @@ fn transCreatePostCrement(
3297 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);3307 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
3298 try block_scope.statements.append(assign);3308 try block_scope.statements.append(assign);
32993309
3300 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);3310 const break_node = blk: {
3301 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);3311 var tmp_ctrl_flow = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
3312 const rhs = try transCreateNodeIdentifier(rp.c, tmp);
3313 break :blk try tmp_ctrl_flow.finish(rhs);
3314 };
3302 try block_scope.statements.append(&break_node.base);3315 try block_scope.statements.append(&break_node.base);
3303 _ = try appendToken(rp.c, .Semicolon, ";");3316 _ = try appendToken(rp.c, .Semicolon, ";");
3304 const block_node = try block_scope.complete(rp.c);3317 const block_node = try block_scope.complete(rp.c);
...@@ -3490,8 +3503,7 @@ fn transCreateCompoundAssign(...@@ -3490,8 +3503,7 @@ fn transCreateCompoundAssign(
3490 try block_scope.statements.append(assign);3503 try block_scope.statements.append(assign);
3491 }3504 }
34923505
3493 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);3506 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node);
3494 break_node.rhs = ref_node;
3495 try block_scope.statements.append(&break_node.base);3507 try block_scope.statements.append(&break_node.base);
3496 const block_node = try block_scope.complete(rp.c);3508 const block_node = try block_scope.complete(rp.c);
3497 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);3509 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
...@@ -3567,10 +3579,8 @@ fn transCPtrCast(...@@ -3567,10 +3579,8 @@ fn transCPtrCast(
35673579
3568fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {3580fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
3569 const break_scope = scope.getBreakableScope();3581 const break_scope = scope.getBreakableScope();
3570 const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch)3582 const label_text: ?[]const u8 = if (break_scope.id == .Switch) "__switch" else null;
3571 "__switch"3583 const br = try transCreateNodeBreak(rp.c, label_text, null);
3572 else
3573 null);
3574 _ = try appendToken(rp.c, .Semicolon, ";");3584 _ = try appendToken(rp.c, .Semicolon, ";");
3575 return &br.base;3585 return &br.base;
3576}3586}
...@@ -3578,8 +3588,9 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {...@@ -3578,8 +3588,9 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
3578fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {3588fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node {
3579 // TODO use something more accurate3589 // TODO use something more accurate
3580 const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt);3590 const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt);
3581 const node = try rp.c.arena.create(ast.Node.FloatLiteral);3591 const node = try rp.c.arena.create(ast.Node.OneToken);
3582 node.* = .{3592 node.* = .{
3593 .base = .{ .tag = .FloatLiteral },
3583 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),3594 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),
3584 };3595 };
3585 return maybeSuppressResult(rp, scope, used, &node.base);3596 return maybeSuppressResult(rp, scope, used, &node.base);
...@@ -3619,7 +3630,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3619,7 +3630,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
3619 });3630 });
3620 try block_scope.statements.append(&tmp_var.base);3631 try block_scope.statements.append(&tmp_var.base);
36213632
3622 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label);3633 var break_node_tmp = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
36233634
3624 const if_node = try transCreateNodeIf(rp.c);3635 const if_node = try transCreateNodeIf(rp.c);
3625 var cond_scope = Scope.Condition{3636 var cond_scope = Scope.Condition{
...@@ -3641,7 +3652,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3641,7 +3652,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
3641 if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value);3652 if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value);
3642 _ = try appendToken(rp.c, .Semicolon, ";");3653 _ = try appendToken(rp.c, .Semicolon, ";");
36433654
3644 break_node.rhs = &if_node.base;3655 const break_node = try break_node_tmp.finish(&if_node.base);
3645 _ = try appendToken(rp.c, .Semicolon, ";");3656 _ = try appendToken(rp.c, .Semicolon, ";");
3646 try block_scope.statements.append(&break_node.base);3657 try block_scope.statements.append(&break_node.base);
3647 const block_node = try block_scope.complete(rp.c);3658 const block_node = try block_scope.complete(rp.c);
...@@ -3822,8 +3833,9 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC...@@ -3822,8 +3833,9 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
3822 if (int_bit_width != 0) {3833 if (int_bit_width != 0) {
3823 // we can perform the log2 now.3834 // we can perform the log2 now.
3824 const cast_bit_width = math.log2_int(u64, int_bit_width);3835 const cast_bit_width = math.log2_int(u64, int_bit_width);
3825 const node = try rp.c.arena.create(ast.Node.IntegerLiteral);3836 const node = try rp.c.arena.create(ast.Node.OneToken);
3826 node.* = .{3837 node.* = .{
3838 .base = .{ .tag = .IntegerLiteral },
3827 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),3839 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
3828 };3840 };
3829 return &node.base;3841 return &node.base;
...@@ -3845,8 +3857,9 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC...@@ -3845,8 +3857,9 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC
38453857
3846 const import_fn_call = try rp.c.createBuiltinCall("@import", 1);3858 const import_fn_call = try rp.c.createBuiltinCall("@import", 1);
3847 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");3859 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
3848 const std_node = try rp.c.arena.create(ast.Node.StringLiteral);3860 const std_node = try rp.c.arena.create(ast.Node.OneToken);
3849 std_node.* = .{3861 std_node.* = .{
3862 .base = .{ .tag = .StringLiteral },
3850 .token = std_token,3863 .token = std_token,
3851 };3864 };
3852 import_fn_call.params()[0] = &std_node.base;3865 import_fn_call.params()[0] = &std_node.base;
...@@ -4081,8 +4094,11 @@ fn transCreateNodeAssign(...@@ -4081,8 +4094,11 @@ fn transCreateNodeAssign(
4081 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);4094 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);
4082 try block_scope.statements.append(assign);4095 try block_scope.statements.append(assign);
40834096
4084 const break_node = try transCreateNodeBreak(rp.c, label_name);4097 const break_node = blk: {
4085 break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp);4098 var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, label_name);
4099 const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp);
4100 break :blk try tmp_ctrl_flow.finish(rhs_expr);
4101 };
4086 _ = try appendToken(rp.c, .Semicolon, ";");4102 _ = try appendToken(rp.c, .Semicolon, ";");
4087 try block_scope.statements.append(&break_node.base);4103 try block_scope.statements.append(&break_node.base);
4088 const block_node = try block_scope.complete(rp.c);4104 const block_node = try block_scope.complete(rp.c);
...@@ -4255,28 +4271,19 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {...@@ -4255,28 +4271,19 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node {
4255 };4271 };
4256 defer c.arena.free(str);4272 defer c.arena.free(str);
4257 const token = try appendToken(c, .IntegerLiteral, str);4273 const token = try appendToken(c, .IntegerLiteral, str);
4258 const node = try c.arena.create(ast.Node.IntegerLiteral);4274 const node = try c.arena.create(ast.Node.OneToken);
4259 node.* = .{4275 node.* = .{
4276 .base = .{ .tag = .IntegerLiteral },
4260 .token = token,4277 .token = token,
4261 };4278 };
4262 return &node.base;4279 return &node.base;
4263}4280}
42644281
4265fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
4266 const ltoken = try appendToken(c, .Keyword_return, "return");
4267 const node = try c.arena.create(ast.Node.ControlFlowExpression);
4268 node.* = .{
4269 .ltoken = ltoken,
4270 .kind = .Return,
4271 .rhs = null,
4272 };
4273 return node;
4274}
4275
4276fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {4282fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
4277 const token = try appendToken(c, .Keyword_undefined, "undefined");4283 const token = try appendToken(c, .Keyword_undefined, "undefined");
4278 const node = try c.arena.create(ast.Node.UndefinedLiteral);4284 const node = try c.arena.create(ast.Node.OneToken);
4279 node.* = .{4285 node.* = .{
4286 .base = .{ .tag = .UndefinedLiteral },
4280 .token = token,4287 .token = token,
4281 };4288 };
4282 return &node.base;4289 return &node.base;
...@@ -4284,8 +4291,9 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {...@@ -4284,8 +4291,9 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
42844291
4285fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {4292fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
4286 const token = try appendToken(c, .Keyword_null, "null");4293 const token = try appendToken(c, .Keyword_null, "null");
4287 const node = try c.arena.create(ast.Node.NullLiteral);4294 const node = try c.arena.create(ast.Node.OneToken);
4288 node.* = .{4295 node.* = .{
4296 .base = .{ .tag = .NullLiteral },
4289 .token = token,4297 .token = token,
4290 };4298 };
4291 return &node.base;4299 return &node.base;
...@@ -4296,8 +4304,9 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {...@@ -4296,8 +4304,9 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
4296 try appendToken(c, .Keyword_true, "true")4304 try appendToken(c, .Keyword_true, "true")
4297 else4305 else
4298 try appendToken(c, .Keyword_false, "false");4306 try appendToken(c, .Keyword_false, "false");
4299 const node = try c.arena.create(ast.Node.BoolLiteral);4307 const node = try c.arena.create(ast.Node.OneToken);
4300 node.* = .{4308 node.* = .{
4309 .base = .{ .tag = .BoolLiteral },
4301 .token = token,4310 .token = token,
4302 };4311 };
4303 return &node.base;4312 return &node.base;
...@@ -4305,8 +4314,9 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {...@@ -4305,8 +4314,9 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
43054314
4306fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {4315fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {
4307 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});4316 const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int});
4308 const node = try c.arena.create(ast.Node.IntegerLiteral);4317 const node = try c.arena.create(ast.Node.OneToken);
4309 node.* = .{4318 node.* = .{
4319 .base = .{ .tag = .IntegerLiteral },
4310 .token = token,4320 .token = token,
4311 };4321 };
4312 return &node.base;4322 return &node.base;
...@@ -4314,8 +4324,9 @@ fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {...@@ -4314,8 +4324,9 @@ fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {
43144324
4315fn transCreateNodeFloat(c: *Context, int: anytype) !*ast.Node {4325fn transCreateNodeFloat(c: *Context, int: anytype) !*ast.Node {
4316 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});4326 const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int});
4317 const node = try c.arena.create(ast.Node.FloatLiteral);4327 const node = try c.arena.create(ast.Node.OneToken);
4318 node.* = .{4328 node.* = .{
4329 .base = .{ .tag = .FloatLiteral },
4319 .token = token,4330 .token = token,
4320 };4331 };
4321 return &node.base;4332 return &node.base;
...@@ -4362,7 +4373,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4362,7 +4373,7 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
43624373
4363 const block_lbrace = try appendToken(c, .LBrace, "{");4374 const block_lbrace = try appendToken(c, .LBrace, "{");
43644375
4365 const return_expr = try transCreateNodeReturnExpr(c);4376 const return_kw = try appendToken(c, .Keyword_return, "return");
4366 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?);4377 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getTrailer("init_node").?);
43674378
4368 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);4379 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
...@@ -4376,7 +4387,12 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4376,7 +4387,12 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
4376 }4387 }
4377 call_expr.rtoken = try appendToken(c, .RParen, ")");4388 call_expr.rtoken = try appendToken(c, .RParen, ")");
43784389
4379 return_expr.rhs = &call_expr.base;4390 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
4391 .ltoken = return_kw,
4392 .tag = .Return,
4393 }, .{
4394 .rhs = &call_expr.base,
4395 });
4380 _ = try appendToken(c, .Semicolon, ";");4396 _ = try appendToken(c, .Semicolon, ";");
43814397
4382 const block = try ast.Node.Block.alloc(c.arena, 1);4398 const block = try ast.Node.Block.alloc(c.arena, 1);
...@@ -4424,8 +4440,9 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {...@@ -4424,8 +4440,9 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
4424}4440}
44254441
4426fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {4442fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {
4427 const node = try c.arena.create(ast.Node.StringLiteral);4443 const node = try c.arena.create(ast.Node.OneToken);
4428 node.* = .{4444 node.* = .{
4445 .base = .{ .tag = .StringLiteral },
4429 .token = try appendToken(c, .StringLiteral, str),4446 .token = try appendToken(c, .StringLiteral, str),
4430 };4447 };
4431 return &node.base;4448 return &node.base;
...@@ -4455,28 +4472,77 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {...@@ -4455,28 +4472,77 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
4455 return node;4472 return node;
4456}4473}
44574474
4458fn transCreateNodeBreakToken(c: *Context, label: ?ast.TokenIndex) !*ast.Node.ControlFlowExpression {4475fn transCreateNodeBreakToken(
4459 const other_token = label orelse return transCreateNodeBreak(c, null);4476 c: *Context,
4477 label: ?ast.TokenIndex,
4478 rhs: ?*ast.Node,
4479) !*ast.Node.ControlFlowExpression {
4480 const other_token = label orelse return transCreateNodeBreak(c, null, rhs);
4460 const loc = c.token_locs.items[other_token];4481 const loc = c.token_locs.items[other_token];
4461 const label_name = c.source_buffer.items[loc.start..loc.end];4482 const label_name = c.source_buffer.items[loc.start..loc.end];
4462 return transCreateNodeBreak(c, label_name);4483 return transCreateNodeBreak(c, label_name, rhs);
4463}4484}
44644485
4465fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression {4486fn transCreateNodeBreak(
4466 const ltoken = try appendToken(c, .Keyword_break, "break");4487 c: *Context,
4467 const label_node = if (label) |l| blk: {4488 label: ?[]const u8,
4468 _ = try appendToken(c, .Colon, ":");4489 rhs: ?*ast.Node,
4469 break :blk try transCreateNodeIdentifier(c, l);4490) !*ast.Node.ControlFlowExpression {
4470 } else null;4491 var ctrl_flow = try CtrlFlow.init(c, .Break, label);
4471 const node = try c.arena.create(ast.Node.ControlFlowExpression);4492 return ctrl_flow.finish(rhs);
4472 node.* = .{
4473 .ltoken = ltoken,
4474 .kind = .{ .Break = label_node },
4475 .rhs = null,
4476 };
4477 return node;
4478}4493}
44794494
4495const CtrlFlow = struct {
4496 c: *Context,
4497 ltoken: ast.TokenIndex,
4498 label_token: ?ast.TokenIndex,
4499 tag: ast.Node.Tag,
4500
4501 /// Does everything except the RHS.
4502 fn init(c: *Context, tag: ast.Node.Tag, label: ?[]const u8) !CtrlFlow {
4503 const kw: Token.Id = switch (tag) {
4504 .Break => .Keyword_break,
4505 .Continue => .Keyword_continue,
4506 .Return => .Keyword_return,
4507 else => unreachable,
4508 };
4509 const kw_text = switch (tag) {
4510 .Break => "break",
4511 .Continue => "continue",
4512 .Return => "return",
4513 else => unreachable,
4514 };
4515 const ltoken = try appendToken(c, kw, kw_text);
4516 const label_token = if (label) |l| blk: {
4517 _ = try appendToken(c, .Colon, ":");
4518 break :blk try appendToken(c, .Identifier, l);
4519 } else null;
4520 return CtrlFlow{
4521 .c = c,
4522 .ltoken = ltoken,
4523 .label_token = label_token,
4524 .tag = tag,
4525 };
4526 }
4527
4528 fn initToken(c: *Context, tag: ast.Node.Tag, label: ?ast.TokenIndex) !CtrlFlow {
4529 const other_token = label orelse return init(c, tag, null);
4530 const loc = c.token_locs.items[other_token];
4531 const label_name = c.source_buffer.items[loc.start..loc.end];
4532 return init(c, tag, label_name);
4533 }
4534
4535 fn finish(self: *CtrlFlow, rhs: ?*ast.Node) !*ast.Node.ControlFlowExpression {
4536 return ast.Node.ControlFlowExpression.create(self.c.arena, .{
4537 .ltoken = self.ltoken,
4538 .tag = self.tag,
4539 }, .{
4540 .label = self.label_token,
4541 .rhs = rhs,
4542 });
4543 }
4544};
4545
4480fn transCreateNodeWhile(c: *Context) !*ast.Node.While {4546fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
4481 const while_tok = try appendToken(c, .Keyword_while, "while");4547 const while_tok = try appendToken(c, .Keyword_while, "while");
4482 _ = try appendToken(c, .LParen, "(");4548 _ = try appendToken(c, .LParen, "(");
...@@ -4497,12 +4563,10 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {...@@ -4497,12 +4563,10 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
44974563
4498fn transCreateNodeContinue(c: *Context) !*ast.Node {4564fn transCreateNodeContinue(c: *Context) !*ast.Node {
4499 const ltoken = try appendToken(c, .Keyword_continue, "continue");4565 const ltoken = try appendToken(c, .Keyword_continue, "continue");
4500 const node = try c.arena.create(ast.Node.ControlFlowExpression);4566 const node = try ast.Node.ControlFlowExpression.create(c.arena, .{
4501 node.* = .{
4502 .ltoken = ltoken,4567 .ltoken = ltoken,
4503 .kind = .{ .Continue = null },4568 .tag = .Continue,
4504 .rhs = null,4569 }, .{});
4505 };
4506 _ = try appendToken(c, .Semicolon, ";");4570 _ = try appendToken(c, .Semicolon, ";");
4507 return &node.base;4571 return &node.base;
4508}4572}
...@@ -5006,8 +5070,9 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp...@@ -5006,8 +5070,9 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp
5006 const semi_tok = try appendToken(c, .Semicolon, ";");5070 const semi_tok = try appendToken(c, .Semicolon, ";");
5007 _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)});5071 _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)});
50085072
5009 const msg_node = try c.arena.create(ast.Node.StringLiteral);5073 const msg_node = try c.arena.create(ast.Node.OneToken);
5010 msg_node.* = .{5074 msg_node.* = .{
5075 .base = .{ .tag = .StringLiteral },
5011 .token = msg_tok,5076 .token = msg_tok,
5012 };5077 };
50135078
...@@ -5110,8 +5175,9 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {...@@ -5110,8 +5175,9 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
51105175
5111fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {5176fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
5112 const token_index = try appendIdentifier(c, name);5177 const token_index = try appendIdentifier(c, name);
5113 const identifier = try c.arena.create(ast.Node.Identifier);5178 const identifier = try c.arena.create(ast.Node.OneToken);
5114 identifier.* = .{5179 identifier.* = .{
5180 .base = .{ .tag = .Identifier },
5115 .token = token_index,5181 .token = token_index,
5116 };5182 };
5117 return &identifier.base;5183 return &identifier.base;
...@@ -5119,8 +5185,9 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {...@@ -5119,8 +5185,9 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
51195185
5120fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {5186fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
5121 const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name});5187 const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name});
5122 const identifier = try c.arena.create(ast.Node.Identifier);5188 const identifier = try c.arena.create(ast.Node.OneToken);
5123 identifier.* = .{5189 identifier.* = .{
5190 .base = .{ .tag = .Identifier },
5124 .token = token_index,5191 .token = token_index,
5125 };5192 };
5126 return &identifier.base;5193 return &identifier.base;
...@@ -5289,8 +5356,9 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5289,8 +5356,9 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5289 const param_name_tok = try appendIdentifier(c, mangled_name);5356 const param_name_tok = try appendIdentifier(c, mangled_name);
5290 _ = try appendToken(c, .Colon, ":");5357 _ = try appendToken(c, .Colon, ":");
52915358
5292 const any_type = try c.arena.create(ast.Node.AnyType);5359 const any_type = try c.arena.create(ast.Node.OneToken);
5293 any_type.* = .{5360 any_type.* = .{
5361 .base = .{ .tag = .AnyType },
5294 .token = try appendToken(c, .Keyword_anytype, "anytype"),5362 .token = try appendToken(c, .Keyword_anytype, "anytype"),
5295 };5363 };
52965364
...@@ -5322,7 +5390,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5322,7 +5390,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
53225390
5323 const type_of = try c.createBuiltinCall("@TypeOf", 1);5391 const type_of = try c.createBuiltinCall("@TypeOf", 1);
53245392
5325 const return_expr = try transCreateNodeReturnExpr(c);5393 const return_kw = try appendToken(c, .Keyword_return, "return");
5326 const expr = try parseCExpr(c, it, source, source_loc, scope);5394 const expr = try parseCExpr(c, it, source, source_loc, scope);
5327 const last = it.next().?;5395 const last = it.next().?;
5328 if (last.id != .Eof and last.id != .Nl)5396 if (last.id != .Eof and last.id != .Nl)
...@@ -5337,13 +5405,17 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5337,13 +5405,17 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5337 const type_of_arg = if (expr.tag != .Block) expr else blk: {5405 const type_of_arg = if (expr.tag != .Block) expr else blk: {
5338 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);5406 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
5339 const blk_last = blk.statements()[blk.statements_len - 1];5407 const blk_last = blk.statements()[blk.statements_len - 1];
5340 std.debug.assert(blk_last.tag == .ControlFlowExpression);5408 const br = blk_last.cast(ast.Node.ControlFlowExpression).?;
5341 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);5409 break :blk br.getRHS().?;
5342 break :blk br.rhs.?;
5343 };5410 };
5344 type_of.params()[0] = type_of_arg;5411 type_of.params()[0] = type_of_arg;
5345 type_of.rparen_token = try appendToken(c, .RParen, ")");5412 type_of.rparen_token = try appendToken(c, .RParen, ")");
5346 return_expr.rhs = expr;5413 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
5414 .ltoken = return_kw,
5415 .tag = .Return,
5416 }, .{
5417 .rhs = expr,
5418 });
53475419
5348 try block_scope.statements.append(&return_expr.base);5420 try block_scope.statements.append(&return_expr.base);
5349 const block_node = try block_scope.complete(c);5421 const block_node = try block_scope.complete(c);
...@@ -5416,8 +5488,7 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_...@@ -5416,8 +5488,7 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
5416 }5488 }
5417 }5489 }
54185490
5419 const break_node = try transCreateNodeBreak(c, label_name);5491 const break_node = try transCreateNodeBreak(c, label_name, last);
5420 break_node.rhs = last;
5421 try block_scope.statements.append(&break_node.base);5492 try block_scope.statements.append(&break_node.base);
5422 const block_node = try block_scope.complete(c);5493 const block_node = try block_scope.complete(c);
5423 return &block_node.base;5494 return &block_node.base;
...@@ -5656,15 +5727,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5656,15 +5727,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5656 const first_tok = it.list.at(0);5727 const first_tok = it.list.at(0);
5657 if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) {5728 if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) {
5658 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));5729 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
5659 const node = try c.arena.create(ast.Node.CharLiteral);5730 const node = try c.arena.create(ast.Node.OneToken);
5660 node.* = .{5731 node.* = .{
5732 .base = .{ .tag = .CharLiteral },
5661 .token = token,5733 .token = token,
5662 };5734 };
5663 return &node.base;5735 return &node.base;
5664 } else {5736 } else {
5665 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start + 1 .. tok.end - 1]});5737 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start + 1 .. tok.end - 1]});
5666 const node = try c.arena.create(ast.Node.IntegerLiteral);5738 const node = try c.arena.create(ast.Node.OneToken);
5667 node.* = .{5739 node.* = .{
5740 .base = .{ .tag = .IntegerLiteral },
5668 .token = token,5741 .token = token,
5669 };5742 };
5670 return &node.base;5743 return &node.base;
...@@ -5673,8 +5746,9 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5673,8 +5746,9 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5673 .StringLiteral => {5746 .StringLiteral => {
5674 const first_tok = it.list.at(0);5747 const first_tok = it.list.at(0);
5675 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));5748 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc));
5676 const node = try c.arena.create(ast.Node.StringLiteral);5749 const node = try c.arena.create(ast.Node.OneToken);
5677 node.* = .{5750 node.* = .{
5751 .base = .{ .tag = .StringLiteral },
5678 .token = token,5752 .token = token,
5679 };5753 };
5680 return &node.base;5754 return &node.base;
...@@ -6224,7 +6298,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6224,7 +6298,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6224 => return node,6298 => return node,
62256299
6226 .Identifier => {6300 .Identifier => {
6227 const ident = node.cast(ast.Node.Identifier).?;6301 const ident = node.castTag(.Identifier).?;
6228 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {6302 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6229 if (value.cast(ast.Node.VarDecl)) |var_decl|6303 if (value.cast(ast.Node.VarDecl)) |var_decl|
6230 return getContainer(c, var_decl.getTrailer("init_node").?);6304 return getContainer(c, var_decl.getTrailer("init_node").?);
...@@ -6238,7 +6312,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6238,7 +6312,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6238 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6312 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6239 for (container.fieldsAndDecls()) |field_ref| {6313 for (container.fieldsAndDecls()) |field_ref| {
6240 const field = field_ref.cast(ast.Node.ContainerField).?;6314 const field = field_ref.cast(ast.Node.ContainerField).?;
6241 const ident = infix.rhs.cast(ast.Node.Identifier).?;6315 const ident = infix.rhs.castTag(.Identifier).?;
6242 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {6316 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6243 return getContainer(c, field.type_expr.?);6317 return getContainer(c, field.type_expr.?);
6244 }6318 }
...@@ -6253,7 +6327,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6253,7 +6327,7 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6253}6327}
62546328
6255fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {6329fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6256 if (ref.cast(ast.Node.Identifier)) |ident| {6330 if (ref.castTag(.Identifier)) |ident| {
6257 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {6331 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6258 if (value.cast(ast.Node.VarDecl)) |var_decl| {6332 if (value.cast(ast.Node.VarDecl)) |var_decl| {
6259 if (var_decl.getTrailer("type_node")) |ty|6333 if (var_decl.getTrailer("type_node")) |ty|
...@@ -6265,7 +6339,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6265,7 +6339,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6265 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6339 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6266 for (container.fieldsAndDecls()) |field_ref| {6340 for (container.fieldsAndDecls()) |field_ref| {
6267 const field = field_ref.cast(ast.Node.ContainerField).?;6341 const field = field_ref.cast(ast.Node.ContainerField).?;
6268 const ident = infix.rhs.cast(ast.Node.Identifier).?;6342 const ident = infix.rhs.castTag(.Identifier).?;
6269 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {6343 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6270 return getContainer(c, field.type_expr.?);6344 return getContainer(c, field.type_expr.?);
6271 }6345 }
src-self-hosted/zir.zig+116-75
...@@ -34,9 +34,17 @@ pub const Inst = struct {...@@ -34,9 +34,17 @@ pub const Inst = struct {
3434
35 /// These names are used directly as the instruction names in the text format.35 /// These names are used directly as the instruction names in the text format.
36 pub const Tag = enum {36 pub const Tag = enum {
37 /// Allocates stack local memory. Its lifetime ends when the block ends that contains
38 /// this instruction.
39 alloc,
40 /// Same as `alloc` except the type is inferred.
41 alloc_inferred,
37 /// Function parameter value. These must be first in a function's main block,42 /// Function parameter value. These must be first in a function's main block,
38 /// in respective order with the parameters.43 /// in respective order with the parameters.
39 arg,44 arg,
45 /// A typed result location pointer is bitcasted to a new result location pointer.
46 /// The new result location pointer has an inferred type.
47 bitcast_result_ptr,
40 /// A labeled block of code, which can return a value.48 /// A labeled block of code, which can return a value.
41 block,49 block,
42 /// Return a value from a `Block`.50 /// Return a value from a `Block`.
...@@ -45,6 +53,17 @@ pub const Inst = struct {...@@ -45,6 +53,17 @@ pub const Inst = struct {
45 /// Same as `break` but without an operand; the operand is assumed to be the void value.53 /// Same as `break` but without an operand; the operand is assumed to be the void value.
46 breakvoid,54 breakvoid,
47 call,55 call,
56 /// Coerces a result location pointer to a new element type. It is evaluated "backwards"-
57 /// as type coercion from the new element type to the old element type.
58 /// LHS is destination element type, RHS is result pointer.
59 coerce_result_ptr,
60 /// This instruction does a `coerce_result_ptr` operation on a `Block`'s
61 /// result location pointer, whose type is inferred by peer type resolution on the
62 /// `Block`'s corresponding `break` instructions.
63 coerce_result_block_ptr,
64 /// Equivalent to `as(ptr_child_type(typeof(ptr)), value)`.
65 coerce_to_ptr_elem,
66 /// Emit an error message and fail compilation.
48 compileerror,67 compileerror,
49 /// Special case, has no textual representation.68 /// Special case, has no textual representation.
50 @"const",69 @"const",
...@@ -57,7 +76,17 @@ pub const Inst = struct {...@@ -57,7 +76,17 @@ pub const Inst = struct {
57 declval,76 declval,
58 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.77 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.
59 declval_in_module,78 declval_in_module,
79 /// Emits a compile error if the operand is not `void`.
80 ensure_result_used,
81 /// Emits a compile error if an error is ignored.
82 ensure_result_non_error,
60 boolnot,83 boolnot,
84 /// Obtains a pointer to the return value.
85 ret_ptr,
86 /// Obtains the return type of the in-scope function.
87 ret_type,
88 /// Write a value to a pointer.
89 store,
61 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.90 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
62 str,91 str,
63 int,92 int,
...@@ -73,6 +102,9 @@ pub const Inst = struct {...@@ -73,6 +102,9 @@ pub const Inst = struct {
73 @"fn",102 @"fn",
74 fntype,103 fntype,
75 @"export",104 @"export",
105 /// Given a reference to a function and a parameter index, returns the
106 /// type of the parameter. TODO what happens when the parameter is `anytype`?
107 param_type,
76 primitive,108 primitive,
77 intcast,109 intcast,
78 bitcast,110 bitcast,
...@@ -96,6 +128,9 @@ pub const Inst = struct {...@@ -96,6 +128,9 @@ pub const Inst = struct {
96 .breakpoint,128 .breakpoint,
97 .@"unreachable",129 .@"unreachable",
98 .returnvoid,130 .returnvoid,
131 .alloc_inferred,
132 .ret_ptr,
133 .ret_type,
99 => NoOp,134 => NoOp,
100135
101 .boolnot,136 .boolnot,
...@@ -103,6 +138,11 @@ pub const Inst = struct {...@@ -103,6 +138,11 @@ pub const Inst = struct {
103 .@"return",138 .@"return",
104 .isnull,139 .isnull,
105 .isnonnull,140 .isnonnull,
141 .ptrtoint,
142 .alloc,
143 .ensure_result_used,
144 .ensure_result_non_error,
145 .bitcast_result_ptr,
106 => UnOp,146 => UnOp,
107147
108 .add,148 .add,
...@@ -113,32 +153,36 @@ pub const Inst = struct {...@@ -113,32 +153,36 @@ pub const Inst = struct {
113 .cmp_gte,153 .cmp_gte,
114 .cmp_gt,154 .cmp_gt,
115 .cmp_neq,155 .cmp_neq,
156 .as,
157 .floatcast,
158 .intcast,
159 .bitcast,
160 .coerce_result_ptr,
116 => BinOp,161 => BinOp,
117162
118 .block => Block,163 .block => Block,
119 .@"break" => Break,164 .@"break" => Break,
120 .breakvoid => BreakVoid,165 .breakvoid => BreakVoid,
121 .call => Call,166 .call => Call,
167 .coerce_to_ptr_elem => CoerceToPtrElem,
122 .declref => DeclRef,168 .declref => DeclRef,
123 .declref_str => DeclRefStr,169 .declref_str => DeclRefStr,
124 .declval => DeclVal,170 .declval => DeclVal,
125 .declval_in_module => DeclValInModule,171 .declval_in_module => DeclValInModule,
172 .coerce_result_block_ptr => CoerceResultBlockPtr,
126 .compileerror => CompileError,173 .compileerror => CompileError,
127 .@"const" => Const,174 .@"const" => Const,
175 .store => Store,
128 .str => Str,176 .str => Str,
129 .int => Int,177 .int => Int,
130 .inttype => IntType,178 .inttype => IntType,
131 .ptrtoint => PtrToInt,
132 .fieldptr => FieldPtr,179 .fieldptr => FieldPtr,
133 .as => As,
134 .@"asm" => Asm,180 .@"asm" => Asm,
135 .@"fn" => Fn,181 .@"fn" => Fn,
136 .@"export" => Export,182 .@"export" => Export,
183 .param_type => ParamType,
137 .primitive => Primitive,184 .primitive => Primitive,
138 .fntype => FnType,185 .fntype => FnType,
139 .intcast => IntCast,
140 .bitcast => BitCast,
141 .floatcast => FloatCast,
142 .elemptr => ElemPtr,186 .elemptr => ElemPtr,
143 .condbr => CondBr,187 .condbr => CondBr,
144 };188 };
...@@ -148,15 +192,26 @@ pub const Inst = struct {...@@ -148,15 +192,26 @@ pub const Inst = struct {
148 /// Function calls do not count.192 /// Function calls do not count.
149 pub fn isNoReturn(tag: Tag) bool {193 pub fn isNoReturn(tag: Tag) bool {
150 return switch (tag) {194 return switch (tag) {
195 .alloc,
196 .alloc_inferred,
151 .arg,197 .arg,
198 .bitcast_result_ptr,
152 .block,199 .block,
153 .breakpoint,200 .breakpoint,
154 .call,201 .call,
202 .coerce_result_ptr,
203 .coerce_result_block_ptr,
204 .coerce_to_ptr_elem,
155 .@"const",205 .@"const",
156 .declref,206 .declref,
157 .declref_str,207 .declref_str,
158 .declval,208 .declval,
159 .declval_in_module,209 .declval_in_module,
210 .ensure_result_used,
211 .ensure_result_non_error,
212 .ret_ptr,
213 .ret_type,
214 .store,
160 .str,215 .str,
161 .int,216 .int,
162 .inttype,217 .inttype,
...@@ -168,6 +223,7 @@ pub const Inst = struct {...@@ -168,6 +223,7 @@ pub const Inst = struct {
168 .@"fn",223 .@"fn",
169 .fntype,224 .fntype,
170 .@"export",225 .@"export",
226 .param_type,
171 .primitive,227 .primitive,
172 .intcast,228 .intcast,
173 .bitcast,229 .bitcast,
...@@ -292,6 +348,17 @@ pub const Inst = struct {...@@ -292,6 +348,17 @@ pub const Inst = struct {
292 },348 },
293 };349 };
294350
351 pub const CoerceToPtrElem = struct {
352 pub const base_tag = Tag.coerce_to_ptr_elem;
353 base: Inst,
354
355 positionals: struct {
356 ptr: *Inst,
357 value: *Inst,
358 },
359 kw_args: struct {},
360 };
361
295 pub const DeclRef = struct {362 pub const DeclRef = struct {
296 pub const base_tag = Tag.declref;363 pub const base_tag = Tag.declref;
297 base: Inst,364 base: Inst,
...@@ -332,6 +399,17 @@ pub const Inst = struct {...@@ -332,6 +399,17 @@ pub const Inst = struct {
332 kw_args: struct {},399 kw_args: struct {},
333 };400 };
334401
402 pub const CoerceResultBlockPtr = struct {
403 pub const base_tag = Tag.coerce_result_block_ptr;
404 base: Inst,
405
406 positionals: struct {
407 dest_type: *Inst,
408 block: *Block,
409 },
410 kw_args: struct {},
411 };
412
335 pub const CompileError = struct {413 pub const CompileError = struct {
336 pub const base_tag = Tag.compileerror;414 pub const base_tag = Tag.compileerror;
337 base: Inst,415 base: Inst,
...@@ -352,33 +430,33 @@ pub const Inst = struct {...@@ -352,33 +430,33 @@ pub const Inst = struct {
352 kw_args: struct {},430 kw_args: struct {},
353 };431 };
354432
355 pub const Str = struct {433 pub const Store = struct {
356 pub const base_tag = Tag.str;434 pub const base_tag = Tag.store;
357 base: Inst,435 base: Inst,
358436
359 positionals: struct {437 positionals: struct {
360 bytes: []const u8,438 ptr: *Inst,
439 value: *Inst,
361 },440 },
362 kw_args: struct {},441 kw_args: struct {},
363 };442 };
364443
365 pub const Int = struct {444 pub const Str = struct {
366 pub const base_tag = Tag.int;445 pub const base_tag = Tag.str;
367 base: Inst,446 base: Inst,
368447
369 positionals: struct {448 positionals: struct {
370 int: BigIntConst,449 bytes: []const u8,
371 },450 },
372 kw_args: struct {},451 kw_args: struct {},
373 };452 };
374453
375 pub const PtrToInt = struct {454 pub const Int = struct {
376 pub const builtin_name = "@ptrToInt";455 pub const base_tag = Tag.int;
377 pub const base_tag = Tag.ptrtoint;
378 base: Inst,456 base: Inst,
379457
380 positionals: struct {458 positionals: struct {
381 operand: *Inst,459 int: BigIntConst,
382 },460 },
383 kw_args: struct {},461 kw_args: struct {},
384 };462 };
...@@ -394,18 +472,6 @@ pub const Inst = struct {...@@ -394,18 +472,6 @@ pub const Inst = struct {
394 kw_args: struct {},472 kw_args: struct {},
395 };473 };
396474
397 pub const As = struct {
398 pub const base_tag = Tag.as;
399 pub const builtin_name = "@as";
400 base: Inst,
401
402 positionals: struct {
403 dest_type: *Inst,
404 value: *Inst,
405 },
406 kw_args: struct {},
407 };
408
409 pub const Asm = struct {475 pub const Asm = struct {
410 pub const base_tag = Tag.@"asm";476 pub const base_tag = Tag.@"asm";
411 base: Inst,477 base: Inst,
...@@ -469,6 +535,17 @@ pub const Inst = struct {...@@ -469,6 +535,17 @@ pub const Inst = struct {
469 kw_args: struct {},535 kw_args: struct {},
470 };536 };
471537
538 pub const ParamType = struct {
539 pub const base_tag = Tag.param_type;
540 base: Inst,
541
542 positionals: struct {
543 func: *Inst,
544 arg_index: usize,
545 },
546 kw_args: struct {},
547 };
548
472 pub const Primitive = struct {549 pub const Primitive = struct {
473 pub const base_tag = Tag.primitive;550 pub const base_tag = Tag.primitive;
474 base: Inst,551 base: Inst,
...@@ -559,42 +636,6 @@ pub const Inst = struct {...@@ -559,42 +636,6 @@ pub const Inst = struct {
559 };636 };
560 };637 };
561638
562 pub const FloatCast = struct {
563 pub const base_tag = Tag.floatcast;
564 pub const builtin_name = "@floatCast";
565 base: Inst,
566
567 positionals: struct {
568 dest_type: *Inst,
569 operand: *Inst,
570 },
571 kw_args: struct {},
572 };
573
574 pub const IntCast = struct {
575 pub const base_tag = Tag.intcast;
576 pub const builtin_name = "@intCast";
577 base: Inst,
578
579 positionals: struct {
580 dest_type: *Inst,
581 operand: *Inst,
582 },
583 kw_args: struct {},
584 };
585
586 pub const BitCast = struct {
587 pub const base_tag = Tag.bitcast;
588 pub const builtin_name = "@bitCast";
589 base: Inst,
590
591 positionals: struct {
592 dest_type: *Inst,
593 operand: *Inst,
594 },
595 kw_args: struct {},
596 };
597
598 pub const ElemPtr = struct {639 pub const ElemPtr = struct {
599 pub const base_tag = Tag.elemptr;640 pub const base_tag = Tag.elemptr;
600 base: Inst,641 base: Inst,
...@@ -1467,15 +1508,15 @@ const EmitZIR = struct {...@@ -1467,15 +1508,15 @@ const EmitZIR = struct {
1467 },1508 },
1468 .ComptimeInt => return self.emitComptimeIntVal(src, typed_value.val),1509 .ComptimeInt => return self.emitComptimeIntVal(src, typed_value.val),
1469 .Int => {1510 .Int => {
1470 const as_inst = try self.arena.allocator.create(Inst.As);1511 const as_inst = try self.arena.allocator.create(Inst.BinOp);
1471 as_inst.* = .{1512 as_inst.* = .{
1472 .base = .{1513 .base = .{
1514 .tag = .as,
1473 .src = src,1515 .src = src,
1474 .tag = Inst.As.base_tag,
1475 },1516 },
1476 .positionals = .{1517 .positionals = .{
1477 .dest_type = (try self.emitType(src, typed_value.ty)).inst,1518 .lhs = (try self.emitType(src, typed_value.ty)).inst,
1478 .value = (try self.emitComptimeIntVal(src, typed_value.val)).inst,1519 .rhs = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
1479 },1520 },
1480 .kw_args = .{},1521 .kw_args = .{},
1481 };1522 };
...@@ -1640,17 +1681,17 @@ const EmitZIR = struct {...@@ -1640,17 +1681,17 @@ const EmitZIR = struct {
1640 src: usize,1681 src: usize,
1641 new_body: ZirBody,1682 new_body: ZirBody,
1642 old_inst: *ir.Inst.UnOp,1683 old_inst: *ir.Inst.UnOp,
1643 comptime I: type,1684 tag: Inst.Tag,
1644 ) Allocator.Error!*Inst {1685 ) Allocator.Error!*Inst {
1645 const new_inst = try self.arena.allocator.create(I);1686 const new_inst = try self.arena.allocator.create(Inst.BinOp);
1646 new_inst.* = .{1687 new_inst.* = .{
1647 .base = .{1688 .base = .{
1648 .src = src,1689 .src = src,
1649 .tag = I.base_tag,1690 .tag = tag,
1650 },1691 },
1651 .positionals = .{1692 .positionals = .{
1652 .dest_type = (try self.emitType(src, old_inst.base.ty)).inst,1693 .lhs = (try self.emitType(old_inst.base.src, old_inst.base.ty)).inst,
1653 .operand = try self.resolveInst(new_body, old_inst.operand),1694 .rhs = try self.resolveInst(new_body, old_inst.operand),
1654 },1695 },
1655 .kw_args = .{},1696 .kw_args = .{},
1656 };1697 };
...@@ -1691,9 +1732,9 @@ const EmitZIR = struct {...@@ -1691,9 +1732,9 @@ const EmitZIR = struct {
1691 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),1732 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),
1692 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),1733 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),
16931734
1694 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, Inst.BitCast),1735 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast),
1695 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, Inst.IntCast),1736 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),
1696 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, Inst.FloatCast),1737 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, .floatcast),
16971738
1698 .block => blk: {1739 .block => blk: {
1699 const old_inst = inst.castTag(.block).?;1740 const old_inst = inst.castTag(.block).?;
test/stage2/cbe.zig+13-35
...@@ -19,13 +19,13 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -19,13 +19,13 @@ pub fn addCases(ctx: *TestContext) !void {
19 \\fn main() noreturn {}19 \\fn main() noreturn {}
20 \\20 \\
21 \\export fn _start() noreturn {21 \\export fn _start() noreturn {
22 \\ main();22 \\ main();
23 \\}23 \\}
24 ,24 ,
25 \\noreturn void main(void);25 \\noreturn void main(void);
26 \\26 \\
27 \\noreturn void _start(void) {27 \\noreturn void _start(void) {
28 \\ main();28 \\ main();
29 \\}29 \\}
30 \\30 \\
31 \\noreturn void main(void) {}31 \\noreturn void main(void) {}
...@@ -35,15 +35,15 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -35,15 +35,15 @@ pub fn addCases(ctx: *TestContext) !void {
35 // TODO: figure out a way to prevent asm constants from being generated35 // TODO: figure out a way to prevent asm constants from being generated
36 ctx.c("inline asm", linux_x64,36 ctx.c("inline asm", linux_x64,
37 \\fn exitGood() void {37 \\fn exitGood() void {
38 \\ asm volatile ("syscall"38 \\ asm volatile ("syscall"
39 \\ :39 \\ :
40 \\ : [number] "{rax}" (231),40 \\ : [number] "{rax}" (231),
41 \\ [arg1] "{rdi}" (0)41 \\ [arg1] "{rdi}" (0)
42 \\ );42 \\ );
43 \\}43 \\}
44 \\44 \\
45 \\export fn _start() noreturn {45 \\export fn _start() noreturn {
46 \\ exitGood();46 \\ exitGood();
47 \\}47 \\}
48 ,48 ,
49 \\#include <stddef.h>49 \\#include <stddef.h>
...@@ -55,36 +55,14 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -55,36 +55,14 @@ pub fn addCases(ctx: *TestContext) !void {
55 \\const char *const exitGood__anon_2 = "syscall";55 \\const char *const exitGood__anon_2 = "syscall";
56 \\56 \\
57 \\noreturn void _start(void) {57 \\noreturn void _start(void) {
58 \\ exitGood();58 \\ exitGood();
59 \\}59 \\}
60 \\60 \\
61 \\void exitGood(void) {61 \\void exitGood(void) {
62 \\ register size_t rax_constant __asm__("rax") = 231;62 \\ register size_t rax_constant __asm__("rax") = 231;
63 \\ register size_t rdi_constant __asm__("rdi") = 0;63 \\ register size_t rdi_constant __asm__("rdi") = 0;
64 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));64 \\ __asm volatile ("syscall" :: ""(rax_constant), ""(rdi_constant));
65 \\ return;65 \\ return;
66 \\}
67 \\
68 );
69 ctx.c("basic return", linux_x64,
70 \\fn main() u8 {
71 \\ return 103;
72 \\}
73 \\
74 \\export fn _start() noreturn {
75 \\ _ = main();
76 \\}
77 ,
78 \\#include <stdint.h>
79 \\
80 \\uint8_t main(void);
81 \\
82 \\noreturn void _start(void) {
83 \\ (void)main();
84 \\}
85 \\
86 \\uint8_t main(void) {
87 \\ return 103;
88 \\}66 \\}
89 \\67 \\
90 );68 );