| author | |
| committer | |
| log | 2ff3995a708b03480d5ca51b3ffa92f52cdf81d0 |
| tree | f6abe8da2a54b481e15bccc7468c7ec283330413 |
| parent | 882921b5dd5d6527198f67f9514bca6d5c24798b |
| parent | 8a3cd82b854164758eef17440d86105472e9e7a9 |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
improve std.zig.parse performance using flat arrays for AST nodes and tokens15 files changed, 5315 insertions(+), 4612 deletions(-)
doc/docgen.zig+18-18| ... | @@ -776,7 +776,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -776,7 +776,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 776 | next_tok_is_fn = false; | 776 | next_tok_is_fn = false; |
| 777 | 777 | ||
| 778 | const token = tokenizer.next(); | 778 | const token = tokenizer.next(); |
| 779 | try writeEscaped(out, src[index..token.start]); | 779 | try writeEscaped(out, src[index..token.loc.start]); |
| 780 | switch (token.id) { | 780 | switch (token.id) { |
| 781 | .Eof => break, | 781 | .Eof => break, |
| 782 | 782 | ||
| ... | @@ -827,13 +827,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -827,13 +827,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 827 | .Keyword_while, | 827 | .Keyword_while, |
| 828 | => { | 828 | => { |
| 829 | try out.writeAll("<span class=\"tok-kw\">"); | 829 | try out.writeAll("<span class=\"tok-kw\">"); |
| 830 | try writeEscaped(out, src[token.start..token.end]); | 830 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 831 | try out.writeAll("</span>"); | 831 | try out.writeAll("</span>"); |
| 832 | }, | 832 | }, |
| 833 | 833 | ||
| 834 | .Keyword_fn => { | 834 | .Keyword_fn => { |
| 835 | try out.writeAll("<span class=\"tok-kw\">"); | 835 | try out.writeAll("<span class=\"tok-kw\">"); |
| 836 | try writeEscaped(out, src[token.start..token.end]); | 836 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 837 | try out.writeAll("</span>"); | 837 | try out.writeAll("</span>"); |
| 838 | next_tok_is_fn = true; | 838 | next_tok_is_fn = true; |
| 839 | }, | 839 | }, |
| ... | @@ -844,7 +844,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -844,7 +844,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 844 | .Keyword_false, | 844 | .Keyword_false, |
| 845 | => { | 845 | => { |
| 846 | try out.writeAll("<span class=\"tok-null\">"); | 846 | try out.writeAll("<span class=\"tok-null\">"); |
| 847 | try writeEscaped(out, src[token.start..token.end]); | 847 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 848 | try out.writeAll("</span>"); | 848 | try out.writeAll("</span>"); |
| 849 | }, | 849 | }, |
| 850 | 850 | ||
| ... | @@ -853,13 +853,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -853,13 +853,13 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 853 | .CharLiteral, | 853 | .CharLiteral, |
| 854 | => { | 854 | => { |
| 855 | try out.writeAll("<span class=\"tok-str\">"); | 855 | try out.writeAll("<span class=\"tok-str\">"); |
| 856 | try writeEscaped(out, src[token.start..token.end]); | 856 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 857 | try out.writeAll("</span>"); | 857 | try out.writeAll("</span>"); |
| 858 | }, | 858 | }, |
| 859 | 859 | ||
| 860 | .Builtin => { | 860 | .Builtin => { |
| 861 | try out.writeAll("<span class=\"tok-builtin\">"); | 861 | try out.writeAll("<span class=\"tok-builtin\">"); |
| 862 | try writeEscaped(out, src[token.start..token.end]); | 862 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 863 | try out.writeAll("</span>"); | 863 | try out.writeAll("</span>"); |
| 864 | }, | 864 | }, |
| 865 | 865 | ||
| ... | @@ -869,34 +869,34 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -869,34 +869,34 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 869 | .ShebangLine, | 869 | .ShebangLine, |
| 870 | => { | 870 | => { |
| 871 | try out.writeAll("<span class=\"tok-comment\">"); | 871 | try out.writeAll("<span class=\"tok-comment\">"); |
| 872 | try writeEscaped(out, src[token.start..token.end]); | 872 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 873 | try out.writeAll("</span>"); | 873 | try out.writeAll("</span>"); |
| 874 | }, | 874 | }, |
| 875 | 875 | ||
| 876 | .Identifier => { | 876 | .Identifier => { |
| 877 | if (prev_tok_was_fn) { | 877 | if (prev_tok_was_fn) { |
| 878 | try out.writeAll("<span class=\"tok-fn\">"); | 878 | try out.writeAll("<span class=\"tok-fn\">"); |
| 879 | try writeEscaped(out, src[token.start..token.end]); | 879 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 880 | try out.writeAll("</span>"); | 880 | try out.writeAll("</span>"); |
| 881 | } else { | 881 | } else { |
| 882 | const is_int = blk: { | 882 | const is_int = blk: { |
| 883 | if (src[token.start] != 'i' and src[token.start] != 'u') | 883 | if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u') |
| 884 | break :blk false; | 884 | break :blk false; |
| 885 | var i = token.start + 1; | 885 | var i = token.loc.start + 1; |
| 886 | if (i == token.end) | 886 | if (i == token.loc.end) |
| 887 | break :blk false; | 887 | break :blk false; |
| 888 | while (i != token.end) : (i += 1) { | 888 | while (i != token.loc.end) : (i += 1) { |
| 889 | if (src[i] < '0' or src[i] > '9') | 889 | if (src[i] < '0' or src[i] > '9') |
| 890 | break :blk false; | 890 | break :blk false; |
| 891 | } | 891 | } |
| 892 | break :blk true; | 892 | break :blk true; |
| 893 | }; | 893 | }; |
| 894 | if (is_int or isType(src[token.start..token.end])) { | 894 | if (is_int or isType(src[token.loc.start..token.loc.end])) { |
| 895 | try out.writeAll("<span class=\"tok-type\">"); | 895 | try out.writeAll("<span class=\"tok-type\">"); |
| 896 | try writeEscaped(out, src[token.start..token.end]); | 896 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 897 | try out.writeAll("</span>"); | 897 | try out.writeAll("</span>"); |
| 898 | } else { | 898 | } else { |
| 899 | try writeEscaped(out, src[token.start..token.end]); | 899 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 900 | } | 900 | } |
| 901 | } | 901 | } |
| 902 | }, | 902 | }, |
| ... | @@ -905,7 +905,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -905,7 +905,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 905 | .FloatLiteral, | 905 | .FloatLiteral, |
| 906 | => { | 906 | => { |
| 907 | try out.writeAll("<span class=\"tok-number\">"); | 907 | try out.writeAll("<span class=\"tok-number\">"); |
| 908 | try writeEscaped(out, src[token.start..token.end]); | 908 | try writeEscaped(out, src[token.loc.start..token.loc.end]); |
| 909 | try out.writeAll("</span>"); | 909 | try out.writeAll("</span>"); |
| 910 | }, | 910 | }, |
| 911 | 911 | ||
| ... | @@ -963,7 +963,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -963,7 +963,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 963 | .AngleBracketAngleBracketRight, | 963 | .AngleBracketAngleBracketRight, |
| 964 | .AngleBracketAngleBracketRightEqual, | 964 | .AngleBracketAngleBracketRightEqual, |
| 965 | .Tilde, | 965 | .Tilde, |
| 966 | => try writeEscaped(out, src[token.start..token.end]), | 966 | => try writeEscaped(out, src[token.loc.start..token.loc.end]), |
| 967 | 967 | ||
| 968 | .Invalid, .Invalid_ampersands => return parseError( | 968 | .Invalid, .Invalid_ampersands => return parseError( |
| 969 | docgen_tokenizer, | 969 | docgen_tokenizer, |
| ... | @@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok | ... | @@ -972,7 +972,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok |
| 972 | .{}, | 972 | .{}, |
| 973 | ), | 973 | ), |
| 974 | } | 974 | } |
| 975 | index = token.end; | 975 | index = token.loc.end; |
| 976 | } | 976 | } |
| 977 | try out.writeAll("</code>"); | 977 | try out.writeAll("</code>"); |
| 978 | } | 978 | } |
lib/std/heap/arena_allocator.zig+3-7| ... | @@ -46,13 +46,9 @@ pub const ArenaAllocator = struct { | ... | @@ -46,13 +46,9 @@ pub const ArenaAllocator = struct { |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode { | 48 | fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode { |
| 49 | const actual_min_size = minimum_size + @sizeOf(BufNode); | 49 | const actual_min_size = minimum_size + (@sizeOf(BufNode) + 16); |
| 50 | var len = prev_len; | 50 | const big_enough_len = prev_len + actual_min_size; |
| 51 | while (true) { | 51 | const len = big_enough_len + big_enough_len / 2; |
| 52 | len += len / 2; | ||
| 53 | len += mem.page_size - @rem(len, mem.page_size); | ||
| 54 | if (len >= actual_min_size) break; | ||
| 55 | } | ||
| 56 | const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len); | 52 | const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len); |
| 57 | const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]); | 53 | const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]); |
| 58 | const buf_node = &buf_node_slice[0]; | 54 | const buf_node = &buf_node_slice[0]; |
lib/std/linked_list.zig+43-71| ... | @@ -21,6 +21,8 @@ pub fn SinglyLinkedList(comptime T: type) type { | ... | @@ -21,6 +21,8 @@ pub fn SinglyLinkedList(comptime T: type) type { |
| 21 | next: ?*Node = null, | 21 | next: ?*Node = null, |
| 22 | data: T, | 22 | data: T, |
| 23 | 23 | ||
| 24 | pub const Data = T; | ||
| 25 | |||
| 24 | pub fn init(data: T) Node { | 26 | pub fn init(data: T) Node { |
| 25 | return Node{ | 27 | return Node{ |
| 26 | .data = data, | 28 | .data = data, |
| ... | @@ -47,28 +49,29 @@ pub fn SinglyLinkedList(comptime T: type) type { | ... | @@ -47,28 +49,29 @@ pub fn SinglyLinkedList(comptime T: type) type { |
| 47 | node.next = next_node.next; | 49 | node.next = next_node.next; |
| 48 | return next_node; | 50 | return next_node; |
| 49 | } | 51 | } |
| 50 | }; | ||
| 51 | 52 | ||
| 52 | first: ?*Node = null, | 53 | /// Iterate over the singly-linked list from this node, until the final node is found. |
| 54 | /// This operation is O(N). | ||
| 55 | pub fn findLast(node: *Node) *Node { | ||
| 56 | var it = node; | ||
| 57 | while (true) { | ||
| 58 | it = it.next orelse return it; | ||
| 59 | } | ||
| 60 | } | ||
| 53 | 61 | ||
| 54 | /// Initialize a linked list. | 62 | /// Iterate over each next node, returning the count of all nodes except the starting one. |
| 55 | /// | 63 | /// This operation is O(N). |
| 56 | /// Returns: | 64 | pub fn countChildren(node: *const Node) usize { |
| 57 | /// An empty linked list. | 65 | var count: usize = 0; |
| 58 | pub fn init() Self { | 66 | var it: ?*const Node = node; |
| 59 | return Self{ | 67 | while (it) |n| : (it = n.next) { |
| 60 | .first = null, | 68 | count += 1; |
| 61 | }; | 69 | } |
| 62 | } | 70 | return count; |
| 71 | } | ||
| 72 | }; | ||
| 63 | 73 | ||
| 64 | /// Insert a new node after an existing one. | 74 | first: ?*Node = null, |
| 65 | /// | ||
| 66 | /// Arguments: | ||
| 67 | /// node: Pointer to a node in the list. | ||
| 68 | /// new_node: Pointer to the new node to insert. | ||
| 69 | pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void { | ||
| 70 | node.insertAfter(new_node); | ||
| 71 | } | ||
| 72 | 75 | ||
| 73 | /// Insert a new node at the head. | 76 | /// Insert a new node at the head. |
| 74 | /// | 77 | /// |
| ... | @@ -105,64 +108,33 @@ pub fn SinglyLinkedList(comptime T: type) type { | ... | @@ -105,64 +108,33 @@ pub fn SinglyLinkedList(comptime T: type) type { |
| 105 | return first; | 108 | return first; |
| 106 | } | 109 | } |
| 107 | 110 | ||
| 108 | /// Allocate a new node. | 111 | /// Iterate over all nodes, returning the count. |
| 109 | /// | 112 | /// This operation is O(N). |
| 110 | /// Arguments: | 113 | pub fn len(list: Self) usize { |
| 111 | /// allocator: Dynamic memory allocator. | 114 | if (list.first) |n| { |
| 112 | /// | 115 | return 1 + n.countChildren(); |
| 113 | /// Returns: | 116 | } else { |
| 114 | /// A pointer to the new node. | 117 | return 0; |
| 115 | pub fn allocateNode(list: *Self, allocator: *Allocator) !*Node { | 118 | } |
| 116 | return allocator.create(Node); | ||
| 117 | } | ||
| 118 | |||
| 119 | /// Deallocate a node. | ||
| 120 | /// | ||
| 121 | /// Arguments: | ||
| 122 | /// node: Pointer to the node to deallocate. | ||
| 123 | /// allocator: Dynamic memory allocator. | ||
| 124 | pub fn destroyNode(list: *Self, node: *Node, allocator: *Allocator) void { | ||
| 125 | allocator.destroy(node); | ||
| 126 | } | ||
| 127 | |||
| 128 | /// Allocate and initialize a node and its data. | ||
| 129 | /// | ||
| 130 | /// Arguments: | ||
| 131 | /// data: The data to put inside the node. | ||
| 132 | /// allocator: Dynamic memory allocator. | ||
| 133 | /// | ||
| 134 | /// Returns: | ||
| 135 | /// A pointer to the new node. | ||
| 136 | pub fn createNode(list: *Self, data: T, allocator: *Allocator) !*Node { | ||
| 137 | var node = try list.allocateNode(allocator); | ||
| 138 | node.* = Node.init(data); | ||
| 139 | return node; | ||
| 140 | } | 119 | } |
| 141 | }; | 120 | }; |
| 142 | } | 121 | } |
| 143 | 122 | ||
| 144 | test "basic SinglyLinkedList test" { | 123 | test "basic SinglyLinkedList test" { |
| 145 | const allocator = testing.allocator; | 124 | const L = SinglyLinkedList(u32); |
| 146 | var list = SinglyLinkedList(u32).init(); | 125 | var list = L{}; |
| 147 | 126 | ||
| 148 | var one = try list.createNode(1, allocator); | 127 | var one = L.Node{.data = 1}; |
| 149 | var two = try list.createNode(2, allocator); | 128 | var two = L.Node{.data = 2}; |
| 150 | var three = try list.createNode(3, allocator); | 129 | var three = L.Node{.data = 3}; |
| 151 | var four = try list.createNode(4, allocator); | 130 | var four = L.Node{.data = 4}; |
| 152 | var five = try list.createNode(5, allocator); | 131 | var five = L.Node{.data = 5}; |
| 153 | defer { | ||
| 154 | list.destroyNode(one, allocator); | ||
| 155 | list.destroyNode(two, allocator); | ||
| 156 | list.destroyNode(three, allocator); | ||
| 157 | list.destroyNode(four, allocator); | ||
| 158 | list.destroyNode(five, allocator); | ||
| 159 | } | ||
| 160 | 132 | ||
| 161 | list.prepend(two); // {2} | 133 | list.prepend(&two); // {2} |
| 162 | list.insertAfter(two, five); // {2, 5} | 134 | two.insertAfter(&five); // {2, 5} |
| 163 | list.prepend(one); // {1, 2, 5} | 135 | list.prepend(&one); // {1, 2, 5} |
| 164 | list.insertAfter(two, three); // {1, 2, 3, 5} | 136 | two.insertAfter(&three); // {1, 2, 3, 5} |
| 165 | list.insertAfter(three, four); // {1, 2, 3, 4, 5} | 137 | three.insertAfter(&four); // {1, 2, 3, 4, 5} |
| 166 | 138 | ||
| 167 | // Traverse forwards. | 139 | // Traverse forwards. |
| 168 | { | 140 | { |
| ... | @@ -175,7 +147,7 @@ test "basic SinglyLinkedList test" { | ... | @@ -175,7 +147,7 @@ test "basic SinglyLinkedList test" { |
| 175 | } | 147 | } |
| 176 | 148 | ||
| 177 | _ = list.popFirst(); // {2, 3, 4, 5} | 149 | _ = list.popFirst(); // {2, 3, 4, 5} |
| 178 | _ = list.remove(five); // {2, 3, 4} | 150 | _ = list.remove(&five); // {2, 3, 4} |
| 179 | _ = two.removeNext(); // {2, 4} | 151 | _ = two.removeNext(); // {2, 4} |
| 180 | 152 | ||
| 181 | testing.expect(list.first.?.data == 2); | 153 | testing.expect(list.first.?.data == 2); |
lib/std/rand.zig+1-1| ... | @@ -658,7 +658,7 @@ pub const Xoroshiro128 = struct { | ... | @@ -658,7 +658,7 @@ pub const Xoroshiro128 = struct { |
| 658 | self.s[1] = s1; | 658 | self.s[1] = s1; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | fn seed(self: *Xoroshiro128, init_s: u64) void { | 661 | pub fn seed(self: *Xoroshiro128, init_s: u64) void { |
| 662 | // Xoroshiro requires 128-bits of seed. | 662 | // Xoroshiro requires 128-bits of seed. |
| 663 | var gen = SplitMix64.init(init_s); | 663 | var gen = SplitMix64.init(init_s); |
| 664 | 664 |
lib/std/testing.zig+4-3| ... | @@ -320,10 +320,11 @@ fn printWithVisibleNewlines(source: []const u8) void { | ... | @@ -320,10 +320,11 @@ fn printWithVisibleNewlines(source: []const u8) void { |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | fn printLine(line: []const u8) void { | 322 | fn printLine(line: []const u8) void { |
| 323 | switch (line[line.len - 1]) { | 323 | if (line.len != 0) switch (line[line.len - 1]) { |
| 324 | ' ', '\t' => warn("{}⏎\n", .{line}), // Carriage return symbol, | 324 | ' ', '\t' => warn("{}⏎\n", .{line}), // Carriage return symbol, |
| 325 | else => warn("{}\n", .{line}), | 325 | else => {}, |
| 326 | } | 326 | }; |
| 327 | warn("{}\n", .{line}); | ||
| 327 | } | 328 | } |
| 328 | 329 | ||
| 329 | test "" { | 330 | test "" { |
lib/std/zig/ast.zig+783-313| ... | @@ -1,51 +1,50 @@ | ... | @@ -1,51 +1,50 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const assert = std.debug.assert; | 2 | const assert = std.debug.assert; |
| 3 | const testing = std.testing; | 3 | const testing = std.testing; |
| 4 | const SegmentedList = std.SegmentedList; | ||
| 5 | const mem = std.mem; | 4 | const mem = std.mem; |
| 6 | const Token = std.zig.Token; | 5 | const Token = std.zig.Token; |
| 7 | 6 | ||
| 8 | pub const TokenIndex = usize; | 7 | pub const TokenIndex = usize; |
| 8 | pub const NodeIndex = usize; | ||
| 9 | 9 | ||
| 10 | pub const Tree = struct { | 10 | pub const Tree = struct { |
| 11 | /// Reference to externally-owned data. | ||
| 11 | source: []const u8, | 12 | source: []const u8, |
| 12 | tokens: TokenList, | 13 | token_ids: []const Token.Id, |
| 13 | 14 | token_locs: []const Token.Loc, | |
| 14 | /// undefined on parse error (errors not empty) | 15 | errors: []const Error, |
| 16 | /// undefined on parse error (when errors field is not empty) | ||
| 15 | root_node: *Node.Root, | 17 | root_node: *Node.Root, |
| 16 | arena_allocator: std.heap.ArenaAllocator, | 18 | |
| 17 | errors: ErrorList, | 19 | arena: std.heap.ArenaAllocator.State, |
| 20 | gpa: *mem.Allocator, | ||
| 18 | 21 | ||
| 19 | /// translate-c uses this to avoid having to emit correct newlines | 22 | /// translate-c uses this to avoid having to emit correct newlines |
| 20 | /// TODO get rid of this hack | 23 | /// TODO get rid of this hack |
| 21 | generated: bool = false, | 24 | generated: bool = false, |
| 22 | 25 | ||
| 23 | pub const TokenList = SegmentedList(Token, 64); | ||
| 24 | pub const ErrorList = SegmentedList(Error, 0); | ||
| 25 | |||
| 26 | pub fn deinit(self: *Tree) void { | 26 | pub fn deinit(self: *Tree) void { |
| 27 | // Here we copy the arena allocator into stack memory, because | 27 | self.gpa.free(self.token_ids); |
| 28 | // otherwise it would destroy itself while it was still working. | 28 | self.gpa.free(self.token_locs); |
| 29 | var arena_allocator = self.arena_allocator; | 29 | self.gpa.free(self.errors); |
| 30 | arena_allocator.deinit(); | 30 | self.arena.promote(self.gpa).deinit(); |
| 31 | // self is destroyed | ||
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | pub fn renderError(self: *Tree, parse_error: *Error, stream: var) !void { | 33 | pub fn renderError(self: *Tree, parse_error: *const Error, stream: var) !void { |
| 35 | return parse_error.render(&self.tokens, stream); | 34 | return parse_error.render(self.token_ids, stream); |
| 36 | } | 35 | } |
| 37 | 36 | ||
| 38 | pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 { | 37 | pub fn tokenSlice(self: *Tree, token_index: TokenIndex) []const u8 { |
| 39 | return self.tokenSlicePtr(self.tokens.at(token_index)); | 38 | return self.tokenSliceLoc(self.token_locs[token_index]); |
| 40 | } | 39 | } |
| 41 | 40 | ||
| 42 | pub fn tokenSlicePtr(self: *Tree, token: *const Token) []const u8 { | 41 | pub fn tokenSliceLoc(self: *Tree, token: Token.Loc) []const u8 { |
| 43 | return self.source[token.start..token.end]; | 42 | return self.source[token.start..token.end]; |
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 { | 45 | pub fn getNodeSource(self: *const Tree, node: *const Node) []const u8 { |
| 47 | const first_token = self.tokens.at(node.firstToken()); | 46 | const first_token = self.token_locs[node.firstToken()]; |
| 48 | const last_token = self.tokens.at(node.lastToken()); | 47 | const last_token = self.token_locs[node.lastToken()]; |
| 49 | return self.source[first_token.start..last_token.end]; | 48 | return self.source[first_token.start..last_token.end]; |
| 50 | } | 49 | } |
| 51 | 50 | ||
| ... | @@ -57,7 +56,7 @@ pub const Tree = struct { | ... | @@ -57,7 +56,7 @@ pub const Tree = struct { |
| 57 | }; | 56 | }; |
| 58 | 57 | ||
| 59 | /// Return the Location of the token relative to the offset specified by `start_index`. | 58 | /// Return the Location of the token relative to the offset specified by `start_index`. |
| 60 | pub fn tokenLocationPtr(self: *Tree, start_index: usize, token: *const Token) Location { | 59 | pub fn tokenLocationLoc(self: *Tree, start_index: usize, token: Token.Loc) Location { |
| 61 | var loc = Location{ | 60 | var loc = Location{ |
| 62 | .line = 0, | 61 | .line = 0, |
| 63 | .column = 0, | 62 | .column = 0, |
| ... | @@ -85,14 +84,14 @@ pub const Tree = struct { | ... | @@ -85,14 +84,14 @@ pub const Tree = struct { |
| 85 | } | 84 | } |
| 86 | 85 | ||
| 87 | pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location { | 86 | pub fn tokenLocation(self: *Tree, start_index: usize, token_index: TokenIndex) Location { |
| 88 | return self.tokenLocationPtr(start_index, self.tokens.at(token_index)); | 87 | return self.tokenLocationLoc(start_index, self.token_locs[token_index]); |
| 89 | } | 88 | } |
| 90 | 89 | ||
| 91 | pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool { | 90 | pub fn tokensOnSameLine(self: *Tree, token1_index: TokenIndex, token2_index: TokenIndex) bool { |
| 92 | return self.tokensOnSameLinePtr(self.tokens.at(token1_index), self.tokens.at(token2_index)); | 91 | return self.tokensOnSameLineLoc(self.token_locs[token1_index], self.token_locs[token2_index]); |
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | pub fn tokensOnSameLinePtr(self: *Tree, token1: *const Token, token2: *const Token) bool { | 94 | pub fn tokensOnSameLineLoc(self: *Tree, token1: Token.Loc, token2: Token.Loc) bool { |
| 96 | return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null; | 95 | return mem.indexOfScalar(u8, self.source[token1.end..token2.start], '\n') == null; |
| 97 | } | 96 | } |
| 98 | 97 | ||
| ... | @@ -103,7 +102,7 @@ pub const Tree = struct { | ... | @@ -103,7 +102,7 @@ pub const Tree = struct { |
| 103 | /// Skips over comments | 102 | /// Skips over comments |
| 104 | pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex { | 103 | pub fn prevToken(self: *Tree, token_index: TokenIndex) TokenIndex { |
| 105 | var index = token_index - 1; | 104 | var index = token_index - 1; |
| 106 | while (self.tokens.at(index).id == Token.Id.LineComment) { | 105 | while (self.token_ids[index] == Token.Id.LineComment) { |
| 107 | index -= 1; | 106 | index -= 1; |
| 108 | } | 107 | } |
| 109 | return index; | 108 | return index; |
| ... | @@ -112,7 +111,7 @@ pub const Tree = struct { | ... | @@ -112,7 +111,7 @@ pub const Tree = struct { |
| 112 | /// Skips over comments | 111 | /// Skips over comments |
| 113 | pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex { | 112 | pub fn nextToken(self: *Tree, token_index: TokenIndex) TokenIndex { |
| 114 | var index = token_index + 1; | 113 | var index = token_index + 1; |
| 115 | while (self.tokens.at(index).id == Token.Id.LineComment) { | 114 | while (self.token_ids[index] == Token.Id.LineComment) { |
| 116 | index += 1; | 115 | index += 1; |
| 117 | } | 116 | } |
| 118 | return index; | 117 | return index; |
| ... | @@ -169,7 +168,7 @@ pub const Error = union(enum) { | ... | @@ -169,7 +168,7 @@ pub const Error = union(enum) { |
| 169 | DeclBetweenFields: DeclBetweenFields, | 168 | DeclBetweenFields: DeclBetweenFields, |
| 170 | InvalidAnd: InvalidAnd, | 169 | InvalidAnd: InvalidAnd, |
| 171 | 170 | ||
| 172 | pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void { | 171 | pub fn render(self: *const Error, tokens: []const Token.Id, stream: var) !void { |
| 173 | switch (self.*) { | 172 | switch (self.*) { |
| 174 | .InvalidToken => |*x| return x.render(tokens, stream), | 173 | .InvalidToken => |*x| return x.render(tokens, stream), |
| 175 | .ExpectedContainerMembers => |*x| return x.render(tokens, stream), | 174 | .ExpectedContainerMembers => |*x| return x.render(tokens, stream), |
| ... | @@ -324,8 +323,8 @@ pub const Error = union(enum) { | ... | @@ -324,8 +323,8 @@ pub const Error = union(enum) { |
| 324 | pub const ExpectedCall = struct { | 323 | pub const ExpectedCall = struct { |
| 325 | node: *Node, | 324 | node: *Node, |
| 326 | 325 | ||
| 327 | pub fn render(self: *const ExpectedCall, tokens: *Tree.TokenList, stream: var) !void { | 326 | pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: var) !void { |
| 328 | return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ ", found {}", .{ | 327 | return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{ |
| 329 | @tagName(self.node.id), | 328 | @tagName(self.node.id), |
| 330 | }); | 329 | }); |
| 331 | } | 330 | } |
| ... | @@ -334,8 +333,8 @@ pub const Error = union(enum) { | ... | @@ -334,8 +333,8 @@ pub const Error = union(enum) { |
| 334 | pub const ExpectedCallOrFnProto = struct { | 333 | pub const ExpectedCallOrFnProto = struct { |
| 335 | node: *Node, | 334 | node: *Node, |
| 336 | 335 | ||
| 337 | pub fn render(self: *const ExpectedCallOrFnProto, tokens: *Tree.TokenList, stream: var) !void { | 336 | pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: var) !void { |
| 338 | return stream.print("expected " ++ @tagName(@TagType(Node.SuffixOp.Op).Call) ++ " or " ++ | 337 | return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++ |
| 339 | @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)}); | 338 | @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)}); |
| 340 | } | 339 | } |
| 341 | }; | 340 | }; |
| ... | @@ -344,14 +343,14 @@ pub const Error = union(enum) { | ... | @@ -344,14 +343,14 @@ pub const Error = union(enum) { |
| 344 | token: TokenIndex, | 343 | token: TokenIndex, |
| 345 | expected_id: Token.Id, | 344 | expected_id: Token.Id, |
| 346 | 345 | ||
| 347 | pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void { | 346 | pub fn render(self: *const ExpectedToken, tokens: []const Token.Id, stream: var) !void { |
| 348 | const found_token = tokens.at(self.token); | 347 | const found_token = tokens[self.token]; |
| 349 | switch (found_token.id) { | 348 | switch (found_token) { |
| 350 | .Invalid => { | 349 | .Invalid => { |
| 351 | return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()}); | 350 | return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()}); |
| 352 | }, | 351 | }, |
| 353 | else => { | 352 | else => { |
| 354 | const token_name = found_token.id.symbol(); | 353 | const token_name = found_token.symbol(); |
| 355 | return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name }); | 354 | return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name }); |
| 356 | }, | 355 | }, |
| 357 | } | 356 | } |
| ... | @@ -362,11 +361,11 @@ pub const Error = union(enum) { | ... | @@ -362,11 +361,11 @@ pub const Error = union(enum) { |
| 362 | token: TokenIndex, | 361 | token: TokenIndex, |
| 363 | end_id: Token.Id, | 362 | end_id: Token.Id, |
| 364 | 363 | ||
| 365 | pub fn render(self: *const ExpectedCommaOrEnd, tokens: *Tree.TokenList, stream: var) !void { | 364 | pub fn render(self: *const ExpectedCommaOrEnd, tokens: []const Token.Id, stream: var) !void { |
| 366 | const actual_token = tokens.at(self.token); | 365 | const actual_token = tokens[self.token]; |
| 367 | return stream.print("expected ',' or '{}', found '{}'", .{ | 366 | return stream.print("expected ',' or '{}', found '{}'", .{ |
| 368 | self.end_id.symbol(), | 367 | self.end_id.symbol(), |
| 369 | actual_token.id.symbol(), | 368 | actual_token.symbol(), |
| 370 | }); | 369 | }); |
| 371 | } | 370 | } |
| 372 | }; | 371 | }; |
| ... | @@ -377,9 +376,9 @@ pub const Error = union(enum) { | ... | @@ -377,9 +376,9 @@ pub const Error = union(enum) { |
| 377 | 376 | ||
| 378 | token: TokenIndex, | 377 | token: TokenIndex, |
| 379 | 378 | ||
| 380 | pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void { | 379 | pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void { |
| 381 | const actual_token = tokens.at(self.token); | 380 | const actual_token = tokens[self.token]; |
| 382 | return stream.print(msg, .{actual_token.id.symbol()}); | 381 | return stream.print(msg, .{actual_token.symbol()}); |
| 383 | } | 382 | } |
| 384 | }; | 383 | }; |
| 385 | } | 384 | } |
| ... | @@ -390,7 +389,7 @@ pub const Error = union(enum) { | ... | @@ -390,7 +389,7 @@ pub const Error = union(enum) { |
| 390 | 389 | ||
| 391 | token: TokenIndex, | 390 | token: TokenIndex, |
| 392 | 391 | ||
| 393 | pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void { | 392 | pub fn render(self: *const ThisError, tokens: []const Token.Id, stream: var) !void { |
| 394 | return stream.writeAll(msg); | 393 | return stream.writeAll(msg); |
| 395 | } | 394 | } |
| 396 | }; | 395 | }; |
| ... | @@ -413,7 +412,19 @@ pub const Node = struct { | ... | @@ -413,7 +412,19 @@ pub const Node = struct { |
| 413 | // Operators | 412 | // Operators |
| 414 | InfixOp, | 413 | InfixOp, |
| 415 | PrefixOp, | 414 | PrefixOp, |
| 415 | /// Not all suffix operations are under this tag. To save memory, some | ||
| 416 | /// suffix operations have dedicated Node tags. | ||
| 416 | SuffixOp, | 417 | SuffixOp, |
| 418 | /// `T{a, b}` | ||
| 419 | ArrayInitializer, | ||
| 420 | /// ArrayInitializer but with `.` instead of a left-hand-side operand. | ||
| 421 | ArrayInitializerDot, | ||
| 422 | /// `T{.a = b}` | ||
| 423 | StructInitializer, | ||
| 424 | /// StructInitializer but with `.` instead of a left-hand-side operand. | ||
| 425 | StructInitializerDot, | ||
| 426 | /// `foo()` | ||
| 427 | Call, | ||
| 417 | 428 | ||
| 418 | // Control flow | 429 | // Control flow |
| 419 | Switch, | 430 | Switch, |
| ... | @@ -460,9 +471,6 @@ pub const Node = struct { | ... | @@ -460,9 +471,6 @@ pub const Node = struct { |
| 460 | PointerIndexPayload, | 471 | PointerIndexPayload, |
| 461 | ContainerField, | 472 | ContainerField, |
| 462 | ErrorTag, | 473 | ErrorTag, |
| 463 | AsmInput, | ||
| 464 | AsmOutput, | ||
| 465 | ParamDecl, | ||
| 466 | FieldInitializer, | 474 | FieldInitializer, |
| 467 | }; | 475 | }; |
| 468 | 476 | ||
| ... | @@ -518,7 +526,6 @@ pub const Node = struct { | ... | @@ -518,7 +526,6 @@ pub const Node = struct { |
| 518 | switch (n.id) { | 526 | switch (n.id) { |
| 519 | .Root, | 527 | .Root, |
| 520 | .ContainerField, | 528 | .ContainerField, |
| 521 | .ParamDecl, | ||
| 522 | .Block, | 529 | .Block, |
| 523 | .Payload, | 530 | .Payload, |
| 524 | .PointerPayload, | 531 | .PointerPayload, |
| ... | @@ -602,26 +609,57 @@ pub const Node = struct { | ... | @@ -602,26 +609,57 @@ pub const Node = struct { |
| 602 | } | 609 | } |
| 603 | } | 610 | } |
| 604 | 611 | ||
| 612 | /// The decls data follows this struct in memory as an array of Node pointers. | ||
| 605 | pub const Root = struct { | 613 | pub const Root = struct { |
| 606 | base: Node = Node{ .id = .Root }, | 614 | base: Node = Node{ .id = .Root }, |
| 607 | decls: DeclList, | ||
| 608 | eof_token: TokenIndex, | 615 | eof_token: TokenIndex, |
| 616 | decls_len: NodeIndex, | ||
| 617 | |||
| 618 | /// After this the caller must initialize the decls list. | ||
| 619 | pub fn create(allocator: *mem.Allocator, decls_len: NodeIndex, eof_token: TokenIndex) !*Root { | ||
| 620 | const bytes = try allocator.alignedAlloc(u8, @alignOf(Root), sizeInBytes(decls_len)); | ||
| 621 | const self = @ptrCast(*Root, bytes.ptr); | ||
| 622 | self.* = .{ | ||
| 623 | .eof_token = eof_token, | ||
| 624 | .decls_len = decls_len, | ||
| 625 | }; | ||
| 626 | return self; | ||
| 627 | } | ||
| 628 | |||
| 629 | pub fn destroy(self: *Decl, allocator: *mem.Allocator) void { | ||
| 630 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.decls_len)]; | ||
| 631 | allocator.free(bytes); | ||
| 632 | } | ||
| 609 | 633 | ||
| 610 | pub const DeclList = SegmentedList(*Node, 4); | 634 | pub fn iterate(self: *const Root, index: usize) ?*Node { |
| 635 | var i = index; | ||
| 611 | 636 | ||
| 612 | pub fn iterate(self: *Root, index: usize) ?*Node { | 637 | if (i < self.decls_len) return self.declsConst()[i]; |
| 613 | if (index < self.decls.len) { | ||
| 614 | return self.decls.at(index).*; | ||
| 615 | } | ||
| 616 | return null; | 638 | return null; |
| 617 | } | 639 | } |
| 618 | 640 | ||
| 641 | pub fn decls(self: *Root) []*Node { | ||
| 642 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(Root); | ||
| 643 | return @ptrCast([*]*Node, decls_start)[0..self.decls_len]; | ||
| 644 | } | ||
| 645 | |||
| 646 | pub fn declsConst(self: *const Root) []const *Node { | ||
| 647 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Root); | ||
| 648 | return @ptrCast([*]const *Node, decls_start)[0..self.decls_len]; | ||
| 649 | } | ||
| 650 | |||
| 619 | pub fn firstToken(self: *const Root) TokenIndex { | 651 | pub fn firstToken(self: *const Root) TokenIndex { |
| 620 | return if (self.decls.len == 0) self.eof_token else (self.decls.at(0).*).firstToken(); | 652 | if (self.decls_len == 0) return self.eof_token; |
| 653 | return self.declsConst()[0].firstToken(); | ||
| 621 | } | 654 | } |
| 622 | 655 | ||
| 623 | pub fn lastToken(self: *const Root) TokenIndex { | 656 | pub fn lastToken(self: *const Root) TokenIndex { |
| 624 | return if (self.decls.len == 0) self.eof_token else (self.decls.at(self.decls.len - 1).*).lastToken(); | 657 | if (self.decls_len == 0) return self.eof_token; |
| 658 | return self.declsConst()[self.decls_len - 1].lastToken(); | ||
| 659 | } | ||
| 660 | |||
| 661 | fn sizeInBytes(decls_len: NodeIndex) usize { | ||
| 662 | return @sizeOf(Root) + @sizeOf(*Node) * @as(usize, decls_len); | ||
| 625 | } | 663 | } |
| 626 | }; | 664 | }; |
| 627 | 665 | ||
| ... | @@ -642,7 +680,7 @@ pub const Node = struct { | ... | @@ -642,7 +680,7 @@ pub const Node = struct { |
| 642 | init_node: ?*Node, | 680 | init_node: ?*Node, |
| 643 | semicolon_token: TokenIndex, | 681 | semicolon_token: TokenIndex, |
| 644 | 682 | ||
| 645 | pub fn iterate(self: *VarDecl, index: usize) ?*Node { | 683 | pub fn iterate(self: *const VarDecl, index: usize) ?*Node { |
| 646 | var i = index; | 684 | var i = index; |
| 647 | 685 | ||
| 648 | if (self.type_node) |type_node| { | 686 | if (self.type_node) |type_node| { |
| ... | @@ -668,6 +706,7 @@ pub const Node = struct { | ... | @@ -668,6 +706,7 @@ pub const Node = struct { |
| 668 | return null; | 706 | return null; |
| 669 | } | 707 | } |
| 670 | 708 | ||
| 709 | |||
| 671 | pub fn firstToken(self: *const VarDecl) TokenIndex { | 710 | pub fn firstToken(self: *const VarDecl) TokenIndex { |
| 672 | if (self.visib_token) |visib_token| return visib_token; | 711 | if (self.visib_token) |visib_token| return visib_token; |
| 673 | if (self.thread_local_token) |thread_local_token| return thread_local_token; | 712 | if (self.thread_local_token) |thread_local_token| return thread_local_token; |
| ... | @@ -690,7 +729,7 @@ pub const Node = struct { | ... | @@ -690,7 +729,7 @@ pub const Node = struct { |
| 690 | expr: *Node, | 729 | expr: *Node, |
| 691 | semicolon_token: TokenIndex, | 730 | semicolon_token: TokenIndex, |
| 692 | 731 | ||
| 693 | pub fn iterate(self: *Use, index: usize) ?*Node { | 732 | pub fn iterate(self: *const Use, index: usize) ?*Node { |
| 694 | var i = index; | 733 | var i = index; |
| 695 | 734 | ||
| 696 | if (i < 1) return self.expr; | 735 | if (i < 1) return self.expr; |
| ... | @@ -712,16 +751,25 @@ pub const Node = struct { | ... | @@ -712,16 +751,25 @@ pub const Node = struct { |
| 712 | pub const ErrorSetDecl = struct { | 751 | pub const ErrorSetDecl = struct { |
| 713 | base: Node = Node{ .id = .ErrorSetDecl }, | 752 | base: Node = Node{ .id = .ErrorSetDecl }, |
| 714 | error_token: TokenIndex, | 753 | error_token: TokenIndex, |
| 715 | decls: DeclList, | ||
| 716 | rbrace_token: TokenIndex, | 754 | rbrace_token: TokenIndex, |
| 755 | decls_len: NodeIndex, | ||
| 717 | 756 | ||
| 718 | pub const DeclList = SegmentedList(*Node, 2); | 757 | /// After this the caller must initialize the decls list. |
| 758 | pub fn alloc(allocator: *mem.Allocator, decls_len: NodeIndex) !*ErrorSetDecl { | ||
| 759 | const bytes = try allocator.alignedAlloc(u8, @alignOf(ErrorSetDecl), sizeInBytes(decls_len)); | ||
| 760 | return @ptrCast(*ErrorSetDecl, bytes.ptr); | ||
| 761 | } | ||
| 719 | 762 | ||
| 720 | pub fn iterate(self: *ErrorSetDecl, index: usize) ?*Node { | 763 | pub fn free(self: *ErrorSetDecl, allocator: *mem.Allocator) void { |
| 764 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.decls_len)]; | ||
| 765 | allocator.free(bytes); | ||
| 766 | } | ||
| 767 | |||
| 768 | pub fn iterate(self: *const ErrorSetDecl, index: usize) ?*Node { | ||
| 721 | var i = index; | 769 | var i = index; |
| 722 | 770 | ||
| 723 | if (i < self.decls.len) return self.decls.at(i).*; | 771 | if (i < self.decls_len) return self.declsConst()[i]; |
| 724 | i -= self.decls.len; | 772 | i -= self.decls_len; |
| 725 | 773 | ||
| 726 | return null; | 774 | return null; |
| 727 | } | 775 | } |
| ... | @@ -733,18 +781,31 @@ pub const Node = struct { | ... | @@ -733,18 +781,31 @@ pub const Node = struct { |
| 733 | pub fn lastToken(self: *const ErrorSetDecl) TokenIndex { | 781 | pub fn lastToken(self: *const ErrorSetDecl) TokenIndex { |
| 734 | return self.rbrace_token; | 782 | return self.rbrace_token; |
| 735 | } | 783 | } |
| 784 | |||
| 785 | pub fn decls(self: *ErrorSetDecl) []*Node { | ||
| 786 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(ErrorSetDecl); | ||
| 787 | return @ptrCast([*]*Node, decls_start)[0..self.decls_len]; | ||
| 788 | } | ||
| 789 | |||
| 790 | pub fn declsConst(self: *const ErrorSetDecl) []const *Node { | ||
| 791 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ErrorSetDecl); | ||
| 792 | return @ptrCast([*]const *Node, decls_start)[0..self.decls_len]; | ||
| 793 | } | ||
| 794 | |||
| 795 | fn sizeInBytes(decls_len: NodeIndex) usize { | ||
| 796 | return @sizeOf(ErrorSetDecl) + @sizeOf(*Node) * @as(usize, decls_len); | ||
| 797 | } | ||
| 736 | }; | 798 | }; |
| 737 | 799 | ||
| 800 | /// The fields and decls Node pointers directly follow this struct in memory. | ||
| 738 | pub const ContainerDecl = struct { | 801 | pub const ContainerDecl = struct { |
| 739 | base: Node = Node{ .id = .ContainerDecl }, | 802 | base: Node = Node{ .id = .ContainerDecl }, |
| 740 | layout_token: ?TokenIndex, | ||
| 741 | kind_token: TokenIndex, | 803 | kind_token: TokenIndex, |
| 742 | init_arg_expr: InitArg, | 804 | layout_token: ?TokenIndex, |
| 743 | fields_and_decls: DeclList, | ||
| 744 | lbrace_token: TokenIndex, | 805 | lbrace_token: TokenIndex, |
| 745 | rbrace_token: TokenIndex, | 806 | rbrace_token: TokenIndex, |
| 746 | 807 | fields_and_decls_len: NodeIndex, | |
| 747 | pub const DeclList = Root.DeclList; | 808 | init_arg_expr: InitArg, |
| 748 | 809 | ||
| 749 | pub const InitArg = union(enum) { | 810 | pub const InitArg = union(enum) { |
| 750 | None, | 811 | None, |
| ... | @@ -752,7 +813,18 @@ pub const Node = struct { | ... | @@ -752,7 +813,18 @@ pub const Node = struct { |
| 752 | Type: *Node, | 813 | Type: *Node, |
| 753 | }; | 814 | }; |
| 754 | 815 | ||
| 755 | pub fn iterate(self: *ContainerDecl, index: usize) ?*Node { | 816 | /// After this the caller must initialize the fields_and_decls list. |
| 817 | pub fn alloc(allocator: *mem.Allocator, fields_and_decls_len: NodeIndex) !*ContainerDecl { | ||
| 818 | const bytes = try allocator.alignedAlloc(u8, @alignOf(ContainerDecl), sizeInBytes(fields_and_decls_len)); | ||
| 819 | return @ptrCast(*ContainerDecl, bytes.ptr); | ||
| 820 | } | ||
| 821 | |||
| 822 | pub fn free(self: *ContainerDecl, allocator: *mem.Allocator) void { | ||
| 823 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.fields_and_decls_len)]; | ||
| 824 | allocator.free(bytes); | ||
| 825 | } | ||
| 826 | |||
| 827 | pub fn iterate(self: *const ContainerDecl, index: usize) ?*Node { | ||
| 756 | var i = index; | 828 | var i = index; |
| 757 | 829 | ||
| 758 | switch (self.init_arg_expr) { | 830 | switch (self.init_arg_expr) { |
| ... | @@ -763,8 +835,8 @@ pub const Node = struct { | ... | @@ -763,8 +835,8 @@ pub const Node = struct { |
| 763 | .None, .Enum => {}, | 835 | .None, .Enum => {}, |
| 764 | } | 836 | } |
| 765 | 837 | ||
| 766 | if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*; | 838 | if (i < self.fields_and_decls_len) return self.fieldsAndDeclsConst()[i]; |
| 767 | i -= self.fields_and_decls.len; | 839 | i -= self.fields_and_decls_len; |
| 768 | 840 | ||
| 769 | return null; | 841 | return null; |
| 770 | } | 842 | } |
| ... | @@ -779,6 +851,20 @@ pub const Node = struct { | ... | @@ -779,6 +851,20 @@ pub const Node = struct { |
| 779 | pub fn lastToken(self: *const ContainerDecl) TokenIndex { | 851 | pub fn lastToken(self: *const ContainerDecl) TokenIndex { |
| 780 | return self.rbrace_token; | 852 | return self.rbrace_token; |
| 781 | } | 853 | } |
| 854 | |||
| 855 | pub fn fieldsAndDecls(self: *ContainerDecl) []*Node { | ||
| 856 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(ContainerDecl); | ||
| 857 | return @ptrCast([*]*Node, decls_start)[0..self.fields_and_decls_len]; | ||
| 858 | } | ||
| 859 | |||
| 860 | pub fn fieldsAndDeclsConst(self: *const ContainerDecl) []const *Node { | ||
| 861 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ContainerDecl); | ||
| 862 | return @ptrCast([*]const *Node, decls_start)[0..self.fields_and_decls_len]; | ||
| 863 | } | ||
| 864 | |||
| 865 | fn sizeInBytes(fields_and_decls_len: NodeIndex) usize { | ||
| 866 | return @sizeOf(ContainerDecl) + @sizeOf(*Node) * @as(usize, fields_and_decls_len); | ||
| 867 | } | ||
| 782 | }; | 868 | }; |
| 783 | 869 | ||
| 784 | pub const ContainerField = struct { | 870 | pub const ContainerField = struct { |
| ... | @@ -790,7 +876,7 @@ pub const Node = struct { | ... | @@ -790,7 +876,7 @@ pub const Node = struct { |
| 790 | value_expr: ?*Node, | 876 | value_expr: ?*Node, |
| 791 | align_expr: ?*Node, | 877 | align_expr: ?*Node, |
| 792 | 878 | ||
| 793 | pub fn iterate(self: *ContainerField, index: usize) ?*Node { | 879 | pub fn iterate(self: *const ContainerField, index: usize) ?*Node { |
| 794 | var i = index; | 880 | var i = index; |
| 795 | 881 | ||
| 796 | if (self.type_expr) |type_expr| { | 882 | if (self.type_expr) |type_expr| { |
| ... | @@ -837,7 +923,7 @@ pub const Node = struct { | ... | @@ -837,7 +923,7 @@ pub const Node = struct { |
| 837 | doc_comments: ?*DocComment, | 923 | doc_comments: ?*DocComment, |
| 838 | name_token: TokenIndex, | 924 | name_token: TokenIndex, |
| 839 | 925 | ||
| 840 | pub fn iterate(self: *ErrorTag, index: usize) ?*Node { | 926 | pub fn iterate(self: *const ErrorTag, index: usize) ?*Node { |
| 841 | var i = index; | 927 | var i = index; |
| 842 | 928 | ||
| 843 | if (self.doc_comments) |comments| { | 929 | if (self.doc_comments) |comments| { |
| ... | @@ -861,7 +947,7 @@ pub const Node = struct { | ... | @@ -861,7 +947,7 @@ pub const Node = struct { |
| 861 | base: Node = Node{ .id = .Identifier }, | 947 | base: Node = Node{ .id = .Identifier }, |
| 862 | token: TokenIndex, | 948 | token: TokenIndex, |
| 863 | 949 | ||
| 864 | pub fn iterate(self: *Identifier, index: usize) ?*Node { | 950 | pub fn iterate(self: *const Identifier, index: usize) ?*Node { |
| 865 | return null; | 951 | return null; |
| 866 | } | 952 | } |
| 867 | 953 | ||
| ... | @@ -874,13 +960,14 @@ pub const Node = struct { | ... | @@ -874,13 +960,14 @@ pub const Node = struct { |
| 874 | } | 960 | } |
| 875 | }; | 961 | }; |
| 876 | 962 | ||
| 963 | /// The params are directly after the FnProto in memory. | ||
| 877 | pub const FnProto = struct { | 964 | pub const FnProto = struct { |
| 878 | base: Node = Node{ .id = .FnProto }, | 965 | base: Node = Node{ .id = .FnProto }, |
| 879 | doc_comments: ?*DocComment, | 966 | doc_comments: ?*DocComment, |
| 880 | visib_token: ?TokenIndex, | 967 | visib_token: ?TokenIndex, |
| 881 | fn_token: TokenIndex, | 968 | fn_token: TokenIndex, |
| 882 | name_token: ?TokenIndex, | 969 | name_token: ?TokenIndex, |
| 883 | params: ParamList, | 970 | params_len: NodeIndex, |
| 884 | return_type: ReturnType, | 971 | return_type: ReturnType, |
| 885 | var_args_token: ?TokenIndex, | 972 | var_args_token: ?TokenIndex, |
| 886 | extern_export_inline_token: ?TokenIndex, | 973 | extern_export_inline_token: ?TokenIndex, |
| ... | @@ -892,15 +979,69 @@ pub const Node = struct { | ... | @@ -892,15 +979,69 @@ pub const Node = struct { |
| 892 | is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is | 979 | is_extern_prototype: bool = false, // TODO: Remove once extern fn rewriting is |
| 893 | is_async: bool = false, // TODO: remove once async fn rewriting is | 980 | is_async: bool = false, // TODO: remove once async fn rewriting is |
| 894 | 981 | ||
| 895 | pub const ParamList = SegmentedList(*Node, 2); | ||
| 896 | |||
| 897 | pub const ReturnType = union(enum) { | 982 | pub const ReturnType = union(enum) { |
| 898 | Explicit: *Node, | 983 | Explicit: *Node, |
| 899 | InferErrorSet: *Node, | 984 | InferErrorSet: *Node, |
| 900 | Invalid: TokenIndex, | 985 | Invalid: TokenIndex, |
| 901 | }; | 986 | }; |
| 902 | 987 | ||
| 903 | pub fn iterate(self: *FnProto, index: usize) ?*Node { | 988 | pub const ParamDecl = struct { |
| 989 | doc_comments: ?*DocComment, | ||
| 990 | comptime_token: ?TokenIndex, | ||
| 991 | noalias_token: ?TokenIndex, | ||
| 992 | name_token: ?TokenIndex, | ||
| 993 | param_type: ParamType, | ||
| 994 | |||
| 995 | pub const ParamType = union(enum) { | ||
| 996 | var_type: *Node, | ||
| 997 | var_args: TokenIndex, | ||
| 998 | type_expr: *Node, | ||
| 999 | }; | ||
| 1000 | |||
| 1001 | pub fn iterate(self: *const ParamDecl, index: usize) ?*Node { | ||
| 1002 | var i = index; | ||
| 1003 | |||
| 1004 | if (i < 1) { | ||
| 1005 | switch (self.param_type) { | ||
| 1006 | .var_args => return null, | ||
| 1007 | .var_type, .type_expr => |node| return node, | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | i -= 1; | ||
| 1011 | |||
| 1012 | return null; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | pub fn firstToken(self: *const ParamDecl) TokenIndex { | ||
| 1016 | if (self.comptime_token) |comptime_token| return comptime_token; | ||
| 1017 | if (self.noalias_token) |noalias_token| return noalias_token; | ||
| 1018 | if (self.name_token) |name_token| return name_token; | ||
| 1019 | switch (self.param_type) { | ||
| 1020 | .var_args => |tok| return tok, | ||
| 1021 | .var_type, .type_expr => |node| return node.firstToken(), | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | pub fn lastToken(self: *const ParamDecl) TokenIndex { | ||
| 1026 | switch (self.param_type) { | ||
| 1027 | .var_args => |tok| return tok, | ||
| 1028 | .var_type, .type_expr => |node| return node.lastToken(), | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | }; | ||
| 1032 | |||
| 1033 | /// After this the caller must initialize the params list. | ||
| 1034 | pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*FnProto { | ||
| 1035 | const bytes = try allocator.alignedAlloc(u8, @alignOf(FnProto), sizeInBytes(params_len)); | ||
| 1036 | return @ptrCast(*FnProto, bytes.ptr); | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | pub fn free(self: *FnProto, allocator: *mem.Allocator) void { | ||
| 1040 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)]; | ||
| 1041 | allocator.free(bytes); | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | pub fn iterate(self: *const FnProto, index: usize) ?*Node { | ||
| 904 | var i = index; | 1045 | var i = index; |
| 905 | 1046 | ||
| 906 | if (self.lib_name) |lib_name| { | 1047 | if (self.lib_name) |lib_name| { |
| ... | @@ -908,8 +1049,18 @@ pub const Node = struct { | ... | @@ -908,8 +1049,18 @@ pub const Node = struct { |
| 908 | i -= 1; | 1049 | i -= 1; |
| 909 | } | 1050 | } |
| 910 | 1051 | ||
| 911 | if (i < self.params.len) return self.params.at(self.params.len - i - 1).*; | 1052 | const params_len = switch (self.paramsConst()[self.params_len - 1].param_type) { |
| 912 | i -= self.params.len; | 1053 | .var_type, .type_expr => self.params_len, |
| 1054 | .var_args => self.params_len - 1, | ||
| 1055 | }; | ||
| 1056 | if (i < params_len) { | ||
| 1057 | switch (self.paramsConst()[i].param_type) { | ||
| 1058 | .var_type => |n| return n, | ||
| 1059 | .var_args => unreachable, | ||
| 1060 | .type_expr => |n| return n, | ||
| 1061 | } | ||
| 1062 | } | ||
| 1063 | i -= params_len; | ||
| 913 | 1064 | ||
| 914 | if (self.align_expr) |align_expr| { | 1065 | if (self.align_expr) |align_expr| { |
| 915 | if (i < 1) return align_expr; | 1066 | if (i < 1) return align_expr; |
| ... | @@ -951,6 +1102,20 @@ pub const Node = struct { | ... | @@ -951,6 +1102,20 @@ pub const Node = struct { |
| 951 | .Invalid => |tok| return tok, | 1102 | .Invalid => |tok| return tok, |
| 952 | } | 1103 | } |
| 953 | } | 1104 | } |
| 1105 | |||
| 1106 | pub fn params(self: *FnProto) []ParamDecl { | ||
| 1107 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(FnProto); | ||
| 1108 | return @ptrCast([*]ParamDecl, decls_start)[0..self.params_len]; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | pub fn paramsConst(self: *const FnProto) []const ParamDecl { | ||
| 1112 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(FnProto); | ||
| 1113 | return @ptrCast([*]const ParamDecl, decls_start)[0..self.params_len]; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | fn sizeInBytes(params_len: NodeIndex) usize { | ||
| 1117 | return @sizeOf(FnProto) + @sizeOf(ParamDecl) * @as(usize, params_len); | ||
| 1118 | } | ||
| 954 | }; | 1119 | }; |
| 955 | 1120 | ||
| 956 | pub const AnyFrameType = struct { | 1121 | pub const AnyFrameType = struct { |
| ... | @@ -963,7 +1128,7 @@ pub const Node = struct { | ... | @@ -963,7 +1128,7 @@ pub const Node = struct { |
| 963 | return_type: *Node, | 1128 | return_type: *Node, |
| 964 | }; | 1129 | }; |
| 965 | 1130 | ||
| 966 | pub fn iterate(self: *AnyFrameType, index: usize) ?*Node { | 1131 | pub fn iterate(self: *const AnyFrameType, index: usize) ?*Node { |
| 967 | var i = index; | 1132 | var i = index; |
| 968 | 1133 | ||
| 969 | if (self.result) |result| { | 1134 | if (self.result) |result| { |
| ... | @@ -984,66 +1149,30 @@ pub const Node = struct { | ... | @@ -984,66 +1149,30 @@ pub const Node = struct { |
| 984 | } | 1149 | } |
| 985 | }; | 1150 | }; |
| 986 | 1151 | ||
| 987 | pub const ParamDecl = struct { | 1152 | /// The statements of the block follow Block directly in memory. |
| 988 | base: Node = Node{ .id = .ParamDecl }, | ||
| 989 | doc_comments: ?*DocComment, | ||
| 990 | comptime_token: ?TokenIndex, | ||
| 991 | noalias_token: ?TokenIndex, | ||
| 992 | name_token: ?TokenIndex, | ||
| 993 | param_type: ParamType, | ||
| 994 | |||
| 995 | pub const ParamType = union(enum) { | ||
| 996 | var_type: *Node, | ||
| 997 | var_args: TokenIndex, | ||
| 998 | type_expr: *Node, | ||
| 999 | }; | ||
| 1000 | |||
| 1001 | pub fn iterate(self: *ParamDecl, index: usize) ?*Node { | ||
| 1002 | var i = index; | ||
| 1003 | |||
| 1004 | if (i < 1) { | ||
| 1005 | switch (self.param_type) { | ||
| 1006 | .var_args => return null, | ||
| 1007 | .var_type, .type_expr => |node| return node, | ||
| 1008 | } | ||
| 1009 | } | ||
| 1010 | i -= 1; | ||
| 1011 | |||
| 1012 | return null; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | pub fn firstToken(self: *const ParamDecl) TokenIndex { | ||
| 1016 | if (self.comptime_token) |comptime_token| return comptime_token; | ||
| 1017 | if (self.noalias_token) |noalias_token| return noalias_token; | ||
| 1018 | if (self.name_token) |name_token| return name_token; | ||
| 1019 | switch (self.param_type) { | ||
| 1020 | .var_args => |tok| return tok, | ||
| 1021 | .var_type, .type_expr => |node| return node.firstToken(), | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | pub fn lastToken(self: *const ParamDecl) TokenIndex { | ||
| 1026 | switch (self.param_type) { | ||
| 1027 | .var_args => |tok| return tok, | ||
| 1028 | .var_type, .type_expr => |node| return node.lastToken(), | ||
| 1029 | } | ||
| 1030 | } | ||
| 1031 | }; | ||
| 1032 | |||
| 1033 | pub const Block = struct { | 1153 | pub const Block = struct { |
| 1034 | base: Node = Node{ .id = .Block }, | 1154 | base: Node = Node{ .id = .Block }, |
| 1035 | label: ?TokenIndex, | 1155 | statements_len: NodeIndex, |
| 1036 | lbrace: TokenIndex, | 1156 | lbrace: TokenIndex, |
| 1037 | statements: StatementList, | ||
| 1038 | rbrace: TokenIndex, | 1157 | rbrace: TokenIndex, |
| 1158 | label: ?TokenIndex, | ||
| 1159 | |||
| 1160 | /// After this the caller must initialize the statements list. | ||
| 1161 | pub fn alloc(allocator: *mem.Allocator, statements_len: NodeIndex) !*Block { | ||
| 1162 | const bytes = try allocator.alignedAlloc(u8, @alignOf(Block), sizeInBytes(statements_len)); | ||
| 1163 | return @ptrCast(*Block, bytes.ptr); | ||
| 1164 | } | ||
| 1039 | 1165 | ||
| 1040 | pub const StatementList = Root.DeclList; | 1166 | pub fn free(self: *Block, allocator: *mem.Allocator) void { |
| 1167 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.statements_len)]; | ||
| 1168 | allocator.free(bytes); | ||
| 1169 | } | ||
| 1041 | 1170 | ||
| 1042 | pub fn iterate(self: *Block, index: usize) ?*Node { | 1171 | pub fn iterate(self: *const Block, index: usize) ?*Node { |
| 1043 | var i = index; | 1172 | var i = index; |
| 1044 | 1173 | ||
| 1045 | if (i < self.statements.len) return self.statements.at(i).*; | 1174 | if (i < self.statements_len) return self.statementsConst()[i]; |
| 1046 | i -= self.statements.len; | 1175 | i -= self.statements_len; |
| 1047 | 1176 | ||
| 1048 | return null; | 1177 | return null; |
| 1049 | } | 1178 | } |
| ... | @@ -1059,6 +1188,20 @@ pub const Node = struct { | ... | @@ -1059,6 +1188,20 @@ pub const Node = struct { |
| 1059 | pub fn lastToken(self: *const Block) TokenIndex { | 1188 | pub fn lastToken(self: *const Block) TokenIndex { |
| 1060 | return self.rbrace; | 1189 | return self.rbrace; |
| 1061 | } | 1190 | } |
| 1191 | |||
| 1192 | pub fn statements(self: *Block) []*Node { | ||
| 1193 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(Block); | ||
| 1194 | return @ptrCast([*]*Node, decls_start)[0..self.statements_len]; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | pub fn statementsConst(self: *const Block) []const *Node { | ||
| 1198 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Block); | ||
| 1199 | return @ptrCast([*]const *Node, decls_start)[0..self.statements_len]; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | fn sizeInBytes(statements_len: NodeIndex) usize { | ||
| 1203 | return @sizeOf(Block) + @sizeOf(*Node) * @as(usize, statements_len); | ||
| 1204 | } | ||
| 1062 | }; | 1205 | }; |
| 1063 | 1206 | ||
| 1064 | pub const Defer = struct { | 1207 | pub const Defer = struct { |
| ... | @@ -1067,7 +1210,7 @@ pub const Node = struct { | ... | @@ -1067,7 +1210,7 @@ pub const Node = struct { |
| 1067 | payload: ?*Node, | 1210 | payload: ?*Node, |
| 1068 | expr: *Node, | 1211 | expr: *Node, |
| 1069 | 1212 | ||
| 1070 | pub fn iterate(self: *Defer, index: usize) ?*Node { | 1213 | pub fn iterate(self: *const Defer, index: usize) ?*Node { |
| 1071 | var i = index; | 1214 | var i = index; |
| 1072 | 1215 | ||
| 1073 | if (i < 1) return self.expr; | 1216 | if (i < 1) return self.expr; |
| ... | @@ -1091,7 +1234,7 @@ pub const Node = struct { | ... | @@ -1091,7 +1234,7 @@ pub const Node = struct { |
| 1091 | comptime_token: TokenIndex, | 1234 | comptime_token: TokenIndex, |
| 1092 | expr: *Node, | 1235 | expr: *Node, |
| 1093 | 1236 | ||
| 1094 | pub fn iterate(self: *Comptime, index: usize) ?*Node { | 1237 | pub fn iterate(self: *const Comptime, index: usize) ?*Node { |
| 1095 | var i = index; | 1238 | var i = index; |
| 1096 | 1239 | ||
| 1097 | if (i < 1) return self.expr; | 1240 | if (i < 1) return self.expr; |
| ... | @@ -1114,7 +1257,7 @@ pub const Node = struct { | ... | @@ -1114,7 +1257,7 @@ pub const Node = struct { |
| 1114 | nosuspend_token: TokenIndex, | 1257 | nosuspend_token: TokenIndex, |
| 1115 | expr: *Node, | 1258 | expr: *Node, |
| 1116 | 1259 | ||
| 1117 | pub fn iterate(self: *Nosuspend, index: usize) ?*Node { | 1260 | pub fn iterate(self: *const Nosuspend, index: usize) ?*Node { |
| 1118 | var i = index; | 1261 | var i = index; |
| 1119 | 1262 | ||
| 1120 | if (i < 1) return self.expr; | 1263 | if (i < 1) return self.expr; |
| ... | @@ -1138,7 +1281,7 @@ pub const Node = struct { | ... | @@ -1138,7 +1281,7 @@ pub const Node = struct { |
| 1138 | error_symbol: *Node, | 1281 | error_symbol: *Node, |
| 1139 | rpipe: TokenIndex, | 1282 | rpipe: TokenIndex, |
| 1140 | 1283 | ||
| 1141 | pub fn iterate(self: *Payload, index: usize) ?*Node { | 1284 | pub fn iterate(self: *const Payload, index: usize) ?*Node { |
| 1142 | var i = index; | 1285 | var i = index; |
| 1143 | 1286 | ||
| 1144 | if (i < 1) return self.error_symbol; | 1287 | if (i < 1) return self.error_symbol; |
| ... | @@ -1163,7 +1306,7 @@ pub const Node = struct { | ... | @@ -1163,7 +1306,7 @@ pub const Node = struct { |
| 1163 | value_symbol: *Node, | 1306 | value_symbol: *Node, |
| 1164 | rpipe: TokenIndex, | 1307 | rpipe: TokenIndex, |
| 1165 | 1308 | ||
| 1166 | pub fn iterate(self: *PointerPayload, index: usize) ?*Node { | 1309 | pub fn iterate(self: *const PointerPayload, index: usize) ?*Node { |
| 1167 | var i = index; | 1310 | var i = index; |
| 1168 | 1311 | ||
| 1169 | if (i < 1) return self.value_symbol; | 1312 | if (i < 1) return self.value_symbol; |
| ... | @@ -1189,7 +1332,7 @@ pub const Node = struct { | ... | @@ -1189,7 +1332,7 @@ pub const Node = struct { |
| 1189 | index_symbol: ?*Node, | 1332 | index_symbol: ?*Node, |
| 1190 | rpipe: TokenIndex, | 1333 | rpipe: TokenIndex, |
| 1191 | 1334 | ||
| 1192 | pub fn iterate(self: *PointerIndexPayload, index: usize) ?*Node { | 1335 | pub fn iterate(self: *const PointerIndexPayload, index: usize) ?*Node { |
| 1193 | var i = index; | 1336 | var i = index; |
| 1194 | 1337 | ||
| 1195 | if (i < 1) return self.value_symbol; | 1338 | if (i < 1) return self.value_symbol; |
| ... | @@ -1218,7 +1361,7 @@ pub const Node = struct { | ... | @@ -1218,7 +1361,7 @@ pub const Node = struct { |
| 1218 | payload: ?*Node, | 1361 | payload: ?*Node, |
| 1219 | body: *Node, | 1362 | body: *Node, |
| 1220 | 1363 | ||
| 1221 | pub fn iterate(self: *Else, index: usize) ?*Node { | 1364 | pub fn iterate(self: *const Else, index: usize) ?*Node { |
| 1222 | var i = index; | 1365 | var i = index; |
| 1223 | 1366 | ||
| 1224 | if (self.payload) |payload| { | 1367 | if (self.payload) |payload| { |
| ... | @@ -1241,25 +1384,34 @@ pub const Node = struct { | ... | @@ -1241,25 +1384,34 @@ pub const Node = struct { |
| 1241 | } | 1384 | } |
| 1242 | }; | 1385 | }; |
| 1243 | 1386 | ||
| 1387 | /// The cases node pointers are found in memory after Switch. | ||
| 1388 | /// They must be SwitchCase or SwitchElse nodes. | ||
| 1244 | pub const Switch = struct { | 1389 | pub const Switch = struct { |
| 1245 | base: Node = Node{ .id = .Switch }, | 1390 | base: Node = Node{ .id = .Switch }, |
| 1246 | switch_token: TokenIndex, | 1391 | switch_token: TokenIndex, |
| 1392 | rbrace: TokenIndex, | ||
| 1393 | cases_len: NodeIndex, | ||
| 1247 | expr: *Node, | 1394 | expr: *Node, |
| 1248 | 1395 | ||
| 1249 | /// these must be SwitchCase nodes | 1396 | /// After this the caller must initialize the fields_and_decls list. |
| 1250 | cases: CaseList, | 1397 | pub fn alloc(allocator: *mem.Allocator, cases_len: NodeIndex) !*Switch { |
| 1251 | rbrace: TokenIndex, | 1398 | const bytes = try allocator.alignedAlloc(u8, @alignOf(Switch), sizeInBytes(cases_len)); |
| 1399 | return @ptrCast(*Switch, bytes.ptr); | ||
| 1400 | } | ||
| 1252 | 1401 | ||
| 1253 | pub const CaseList = SegmentedList(*Node, 2); | 1402 | pub fn free(self: *Switch, allocator: *mem.Allocator) void { |
| 1403 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.cases_len)]; | ||
| 1404 | allocator.free(bytes); | ||
| 1405 | } | ||
| 1254 | 1406 | ||
| 1255 | pub fn iterate(self: *Switch, index: usize) ?*Node { | 1407 | pub fn iterate(self: *const Switch, index: usize) ?*Node { |
| 1256 | var i = index; | 1408 | var i = index; |
| 1257 | 1409 | ||
| 1258 | if (i < 1) return self.expr; | 1410 | if (i < 1) return self.expr; |
| 1259 | i -= 1; | 1411 | i -= 1; |
| 1260 | 1412 | ||
| 1261 | if (i < self.cases.len) return self.cases.at(i).*; | 1413 | if (i < self.cases_len) return self.casesConst()[i]; |
| 1262 | i -= self.cases.len; | 1414 | i -= self.cases_len; |
| 1263 | 1415 | ||
| 1264 | return null; | 1416 | return null; |
| 1265 | } | 1417 | } |
| ... | @@ -1271,22 +1423,46 @@ pub const Node = struct { | ... | @@ -1271,22 +1423,46 @@ pub const Node = struct { |
| 1271 | pub fn lastToken(self: *const Switch) TokenIndex { | 1423 | pub fn lastToken(self: *const Switch) TokenIndex { |
| 1272 | return self.rbrace; | 1424 | return self.rbrace; |
| 1273 | } | 1425 | } |
| 1426 | |||
| 1427 | pub fn cases(self: *Switch) []*Node { | ||
| 1428 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(Switch); | ||
| 1429 | return @ptrCast([*]*Node, decls_start)[0..self.cases_len]; | ||
| 1430 | } | ||
| 1431 | |||
| 1432 | pub fn casesConst(self: *const Switch) []const *Node { | ||
| 1433 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Switch); | ||
| 1434 | return @ptrCast([*]const *Node, decls_start)[0..self.cases_len]; | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | fn sizeInBytes(cases_len: NodeIndex) usize { | ||
| 1438 | return @sizeOf(Switch) + @sizeOf(*Node) * @as(usize, cases_len); | ||
| 1439 | } | ||
| 1274 | }; | 1440 | }; |
| 1275 | 1441 | ||
| 1442 | /// Items sub-nodes appear in memory directly following SwitchCase. | ||
| 1276 | pub const SwitchCase = struct { | 1443 | pub const SwitchCase = struct { |
| 1277 | base: Node = Node{ .id = .SwitchCase }, | 1444 | base: Node = Node{ .id = .SwitchCase }, |
| 1278 | items: ItemList, | ||
| 1279 | arrow_token: TokenIndex, | 1445 | arrow_token: TokenIndex, |
| 1280 | payload: ?*Node, | 1446 | payload: ?*Node, |
| 1281 | expr: *Node, | 1447 | expr: *Node, |
| 1448 | items_len: NodeIndex, | ||
| 1282 | 1449 | ||
| 1283 | pub const ItemList = SegmentedList(*Node, 1); | 1450 | /// After this the caller must initialize the fields_and_decls list. |
| 1451 | pub fn alloc(allocator: *mem.Allocator, items_len: NodeIndex) !*SwitchCase { | ||
| 1452 | const bytes = try allocator.alignedAlloc(u8, @alignOf(SwitchCase), sizeInBytes(items_len)); | ||
| 1453 | return @ptrCast(*SwitchCase, bytes.ptr); | ||
| 1454 | } | ||
| 1455 | |||
| 1456 | pub fn free(self: *SwitchCase, allocator: *mem.Allocator) void { | ||
| 1457 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.items_len)]; | ||
| 1458 | allocator.free(bytes); | ||
| 1459 | } | ||
| 1284 | 1460 | ||
| 1285 | pub fn iterate(self: *SwitchCase, index: usize) ?*Node { | 1461 | pub fn iterate(self: *const SwitchCase, index: usize) ?*Node { |
| 1286 | var i = index; | 1462 | var i = index; |
| 1287 | 1463 | ||
| 1288 | if (i < self.items.len) return self.items.at(i).*; | 1464 | if (i < self.items_len) return self.itemsConst()[i]; |
| 1289 | i -= self.items.len; | 1465 | i -= self.items_len; |
| 1290 | 1466 | ||
| 1291 | if (self.payload) |payload| { | 1467 | if (self.payload) |payload| { |
| 1292 | if (i < 1) return payload; | 1468 | if (i < 1) return payload; |
| ... | @@ -1300,19 +1476,33 @@ pub const Node = struct { | ... | @@ -1300,19 +1476,33 @@ pub const Node = struct { |
| 1300 | } | 1476 | } |
| 1301 | 1477 | ||
| 1302 | pub fn firstToken(self: *const SwitchCase) TokenIndex { | 1478 | pub fn firstToken(self: *const SwitchCase) TokenIndex { |
| 1303 | return (self.items.at(0).*).firstToken(); | 1479 | return self.itemsConst()[0].firstToken(); |
| 1304 | } | 1480 | } |
| 1305 | 1481 | ||
| 1306 | pub fn lastToken(self: *const SwitchCase) TokenIndex { | 1482 | pub fn lastToken(self: *const SwitchCase) TokenIndex { |
| 1307 | return self.expr.lastToken(); | 1483 | return self.expr.lastToken(); |
| 1308 | } | 1484 | } |
| 1485 | |||
| 1486 | pub fn items(self: *SwitchCase) []*Node { | ||
| 1487 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(SwitchCase); | ||
| 1488 | return @ptrCast([*]*Node, decls_start)[0..self.items_len]; | ||
| 1489 | } | ||
| 1490 | |||
| 1491 | pub fn itemsConst(self: *const SwitchCase) []const *Node { | ||
| 1492 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(SwitchCase); | ||
| 1493 | return @ptrCast([*]const *Node, decls_start)[0..self.items_len]; | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | fn sizeInBytes(items_len: NodeIndex) usize { | ||
| 1497 | return @sizeOf(SwitchCase) + @sizeOf(*Node) * @as(usize, items_len); | ||
| 1498 | } | ||
| 1309 | }; | 1499 | }; |
| 1310 | 1500 | ||
| 1311 | pub const SwitchElse = struct { | 1501 | pub const SwitchElse = struct { |
| 1312 | base: Node = Node{ .id = .SwitchElse }, | 1502 | base: Node = Node{ .id = .SwitchElse }, |
| 1313 | token: TokenIndex, | 1503 | token: TokenIndex, |
| 1314 | 1504 | ||
| 1315 | pub fn iterate(self: *SwitchElse, index: usize) ?*Node { | 1505 | pub fn iterate(self: *const SwitchElse, index: usize) ?*Node { |
| 1316 | return null; | 1506 | return null; |
| 1317 | } | 1507 | } |
| 1318 | 1508 | ||
| ... | @@ -1336,7 +1526,7 @@ pub const Node = struct { | ... | @@ -1336,7 +1526,7 @@ pub const Node = struct { |
| 1336 | body: *Node, | 1526 | body: *Node, |
| 1337 | @"else": ?*Else, | 1527 | @"else": ?*Else, |
| 1338 | 1528 | ||
| 1339 | pub fn iterate(self: *While, index: usize) ?*Node { | 1529 | pub fn iterate(self: *const While, index: usize) ?*Node { |
| 1340 | var i = index; | 1530 | var i = index; |
| 1341 | 1531 | ||
| 1342 | if (i < 1) return self.condition; | 1532 | if (i < 1) return self.condition; |
| ... | @@ -1394,7 +1584,7 @@ pub const Node = struct { | ... | @@ -1394,7 +1584,7 @@ pub const Node = struct { |
| 1394 | body: *Node, | 1584 | body: *Node, |
| 1395 | @"else": ?*Else, | 1585 | @"else": ?*Else, |
| 1396 | 1586 | ||
| 1397 | pub fn iterate(self: *For, index: usize) ?*Node { | 1587 | pub fn iterate(self: *const For, index: usize) ?*Node { |
| 1398 | var i = index; | 1588 | var i = index; |
| 1399 | 1589 | ||
| 1400 | if (i < 1) return self.array_expr; | 1590 | if (i < 1) return self.array_expr; |
| ... | @@ -1443,7 +1633,7 @@ pub const Node = struct { | ... | @@ -1443,7 +1633,7 @@ pub const Node = struct { |
| 1443 | body: *Node, | 1633 | body: *Node, |
| 1444 | @"else": ?*Else, | 1634 | @"else": ?*Else, |
| 1445 | 1635 | ||
| 1446 | pub fn iterate(self: *If, index: usize) ?*Node { | 1636 | pub fn iterate(self: *const If, index: usize) ?*Node { |
| 1447 | var i = index; | 1637 | var i = index; |
| 1448 | 1638 | ||
| 1449 | if (i < 1) return self.condition; | 1639 | if (i < 1) return self.condition; |
| ... | @@ -1531,7 +1721,7 @@ pub const Node = struct { | ... | @@ -1531,7 +1721,7 @@ pub const Node = struct { |
| 1531 | UnwrapOptional, | 1721 | UnwrapOptional, |
| 1532 | }; | 1722 | }; |
| 1533 | 1723 | ||
| 1534 | pub fn iterate(self: *InfixOp, index: usize) ?*Node { | 1724 | pub fn iterate(self: *const InfixOp, index: usize) ?*Node { |
| 1535 | var i = index; | 1725 | var i = index; |
| 1536 | 1726 | ||
| 1537 | if (i < 1) return self.lhs; | 1727 | if (i < 1) return self.lhs; |
| ... | @@ -1649,7 +1839,7 @@ pub const Node = struct { | ... | @@ -1649,7 +1839,7 @@ pub const Node = struct { |
| 1649 | }; | 1839 | }; |
| 1650 | }; | 1840 | }; |
| 1651 | 1841 | ||
| 1652 | pub fn iterate(self: *PrefixOp, index: usize) ?*Node { | 1842 | pub fn iterate(self: *const PrefixOp, index: usize) ?*Node { |
| 1653 | var i = index; | 1843 | var i = index; |
| 1654 | 1844 | ||
| 1655 | switch (self.op) { | 1845 | switch (self.op) { |
| ... | @@ -1707,7 +1897,7 @@ pub const Node = struct { | ... | @@ -1707,7 +1897,7 @@ pub const Node = struct { |
| 1707 | name_token: TokenIndex, | 1897 | name_token: TokenIndex, |
| 1708 | expr: *Node, | 1898 | expr: *Node, |
| 1709 | 1899 | ||
| 1710 | pub fn iterate(self: *FieldInitializer, index: usize) ?*Node { | 1900 | pub fn iterate(self: *const FieldInitializer, index: usize) ?*Node { |
| 1711 | var i = index; | 1901 | var i = index; |
| 1712 | 1902 | ||
| 1713 | if (i < 1) return self.expr; | 1903 | if (i < 1) return self.expr; |
| ... | @@ -1725,35 +1915,279 @@ pub const Node = struct { | ... | @@ -1725,35 +1915,279 @@ pub const Node = struct { |
| 1725 | } | 1915 | } |
| 1726 | }; | 1916 | }; |
| 1727 | 1917 | ||
| 1918 | /// Elements occur directly in memory after ArrayInitializer. | ||
| 1919 | pub const ArrayInitializer = struct { | ||
| 1920 | base: Node = Node{ .id = .ArrayInitializer }, | ||
| 1921 | rtoken: TokenIndex, | ||
| 1922 | list_len: NodeIndex, | ||
| 1923 | lhs: *Node, | ||
| 1924 | |||
| 1925 | /// After this the caller must initialize the fields_and_decls list. | ||
| 1926 | pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*ArrayInitializer { | ||
| 1927 | const bytes = try allocator.alignedAlloc(u8, @alignOf(ArrayInitializer), sizeInBytes(list_len)); | ||
| 1928 | return @ptrCast(*ArrayInitializer, bytes.ptr); | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | pub fn free(self: *ArrayInitializer, allocator: *mem.Allocator) void { | ||
| 1932 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)]; | ||
| 1933 | allocator.free(bytes); | ||
| 1934 | } | ||
| 1935 | |||
| 1936 | pub fn iterate(self: *const ArrayInitializer, index: usize) ?*Node { | ||
| 1937 | var i = index; | ||
| 1938 | |||
| 1939 | if (i < 1) return self.lhs; | ||
| 1940 | i -= 1; | ||
| 1941 | |||
| 1942 | if (i < self.list_len) return self.listConst()[i]; | ||
| 1943 | i -= self.list_len; | ||
| 1944 | |||
| 1945 | return null; | ||
| 1946 | } | ||
| 1947 | |||
| 1948 | pub fn firstToken(self: *const ArrayInitializer) TokenIndex { | ||
| 1949 | return self.lhs.firstToken(); | ||
| 1950 | } | ||
| 1951 | |||
| 1952 | pub fn lastToken(self: *const ArrayInitializer) TokenIndex { | ||
| 1953 | return self.rtoken; | ||
| 1954 | } | ||
| 1955 | |||
| 1956 | pub fn list(self: *ArrayInitializer) []*Node { | ||
| 1957 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(ArrayInitializer); | ||
| 1958 | return @ptrCast([*]*Node, decls_start)[0..self.list_len]; | ||
| 1959 | } | ||
| 1960 | |||
| 1961 | pub fn listConst(self: *const ArrayInitializer) []const *Node { | ||
| 1962 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ArrayInitializer); | ||
| 1963 | return @ptrCast([*]const *Node, decls_start)[0..self.list_len]; | ||
| 1964 | } | ||
| 1965 | |||
| 1966 | fn sizeInBytes(list_len: NodeIndex) usize { | ||
| 1967 | return @sizeOf(ArrayInitializer) + @sizeOf(*Node) * @as(usize, list_len); | ||
| 1968 | } | ||
| 1969 | }; | ||
| 1970 | |||
| 1971 | /// Elements occur directly in memory after ArrayInitializerDot. | ||
| 1972 | pub const ArrayInitializerDot = struct { | ||
| 1973 | base: Node = Node{ .id = .ArrayInitializerDot }, | ||
| 1974 | dot: TokenIndex, | ||
| 1975 | rtoken: TokenIndex, | ||
| 1976 | list_len: NodeIndex, | ||
| 1977 | |||
| 1978 | /// After this the caller must initialize the fields_and_decls list. | ||
| 1979 | pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*ArrayInitializerDot { | ||
| 1980 | const bytes = try allocator.alignedAlloc(u8, @alignOf(ArrayInitializerDot), sizeInBytes(list_len)); | ||
| 1981 | return @ptrCast(*ArrayInitializerDot, bytes.ptr); | ||
| 1982 | } | ||
| 1983 | |||
| 1984 | pub fn free(self: *ArrayInitializerDot, allocator: *mem.Allocator) void { | ||
| 1985 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)]; | ||
| 1986 | allocator.free(bytes); | ||
| 1987 | } | ||
| 1988 | |||
| 1989 | pub fn iterate(self: *const ArrayInitializerDot, index: usize) ?*Node { | ||
| 1990 | var i = index; | ||
| 1991 | |||
| 1992 | if (i < self.list_len) return self.listConst()[i]; | ||
| 1993 | i -= self.list_len; | ||
| 1994 | |||
| 1995 | return null; | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | pub fn firstToken(self: *const ArrayInitializerDot) TokenIndex { | ||
| 1999 | return self.dot; | ||
| 2000 | } | ||
| 2001 | |||
| 2002 | pub fn lastToken(self: *const ArrayInitializerDot) TokenIndex { | ||
| 2003 | return self.rtoken; | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | pub fn list(self: *ArrayInitializerDot) []*Node { | ||
| 2007 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(ArrayInitializerDot); | ||
| 2008 | return @ptrCast([*]*Node, decls_start)[0..self.list_len]; | ||
| 2009 | } | ||
| 2010 | |||
| 2011 | pub fn listConst(self: *const ArrayInitializerDot) []const *Node { | ||
| 2012 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(ArrayInitializerDot); | ||
| 2013 | return @ptrCast([*]const *Node, decls_start)[0..self.list_len]; | ||
| 2014 | } | ||
| 2015 | |||
| 2016 | fn sizeInBytes(list_len: NodeIndex) usize { | ||
| 2017 | return @sizeOf(ArrayInitializerDot) + @sizeOf(*Node) * @as(usize, list_len); | ||
| 2018 | } | ||
| 2019 | }; | ||
| 2020 | |||
| 2021 | /// Elements occur directly in memory after StructInitializer. | ||
| 2022 | pub const StructInitializer = struct { | ||
| 2023 | base: Node = Node{ .id = .StructInitializer }, | ||
| 2024 | rtoken: TokenIndex, | ||
| 2025 | list_len: NodeIndex, | ||
| 2026 | lhs: *Node, | ||
| 2027 | |||
| 2028 | /// After this the caller must initialize the fields_and_decls list. | ||
| 2029 | pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*StructInitializer { | ||
| 2030 | const bytes = try allocator.alignedAlloc(u8, @alignOf(StructInitializer), sizeInBytes(list_len)); | ||
| 2031 | return @ptrCast(*StructInitializer, bytes.ptr); | ||
| 2032 | } | ||
| 2033 | |||
| 2034 | pub fn free(self: *StructInitializer, allocator: *mem.Allocator) void { | ||
| 2035 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)]; | ||
| 2036 | allocator.free(bytes); | ||
| 2037 | } | ||
| 2038 | |||
| 2039 | pub fn iterate(self: *const StructInitializer, index: usize) ?*Node { | ||
| 2040 | var i = index; | ||
| 2041 | |||
| 2042 | if (i < 1) return self.lhs; | ||
| 2043 | i -= 1; | ||
| 2044 | |||
| 2045 | if (i < self.list_len) return self.listConst()[i]; | ||
| 2046 | i -= self.list_len; | ||
| 2047 | |||
| 2048 | return null; | ||
| 2049 | } | ||
| 2050 | |||
| 2051 | pub fn firstToken(self: *const StructInitializer) TokenIndex { | ||
| 2052 | return self.lhs.firstToken(); | ||
| 2053 | } | ||
| 2054 | |||
| 2055 | pub fn lastToken(self: *const StructInitializer) TokenIndex { | ||
| 2056 | return self.rtoken; | ||
| 2057 | } | ||
| 2058 | |||
| 2059 | pub fn list(self: *StructInitializer) []*Node { | ||
| 2060 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(StructInitializer); | ||
| 2061 | return @ptrCast([*]*Node, decls_start)[0..self.list_len]; | ||
| 2062 | } | ||
| 2063 | |||
| 2064 | pub fn listConst(self: *const StructInitializer) []const *Node { | ||
| 2065 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(StructInitializer); | ||
| 2066 | return @ptrCast([*]const *Node, decls_start)[0..self.list_len]; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | fn sizeInBytes(list_len: NodeIndex) usize { | ||
| 2070 | return @sizeOf(StructInitializer) + @sizeOf(*Node) * @as(usize, list_len); | ||
| 2071 | } | ||
| 2072 | }; | ||
| 2073 | |||
| 2074 | /// Elements occur directly in memory after StructInitializerDot. | ||
| 2075 | pub const StructInitializerDot = struct { | ||
| 2076 | base: Node = Node{ .id = .StructInitializerDot }, | ||
| 2077 | dot: TokenIndex, | ||
| 2078 | rtoken: TokenIndex, | ||
| 2079 | list_len: NodeIndex, | ||
| 2080 | |||
| 2081 | /// After this the caller must initialize the fields_and_decls list. | ||
| 2082 | pub fn alloc(allocator: *mem.Allocator, list_len: NodeIndex) !*StructInitializerDot { | ||
| 2083 | const bytes = try allocator.alignedAlloc(u8, @alignOf(StructInitializerDot), sizeInBytes(list_len)); | ||
| 2084 | return @ptrCast(*StructInitializerDot, bytes.ptr); | ||
| 2085 | } | ||
| 2086 | |||
| 2087 | pub fn free(self: *StructInitializerDot, allocator: *mem.Allocator) void { | ||
| 2088 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.list_len)]; | ||
| 2089 | allocator.free(bytes); | ||
| 2090 | } | ||
| 2091 | |||
| 2092 | pub fn iterate(self: *const StructInitializerDot, index: usize) ?*Node { | ||
| 2093 | var i = index; | ||
| 2094 | |||
| 2095 | if (i < self.list_len) return self.listConst()[i]; | ||
| 2096 | i -= self.list_len; | ||
| 2097 | |||
| 2098 | return null; | ||
| 2099 | } | ||
| 2100 | |||
| 2101 | pub fn firstToken(self: *const StructInitializerDot) TokenIndex { | ||
| 2102 | return self.dot; | ||
| 2103 | } | ||
| 2104 | |||
| 2105 | pub fn lastToken(self: *const StructInitializerDot) TokenIndex { | ||
| 2106 | return self.rtoken; | ||
| 2107 | } | ||
| 2108 | |||
| 2109 | pub fn list(self: *StructInitializerDot) []*Node { | ||
| 2110 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(StructInitializerDot); | ||
| 2111 | return @ptrCast([*]*Node, decls_start)[0..self.list_len]; | ||
| 2112 | } | ||
| 2113 | |||
| 2114 | pub fn listConst(self: *const StructInitializerDot) []const *Node { | ||
| 2115 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(StructInitializerDot); | ||
| 2116 | return @ptrCast([*]const *Node, decls_start)[0..self.list_len]; | ||
| 2117 | } | ||
| 2118 | |||
| 2119 | fn sizeInBytes(list_len: NodeIndex) usize { | ||
| 2120 | return @sizeOf(StructInitializerDot) + @sizeOf(*Node) * @as(usize, list_len); | ||
| 2121 | } | ||
| 2122 | }; | ||
| 2123 | |||
| 2124 | /// Parameter nodes directly follow Call in memory. | ||
| 2125 | pub const Call = struct { | ||
| 2126 | base: Node = Node{ .id = .Call }, | ||
| 2127 | lhs: *Node, | ||
| 2128 | rtoken: TokenIndex, | ||
| 2129 | params_len: NodeIndex, | ||
| 2130 | async_token: ?TokenIndex, | ||
| 2131 | |||
| 2132 | /// After this the caller must initialize the fields_and_decls list. | ||
| 2133 | pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*Call { | ||
| 2134 | const bytes = try allocator.alignedAlloc(u8, @alignOf(Call), sizeInBytes(params_len)); | ||
| 2135 | return @ptrCast(*Call, bytes.ptr); | ||
| 2136 | } | ||
| 2137 | |||
| 2138 | pub fn free(self: *Call, allocator: *mem.Allocator) void { | ||
| 2139 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)]; | ||
| 2140 | allocator.free(bytes); | ||
| 2141 | } | ||
| 2142 | |||
| 2143 | pub fn iterate(self: *const Call, index: usize) ?*Node { | ||
| 2144 | var i = index; | ||
| 2145 | |||
| 2146 | if (i < 1) return self.lhs; | ||
| 2147 | i -= 1; | ||
| 2148 | |||
| 2149 | if (i < self.params_len) return self.paramsConst()[i]; | ||
| 2150 | i -= self.params_len; | ||
| 2151 | |||
| 2152 | return null; | ||
| 2153 | } | ||
| 2154 | |||
| 2155 | pub fn firstToken(self: *const Call) TokenIndex { | ||
| 2156 | if (self.async_token) |async_token| return async_token; | ||
| 2157 | return self.lhs.firstToken(); | ||
| 2158 | } | ||
| 2159 | |||
| 2160 | pub fn lastToken(self: *const Call) TokenIndex { | ||
| 2161 | return self.rtoken; | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | pub fn params(self: *Call) []*Node { | ||
| 2165 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(Call); | ||
| 2166 | return @ptrCast([*]*Node, decls_start)[0..self.params_len]; | ||
| 2167 | } | ||
| 2168 | |||
| 2169 | pub fn paramsConst(self: *const Call) []const *Node { | ||
| 2170 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(Call); | ||
| 2171 | return @ptrCast([*]const *Node, decls_start)[0..self.params_len]; | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | fn sizeInBytes(params_len: NodeIndex) usize { | ||
| 2175 | return @sizeOf(Call) + @sizeOf(*Node) * @as(usize, params_len); | ||
| 2176 | } | ||
| 2177 | }; | ||
| 2178 | |||
| 1728 | pub const SuffixOp = struct { | 2179 | pub const SuffixOp = struct { |
| 1729 | base: Node = Node{ .id = .SuffixOp }, | 2180 | base: Node = Node{ .id = .SuffixOp }, |
| 1730 | lhs: Lhs, | ||
| 1731 | op: Op, | 2181 | op: Op, |
| 2182 | lhs: *Node, | ||
| 1732 | rtoken: TokenIndex, | 2183 | rtoken: TokenIndex, |
| 1733 | 2184 | ||
| 1734 | pub const Lhs = union(enum) { | ||
| 1735 | node: *Node, | ||
| 1736 | dot: TokenIndex, | ||
| 1737 | }; | ||
| 1738 | |||
| 1739 | pub const Op = union(enum) { | 2185 | pub const Op = union(enum) { |
| 1740 | Call: Call, | ||
| 1741 | ArrayAccess: *Node, | 2186 | ArrayAccess: *Node, |
| 1742 | Slice: Slice, | 2187 | Slice: Slice, |
| 1743 | ArrayInitializer: InitList, | ||
| 1744 | StructInitializer: InitList, | ||
| 1745 | Deref, | 2188 | Deref, |
| 1746 | UnwrapOptional, | 2189 | UnwrapOptional, |
| 1747 | 2190 | ||
| 1748 | pub const InitList = SegmentedList(*Node, 2); | ||
| 1749 | |||
| 1750 | pub const Call = struct { | ||
| 1751 | params: ParamList, | ||
| 1752 | async_token: ?TokenIndex, | ||
| 1753 | |||
| 1754 | pub const ParamList = SegmentedList(*Node, 2); | ||
| 1755 | }; | ||
| 1756 | |||
| 1757 | pub const Slice = struct { | 2191 | pub const Slice = struct { |
| 1758 | start: *Node, | 2192 | start: *Node, |
| 1759 | end: ?*Node, | 2193 | end: ?*Node, |
| ... | @@ -1761,22 +2195,13 @@ pub const Node = struct { | ... | @@ -1761,22 +2195,13 @@ pub const Node = struct { |
| 1761 | }; | 2195 | }; |
| 1762 | }; | 2196 | }; |
| 1763 | 2197 | ||
| 1764 | pub fn iterate(self: *SuffixOp, index: usize) ?*Node { | 2198 | pub fn iterate(self: *const SuffixOp, index: usize) ?*Node { |
| 1765 | var i = index; | 2199 | var i = index; |
| 1766 | 2200 | ||
| 1767 | switch (self.lhs) { | 2201 | if (i == 0) return self.lhs; |
| 1768 | .node => |node| { | 2202 | i -= 1; |
| 1769 | if (i == 0) return node; | ||
| 1770 | i -= 1; | ||
| 1771 | }, | ||
| 1772 | .dot => {}, | ||
| 1773 | } | ||
| 1774 | 2203 | ||
| 1775 | switch (self.op) { | 2204 | switch (self.op) { |
| 1776 | .Call => |*call_info| { | ||
| 1777 | if (i < call_info.params.len) return call_info.params.at(i).*; | ||
| 1778 | i -= call_info.params.len; | ||
| 1779 | }, | ||
| 1780 | .ArrayAccess => |index_expr| { | 2205 | .ArrayAccess => |index_expr| { |
| 1781 | if (i < 1) return index_expr; | 2206 | if (i < 1) return index_expr; |
| 1782 | i -= 1; | 2207 | i -= 1; |
| ... | @@ -1794,14 +2219,6 @@ pub const Node = struct { | ... | @@ -1794,14 +2219,6 @@ pub const Node = struct { |
| 1794 | i -= 1; | 2219 | i -= 1; |
| 1795 | } | 2220 | } |
| 1796 | }, | 2221 | }, |
| 1797 | .ArrayInitializer => |*exprs| { | ||
| 1798 | if (i < exprs.len) return exprs.at(i).*; | ||
| 1799 | i -= exprs.len; | ||
| 1800 | }, | ||
| 1801 | .StructInitializer => |*fields| { | ||
| 1802 | if (i < fields.len) return fields.at(i).*; | ||
| 1803 | i -= fields.len; | ||
| 1804 | }, | ||
| 1805 | .UnwrapOptional, | 2222 | .UnwrapOptional, |
| 1806 | .Deref, | 2223 | .Deref, |
| 1807 | => {}, | 2224 | => {}, |
| ... | @@ -1811,14 +2228,7 @@ pub const Node = struct { | ... | @@ -1811,14 +2228,7 @@ pub const Node = struct { |
| 1811 | } | 2228 | } |
| 1812 | 2229 | ||
| 1813 | pub fn firstToken(self: *const SuffixOp) TokenIndex { | 2230 | pub fn firstToken(self: *const SuffixOp) TokenIndex { |
| 1814 | switch (self.op) { | 2231 | return self.lhs.firstToken(); |
| 1815 | .Call => |*call_info| if (call_info.async_token) |async_token| return async_token, | ||
| 1816 | else => {}, | ||
| 1817 | } | ||
| 1818 | switch (self.lhs) { | ||
| 1819 | .node => |node| return node.firstToken(), | ||
| 1820 | .dot => |dot| return dot, | ||
| 1821 | } | ||
| 1822 | } | 2232 | } |
| 1823 | 2233 | ||
| 1824 | pub fn lastToken(self: *const SuffixOp) TokenIndex { | 2234 | pub fn lastToken(self: *const SuffixOp) TokenIndex { |
| ... | @@ -1832,7 +2242,7 @@ pub const Node = struct { | ... | @@ -1832,7 +2242,7 @@ pub const Node = struct { |
| 1832 | expr: *Node, | 2242 | expr: *Node, |
| 1833 | rparen: TokenIndex, | 2243 | rparen: TokenIndex, |
| 1834 | 2244 | ||
| 1835 | pub fn iterate(self: *GroupedExpression, index: usize) ?*Node { | 2245 | pub fn iterate(self: *const GroupedExpression, index: usize) ?*Node { |
| 1836 | var i = index; | 2246 | var i = index; |
| 1837 | 2247 | ||
| 1838 | if (i < 1) return self.expr; | 2248 | if (i < 1) return self.expr; |
| ... | @@ -1862,7 +2272,7 @@ pub const Node = struct { | ... | @@ -1862,7 +2272,7 @@ pub const Node = struct { |
| 1862 | Return, | 2272 | Return, |
| 1863 | }; | 2273 | }; |
| 1864 | 2274 | ||
| 1865 | pub fn iterate(self: *ControlFlowExpression, index: usize) ?*Node { | 2275 | pub fn iterate(self: *const ControlFlowExpression, index: usize) ?*Node { |
| 1866 | var i = index; | 2276 | var i = index; |
| 1867 | 2277 | ||
| 1868 | switch (self.kind) { | 2278 | switch (self.kind) { |
| ... | @@ -1910,7 +2320,7 @@ pub const Node = struct { | ... | @@ -1910,7 +2320,7 @@ pub const Node = struct { |
| 1910 | suspend_token: TokenIndex, | 2320 | suspend_token: TokenIndex, |
| 1911 | body: ?*Node, | 2321 | body: ?*Node, |
| 1912 | 2322 | ||
| 1913 | pub fn iterate(self: *Suspend, index: usize) ?*Node { | 2323 | pub fn iterate(self: *const Suspend, index: usize) ?*Node { |
| 1914 | var i = index; | 2324 | var i = index; |
| 1915 | 2325 | ||
| 1916 | if (self.body) |body| { | 2326 | if (self.body) |body| { |
| ... | @@ -1938,7 +2348,7 @@ pub const Node = struct { | ... | @@ -1938,7 +2348,7 @@ pub const Node = struct { |
| 1938 | base: Node = Node{ .id = .IntegerLiteral }, | 2348 | base: Node = Node{ .id = .IntegerLiteral }, |
| 1939 | token: TokenIndex, | 2349 | token: TokenIndex, |
| 1940 | 2350 | ||
| 1941 | pub fn iterate(self: *IntegerLiteral, index: usize) ?*Node { | 2351 | pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node { |
| 1942 | return null; | 2352 | return null; |
| 1943 | } | 2353 | } |
| 1944 | 2354 | ||
| ... | @@ -1956,7 +2366,7 @@ pub const Node = struct { | ... | @@ -1956,7 +2366,7 @@ pub const Node = struct { |
| 1956 | dot: TokenIndex, | 2366 | dot: TokenIndex, |
| 1957 | name: TokenIndex, | 2367 | name: TokenIndex, |
| 1958 | 2368 | ||
| 1959 | pub fn iterate(self: *EnumLiteral, index: usize) ?*Node { | 2369 | pub fn iterate(self: *const EnumLiteral, index: usize) ?*Node { |
| 1960 | return null; | 2370 | return null; |
| 1961 | } | 2371 | } |
| 1962 | 2372 | ||
| ... | @@ -1973,7 +2383,7 @@ pub const Node = struct { | ... | @@ -1973,7 +2383,7 @@ pub const Node = struct { |
| 1973 | base: Node = Node{ .id = .FloatLiteral }, | 2383 | base: Node = Node{ .id = .FloatLiteral }, |
| 1974 | token: TokenIndex, | 2384 | token: TokenIndex, |
| 1975 | 2385 | ||
| 1976 | pub fn iterate(self: *FloatLiteral, index: usize) ?*Node { | 2386 | pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node { |
| 1977 | return null; | 2387 | return null; |
| 1978 | } | 2388 | } |
| 1979 | 2389 | ||
| ... | @@ -1986,19 +2396,29 @@ pub const Node = struct { | ... | @@ -1986,19 +2396,29 @@ pub const Node = struct { |
| 1986 | } | 2396 | } |
| 1987 | }; | 2397 | }; |
| 1988 | 2398 | ||
| 2399 | /// Parameters are in memory following BuiltinCall. | ||
| 1989 | pub const BuiltinCall = struct { | 2400 | pub const BuiltinCall = struct { |
| 1990 | base: Node = Node{ .id = .BuiltinCall }, | 2401 | base: Node = Node{ .id = .BuiltinCall }, |
| 2402 | params_len: NodeIndex, | ||
| 1991 | builtin_token: TokenIndex, | 2403 | builtin_token: TokenIndex, |
| 1992 | params: ParamList, | ||
| 1993 | rparen_token: TokenIndex, | 2404 | rparen_token: TokenIndex, |
| 1994 | 2405 | ||
| 1995 | pub const ParamList = SegmentedList(*Node, 2); | 2406 | /// After this the caller must initialize the fields_and_decls list. |
| 2407 | pub fn alloc(allocator: *mem.Allocator, params_len: NodeIndex) !*BuiltinCall { | ||
| 2408 | const bytes = try allocator.alignedAlloc(u8, @alignOf(BuiltinCall), sizeInBytes(params_len)); | ||
| 2409 | return @ptrCast(*BuiltinCall, bytes.ptr); | ||
| 2410 | } | ||
| 1996 | 2411 | ||
| 1997 | pub fn iterate(self: *BuiltinCall, index: usize) ?*Node { | 2412 | pub fn free(self: *BuiltinCall, allocator: *mem.Allocator) void { |
| 2413 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.params_len)]; | ||
| 2414 | allocator.free(bytes); | ||
| 2415 | } | ||
| 2416 | |||
| 2417 | pub fn iterate(self: *const BuiltinCall, index: usize) ?*Node { | ||
| 1998 | var i = index; | 2418 | var i = index; |
| 1999 | 2419 | ||
| 2000 | if (i < self.params.len) return self.params.at(i).*; | 2420 | if (i < self.params_len) return self.paramsConst()[i]; |
| 2001 | i -= self.params.len; | 2421 | i -= self.params_len; |
| 2002 | 2422 | ||
| 2003 | return null; | 2423 | return null; |
| 2004 | } | 2424 | } |
| ... | @@ -2010,13 +2430,27 @@ pub const Node = struct { | ... | @@ -2010,13 +2430,27 @@ pub const Node = struct { |
| 2010 | pub fn lastToken(self: *const BuiltinCall) TokenIndex { | 2430 | pub fn lastToken(self: *const BuiltinCall) TokenIndex { |
| 2011 | return self.rparen_token; | 2431 | return self.rparen_token; |
| 2012 | } | 2432 | } |
| 2433 | |||
| 2434 | pub fn params(self: *BuiltinCall) []*Node { | ||
| 2435 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(BuiltinCall); | ||
| 2436 | return @ptrCast([*]*Node, decls_start)[0..self.params_len]; | ||
| 2437 | } | ||
| 2438 | |||
| 2439 | pub fn paramsConst(self: *const BuiltinCall) []const *Node { | ||
| 2440 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(BuiltinCall); | ||
| 2441 | return @ptrCast([*]const *Node, decls_start)[0..self.params_len]; | ||
| 2442 | } | ||
| 2443 | |||
| 2444 | fn sizeInBytes(params_len: NodeIndex) usize { | ||
| 2445 | return @sizeOf(BuiltinCall) + @sizeOf(*Node) * @as(usize, params_len); | ||
| 2446 | } | ||
| 2013 | }; | 2447 | }; |
| 2014 | 2448 | ||
| 2015 | pub const StringLiteral = struct { | 2449 | pub const StringLiteral = struct { |
| 2016 | base: Node = Node{ .id = .StringLiteral }, | 2450 | base: Node = Node{ .id = .StringLiteral }, |
| 2017 | token: TokenIndex, | 2451 | token: TokenIndex, |
| 2018 | 2452 | ||
| 2019 | pub fn iterate(self: *StringLiteral, index: usize) ?*Node { | 2453 | pub fn iterate(self: *const StringLiteral, index: usize) ?*Node { |
| 2020 | return null; | 2454 | return null; |
| 2021 | } | 2455 | } |
| 2022 | 2456 | ||
| ... | @@ -2029,22 +2463,46 @@ pub const Node = struct { | ... | @@ -2029,22 +2463,46 @@ pub const Node = struct { |
| 2029 | } | 2463 | } |
| 2030 | }; | 2464 | }; |
| 2031 | 2465 | ||
| 2466 | /// The string literal tokens appear directly in memory after MultilineStringLiteral. | ||
| 2032 | pub const MultilineStringLiteral = struct { | 2467 | pub const MultilineStringLiteral = struct { |
| 2033 | base: Node = Node{ .id = .MultilineStringLiteral }, | 2468 | base: Node = Node{ .id = .MultilineStringLiteral }, |
| 2034 | lines: LineList, | 2469 | lines_len: TokenIndex, |
| 2035 | 2470 | ||
| 2036 | pub const LineList = SegmentedList(TokenIndex, 4); | 2471 | /// After this the caller must initialize the lines list. |
| 2472 | pub fn alloc(allocator: *mem.Allocator, lines_len: NodeIndex) !*MultilineStringLiteral { | ||
| 2473 | const bytes = try allocator.alignedAlloc(u8, @alignOf(MultilineStringLiteral), sizeInBytes(lines_len)); | ||
| 2474 | return @ptrCast(*MultilineStringLiteral, bytes.ptr); | ||
| 2475 | } | ||
| 2037 | 2476 | ||
| 2038 | pub fn iterate(self: *MultilineStringLiteral, index: usize) ?*Node { | 2477 | pub fn free(self: *MultilineStringLiteral, allocator: *mem.Allocator) void { |
| 2478 | const bytes = @ptrCast([*]u8, self)[0..sizeInBytes(self.lines_len)]; | ||
| 2479 | allocator.free(bytes); | ||
| 2480 | } | ||
| 2481 | |||
| 2482 | pub fn iterate(self: *const MultilineStringLiteral, index: usize) ?*Node { | ||
| 2039 | return null; | 2483 | return null; |
| 2040 | } | 2484 | } |
| 2041 | 2485 | ||
| 2042 | pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex { | 2486 | pub fn firstToken(self: *const MultilineStringLiteral) TokenIndex { |
| 2043 | return self.lines.at(0).*; | 2487 | return self.linesConst()[0]; |
| 2044 | } | 2488 | } |
| 2045 | 2489 | ||
| 2046 | pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex { | 2490 | pub fn lastToken(self: *const MultilineStringLiteral) TokenIndex { |
| 2047 | return self.lines.at(self.lines.len - 1).*; | 2491 | return self.linesConst()[self.lines_len - 1]; |
| 2492 | } | ||
| 2493 | |||
| 2494 | pub fn lines(self: *MultilineStringLiteral) []TokenIndex { | ||
| 2495 | const decls_start = @ptrCast([*]u8, self) + @sizeOf(MultilineStringLiteral); | ||
| 2496 | return @ptrCast([*]TokenIndex, decls_start)[0..self.lines_len]; | ||
| 2497 | } | ||
| 2498 | |||
| 2499 | pub fn linesConst(self: *const MultilineStringLiteral) []const TokenIndex { | ||
| 2500 | const decls_start = @ptrCast([*]const u8, self) + @sizeOf(MultilineStringLiteral); | ||
| 2501 | return @ptrCast([*]const TokenIndex, decls_start)[0..self.lines_len]; | ||
| 2502 | } | ||
| 2503 | |||
| 2504 | fn sizeInBytes(lines_len: NodeIndex) usize { | ||
| 2505 | return @sizeOf(MultilineStringLiteral) + @sizeOf(TokenIndex) * @as(usize, lines_len); | ||
| 2048 | } | 2506 | } |
| 2049 | }; | 2507 | }; |
| 2050 | 2508 | ||
| ... | @@ -2052,7 +2510,7 @@ pub const Node = struct { | ... | @@ -2052,7 +2510,7 @@ pub const Node = struct { |
| 2052 | base: Node = Node{ .id = .CharLiteral }, | 2510 | base: Node = Node{ .id = .CharLiteral }, |
| 2053 | token: TokenIndex, | 2511 | token: TokenIndex, |
| 2054 | 2512 | ||
| 2055 | pub fn iterate(self: *CharLiteral, index: usize) ?*Node { | 2513 | pub fn iterate(self: *const CharLiteral, index: usize) ?*Node { |
| 2056 | return null; | 2514 | return null; |
| 2057 | } | 2515 | } |
| 2058 | 2516 | ||
| ... | @@ -2069,7 +2527,7 @@ pub const Node = struct { | ... | @@ -2069,7 +2527,7 @@ pub const Node = struct { |
| 2069 | base: Node = Node{ .id = .BoolLiteral }, | 2527 | base: Node = Node{ .id = .BoolLiteral }, |
| 2070 | token: TokenIndex, | 2528 | token: TokenIndex, |
| 2071 | 2529 | ||
| 2072 | pub fn iterate(self: *BoolLiteral, index: usize) ?*Node { | 2530 | pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node { |
| 2073 | return null; | 2531 | return null; |
| 2074 | } | 2532 | } |
| 2075 | 2533 | ||
| ... | @@ -2086,7 +2544,7 @@ pub const Node = struct { | ... | @@ -2086,7 +2544,7 @@ pub const Node = struct { |
| 2086 | base: Node = Node{ .id = .NullLiteral }, | 2544 | base: Node = Node{ .id = .NullLiteral }, |
| 2087 | token: TokenIndex, | 2545 | token: TokenIndex, |
| 2088 | 2546 | ||
| 2089 | pub fn iterate(self: *NullLiteral, index: usize) ?*Node { | 2547 | pub fn iterate(self: *const NullLiteral, index: usize) ?*Node { |
| 2090 | return null; | 2548 | return null; |
| 2091 | } | 2549 | } |
| 2092 | 2550 | ||
| ... | @@ -2103,7 +2561,7 @@ pub const Node = struct { | ... | @@ -2103,7 +2561,7 @@ pub const Node = struct { |
| 2103 | base: Node = Node{ .id = .UndefinedLiteral }, | 2561 | base: Node = Node{ .id = .UndefinedLiteral }, |
| 2104 | token: TokenIndex, | 2562 | token: TokenIndex, |
| 2105 | 2563 | ||
| 2106 | pub fn iterate(self: *UndefinedLiteral, index: usize) ?*Node { | 2564 | pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node { |
| 2107 | return null; | 2565 | return null; |
| 2108 | } | 2566 | } |
| 2109 | 2567 | ||
| ... | @@ -2116,105 +2574,114 @@ pub const Node = struct { | ... | @@ -2116,105 +2574,114 @@ pub const Node = struct { |
| 2116 | } | 2574 | } |
| 2117 | }; | 2575 | }; |
| 2118 | 2576 | ||
| 2119 | pub const AsmOutput = struct { | 2577 | pub const Asm = struct { |
| 2120 | base: Node = Node{ .id = .AsmOutput }, | 2578 | base: Node = Node{ .id = .Asm }, |
| 2121 | lbracket: TokenIndex, | 2579 | asm_token: TokenIndex, |
| 2122 | symbolic_name: *Node, | ||
| 2123 | constraint: *Node, | ||
| 2124 | kind: Kind, | ||
| 2125 | rparen: TokenIndex, | 2580 | rparen: TokenIndex, |
| 2581 | volatile_token: ?TokenIndex, | ||
| 2582 | template: *Node, | ||
| 2583 | outputs: []Output, | ||
| 2584 | inputs: []Input, | ||
| 2585 | /// A clobber node must be a StringLiteral or MultilineStringLiteral. | ||
| 2586 | clobbers: []*Node, | ||
| 2587 | |||
| 2588 | pub const Output = struct { | ||
| 2589 | lbracket: TokenIndex, | ||
| 2590 | symbolic_name: *Node, | ||
| 2591 | constraint: *Node, | ||
| 2592 | kind: Kind, | ||
| 2593 | rparen: TokenIndex, | ||
| 2594 | |||
| 2595 | pub const Kind = union(enum) { | ||
| 2596 | Variable: *Identifier, | ||
| 2597 | Return: *Node, | ||
| 2598 | }; | ||
| 2126 | 2599 | ||
| 2127 | pub const Kind = union(enum) { | 2600 | pub fn iterate(self: *const Output, index: usize) ?*Node { |
| 2128 | Variable: *Identifier, | 2601 | var i = index; |
| 2129 | Return: *Node, | ||
| 2130 | }; | ||
| 2131 | 2602 | ||
| 2132 | pub fn iterate(self: *AsmOutput, index: usize) ?*Node { | 2603 | if (i < 1) return self.symbolic_name; |
| 2133 | var i = index; | 2604 | i -= 1; |
| 2134 | 2605 | ||
| 2135 | if (i < 1) return self.symbolic_name; | 2606 | if (i < 1) return self.constraint; |
| 2136 | i -= 1; | 2607 | i -= 1; |
| 2137 | 2608 | ||
| 2138 | if (i < 1) return self.constraint; | 2609 | switch (self.kind) { |
| 2139 | i -= 1; | 2610 | .Variable => |variable_name| { |
| 2611 | if (i < 1) return &variable_name.base; | ||
| 2612 | i -= 1; | ||
| 2613 | }, | ||
| 2614 | .Return => |return_type| { | ||
| 2615 | if (i < 1) return return_type; | ||
| 2616 | i -= 1; | ||
| 2617 | }, | ||
| 2618 | } | ||
| 2140 | 2619 | ||
| 2141 | switch (self.kind) { | 2620 | return null; |
| 2142 | .Variable => |variable_name| { | ||
| 2143 | if (i < 1) return &variable_name.base; | ||
| 2144 | i -= 1; | ||
| 2145 | }, | ||
| 2146 | .Return => |return_type| { | ||
| 2147 | if (i < 1) return return_type; | ||
| 2148 | i -= 1; | ||
| 2149 | }, | ||
| 2150 | } | 2621 | } |
| 2151 | 2622 | ||
| 2152 | return null; | 2623 | pub fn firstToken(self: *const Output) TokenIndex { |
| 2153 | } | 2624 | return self.lbracket; |
| 2154 | 2625 | } | |
| 2155 | pub fn firstToken(self: *const AsmOutput) TokenIndex { | ||
| 2156 | return self.lbracket; | ||
| 2157 | } | ||
| 2158 | |||
| 2159 | pub fn lastToken(self: *const AsmOutput) TokenIndex { | ||
| 2160 | return self.rparen; | ||
| 2161 | } | ||
| 2162 | }; | ||
| 2163 | 2626 | ||
| 2164 | pub const AsmInput = struct { | 2627 | pub fn lastToken(self: *const Output) TokenIndex { |
| 2165 | base: Node = Node{ .id = .AsmInput }, | 2628 | return self.rparen; |
| 2166 | lbracket: TokenIndex, | 2629 | } |
| 2167 | symbolic_name: *Node, | 2630 | }; |
| 2168 | constraint: *Node, | ||
| 2169 | expr: *Node, | ||
| 2170 | rparen: TokenIndex, | ||
| 2171 | 2631 | ||
| 2172 | pub fn iterate(self: *AsmInput, index: usize) ?*Node { | 2632 | pub const Input = struct { |
| 2173 | var i = index; | 2633 | lbracket: TokenIndex, |
| 2634 | symbolic_name: *Node, | ||
| 2635 | constraint: *Node, | ||
| 2636 | expr: *Node, | ||
| 2637 | rparen: TokenIndex, | ||
| 2174 | 2638 | ||
| 2175 | if (i < 1) return self.symbolic_name; | 2639 | pub fn iterate(self: *const Input, index: usize) ?*Node { |
| 2176 | i -= 1; | 2640 | var i = index; |
| 2177 | 2641 | ||
| 2178 | if (i < 1) return self.constraint; | 2642 | if (i < 1) return self.symbolic_name; |
| 2179 | i -= 1; | 2643 | i -= 1; |
| 2180 | 2644 | ||
| 2181 | if (i < 1) return self.expr; | 2645 | if (i < 1) return self.constraint; |
| 2182 | i -= 1; | 2646 | i -= 1; |
| 2183 | 2647 | ||
| 2184 | return null; | 2648 | if (i < 1) return self.expr; |
| 2185 | } | 2649 | i -= 1; |
| 2186 | 2650 | ||
| 2187 | pub fn firstToken(self: *const AsmInput) TokenIndex { | 2651 | return null; |
| 2188 | return self.lbracket; | 2652 | } |
| 2189 | } | ||
| 2190 | 2653 | ||
| 2191 | pub fn lastToken(self: *const AsmInput) TokenIndex { | 2654 | pub fn firstToken(self: *const Input) TokenIndex { |
| 2192 | return self.rparen; | 2655 | return self.lbracket; |
| 2193 | } | 2656 | } |
| 2194 | }; | ||
| 2195 | 2657 | ||
| 2196 | pub const Asm = struct { | 2658 | pub fn lastToken(self: *const Input) TokenIndex { |
| 2197 | base: Node = Node{ .id = .Asm }, | 2659 | return self.rparen; |
| 2198 | asm_token: TokenIndex, | 2660 | } |
| 2199 | volatile_token: ?TokenIndex, | 2661 | }; |
| 2200 | template: *Node, | ||
| 2201 | outputs: OutputList, | ||
| 2202 | inputs: InputList, | ||
| 2203 | clobbers: ClobberList, | ||
| 2204 | rparen: TokenIndex, | ||
| 2205 | 2662 | ||
| 2206 | pub const OutputList = SegmentedList(*AsmOutput, 2); | ||
| 2207 | pub const InputList = SegmentedList(*AsmInput, 2); | ||
| 2208 | pub const ClobberList = SegmentedList(*Node, 2); | ||
| 2209 | 2663 | ||
| 2210 | pub fn iterate(self: *Asm, index: usize) ?*Node { | 2664 | pub fn iterate(self: *const Asm, index: usize) ?*Node { |
| 2211 | var i = index; | 2665 | var i = index; |
| 2212 | 2666 | ||
| 2213 | if (i < self.outputs.len) return &self.outputs.at(i).*.base; | 2667 | if (i < self.outputs.len * 3) switch (i % 3) { |
| 2214 | i -= self.outputs.len; | 2668 | 0 => return self.outputs[i / 3].symbolic_name, |
| 2669 | 1 => return self.outputs[i / 3].constraint, | ||
| 2670 | 2 => switch (self.outputs[i / 3].kind) { | ||
| 2671 | .Variable => |variable_name| return &variable_name.base, | ||
| 2672 | .Return => |return_type| return return_type, | ||
| 2673 | }, | ||
| 2674 | else => unreachable, | ||
| 2675 | }; | ||
| 2676 | i -= self.outputs.len * 3; | ||
| 2215 | 2677 | ||
| 2216 | if (i < self.inputs.len) return &self.inputs.at(i).*.base; | 2678 | if (i < self.inputs.len * 3) switch (i % 3) { |
| 2217 | i -= self.inputs.len; | 2679 | 0 => return self.inputs[i / 3].symbolic_name, |
| 2680 | 1 => return self.inputs[i / 3].constraint, | ||
| 2681 | 2 => return self.inputs[i / 3].expr, | ||
| 2682 | else => unreachable, | ||
| 2683 | }; | ||
| 2684 | i -= self.inputs.len * 3; | ||
| 2218 | 2685 | ||
| 2219 | return null; | 2686 | return null; |
| 2220 | } | 2687 | } |
| ... | @@ -2232,7 +2699,7 @@ pub const Node = struct { | ... | @@ -2232,7 +2699,7 @@ pub const Node = struct { |
| 2232 | base: Node = Node{ .id = .Unreachable }, | 2699 | base: Node = Node{ .id = .Unreachable }, |
| 2233 | token: TokenIndex, | 2700 | token: TokenIndex, |
| 2234 | 2701 | ||
| 2235 | pub fn iterate(self: *Unreachable, index: usize) ?*Node { | 2702 | pub fn iterate(self: *const Unreachable, index: usize) ?*Node { |
| 2236 | return null; | 2703 | return null; |
| 2237 | } | 2704 | } |
| 2238 | 2705 | ||
| ... | @@ -2249,7 +2716,7 @@ pub const Node = struct { | ... | @@ -2249,7 +2716,7 @@ pub const Node = struct { |
| 2249 | base: Node = Node{ .id = .ErrorType }, | 2716 | base: Node = Node{ .id = .ErrorType }, |
| 2250 | token: TokenIndex, | 2717 | token: TokenIndex, |
| 2251 | 2718 | ||
| 2252 | pub fn iterate(self: *ErrorType, index: usize) ?*Node { | 2719 | pub fn iterate(self: *const ErrorType, index: usize) ?*Node { |
| 2253 | return null; | 2720 | return null; |
| 2254 | } | 2721 | } |
| 2255 | 2722 | ||
| ... | @@ -2266,7 +2733,7 @@ pub const Node = struct { | ... | @@ -2266,7 +2733,7 @@ pub const Node = struct { |
| 2266 | base: Node = Node{ .id = .VarType }, | 2733 | base: Node = Node{ .id = .VarType }, |
| 2267 | token: TokenIndex, | 2734 | token: TokenIndex, |
| 2268 | 2735 | ||
| 2269 | pub fn iterate(self: *VarType, index: usize) ?*Node { | 2736 | pub fn iterate(self: *const VarType, index: usize) ?*Node { |
| 2270 | return null; | 2737 | return null; |
| 2271 | } | 2738 | } |
| 2272 | 2739 | ||
| ... | @@ -2281,20 +2748,23 @@ pub const Node = struct { | ... | @@ -2281,20 +2748,23 @@ pub const Node = struct { |
| 2281 | 2748 | ||
| 2282 | pub const DocComment = struct { | 2749 | pub const DocComment = struct { |
| 2283 | base: Node = Node{ .id = .DocComment }, | 2750 | base: Node = Node{ .id = .DocComment }, |
| 2284 | lines: LineList, | 2751 | /// Points to the first doc comment token. API users are expected to iterate over the |
| 2285 | 2752 | /// tokens array, looking for more doc comments, ignoring line comments, and stopping | |
| 2286 | pub const LineList = SegmentedList(TokenIndex, 4); | 2753 | /// at the first other token. |
| 2754 | first_line: TokenIndex, | ||
| 2287 | 2755 | ||
| 2288 | pub fn iterate(self: *DocComment, index: usize) ?*Node { | 2756 | pub fn iterate(self: *const DocComment, index: usize) ?*Node { |
| 2289 | return null; | 2757 | return null; |
| 2290 | } | 2758 | } |
| 2291 | 2759 | ||
| 2292 | pub fn firstToken(self: *const DocComment) TokenIndex { | 2760 | pub fn firstToken(self: *const DocComment) TokenIndex { |
| 2293 | return self.lines.at(0).*; | 2761 | return self.first_line; |
| 2294 | } | 2762 | } |
| 2295 | 2763 | ||
| 2764 | /// Returns the first doc comment line. Be careful, this may not be the desired behavior, | ||
| 2765 | /// which would require the tokens array. | ||
| 2296 | pub fn lastToken(self: *const DocComment) TokenIndex { | 2766 | pub fn lastToken(self: *const DocComment) TokenIndex { |
| 2297 | return self.lines.at(self.lines.len - 1).*; | 2767 | return self.first_line; |
| 2298 | } | 2768 | } |
| 2299 | }; | 2769 | }; |
| 2300 | 2770 | ||
| ... | @@ -2305,7 +2775,7 @@ pub const Node = struct { | ... | @@ -2305,7 +2775,7 @@ pub const Node = struct { |
| 2305 | name: *Node, | 2775 | name: *Node, |
| 2306 | body_node: *Node, | 2776 | body_node: *Node, |
| 2307 | 2777 | ||
| 2308 | pub fn iterate(self: *TestDecl, index: usize) ?*Node { | 2778 | pub fn iterate(self: *const TestDecl, index: usize) ?*Node { |
| 2309 | var i = index; | 2779 | var i = index; |
| 2310 | 2780 | ||
| 2311 | if (i < 1) return self.body_node; | 2781 | if (i < 1) return self.body_node; |
| ... | @@ -2327,7 +2797,7 @@ pub const Node = struct { | ... | @@ -2327,7 +2797,7 @@ pub const Node = struct { |
| 2327 | test "iterate" { | 2797 | test "iterate" { |
| 2328 | var root = Node.Root{ | 2798 | var root = Node.Root{ |
| 2329 | .base = Node{ .id = Node.Id.Root }, | 2799 | .base = Node{ .id = Node.Id.Root }, |
| 2330 | .decls = Node.Root.DeclList.init(std.testing.allocator), | 2800 | .decls_len = 0, |
| 2331 | .eof_token = 0, | 2801 | .eof_token = 0, |
| 2332 | }; | 2802 | }; |
| 2333 | var base = &root.base; | 2803 | var base = &root.base; |
lib/std/zig/parse.zig+2886-2803| ... | @@ -6,3304 +6,3387 @@ const Node = ast.Node; | ... | @@ -6,3304 +6,3387 @@ const Node = ast.Node; |
| 6 | const Tree = ast.Tree; | 6 | const Tree = ast.Tree; |
| 7 | const AstError = ast.Error; | 7 | const AstError = ast.Error; |
| 8 | const TokenIndex = ast.TokenIndex; | 8 | const TokenIndex = ast.TokenIndex; |
| 9 | const NodeIndex = ast.NodeIndex; | ||
| 9 | const Token = std.zig.Token; | 10 | const Token = std.zig.Token; |
| 10 | const TokenIterator = Tree.TokenList.Iterator; | ||
| 11 | 11 | ||
| 12 | pub const Error = error{ParseError} || Allocator.Error; | 12 | pub const Error = error{ParseError} || Allocator.Error; |
| 13 | 13 | ||
| 14 | /// Result should be freed with tree.deinit() when there are | 14 | /// Result should be freed with tree.deinit() when there are |
| 15 | /// no more references to any of the tokens or nodes. | 15 | /// no more references to any of the tokens or nodes. |
| 16 | pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { | 16 | pub fn parse(gpa: *Allocator, source: []const u8) Allocator.Error!*Tree { |
| 17 | const tree = blk: { | 17 | // TODO optimization idea: ensureCapacity on the tokens list and |
| 18 | // This block looks unnecessary, but is a "foot-shield" to prevent the SegmentedLists | 18 | // then appendAssumeCapacity inside the loop. |
| 19 | // from being initialized with a pointer to this `arena`, which is created on | 19 | var token_ids = std.ArrayList(Token.Id).init(gpa); |
| 20 | // the stack. Following code should instead refer to `&tree.arena_allocator`, a | 20 | defer token_ids.deinit(); |
| 21 | // pointer to data which lives safely on the heap and will outlive `parse`. See: | 21 | var token_locs = std.ArrayList(Token.Loc).init(gpa); |
| 22 | // https://github.com/ziglang/zig/commit/cb4fb14b6e66bd213575f69eec9598be8394fae6 | 22 | defer token_locs.deinit(); |
| 23 | var arena = std.heap.ArenaAllocator.init(allocator); | ||
| 24 | errdefer arena.deinit(); | ||
| 25 | const tree = try arena.allocator.create(ast.Tree); | ||
| 26 | tree.* = .{ | ||
| 27 | .source = source, | ||
| 28 | .root_node = undefined, | ||
| 29 | .arena_allocator = arena, | ||
| 30 | .tokens = undefined, | ||
| 31 | .errors = undefined, | ||
| 32 | }; | ||
| 33 | break :blk tree; | ||
| 34 | }; | ||
| 35 | errdefer tree.deinit(); | ||
| 36 | const arena = &tree.arena_allocator.allocator; | ||
| 37 | |||
| 38 | tree.tokens = ast.Tree.TokenList.init(arena); | ||
| 39 | tree.errors = ast.Tree.ErrorList.init(arena); | ||
| 40 | 23 | ||
| 41 | var tokenizer = std.zig.Tokenizer.init(source); | 24 | var tokenizer = std.zig.Tokenizer.init(source); |
| 42 | while (true) { | 25 | while (true) { |
| 43 | const tree_token = try tree.tokens.addOne(); | 26 | const token = tokenizer.next(); |
| 44 | tree_token.* = tokenizer.next(); | 27 | try token_ids.append(token.id); |
| 45 | if (tree_token.id == .Eof) break; | 28 | try token_locs.append(token.loc); |
| 46 | } | 29 | if (token.id == .Eof) break; |
| 47 | var it = tree.tokens.iterator(0); | 30 | } |
| 48 | 31 | ||
| 49 | while (it.peek().?.id == .LineComment) _ = it.next(); | 32 | var parser: Parser = .{ |
| 50 | 33 | .source = source, | |
| 51 | tree.root_node = try parseRoot(arena, &it, tree); | 34 | .arena = std.heap.ArenaAllocator.init(gpa), |
| 52 | 35 | .gpa = gpa, | |
| 36 | .token_ids = token_ids.items, | ||
| 37 | .token_locs = token_locs.items, | ||
| 38 | .errors = .{}, | ||
| 39 | .tok_i = 0, | ||
| 40 | }; | ||
| 41 | defer parser.errors.deinit(gpa); | ||
| 42 | errdefer parser.arena.deinit(); | ||
| 43 | |||
| 44 | while (token_ids.items[parser.tok_i] == .LineComment) parser.tok_i += 1; | ||
| 45 | |||
| 46 | const root_node = try parser.parseRoot(); | ||
| 47 | |||
| 48 | const tree = try parser.arena.allocator.create(Tree); | ||
| 49 | tree.* = .{ | ||
| 50 | .gpa = gpa, | ||
| 51 | .source = source, | ||
| 52 | .token_ids = token_ids.toOwnedSlice(), | ||
| 53 | .token_locs = token_locs.toOwnedSlice(), | ||
| 54 | .errors = parser.errors.toOwnedSlice(gpa), | ||
| 55 | .root_node = root_node, | ||
| 56 | .arena = parser.arena.state, | ||
| 57 | }; | ||
| 53 | return tree; | 58 | return tree; |
| 54 | } | 59 | } |
| 55 | 60 | ||
| 56 | /// Root <- skip ContainerMembers eof | 61 | /// Represents in-progress parsing, will be converted to an ast.Tree after completion. |
| 57 | fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node.Root { | 62 | const Parser = struct { |
| 58 | const node = try arena.create(Node.Root); | 63 | arena: std.heap.ArenaAllocator, |
| 59 | node.* = .{ | 64 | gpa: *Allocator, |
| 60 | .decls = try parseContainerMembers(arena, it, tree, true), | 65 | source: []const u8, |
| 66 | token_ids: []const Token.Id, | ||
| 67 | token_locs: []const Token.Loc, | ||
| 68 | tok_i: TokenIndex, | ||
| 69 | errors: std.ArrayListUnmanaged(AstError), | ||
| 70 | |||
| 71 | /// Root <- skip ContainerMembers eof | ||
| 72 | fn parseRoot(p: *Parser) Allocator.Error!*Node.Root { | ||
| 73 | const decls = try parseContainerMembers(p, true); | ||
| 74 | defer p.gpa.free(decls); | ||
| 75 | |||
| 61 | // parseContainerMembers will try to skip as much | 76 | // parseContainerMembers will try to skip as much |
| 62 | // invalid tokens as it can so this can only be the EOF | 77 | // invalid tokens as it can so this can only be the EOF |
| 63 | .eof_token = eatToken(it, .Eof).?, | 78 | const eof_token = p.eatToken(.Eof).?; |
| 64 | }; | ||
| 65 | return node; | ||
| 66 | } | ||
| 67 | 79 | ||
| 68 | /// ContainerMembers | 80 | const decls_len = @intCast(NodeIndex, decls.len); |
| 69 | /// <- TestDecl ContainerMembers | 81 | const node = try Node.Root.create(&p.arena.allocator, decls_len, eof_token); |
| 70 | /// / TopLevelComptime ContainerMembers | 82 | std.mem.copy(*Node, node.decls(), decls); |
| 71 | /// / KEYWORD_pub? TopLevelDecl ContainerMembers | ||
| 72 | /// / ContainerField COMMA ContainerMembers | ||
| 73 | /// / ContainerField | ||
| 74 | /// / | ||
| 75 | fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree, top_level: bool) !Node.Root.DeclList { | ||
| 76 | var list = Node.Root.DeclList.init(arena); | ||
| 77 | |||
| 78 | var field_state: union(enum) { | ||
| 79 | /// no fields have been seen | ||
| 80 | none, | ||
| 81 | /// currently parsing fields | ||
| 82 | seen, | ||
| 83 | /// saw fields and then a declaration after them. | ||
| 84 | /// payload is first token of previous declaration. | ||
| 85 | end: TokenIndex, | ||
| 86 | /// ther was a declaration between fields, don't report more errors | ||
| 87 | err, | ||
| 88 | } = .none; | ||
| 89 | 83 | ||
| 90 | while (true) { | 84 | return node; |
| 91 | if (try parseContainerDocComments(arena, it, tree)) |node| { | 85 | } |
| 92 | try list.push(node); | ||
| 93 | continue; | ||
| 94 | } | ||
| 95 | 86 | ||
| 96 | const doc_comments = try parseDocComment(arena, it, tree); | 87 | /// ContainerMembers |
| 88 | /// <- TestDecl ContainerMembers | ||
| 89 | /// / TopLevelComptime ContainerMembers | ||
| 90 | /// / KEYWORD_pub? TopLevelDecl ContainerMembers | ||
| 91 | /// / ContainerField COMMA ContainerMembers | ||
| 92 | /// / ContainerField | ||
| 93 | /// / | ||
| 94 | fn parseContainerMembers(p: *Parser, top_level: bool) ![]*Node { | ||
| 95 | var list = std.ArrayList(*Node).init(p.gpa); | ||
| 96 | defer list.deinit(); | ||
| 97 | |||
| 98 | var field_state: union(enum) { | ||
| 99 | /// no fields have been seen | ||
| 100 | none, | ||
| 101 | /// currently parsing fields | ||
| 102 | seen, | ||
| 103 | /// saw fields and then a declaration after them. | ||
| 104 | /// payload is first token of previous declaration. | ||
| 105 | end: TokenIndex, | ||
| 106 | /// ther was a declaration between fields, don't report more errors | ||
| 107 | err, | ||
| 108 | } = .none; | ||
| 97 | 109 | ||
| 98 | if (parseTestDecl(arena, it, tree) catch |err| switch (err) { | 110 | while (true) { |
| 99 | error.OutOfMemory => return error.OutOfMemory, | 111 | if (try p.parseContainerDocComments()) |node| { |
| 100 | error.ParseError => { | 112 | try list.append(node); |
| 101 | findNextContainerMember(it); | ||
| 102 | continue; | 113 | continue; |
| 103 | }, | ||
| 104 | }) |node| { | ||
| 105 | if (field_state == .seen) { | ||
| 106 | field_state = .{ .end = node.firstToken() }; | ||
| 107 | } | 114 | } |
| 108 | node.cast(Node.TestDecl).?.doc_comments = doc_comments; | ||
| 109 | try list.push(node); | ||
| 110 | continue; | ||
| 111 | } | ||
| 112 | 115 | ||
| 113 | if (parseTopLevelComptime(arena, it, tree) catch |err| switch (err) { | 116 | const doc_comments = try p.parseDocComment(); |
| 114 | error.OutOfMemory => return error.OutOfMemory, | 117 | |
| 115 | error.ParseError => { | 118 | if (p.parseTestDecl() catch |err| switch (err) { |
| 116 | findNextContainerMember(it); | 119 | error.OutOfMemory => return error.OutOfMemory, |
| 120 | error.ParseError => { | ||
| 121 | p.findNextContainerMember(); | ||
| 122 | continue; | ||
| 123 | }, | ||
| 124 | }) |node| { | ||
| 125 | if (field_state == .seen) { | ||
| 126 | field_state = .{ .end = node.firstToken() }; | ||
| 127 | } | ||
| 128 | node.cast(Node.TestDecl).?.doc_comments = doc_comments; | ||
| 129 | try list.append(node); | ||
| 117 | continue; | 130 | continue; |
| 118 | }, | ||
| 119 | }) |node| { | ||
| 120 | if (field_state == .seen) { | ||
| 121 | field_state = .{ .end = node.firstToken() }; | ||
| 122 | } | 131 | } |
| 123 | node.cast(Node.Comptime).?.doc_comments = doc_comments; | ||
| 124 | try list.push(node); | ||
| 125 | continue; | ||
| 126 | } | ||
| 127 | 132 | ||
| 128 | const visib_token = eatToken(it, .Keyword_pub); | 133 | if (p.parseTopLevelComptime() catch |err| switch (err) { |
| 129 | 134 | error.OutOfMemory => return error.OutOfMemory, | |
| 130 | if (parseTopLevelDecl(arena, it, tree) catch |err| switch (err) { | 135 | error.ParseError => { |
| 131 | error.OutOfMemory => return error.OutOfMemory, | 136 | p.findNextContainerMember(); |
| 132 | error.ParseError => { | 137 | continue; |
| 133 | findNextContainerMember(it); | 138 | }, |
| 139 | }) |node| { | ||
| 140 | if (field_state == .seen) { | ||
| 141 | field_state = .{ .end = node.firstToken() }; | ||
| 142 | } | ||
| 143 | node.cast(Node.Comptime).?.doc_comments = doc_comments; | ||
| 144 | try list.append(node); | ||
| 134 | continue; | 145 | continue; |
| 135 | }, | ||
| 136 | }) |node| { | ||
| 137 | if (field_state == .seen) { | ||
| 138 | field_state = .{ .end = visib_token orelse node.firstToken() }; | ||
| 139 | } | 146 | } |
| 140 | switch (node.id) { | 147 | |
| 141 | .FnProto => { | 148 | const visib_token = p.eatToken(.Keyword_pub); |
| 142 | node.cast(Node.FnProto).?.doc_comments = doc_comments; | 149 | |
| 143 | node.cast(Node.FnProto).?.visib_token = visib_token; | 150 | if (p.parseTopLevelDecl() catch |err| switch (err) { |
| 144 | }, | 151 | error.OutOfMemory => return error.OutOfMemory, |
| 145 | .VarDecl => { | 152 | error.ParseError => { |
| 146 | node.cast(Node.VarDecl).?.doc_comments = doc_comments; | 153 | p.findNextContainerMember(); |
| 147 | node.cast(Node.VarDecl).?.visib_token = visib_token; | 154 | continue; |
| 148 | }, | ||
| 149 | .Use => { | ||
| 150 | node.cast(Node.Use).?.doc_comments = doc_comments; | ||
| 151 | node.cast(Node.Use).?.visib_token = visib_token; | ||
| 152 | }, | 155 | }, |
| 153 | else => unreachable, | 156 | }) |node| { |
| 154 | } | 157 | if (field_state == .seen) { |
| 155 | try list.push(node); | 158 | field_state = .{ .end = visib_token orelse node.firstToken() }; |
| 156 | if (try parseAppendedDocComment(arena, it, tree, node.lastToken())) |appended_comment| { | 159 | } |
| 157 | switch (node.id) { | 160 | switch (node.id) { |
| 158 | .FnProto => {}, | 161 | .FnProto => { |
| 159 | .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment, | 162 | node.cast(Node.FnProto).?.doc_comments = doc_comments; |
| 160 | .Use => node.cast(Node.Use).?.doc_comments = appended_comment, | 163 | node.cast(Node.FnProto).?.visib_token = visib_token; |
| 164 | }, | ||
| 165 | .VarDecl => { | ||
| 166 | node.cast(Node.VarDecl).?.doc_comments = doc_comments; | ||
| 167 | node.cast(Node.VarDecl).?.visib_token = visib_token; | ||
| 168 | }, | ||
| 169 | .Use => { | ||
| 170 | node.cast(Node.Use).?.doc_comments = doc_comments; | ||
| 171 | node.cast(Node.Use).?.visib_token = visib_token; | ||
| 172 | }, | ||
| 161 | else => unreachable, | 173 | else => unreachable, |
| 162 | } | 174 | } |
| 175 | try list.append(node); | ||
| 176 | if (try p.parseAppendedDocComment(node.lastToken())) |appended_comment| { | ||
| 177 | switch (node.id) { | ||
| 178 | .FnProto => {}, | ||
| 179 | .VarDecl => node.cast(Node.VarDecl).?.doc_comments = appended_comment, | ||
| 180 | .Use => node.cast(Node.Use).?.doc_comments = appended_comment, | ||
| 181 | else => unreachable, | ||
| 182 | } | ||
| 183 | } | ||
| 184 | continue; | ||
| 163 | } | 185 | } |
| 164 | continue; | ||
| 165 | } | ||
| 166 | |||
| 167 | if (visib_token != null) { | ||
| 168 | try tree.errors.push(.{ | ||
| 169 | .ExpectedPubItem = .{ .token = it.index }, | ||
| 170 | }); | ||
| 171 | // ignore this pub | ||
| 172 | continue; | ||
| 173 | } | ||
| 174 | 186 | ||
| 175 | if (parseContainerField(arena, it, tree) catch |err| switch (err) { | 187 | if (visib_token != null) { |
| 176 | error.OutOfMemory => return error.OutOfMemory, | 188 | try p.errors.append(p.gpa, .{ |
| 177 | error.ParseError => { | 189 | .ExpectedPubItem = .{ .token = p.tok_i }, |
| 178 | // attempt to recover | 190 | }); |
| 179 | findNextContainerMember(it); | 191 | // ignore this pub |
| 180 | continue; | 192 | continue; |
| 181 | }, | ||
| 182 | }) |node| { | ||
| 183 | switch (field_state) { | ||
| 184 | .none => field_state = .seen, | ||
| 185 | .err, .seen => {}, | ||
| 186 | .end => |tok| { | ||
| 187 | try tree.errors.push(.{ | ||
| 188 | .DeclBetweenFields = .{ .token = tok }, | ||
| 189 | }); | ||
| 190 | // continue parsing, error will be reported later | ||
| 191 | field_state = .err; | ||
| 192 | }, | ||
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | const field = node.cast(Node.ContainerField).?; | 195 | if (p.parseContainerField() catch |err| switch (err) { |
| 196 | field.doc_comments = doc_comments; | 196 | error.OutOfMemory => return error.OutOfMemory, |
| 197 | try list.push(node); | 197 | error.ParseError => { |
| 198 | const comma = eatToken(it, .Comma) orelse { | 198 | // attempt to recover |
| 199 | // try to continue parsing | 199 | p.findNextContainerMember(); |
| 200 | const index = it.index; | 200 | continue; |
| 201 | findNextContainerMember(it); | 201 | }, |
| 202 | const next = it.peek().?.id; | 202 | }) |node| { |
| 203 | switch (next) { | 203 | switch (field_state) { |
| 204 | .Eof => break, | 204 | .none => field_state = .seen, |
| 205 | else => { | 205 | .err, .seen => {}, |
| 206 | if (next == .RBrace) { | 206 | .end => |tok| { |
| 207 | if (!top_level) break; | 207 | try p.errors.append(p.gpa, .{ |
| 208 | _ = nextToken(it); | 208 | .DeclBetweenFields = .{ .token = tok }, |
| 209 | } | ||
| 210 | |||
| 211 | // add error and continue | ||
| 212 | try tree.errors.push(.{ | ||
| 213 | .ExpectedToken = .{ .token = index, .expected_id = .Comma }, | ||
| 214 | }); | 209 | }); |
| 215 | continue; | 210 | // continue parsing, error will be reported later |
| 211 | field_state = .err; | ||
| 216 | }, | 212 | }, |
| 217 | } | 213 | } |
| 218 | }; | ||
| 219 | if (try parseAppendedDocComment(arena, it, tree, comma)) |appended_comment| | ||
| 220 | field.doc_comments = appended_comment; | ||
| 221 | continue; | ||
| 222 | } | ||
| 223 | |||
| 224 | // Dangling doc comment | ||
| 225 | if (doc_comments != null) { | ||
| 226 | try tree.errors.push(.{ | ||
| 227 | .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, | ||
| 228 | }); | ||
| 229 | } | ||
| 230 | 214 | ||
| 231 | const next = it.peek().?.id; | 215 | const field = node.cast(Node.ContainerField).?; |
| 232 | switch (next) { | 216 | field.doc_comments = doc_comments; |
| 233 | .Eof => break, | 217 | try list.append(node); |
| 234 | .Keyword_comptime => { | 218 | const comma = p.eatToken(.Comma) orelse { |
| 235 | _ = nextToken(it); | 219 | // try to continue parsing |
| 236 | try tree.errors.push(.{ | 220 | const index = p.tok_i; |
| 237 | .ExpectedBlockOrField = .{ .token = it.index }, | 221 | p.findNextContainerMember(); |
| 238 | }); | 222 | const next = p.token_ids[p.tok_i]; |
| 239 | }, | 223 | switch (next) { |
| 240 | else => { | 224 | .Eof => break, |
| 241 | const index = it.index; | 225 | else => { |
| 242 | if (next == .RBrace) { | 226 | if (next == .RBrace) { |
| 243 | if (!top_level) break; | 227 | if (!top_level) break; |
| 244 | _ = nextToken(it); | 228 | _ = p.nextToken(); |
| 245 | } | 229 | } |
| 230 | |||
| 231 | // add error and continue | ||
| 232 | try p.errors.append(p.gpa, .{ | ||
| 233 | .ExpectedToken = .{ .token = index, .expected_id = .Comma }, | ||
| 234 | }); | ||
| 235 | continue; | ||
| 236 | }, | ||
| 237 | } | ||
| 238 | }; | ||
| 239 | if (try p.parseAppendedDocComment(comma)) |appended_comment| | ||
| 240 | field.doc_comments = appended_comment; | ||
| 241 | continue; | ||
| 242 | } | ||
| 246 | 243 | ||
| 247 | // this was likely not supposed to end yet, | 244 | // Dangling doc comment |
| 248 | // try to find the next declaration | 245 | if (doc_comments != null) { |
| 249 | findNextContainerMember(it); | 246 | try p.errors.append(p.gpa, .{ |
| 250 | try tree.errors.push(.{ | 247 | .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, |
| 251 | .ExpectedContainerMembers = .{ .token = index }, | ||
| 252 | }); | 248 | }); |
| 253 | }, | 249 | } |
| 254 | } | ||
| 255 | } | ||
| 256 | 250 | ||
| 257 | return list; | 251 | const next = p.token_ids[p.tok_i]; |
| 258 | } | 252 | switch (next) { |
| 253 | .Eof => break, | ||
| 254 | .Keyword_comptime => { | ||
| 255 | _ = p.nextToken(); | ||
| 256 | try p.errors.append(p.gpa, .{ | ||
| 257 | .ExpectedBlockOrField = .{ .token = p.tok_i }, | ||
| 258 | }); | ||
| 259 | }, | ||
| 260 | else => { | ||
| 261 | const index = p.tok_i; | ||
| 262 | if (next == .RBrace) { | ||
| 263 | if (!top_level) break; | ||
| 264 | _ = p.nextToken(); | ||
| 265 | } | ||
| 259 | 266 | ||
| 260 | /// Attempts to find next container member by searching for certain tokens | 267 | // this was likely not supposed to end yet, |
| 261 | fn findNextContainerMember(it: *TokenIterator) void { | 268 | // try to find the next declaration |
| 262 | var level: u32 = 0; | 269 | p.findNextContainerMember(); |
| 263 | while (true) { | 270 | try p.errors.append(p.gpa, .{ |
| 264 | const tok = nextToken(it); | 271 | .ExpectedContainerMembers = .{ .token = index }, |
| 265 | switch (tok.ptr.id) { | 272 | }); |
| 266 | // any of these can start a new top level declaration | 273 | }, |
| 267 | .Keyword_test, | 274 | } |
| 268 | .Keyword_comptime, | ||
| 269 | .Keyword_pub, | ||
| 270 | .Keyword_export, | ||
| 271 | .Keyword_extern, | ||
| 272 | .Keyword_inline, | ||
| 273 | .Keyword_noinline, | ||
| 274 | .Keyword_usingnamespace, | ||
| 275 | .Keyword_threadlocal, | ||
| 276 | .Keyword_const, | ||
| 277 | .Keyword_var, | ||
| 278 | .Keyword_fn, | ||
| 279 | .Identifier, | ||
| 280 | => { | ||
| 281 | if (level == 0) { | ||
| 282 | putBackToken(it, tok.index); | ||
| 283 | return; | ||
| 284 | } | ||
| 285 | }, | ||
| 286 | .Comma, .Semicolon => { | ||
| 287 | // this decl was likely meant to end here | ||
| 288 | if (level == 0) { | ||
| 289 | return; | ||
| 290 | } | ||
| 291 | }, | ||
| 292 | .LParen, .LBracket, .LBrace => level += 1, | ||
| 293 | .RParen, .RBracket => { | ||
| 294 | if (level != 0) level -= 1; | ||
| 295 | }, | ||
| 296 | .RBrace => { | ||
| 297 | if (level == 0) { | ||
| 298 | // end of container, exit | ||
| 299 | putBackToken(it, tok.index); | ||
| 300 | return; | ||
| 301 | } | ||
| 302 | level -= 1; | ||
| 303 | }, | ||
| 304 | .Eof => { | ||
| 305 | putBackToken(it, tok.index); | ||
| 306 | return; | ||
| 307 | }, | ||
| 308 | else => {}, | ||
| 309 | } | 275 | } |
| 276 | |||
| 277 | return list.toOwnedSlice(); | ||
| 310 | } | 278 | } |
| 311 | } | ||
| 312 | 279 | ||
| 313 | /// Attempts to find the next statement by searching for a semicolon | 280 | /// Attempts to find next container member by searching for certain tokens |
| 314 | fn findNextStmt(it: *TokenIterator) void { | 281 | fn findNextContainerMember(p: *Parser) void { |
| 315 | var level: u32 = 0; | 282 | var level: u32 = 0; |
| 316 | while (true) { | 283 | while (true) { |
| 317 | const tok = nextToken(it); | 284 | const tok = p.nextToken(); |
| 318 | switch (tok.ptr.id) { | 285 | switch (p.token_ids[tok]) { |
| 319 | .LBrace => level += 1, | 286 | // any of these can start a new top level declaration |
| 320 | .RBrace => { | 287 | .Keyword_test, |
| 321 | if (level == 0) { | 288 | .Keyword_comptime, |
| 322 | putBackToken(it, tok.index); | 289 | .Keyword_pub, |
| 323 | return; | 290 | .Keyword_export, |
| 324 | } | 291 | .Keyword_extern, |
| 325 | level -= 1; | 292 | .Keyword_inline, |
| 326 | }, | 293 | .Keyword_noinline, |
| 327 | .Semicolon => { | 294 | .Keyword_usingnamespace, |
| 328 | if (level == 0) { | 295 | .Keyword_threadlocal, |
| 296 | .Keyword_const, | ||
| 297 | .Keyword_var, | ||
| 298 | .Keyword_fn, | ||
| 299 | .Identifier, | ||
| 300 | => { | ||
| 301 | if (level == 0) { | ||
| 302 | p.putBackToken(tok); | ||
| 303 | return; | ||
| 304 | } | ||
| 305 | }, | ||
| 306 | .Comma, .Semicolon => { | ||
| 307 | // this decl was likely meant to end here | ||
| 308 | if (level == 0) { | ||
| 309 | return; | ||
| 310 | } | ||
| 311 | }, | ||
| 312 | .LParen, .LBracket, .LBrace => level += 1, | ||
| 313 | .RParen, .RBracket => { | ||
| 314 | if (level != 0) level -= 1; | ||
| 315 | }, | ||
| 316 | .RBrace => { | ||
| 317 | if (level == 0) { | ||
| 318 | // end of container, exit | ||
| 319 | p.putBackToken(tok); | ||
| 320 | return; | ||
| 321 | } | ||
| 322 | level -= 1; | ||
| 323 | }, | ||
| 324 | .Eof => { | ||
| 325 | p.putBackToken(tok); | ||
| 329 | return; | 326 | return; |
| 330 | } | 327 | }, |
| 331 | }, | 328 | else => {}, |
| 332 | .Eof => { | 329 | } |
| 333 | putBackToken(it, tok.index); | ||
| 334 | return; | ||
| 335 | }, | ||
| 336 | else => {}, | ||
| 337 | } | 330 | } |
| 338 | } | 331 | } |
| 339 | } | ||
| 340 | |||
| 341 | /// Eat a multiline container doc comment | ||
| 342 | fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 343 | var lines = Node.DocComment.LineList.init(arena); | ||
| 344 | while (eatToken(it, .ContainerDocComment)) |line| { | ||
| 345 | try lines.push(line); | ||
| 346 | } | ||
| 347 | |||
| 348 | if (lines.len == 0) return null; | ||
| 349 | |||
| 350 | const node = try arena.create(Node.DocComment); | ||
| 351 | node.* = .{ | ||
| 352 | .lines = lines, | ||
| 353 | }; | ||
| 354 | return &node.base; | ||
| 355 | } | ||
| 356 | |||
| 357 | /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block | ||
| 358 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 359 | const test_token = eatToken(it, .Keyword_test) orelse return null; | ||
| 360 | const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{ | ||
| 361 | .ExpectedStringLiteral = .{ .token = it.index }, | ||
| 362 | }); | ||
| 363 | const block_node = try expectNode(arena, it, tree, parseBlock, .{ | ||
| 364 | .ExpectedLBrace = .{ .token = it.index }, | ||
| 365 | }); | ||
| 366 | |||
| 367 | const test_node = try arena.create(Node.TestDecl); | ||
| 368 | test_node.* = .{ | ||
| 369 | .doc_comments = null, | ||
| 370 | .test_token = test_token, | ||
| 371 | .name = name_node, | ||
| 372 | .body_node = block_node, | ||
| 373 | }; | ||
| 374 | return &test_node.base; | ||
| 375 | } | ||
| 376 | |||
| 377 | /// TopLevelComptime <- KEYWORD_comptime BlockExpr | ||
| 378 | fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 379 | const tok = eatToken(it, .Keyword_comptime) orelse return null; | ||
| 380 | const lbrace = eatToken(it, .LBrace) orelse { | ||
| 381 | putBackToken(it, tok); | ||
| 382 | return null; | ||
| 383 | }; | ||
| 384 | putBackToken(it, lbrace); | ||
| 385 | const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{ | ||
| 386 | .ExpectedLabelOrLBrace = .{ .token = it.index }, | ||
| 387 | }); | ||
| 388 | |||
| 389 | const comptime_node = try arena.create(Node.Comptime); | ||
| 390 | comptime_node.* = .{ | ||
| 391 | .doc_comments = null, | ||
| 392 | .comptime_token = tok, | ||
| 393 | .expr = block_node, | ||
| 394 | }; | ||
| 395 | return &comptime_node.base; | ||
| 396 | } | ||
| 397 | |||
| 398 | /// TopLevelDecl | ||
| 399 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) | ||
| 400 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl | ||
| 401 | /// / KEYWORD_usingnamespace Expr SEMICOLON | ||
| 402 | fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 403 | var lib_name: ?*Node = null; | ||
| 404 | const extern_export_inline_token = blk: { | ||
| 405 | if (eatToken(it, .Keyword_export)) |token| break :blk token; | ||
| 406 | if (eatToken(it, .Keyword_extern)) |token| { | ||
| 407 | lib_name = try parseStringLiteralSingle(arena, it, tree); | ||
| 408 | break :blk token; | ||
| 409 | } | ||
| 410 | if (eatToken(it, .Keyword_inline)) |token| break :blk token; | ||
| 411 | if (eatToken(it, .Keyword_noinline)) |token| break :blk token; | ||
| 412 | break :blk null; | ||
| 413 | }; | ||
| 414 | 332 | ||
| 415 | if (try parseFnProto(arena, it, tree)) |node| { | 333 | /// Attempts to find the next statement by searching for a semicolon |
| 416 | const fn_node = node.cast(Node.FnProto).?; | 334 | fn findNextStmt(p: *Parser) void { |
| 417 | fn_node.*.extern_export_inline_token = extern_export_inline_token; | 335 | var level: u32 = 0; |
| 418 | fn_node.*.lib_name = lib_name; | 336 | while (true) { |
| 419 | if (eatToken(it, .Semicolon)) |_| return node; | 337 | const tok = p.nextToken(); |
| 420 | 338 | switch (p.token_ids[tok]) { | |
| 421 | if (try expectNodeRecoverable(arena, it, tree, parseBlock, .{ | 339 | .LBrace => level += 1, |
| 422 | // since parseBlock only return error.ParseError on | 340 | .RBrace => { |
| 423 | // a missing '}' we can assume this function was | 341 | if (level == 0) { |
| 424 | // supposed to end here. | 342 | p.putBackToken(tok); |
| 425 | .ExpectedSemiOrLBrace = .{ .token = it.index }, | 343 | return; |
| 426 | })) |body_node| { | 344 | } |
| 427 | fn_node.body_node = body_node; | 345 | level -= 1; |
| 346 | }, | ||
| 347 | .Semicolon => { | ||
| 348 | if (level == 0) { | ||
| 349 | return; | ||
| 350 | } | ||
| 351 | }, | ||
| 352 | .Eof => { | ||
| 353 | p.putBackToken(tok); | ||
| 354 | return; | ||
| 355 | }, | ||
| 356 | else => {}, | ||
| 357 | } | ||
| 428 | } | 358 | } |
| 429 | return node; | ||
| 430 | } | 359 | } |
| 431 | 360 | ||
| 432 | if (extern_export_inline_token) |token| { | 361 | /// Eat a multiline container doc comment |
| 433 | if (tree.tokens.at(token).id == .Keyword_inline or | 362 | fn parseContainerDocComments(p: *Parser) !?*Node { |
| 434 | tree.tokens.at(token).id == .Keyword_noinline) | 363 | if (p.eatToken(.ContainerDocComment)) |first_line| { |
| 435 | { | 364 | while (p.eatToken(.ContainerDocComment)) |_| {} |
| 436 | try tree.errors.push(.{ | 365 | const node = try p.arena.allocator.create(Node.DocComment); |
| 437 | .ExpectedFn = .{ .token = it.index }, | 366 | node.* = .{ .first_line = first_line }; |
| 438 | }); | 367 | return &node.base; |
| 439 | return error.ParseError; | ||
| 440 | } | 368 | } |
| 369 | return null; | ||
| 441 | } | 370 | } |
| 442 | 371 | ||
| 443 | const thread_local_token = eatToken(it, .Keyword_threadlocal); | 372 | /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block |
| 444 | 373 | fn parseTestDecl(p: *Parser) !?*Node { | |
| 445 | if (try parseVarDecl(arena, it, tree)) |node| { | 374 | const test_token = p.eatToken(.Keyword_test) orelse return null; |
| 446 | var var_decl = node.cast(Node.VarDecl).?; | 375 | const name_node = try p.expectNode(parseStringLiteralSingle, .{ |
| 447 | var_decl.*.thread_local_token = thread_local_token; | 376 | .ExpectedStringLiteral = .{ .token = p.tok_i }, |
| 448 | var_decl.*.comptime_token = null; | ||
| 449 | var_decl.*.extern_export_token = extern_export_inline_token; | ||
| 450 | var_decl.*.lib_name = lib_name; | ||
| 451 | return node; | ||
| 452 | } | ||
| 453 | |||
| 454 | if (thread_local_token != null) { | ||
| 455 | try tree.errors.push(.{ | ||
| 456 | .ExpectedVarDecl = .{ .token = it.index }, | ||
| 457 | }); | 377 | }); |
| 458 | // ignore this and try again; | 378 | const block_node = try p.expectNode(parseBlock, .{ |
| 459 | return error.ParseError; | 379 | .ExpectedLBrace = .{ .token = p.tok_i }, |
| 460 | } | ||
| 461 | |||
| 462 | if (extern_export_inline_token) |token| { | ||
| 463 | try tree.errors.push(.{ | ||
| 464 | .ExpectedVarDeclOrFn = .{ .token = it.index }, | ||
| 465 | }); | 380 | }); |
| 466 | // ignore this and try again; | 381 | |
| 467 | return error.ParseError; | 382 | const test_node = try p.arena.allocator.create(Node.TestDecl); |
| 383 | test_node.* = .{ | ||
| 384 | .doc_comments = null, | ||
| 385 | .test_token = test_token, | ||
| 386 | .name = name_node, | ||
| 387 | .body_node = block_node, | ||
| 388 | }; | ||
| 389 | return &test_node.base; | ||
| 468 | } | 390 | } |
| 469 | 391 | ||
| 470 | return try parseUse(arena, it, tree); | 392 | /// TopLevelComptime <- KEYWORD_comptime BlockExpr |
| 471 | } | 393 | fn parseTopLevelComptime(p: *Parser) !?*Node { |
| 394 | const tok = p.eatToken(.Keyword_comptime) orelse return null; | ||
| 395 | const lbrace = p.eatToken(.LBrace) orelse { | ||
| 396 | p.putBackToken(tok); | ||
| 397 | return null; | ||
| 398 | }; | ||
| 399 | p.putBackToken(lbrace); | ||
| 400 | const block_node = try p.expectNode(parseBlockExpr, .{ | ||
| 401 | .ExpectedLabelOrLBrace = .{ .token = p.tok_i }, | ||
| 402 | }); | ||
| 472 | 403 | ||
| 473 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) | 404 | const comptime_node = try p.arena.allocator.create(Node.Comptime); |
| 474 | fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 405 | comptime_node.* = .{ |
| 475 | // TODO: Remove once extern/async fn rewriting is | 406 | .doc_comments = null, |
| 476 | var is_async = false; | 407 | .comptime_token = tok, |
| 477 | var is_extern = false; | 408 | .expr = block_node, |
| 478 | const cc_token: ?usize = blk: { | 409 | }; |
| 479 | if (eatToken(it, .Keyword_extern)) |token| { | 410 | return &comptime_node.base; |
| 480 | is_extern = true; | 411 | } |
| 481 | break :blk token; | 412 | |
| 482 | } | 413 | /// TopLevelDecl |
| 483 | if (eatToken(it, .Keyword_async)) |token| { | 414 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) |
| 484 | is_async = true; | 415 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl |
| 485 | break :blk token; | 416 | /// / KEYWORD_usingnamespace Expr SEMICOLON |
| 486 | } | 417 | fn parseTopLevelDecl(p: *Parser) !?*Node { |
| 487 | break :blk null; | 418 | var lib_name: ?*Node = null; |
| 488 | }; | 419 | const extern_export_inline_token = blk: { |
| 489 | const fn_token = eatToken(it, .Keyword_fn) orelse { | 420 | if (p.eatToken(.Keyword_export)) |token| break :blk token; |
| 490 | if (cc_token) |token| | 421 | if (p.eatToken(.Keyword_extern)) |token| { |
| 491 | putBackToken(it, token); | 422 | lib_name = try p.parseStringLiteralSingle(); |
| 492 | return null; | 423 | break :blk token; |
| 493 | }; | 424 | } |
| 494 | const name_token = eatToken(it, .Identifier); | 425 | if (p.eatToken(.Keyword_inline)) |token| break :blk token; |
| 495 | const lparen = try expectToken(it, tree, .LParen); | 426 | if (p.eatToken(.Keyword_noinline)) |token| break :blk token; |
| 496 | const params = try parseParamDeclList(arena, it, tree); | 427 | break :blk null; |
| 497 | const rparen = try expectToken(it, tree, .RParen); | 428 | }; |
| 498 | const align_expr = try parseByteAlign(arena, it, tree); | ||
| 499 | const section_expr = try parseLinkSection(arena, it, tree); | ||
| 500 | const callconv_expr = try parseCallconv(arena, it, tree); | ||
| 501 | const exclamation_token = eatToken(it, .Bang); | ||
| 502 | |||
| 503 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse | ||
| 504 | try expectNodeRecoverable(arena, it, tree, parseTypeExpr, .{ | ||
| 505 | // most likely the user forgot to specify the return type. | ||
| 506 | // Mark return type as invalid and try to continue. | ||
| 507 | .ExpectedReturnType = .{ .token = it.index }, | ||
| 508 | }); | ||
| 509 | |||
| 510 | // TODO https://github.com/ziglang/zig/issues/3750 | ||
| 511 | const R = Node.FnProto.ReturnType; | ||
| 512 | const return_type = if (return_type_expr == null) | ||
| 513 | R{ .Invalid = rparen } | ||
| 514 | else if (exclamation_token != null) | ||
| 515 | R{ .InferErrorSet = return_type_expr.? } | ||
| 516 | else | ||
| 517 | R{ .Explicit = return_type_expr.? }; | ||
| 518 | |||
| 519 | const var_args_token = if (params.len > 0) blk: { | ||
| 520 | const param_type = params.at(params.len - 1).*.cast(Node.ParamDecl).?.param_type; | ||
| 521 | break :blk if (param_type == .var_args) param_type.var_args else null; | ||
| 522 | } else | ||
| 523 | null; | ||
| 524 | |||
| 525 | const fn_proto_node = try arena.create(Node.FnProto); | ||
| 526 | fn_proto_node.* = .{ | ||
| 527 | .doc_comments = null, | ||
| 528 | .visib_token = null, | ||
| 529 | .fn_token = fn_token, | ||
| 530 | .name_token = name_token, | ||
| 531 | .params = params, | ||
| 532 | .return_type = return_type, | ||
| 533 | .var_args_token = var_args_token, | ||
| 534 | .extern_export_inline_token = null, | ||
| 535 | .body_node = null, | ||
| 536 | .lib_name = null, | ||
| 537 | .align_expr = align_expr, | ||
| 538 | .section_expr = section_expr, | ||
| 539 | .callconv_expr = callconv_expr, | ||
| 540 | .is_extern_prototype = is_extern, | ||
| 541 | .is_async = is_async, | ||
| 542 | }; | ||
| 543 | 429 | ||
| 544 | return &fn_proto_node.base; | 430 | if (try p.parseFnProto()) |node| { |
| 545 | } | 431 | const fn_node = node.cast(Node.FnProto).?; |
| 432 | fn_node.*.extern_export_inline_token = extern_export_inline_token; | ||
| 433 | fn_node.*.lib_name = lib_name; | ||
| 434 | if (p.eatToken(.Semicolon)) |_| return node; | ||
| 435 | |||
| 436 | if (try p.expectNodeRecoverable(parseBlock, .{ | ||
| 437 | // since parseBlock only return error.ParseError on | ||
| 438 | // a missing '}' we can assume this function was | ||
| 439 | // supposed to end here. | ||
| 440 | .ExpectedSemiOrLBrace = .{ .token = p.tok_i }, | ||
| 441 | })) |body_node| { | ||
| 442 | fn_node.body_node = body_node; | ||
| 443 | } | ||
| 444 | return node; | ||
| 445 | } | ||
| 546 | 446 | ||
| 547 | /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON | 447 | if (extern_export_inline_token) |token| { |
| 548 | fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 448 | if (p.token_ids[token] == .Keyword_inline or |
| 549 | const mut_token = eatToken(it, .Keyword_const) orelse | 449 | p.token_ids[token] == .Keyword_noinline) |
| 550 | eatToken(it, .Keyword_var) orelse | 450 | { |
| 551 | return null; | 451 | try p.errors.append(p.gpa, .{ |
| 452 | .ExpectedFn = .{ .token = p.tok_i }, | ||
| 453 | }); | ||
| 454 | return error.ParseError; | ||
| 455 | } | ||
| 456 | } | ||
| 552 | 457 | ||
| 553 | const name_token = try expectToken(it, tree, .Identifier); | 458 | const thread_local_token = p.eatToken(.Keyword_threadlocal); |
| 554 | const type_node = if (eatToken(it, .Colon) != null) | ||
| 555 | try expectNode(arena, it, tree, parseTypeExpr, .{ | ||
| 556 | .ExpectedTypeExpr = .{ .token = it.index }, | ||
| 557 | }) | ||
| 558 | else | ||
| 559 | null; | ||
| 560 | const align_node = try parseByteAlign(arena, it, tree); | ||
| 561 | const section_node = try parseLinkSection(arena, it, tree); | ||
| 562 | const eq_token = eatToken(it, .Equal); | ||
| 563 | const init_node = if (eq_token != null) blk: { | ||
| 564 | break :blk try expectNode(arena, it, tree, parseExpr, .{ | ||
| 565 | .ExpectedExpr = .{ .token = it.index }, | ||
| 566 | }); | ||
| 567 | } else null; | ||
| 568 | const semicolon_token = try expectToken(it, tree, .Semicolon); | ||
| 569 | |||
| 570 | const node = try arena.create(Node.VarDecl); | ||
| 571 | node.* = .{ | ||
| 572 | .doc_comments = null, | ||
| 573 | .visib_token = null, | ||
| 574 | .thread_local_token = null, | ||
| 575 | .name_token = name_token, | ||
| 576 | .eq_token = eq_token, | ||
| 577 | .mut_token = mut_token, | ||
| 578 | .comptime_token = null, | ||
| 579 | .extern_export_token = null, | ||
| 580 | .lib_name = null, | ||
| 581 | .type_node = type_node, | ||
| 582 | .align_node = align_node, | ||
| 583 | .section_node = section_node, | ||
| 584 | .init_node = init_node, | ||
| 585 | .semicolon_token = semicolon_token, | ||
| 586 | }; | ||
| 587 | return &node.base; | ||
| 588 | } | ||
| 589 | 459 | ||
| 590 | /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? | 460 | if (try p.parseVarDecl()) |node| { |
| 591 | fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 461 | var var_decl = node.cast(Node.VarDecl).?; |
| 592 | const comptime_token = eatToken(it, .Keyword_comptime); | 462 | var_decl.*.thread_local_token = thread_local_token; |
| 593 | const name_token = eatToken(it, .Identifier) orelse { | 463 | var_decl.*.comptime_token = null; |
| 594 | if (comptime_token) |t| putBackToken(it, t); | 464 | var_decl.*.extern_export_token = extern_export_inline_token; |
| 595 | return null; | 465 | var_decl.*.lib_name = lib_name; |
| 596 | }; | 466 | return node; |
| 467 | } | ||
| 597 | 468 | ||
| 598 | var align_expr: ?*Node = null; | 469 | if (thread_local_token != null) { |
| 599 | var type_expr: ?*Node = null; | 470 | try p.errors.append(p.gpa, .{ |
| 600 | if (eatToken(it, .Colon)) |_| { | 471 | .ExpectedVarDecl = .{ .token = p.tok_i }, |
| 601 | if (eatToken(it, .Keyword_var)) |var_tok| { | ||
| 602 | const node = try arena.create(ast.Node.VarType); | ||
| 603 | node.* = .{ .token = var_tok }; | ||
| 604 | type_expr = &node.base; | ||
| 605 | } else { | ||
| 606 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | ||
| 607 | .ExpectedTypeExpr = .{ .token = it.index }, | ||
| 608 | }); | 472 | }); |
| 609 | align_expr = try parseByteAlign(arena, it, tree); | 473 | // ignore this and try again; |
| 474 | return error.ParseError; | ||
| 610 | } | 475 | } |
| 611 | } | ||
| 612 | 476 | ||
| 613 | const value_expr = if (eatToken(it, .Equal)) |_| | 477 | if (extern_export_inline_token) |token| { |
| 614 | try expectNode(arena, it, tree, parseExpr, .{ | 478 | try p.errors.append(p.gpa, .{ |
| 615 | .ExpectedExpr = .{ .token = it.index }, | 479 | .ExpectedVarDeclOrFn = .{ .token = p.tok_i }, |
| 616 | }) | 480 | }); |
| 617 | else | 481 | // ignore this and try again; |
| 618 | null; | 482 | return error.ParseError; |
| 619 | 483 | } | |
| 620 | const node = try arena.create(Node.ContainerField); | ||
| 621 | node.* = .{ | ||
| 622 | .doc_comments = null, | ||
| 623 | .comptime_token = comptime_token, | ||
| 624 | .name_token = name_token, | ||
| 625 | .type_expr = type_expr, | ||
| 626 | .value_expr = value_expr, | ||
| 627 | .align_expr = align_expr, | ||
| 628 | }; | ||
| 629 | return &node.base; | ||
| 630 | } | ||
| 631 | 484 | ||
| 632 | /// Statement | 485 | return p.parseUse(); |
| 633 | /// <- KEYWORD_comptime? VarDecl | ||
| 634 | /// / KEYWORD_comptime BlockExprStatement | ||
| 635 | /// / KEYWORD_nosuspend BlockExprStatement | ||
| 636 | /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) | ||
| 637 | /// / KEYWORD_defer BlockExprStatement | ||
| 638 | /// / KEYWORD_errdefer Payload? BlockExprStatement | ||
| 639 | /// / IfStatement | ||
| 640 | /// / LabeledStatement | ||
| 641 | /// / SwitchExpr | ||
| 642 | /// / AssignExpr SEMICOLON | ||
| 643 | fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { | ||
| 644 | const comptime_token = eatToken(it, .Keyword_comptime); | ||
| 645 | |||
| 646 | const var_decl_node = try parseVarDecl(arena, it, tree); | ||
| 647 | if (var_decl_node) |node| { | ||
| 648 | const var_decl = node.cast(Node.VarDecl).?; | ||
| 649 | var_decl.comptime_token = comptime_token; | ||
| 650 | return node; | ||
| 651 | } | 486 | } |
| 652 | 487 | ||
| 653 | if (comptime_token) |token| { | 488 | /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) |
| 654 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ | 489 | fn parseFnProto(p: *Parser) !?*Node { |
| 655 | .ExpectedBlockOrAssignment = .{ .token = it.index }, | 490 | // TODO: Remove once extern/async fn rewriting is |
| 491 | var is_async = false; | ||
| 492 | var is_extern = false; | ||
| 493 | const cc_token: ?TokenIndex = blk: { | ||
| 494 | if (p.eatToken(.Keyword_extern)) |token| { | ||
| 495 | is_extern = true; | ||
| 496 | break :blk token; | ||
| 497 | } | ||
| 498 | if (p.eatToken(.Keyword_async)) |token| { | ||
| 499 | is_async = true; | ||
| 500 | break :blk token; | ||
| 501 | } | ||
| 502 | break :blk null; | ||
| 503 | }; | ||
| 504 | const fn_token = p.eatToken(.Keyword_fn) orelse { | ||
| 505 | if (cc_token) |token| | ||
| 506 | p.putBackToken(token); | ||
| 507 | return null; | ||
| 508 | }; | ||
| 509 | const name_token = p.eatToken(.Identifier); | ||
| 510 | const lparen = try p.expectToken(.LParen); | ||
| 511 | const params = try p.parseParamDeclList(); | ||
| 512 | defer p.gpa.free(params); | ||
| 513 | const rparen = try p.expectToken(.RParen); | ||
| 514 | const align_expr = try p.parseByteAlign(); | ||
| 515 | const section_expr = try p.parseLinkSection(); | ||
| 516 | const callconv_expr = try p.parseCallconv(); | ||
| 517 | const exclamation_token = p.eatToken(.Bang); | ||
| 518 | |||
| 519 | const return_type_expr = (try p.parseVarType()) orelse | ||
| 520 | try p.expectNodeRecoverable(parseTypeExpr, .{ | ||
| 521 | // most likely the user forgot to specify the return type. | ||
| 522 | // Mark return type as invalid and try to continue. | ||
| 523 | .ExpectedReturnType = .{ .token = p.tok_i }, | ||
| 656 | }); | 524 | }); |
| 657 | 525 | ||
| 658 | const node = try arena.create(Node.Comptime); | 526 | // TODO https://github.com/ziglang/zig/issues/3750 |
| 659 | node.* = .{ | 527 | const R = Node.FnProto.ReturnType; |
| 660 | .doc_comments = null, | 528 | const return_type = if (return_type_expr == null) |
| 661 | .comptime_token = token, | 529 | R{ .Invalid = rparen } |
| 662 | .expr = block_expr, | 530 | else if (exclamation_token != null) |
| 663 | }; | 531 | R{ .InferErrorSet = return_type_expr.? } |
| 664 | return &node.base; | 532 | else |
| 665 | } | 533 | R{ .Explicit = return_type_expr.? }; |
| 666 | 534 | ||
| 667 | if (eatToken(it, .Keyword_nosuspend)) |nosuspend_token| { | 535 | const var_args_token = if (params.len > 0) blk: { |
| 668 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ | 536 | const param_type = params[params.len - 1].param_type; |
| 669 | .ExpectedBlockOrAssignment = .{ .token = it.index }, | 537 | break :blk if (param_type == .var_args) param_type.var_args else null; |
| 670 | }); | 538 | } else |
| 539 | null; | ||
| 671 | 540 | ||
| 672 | const node = try arena.create(Node.Nosuspend); | 541 | const fn_proto_node = try Node.FnProto.alloc(&p.arena.allocator, params.len); |
| 673 | node.* = .{ | 542 | fn_proto_node.* = .{ |
| 674 | .nosuspend_token = nosuspend_token, | 543 | .doc_comments = null, |
| 675 | .expr = block_expr, | 544 | .visib_token = null, |
| 545 | .fn_token = fn_token, | ||
| 546 | .name_token = name_token, | ||
| 547 | .params_len = params.len, | ||
| 548 | .return_type = return_type, | ||
| 549 | .var_args_token = var_args_token, | ||
| 550 | .extern_export_inline_token = null, | ||
| 551 | .body_node = null, | ||
| 552 | .lib_name = null, | ||
| 553 | .align_expr = align_expr, | ||
| 554 | .section_expr = section_expr, | ||
| 555 | .callconv_expr = callconv_expr, | ||
| 556 | .is_extern_prototype = is_extern, | ||
| 557 | .is_async = is_async, | ||
| 676 | }; | 558 | }; |
| 677 | return &node.base; | 559 | std.mem.copy(Node.FnProto.ParamDecl, fn_proto_node.params(), params); |
| 560 | |||
| 561 | return &fn_proto_node.base; | ||
| 678 | } | 562 | } |
| 679 | 563 | ||
| 680 | if (eatToken(it, .Keyword_suspend)) |suspend_token| { | 564 | /// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON |
| 681 | const semicolon = eatToken(it, .Semicolon); | 565 | fn parseVarDecl(p: *Parser) !?*Node { |
| 566 | const mut_token = p.eatToken(.Keyword_const) orelse | ||
| 567 | p.eatToken(.Keyword_var) orelse | ||
| 568 | return null; | ||
| 682 | 569 | ||
| 683 | const body_node = if (semicolon == null) blk: { | 570 | const name_token = try p.expectToken(.Identifier); |
| 684 | break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{ | 571 | const type_node = if (p.eatToken(.Colon) != null) |
| 685 | .ExpectedBlockOrExpression = .{ .token = it.index }, | 572 | try p.expectNode(parseTypeExpr, .{ |
| 573 | .ExpectedTypeExpr = .{ .token = p.tok_i }, | ||
| 574 | }) | ||
| 575 | else | ||
| 576 | null; | ||
| 577 | const align_node = try p.parseByteAlign(); | ||
| 578 | const section_node = try p.parseLinkSection(); | ||
| 579 | const eq_token = p.eatToken(.Equal); | ||
| 580 | const init_node = if (eq_token != null) blk: { | ||
| 581 | break :blk try p.expectNode(parseExpr, .{ | ||
| 582 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 686 | }); | 583 | }); |
| 687 | } else null; | 584 | } else null; |
| 585 | const semicolon_token = try p.expectToken(.Semicolon); | ||
| 688 | 586 | ||
| 689 | const node = try arena.create(Node.Suspend); | 587 | const node = try p.arena.allocator.create(Node.VarDecl); |
| 690 | node.* = .{ | 588 | node.* = .{ |
| 691 | .suspend_token = suspend_token, | 589 | .doc_comments = null, |
| 692 | .body = body_node, | 590 | .visib_token = null, |
| 591 | .thread_local_token = null, | ||
| 592 | .name_token = name_token, | ||
| 593 | .eq_token = eq_token, | ||
| 594 | .mut_token = mut_token, | ||
| 595 | .comptime_token = null, | ||
| 596 | .extern_export_token = null, | ||
| 597 | .lib_name = null, | ||
| 598 | .type_node = type_node, | ||
| 599 | .align_node = align_node, | ||
| 600 | .section_node = section_node, | ||
| 601 | .init_node = init_node, | ||
| 602 | .semicolon_token = semicolon_token, | ||
| 693 | }; | 603 | }; |
| 694 | return &node.base; | 604 | return &node.base; |
| 695 | } | 605 | } |
| 696 | 606 | ||
| 697 | const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); | 607 | /// ContainerField <- KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? |
| 698 | if (defer_token) |token| { | 608 | fn parseContainerField(p: *Parser) !?*Node { |
| 699 | const payload = if (tree.tokens.at(token).id == .Keyword_errdefer) | 609 | const comptime_token = p.eatToken(.Keyword_comptime); |
| 700 | try parsePayload(arena, it, tree) | 610 | const name_token = p.eatToken(.Identifier) orelse { |
| 611 | if (comptime_token) |t| p.putBackToken(t); | ||
| 612 | return null; | ||
| 613 | }; | ||
| 614 | |||
| 615 | var align_expr: ?*Node = null; | ||
| 616 | var type_expr: ?*Node = null; | ||
| 617 | if (p.eatToken(.Colon)) |_| { | ||
| 618 | if (p.eatToken(.Keyword_var)) |var_tok| { | ||
| 619 | const node = try p.arena.allocator.create(Node.VarType); | ||
| 620 | node.* = .{ .token = var_tok }; | ||
| 621 | type_expr = &node.base; | ||
| 622 | } else { | ||
| 623 | type_expr = try p.expectNode(parseTypeExpr, .{ | ||
| 624 | .ExpectedTypeExpr = .{ .token = p.tok_i }, | ||
| 625 | }); | ||
| 626 | align_expr = try p.parseByteAlign(); | ||
| 627 | } | ||
| 628 | } | ||
| 629 | |||
| 630 | const value_expr = if (p.eatToken(.Equal)) |_| | ||
| 631 | try p.expectNode(parseExpr, .{ | ||
| 632 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 633 | }) | ||
| 701 | else | 634 | else |
| 702 | null; | 635 | null; |
| 703 | const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{ | 636 | |
| 704 | .ExpectedBlockOrExpression = .{ .token = it.index }, | 637 | const node = try p.arena.allocator.create(Node.ContainerField); |
| 705 | }); | ||
| 706 | const node = try arena.create(Node.Defer); | ||
| 707 | node.* = .{ | 638 | node.* = .{ |
| 708 | .defer_token = token, | 639 | .doc_comments = null, |
| 709 | .expr = expr_node, | 640 | .comptime_token = comptime_token, |
| 710 | .payload = payload, | 641 | .name_token = name_token, |
| 642 | .type_expr = type_expr, | ||
| 643 | .value_expr = value_expr, | ||
| 644 | .align_expr = align_expr, | ||
| 711 | }; | 645 | }; |
| 712 | return &node.base; | 646 | return &node.base; |
| 713 | } | 647 | } |
| 714 | 648 | ||
| 715 | if (try parseIfStatement(arena, it, tree)) |node| return node; | 649 | /// Statement |
| 716 | if (try parseLabeledStatement(arena, it, tree)) |node| return node; | 650 | /// <- KEYWORD_comptime? VarDecl |
| 717 | if (try parseSwitchExpr(arena, it, tree)) |node| return node; | 651 | /// / KEYWORD_comptime BlockExprStatement |
| 718 | if (try parseAssignExpr(arena, it, tree)) |node| { | 652 | /// / KEYWORD_nosuspend BlockExprStatement |
| 719 | _ = try expectTokenRecoverable(it, tree, .Semicolon); | 653 | /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) |
| 720 | return node; | 654 | /// / KEYWORD_defer BlockExprStatement |
| 721 | } | 655 | /// / KEYWORD_errdefer Payload? BlockExprStatement |
| 656 | /// / IfStatement | ||
| 657 | /// / LabeledStatement | ||
| 658 | /// / SwitchExpr | ||
| 659 | /// / AssignExpr SEMICOLON | ||
| 660 | fn parseStatement(p: *Parser) Error!?*Node { | ||
| 661 | const comptime_token = p.eatToken(.Keyword_comptime); | ||
| 662 | |||
| 663 | const var_decl_node = try p.parseVarDecl(); | ||
| 664 | if (var_decl_node) |node| { | ||
| 665 | const var_decl = node.cast(Node.VarDecl).?; | ||
| 666 | var_decl.comptime_token = comptime_token; | ||
| 667 | return node; | ||
| 668 | } | ||
| 722 | 669 | ||
| 723 | return null; | 670 | if (comptime_token) |token| { |
| 724 | } | 671 | const block_expr = try p.expectNode(parseBlockExprStatement, .{ |
| 672 | .ExpectedBlockOrAssignment = .{ .token = p.tok_i }, | ||
| 673 | }); | ||
| 725 | 674 | ||
| 726 | /// IfStatement | 675 | const node = try p.arena.allocator.create(Node.Comptime); |
| 727 | /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? | 676 | node.* = .{ |
| 728 | /// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | 677 | .doc_comments = null, |
| 729 | fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 678 | .comptime_token = token, |
| 730 | const if_node = (try parseIfPrefix(arena, it, tree)) orelse return null; | 679 | .expr = block_expr, |
| 731 | const if_prefix = if_node.cast(Node.If).?; | 680 | }; |
| 732 | 681 | return &node.base; | |
| 733 | const block_expr = (try parseBlockExpr(arena, it, tree)); | 682 | } |
| 734 | const assign_expr = if (block_expr == null) | ||
| 735 | try expectNode(arena, it, tree, parseAssignExpr, .{ | ||
| 736 | .ExpectedBlockOrAssignment = .{ .token = it.index }, | ||
| 737 | }) | ||
| 738 | else | ||
| 739 | null; | ||
| 740 | |||
| 741 | const semicolon = if (assign_expr != null) eatToken(it, .Semicolon) else null; | ||
| 742 | |||
| 743 | const else_node = if (semicolon == null) blk: { | ||
| 744 | const else_token = eatToken(it, .Keyword_else) orelse break :blk null; | ||
| 745 | const payload = try parsePayload(arena, it, tree); | ||
| 746 | const else_body = try expectNode(arena, it, tree, parseStatement, .{ | ||
| 747 | .InvalidToken = .{ .token = it.index }, | ||
| 748 | }); | ||
| 749 | 683 | ||
| 750 | const node = try arena.create(Node.Else); | 684 | if (p.eatToken(.Keyword_nosuspend)) |nosuspend_token| { |
| 751 | node.* = .{ | 685 | const block_expr = try p.expectNode(parseBlockExprStatement, .{ |
| 752 | .else_token = else_token, | 686 | .ExpectedBlockOrAssignment = .{ .token = p.tok_i }, |
| 753 | .payload = payload, | 687 | }); |
| 754 | .body = else_body, | ||
| 755 | }; | ||
| 756 | 688 | ||
| 757 | break :blk node; | 689 | const node = try p.arena.allocator.create(Node.Nosuspend); |
| 758 | } else null; | 690 | node.* = .{ |
| 691 | .nosuspend_token = nosuspend_token, | ||
| 692 | .expr = block_expr, | ||
| 693 | }; | ||
| 694 | return &node.base; | ||
| 695 | } | ||
| 759 | 696 | ||
| 760 | if (block_expr) |body| { | 697 | if (p.eatToken(.Keyword_suspend)) |suspend_token| { |
| 761 | if_prefix.body = body; | 698 | const semicolon = p.eatToken(.Semicolon); |
| 762 | if_prefix.@"else" = else_node; | ||
| 763 | return if_node; | ||
| 764 | } | ||
| 765 | 699 | ||
| 766 | if (assign_expr) |body| { | 700 | const body_node = if (semicolon == null) blk: { |
| 767 | if_prefix.body = body; | 701 | break :blk try p.expectNode(parseBlockExprStatement, .{ |
| 768 | if (semicolon != null) return if_node; | 702 | .ExpectedBlockOrExpression = .{ .token = p.tok_i }, |
| 769 | if (else_node != null) { | 703 | }); |
| 770 | if_prefix.@"else" = else_node; | 704 | } else null; |
| 771 | return if_node; | ||
| 772 | } | ||
| 773 | try tree.errors.push(.{ | ||
| 774 | .ExpectedSemiOrElse = .{ .token = it.index }, | ||
| 775 | }); | ||
| 776 | } | ||
| 777 | |||
| 778 | return if_node; | ||
| 779 | } | ||
| 780 | 705 | ||
| 781 | /// LabeledStatement <- BlockLabel? (Block / LoopStatement) | 706 | const node = try p.arena.allocator.create(Node.Suspend); |
| 782 | fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 707 | node.* = .{ |
| 783 | var colon: TokenIndex = undefined; | 708 | .suspend_token = suspend_token, |
| 784 | const label_token = parseBlockLabel(arena, it, tree, &colon); | 709 | .body = body_node, |
| 710 | }; | ||
| 711 | return &node.base; | ||
| 712 | } | ||
| 785 | 713 | ||
| 786 | if (try parseBlock(arena, it, tree)) |node| { | 714 | const defer_token = p.eatToken(.Keyword_defer) orelse p.eatToken(.Keyword_errdefer); |
| 787 | node.cast(Node.Block).?.label = label_token; | 715 | if (defer_token) |token| { |
| 788 | return node; | 716 | const payload = if (p.token_ids[token] == .Keyword_errdefer) |
| 789 | } | 717 | try p.parsePayload() |
| 718 | else | ||
| 719 | null; | ||
| 720 | const expr_node = try p.expectNode(parseBlockExprStatement, .{ | ||
| 721 | .ExpectedBlockOrExpression = .{ .token = p.tok_i }, | ||
| 722 | }); | ||
| 723 | const node = try p.arena.allocator.create(Node.Defer); | ||
| 724 | node.* = .{ | ||
| 725 | .defer_token = token, | ||
| 726 | .expr = expr_node, | ||
| 727 | .payload = payload, | ||
| 728 | }; | ||
| 729 | return &node.base; | ||
| 730 | } | ||
| 790 | 731 | ||
| 791 | if (try parseLoopStatement(arena, it, tree)) |node| { | 732 | if (try p.parseIfStatement()) |node| return node; |
| 792 | if (node.cast(Node.For)) |for_node| { | 733 | if (try p.parseLabeledStatement()) |node| return node; |
| 793 | for_node.label = label_token; | 734 | if (try p.parseSwitchExpr()) |node| return node; |
| 794 | } else if (node.cast(Node.While)) |while_node| { | 735 | if (try p.parseAssignExpr()) |node| { |
| 795 | while_node.label = label_token; | 736 | _ = try p.expectTokenRecoverable(.Semicolon); |
| 796 | } else unreachable; | 737 | return node; |
| 797 | return node; | 738 | } |
| 798 | } | ||
| 799 | 739 | ||
| 800 | if (label_token != null) { | 740 | return null; |
| 801 | try tree.errors.push(.{ | ||
| 802 | .ExpectedLabelable = .{ .token = it.index }, | ||
| 803 | }); | ||
| 804 | return error.ParseError; | ||
| 805 | } | 741 | } |
| 806 | 742 | ||
| 807 | return null; | 743 | /// IfStatement |
| 808 | } | 744 | /// <- IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )? |
| 745 | /// / IfPrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | ||
| 746 | fn parseIfStatement(p: *Parser) !?*Node { | ||
| 747 | const if_node = (try p.parseIfPrefix()) orelse return null; | ||
| 748 | const if_prefix = if_node.cast(Node.If).?; | ||
| 809 | 749 | ||
| 810 | /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) | 750 | const block_expr = (try p.parseBlockExpr()); |
| 811 | fn parseLoopStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 751 | const assign_expr = if (block_expr == null) |
| 812 | const inline_token = eatToken(it, .Keyword_inline); | 752 | try p.expectNode(parseAssignExpr, .{ |
| 753 | .ExpectedBlockOrAssignment = .{ .token = p.tok_i }, | ||
| 754 | }) | ||
| 755 | else | ||
| 756 | null; | ||
| 813 | 757 | ||
| 814 | if (try parseForStatement(arena, it, tree)) |node| { | 758 | const semicolon = if (assign_expr != null) p.eatToken(.Semicolon) else null; |
| 815 | node.cast(Node.For).?.inline_token = inline_token; | ||
| 816 | return node; | ||
| 817 | } | ||
| 818 | 759 | ||
| 819 | if (try parseWhileStatement(arena, it, tree)) |node| { | 760 | const else_node = if (semicolon == null) blk: { |
| 820 | node.cast(Node.While).?.inline_token = inline_token; | 761 | const else_token = p.eatToken(.Keyword_else) orelse break :blk null; |
| 821 | return node; | 762 | const payload = try p.parsePayload(); |
| 822 | } | 763 | const else_body = try p.expectNode(parseStatement, .{ |
| 823 | if (inline_token == null) return null; | 764 | .InvalidToken = .{ .token = p.tok_i }, |
| 765 | }); | ||
| 824 | 766 | ||
| 825 | // If we've seen "inline", there should have been a "for" or "while" | 767 | const node = try p.arena.allocator.create(Node.Else); |
| 826 | try tree.errors.push(.{ | 768 | node.* = .{ |
| 827 | .ExpectedInlinable = .{ .token = it.index }, | 769 | .else_token = else_token, |
| 828 | }); | 770 | .payload = payload, |
| 829 | return error.ParseError; | 771 | .body = else_body, |
| 830 | } | 772 | }; |
| 831 | 773 | ||
| 832 | /// ForStatement | 774 | break :blk node; |
| 833 | /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? | 775 | } else null; |
| 834 | /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) | ||
| 835 | fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 836 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; | ||
| 837 | const for_prefix = node.cast(Node.For).?; | ||
| 838 | 776 | ||
| 839 | if (try parseBlockExpr(arena, it, tree)) |block_expr_node| { | 777 | if (block_expr) |body| { |
| 840 | for_prefix.body = block_expr_node; | 778 | if_prefix.body = body; |
| 779 | if_prefix.@"else" = else_node; | ||
| 780 | return if_node; | ||
| 781 | } | ||
| 841 | 782 | ||
| 842 | if (eatToken(it, .Keyword_else)) |else_token| { | 783 | if (assign_expr) |body| { |
| 843 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | 784 | if_prefix.body = body; |
| 844 | .InvalidToken = .{ .token = it.index }, | 785 | if (semicolon != null) return if_node; |
| 786 | if (else_node != null) { | ||
| 787 | if_prefix.@"else" = else_node; | ||
| 788 | return if_node; | ||
| 789 | } | ||
| 790 | try p.errors.append(p.gpa, .{ | ||
| 791 | .ExpectedSemiOrElse = .{ .token = p.tok_i }, | ||
| 845 | }); | 792 | }); |
| 793 | } | ||
| 846 | 794 | ||
| 847 | const else_node = try arena.create(Node.Else); | 795 | return if_node; |
| 848 | else_node.* = .{ | 796 | } |
| 849 | .else_token = else_token, | ||
| 850 | .payload = null, | ||
| 851 | .body = statement_node, | ||
| 852 | }; | ||
| 853 | for_prefix.@"else" = else_node; | ||
| 854 | 797 | ||
| 798 | /// LabeledStatement <- BlockLabel? (Block / LoopStatement) | ||
| 799 | fn parseLabeledStatement(p: *Parser) !?*Node { | ||
| 800 | var colon: TokenIndex = undefined; | ||
| 801 | const label_token = p.parseBlockLabel(&colon); | ||
| 802 | |||
| 803 | if (try p.parseBlock()) |node| { | ||
| 804 | node.cast(Node.Block).?.label = label_token; | ||
| 855 | return node; | 805 | return node; |
| 856 | } | 806 | } |
| 857 | 807 | ||
| 858 | return node; | 808 | if (try p.parseLoopStatement()) |node| { |
| 859 | } | 809 | if (node.cast(Node.For)) |for_node| { |
| 810 | for_node.label = label_token; | ||
| 811 | } else if (node.cast(Node.While)) |while_node| { | ||
| 812 | while_node.label = label_token; | ||
| 813 | } else unreachable; | ||
| 814 | return node; | ||
| 815 | } | ||
| 860 | 816 | ||
| 861 | if (try parseAssignExpr(arena, it, tree)) |assign_expr| { | 817 | if (label_token != null) { |
| 862 | for_prefix.body = assign_expr; | 818 | try p.errors.append(p.gpa, .{ |
| 819 | .ExpectedLabelable = .{ .token = p.tok_i }, | ||
| 820 | }); | ||
| 821 | return error.ParseError; | ||
| 822 | } | ||
| 863 | 823 | ||
| 864 | if (eatToken(it, .Semicolon) != null) return node; | 824 | return null; |
| 825 | } | ||
| 865 | 826 | ||
| 866 | if (eatToken(it, .Keyword_else)) |else_token| { | 827 | /// LoopStatement <- KEYWORD_inline? (ForStatement / WhileStatement) |
| 867 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | 828 | fn parseLoopStatement(p: *Parser) !?*Node { |
| 868 | .ExpectedStatement = .{ .token = it.index }, | 829 | const inline_token = p.eatToken(.Keyword_inline); |
| 869 | }); | ||
| 870 | 830 | ||
| 871 | const else_node = try arena.create(Node.Else); | 831 | if (try p.parseForStatement()) |node| { |
| 872 | else_node.* = .{ | 832 | node.cast(Node.For).?.inline_token = inline_token; |
| 873 | .else_token = else_token, | ||
| 874 | .payload = null, | ||
| 875 | .body = statement_node, | ||
| 876 | }; | ||
| 877 | for_prefix.@"else" = else_node; | ||
| 878 | return node; | 833 | return node; |
| 879 | } | 834 | } |
| 880 | 835 | ||
| 881 | try tree.errors.push(.{ | 836 | if (try p.parseWhileStatement()) |node| { |
| 882 | .ExpectedSemiOrElse = .{ .token = it.index }, | 837 | node.cast(Node.While).?.inline_token = inline_token; |
| 883 | }); | 838 | return node; |
| 839 | } | ||
| 840 | if (inline_token == null) return null; | ||
| 884 | 841 | ||
| 885 | return node; | 842 | // If we've seen "inline", there should have been a "for" or "while" |
| 843 | try p.errors.append(p.gpa, .{ | ||
| 844 | .ExpectedInlinable = .{ .token = p.tok_i }, | ||
| 845 | }); | ||
| 846 | return error.ParseError; | ||
| 886 | } | 847 | } |
| 887 | 848 | ||
| 888 | return null; | 849 | /// ForStatement |
| 889 | } | 850 | /// <- ForPrefix BlockExpr ( KEYWORD_else Statement )? |
| 890 | 851 | /// / ForPrefix AssignExpr ( SEMICOLON / KEYWORD_else Statement ) | |
| 891 | /// WhileStatement | 852 | fn parseForStatement(p: *Parser) !?*Node { |
| 892 | /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? | 853 | const node = (try p.parseForPrefix()) orelse return null; |
| 893 | /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | 854 | const for_prefix = node.cast(Node.For).?; |
| 894 | fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 895 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; | ||
| 896 | const while_prefix = node.cast(Node.While).?; | ||
| 897 | 855 | ||
| 898 | if (try parseBlockExpr(arena, it, tree)) |block_expr_node| { | 856 | if (try p.parseBlockExpr()) |block_expr_node| { |
| 899 | while_prefix.body = block_expr_node; | 857 | for_prefix.body = block_expr_node; |
| 900 | 858 | ||
| 901 | if (eatToken(it, .Keyword_else)) |else_token| { | 859 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 902 | const payload = try parsePayload(arena, it, tree); | 860 | const statement_node = try p.expectNode(parseStatement, .{ |
| 861 | .InvalidToken = .{ .token = p.tok_i }, | ||
| 862 | }); | ||
| 903 | 863 | ||
| 904 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | 864 | const else_node = try p.arena.allocator.create(Node.Else); |
| 905 | .InvalidToken = .{ .token = it.index }, | 865 | else_node.* = .{ |
| 906 | }); | 866 | .else_token = else_token, |
| 867 | .payload = null, | ||
| 868 | .body = statement_node, | ||
| 869 | }; | ||
| 870 | for_prefix.@"else" = else_node; | ||
| 907 | 871 | ||
| 908 | const else_node = try arena.create(Node.Else); | 872 | return node; |
| 909 | else_node.* = .{ | 873 | } |
| 910 | .else_token = else_token, | ||
| 911 | .payload = payload, | ||
| 912 | .body = statement_node, | ||
| 913 | }; | ||
| 914 | while_prefix.@"else" = else_node; | ||
| 915 | 874 | ||
| 916 | return node; | 875 | return node; |
| 917 | } | 876 | } |
| 918 | 877 | ||
| 919 | return node; | 878 | if (try p.parseAssignExpr()) |assign_expr| { |
| 920 | } | 879 | for_prefix.body = assign_expr; |
| 921 | 880 | ||
| 922 | if (try parseAssignExpr(arena, it, tree)) |assign_expr_node| { | 881 | if (p.eatToken(.Semicolon) != null) return node; |
| 923 | while_prefix.body = assign_expr_node; | ||
| 924 | 882 | ||
| 925 | if (eatToken(it, .Semicolon) != null) return node; | 883 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 884 | const statement_node = try p.expectNode(parseStatement, .{ | ||
| 885 | .ExpectedStatement = .{ .token = p.tok_i }, | ||
| 886 | }); | ||
| 926 | 887 | ||
| 927 | if (eatToken(it, .Keyword_else)) |else_token| { | 888 | const else_node = try p.arena.allocator.create(Node.Else); |
| 928 | const payload = try parsePayload(arena, it, tree); | 889 | else_node.* = .{ |
| 890 | .else_token = else_token, | ||
| 891 | .payload = null, | ||
| 892 | .body = statement_node, | ||
| 893 | }; | ||
| 894 | for_prefix.@"else" = else_node; | ||
| 895 | return node; | ||
| 896 | } | ||
| 929 | 897 | ||
| 930 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | 898 | try p.errors.append(p.gpa, .{ |
| 931 | .ExpectedStatement = .{ .token = it.index }, | 899 | .ExpectedSemiOrElse = .{ .token = p.tok_i }, |
| 932 | }); | 900 | }); |
| 933 | 901 | ||
| 934 | const else_node = try arena.create(Node.Else); | ||
| 935 | else_node.* = .{ | ||
| 936 | .else_token = else_token, | ||
| 937 | .payload = payload, | ||
| 938 | .body = statement_node, | ||
| 939 | }; | ||
| 940 | while_prefix.@"else" = else_node; | ||
| 941 | return node; | 902 | return node; |
| 942 | } | 903 | } |
| 943 | 904 | ||
| 944 | try tree.errors.push(.{ | 905 | return null; |
| 945 | .ExpectedSemiOrElse = .{ .token = it.index }, | ||
| 946 | }); | ||
| 947 | |||
| 948 | return node; | ||
| 949 | } | 906 | } |
| 950 | 907 | ||
| 951 | return null; | 908 | /// WhileStatement |
| 952 | } | 909 | /// <- WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )? |
| 910 | /// / WhilePrefix AssignExpr ( SEMICOLON / KEYWORD_else Payload? Statement ) | ||
| 911 | fn parseWhileStatement(p: *Parser) !?*Node { | ||
| 912 | const node = (try p.parseWhilePrefix()) orelse return null; | ||
| 913 | const while_prefix = node.cast(Node.While).?; | ||
| 953 | 914 | ||
| 954 | /// BlockExprStatement | 915 | if (try p.parseBlockExpr()) |block_expr_node| { |
| 955 | /// <- BlockExpr | 916 | while_prefix.body = block_expr_node; |
| 956 | /// / AssignExpr SEMICOLON | ||
| 957 | fn parseBlockExprStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 958 | if (try parseBlockExpr(arena, it, tree)) |node| return node; | ||
| 959 | if (try parseAssignExpr(arena, it, tree)) |node| { | ||
| 960 | _ = try expectTokenRecoverable(it, tree, .Semicolon); | ||
| 961 | return node; | ||
| 962 | } | ||
| 963 | return null; | ||
| 964 | } | ||
| 965 | 917 | ||
| 966 | /// BlockExpr <- BlockLabel? Block | 918 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 967 | fn parseBlockExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { | 919 | const payload = try p.parsePayload(); |
| 968 | var colon: TokenIndex = undefined; | ||
| 969 | const label_token = parseBlockLabel(arena, it, tree, &colon); | ||
| 970 | const block_node = (try parseBlock(arena, it, tree)) orelse { | ||
| 971 | if (label_token) |label| { | ||
| 972 | putBackToken(it, label + 1); // ":" | ||
| 973 | putBackToken(it, label); // IDENTIFIER | ||
| 974 | } | ||
| 975 | return null; | ||
| 976 | }; | ||
| 977 | block_node.cast(Node.Block).?.label = label_token; | ||
| 978 | return block_node; | ||
| 979 | } | ||
| 980 | 920 | ||
| 981 | /// AssignExpr <- Expr (AssignOp Expr)? | 921 | const statement_node = try p.expectNode(parseStatement, .{ |
| 982 | fn parseAssignExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 922 | .InvalidToken = .{ .token = p.tok_i }, |
| 983 | return parseBinOpExpr(arena, it, tree, parseAssignOp, parseExpr, .Once); | 923 | }); |
| 984 | } | ||
| 985 | 924 | ||
| 986 | /// Expr <- KEYWORD_try* BoolOrExpr | 925 | const else_node = try p.arena.allocator.create(Node.Else); |
| 987 | fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { | 926 | else_node.* = .{ |
| 988 | return parsePrefixOpExpr(arena, it, tree, parseTry, parseBoolOrExpr); | 927 | .else_token = else_token, |
| 989 | } | 928 | .payload = payload, |
| 929 | .body = statement_node, | ||
| 930 | }; | ||
| 931 | while_prefix.@"else" = else_node; | ||
| 990 | 932 | ||
| 991 | /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* | 933 | return node; |
| 992 | fn parseBoolOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 934 | } |
| 993 | return parseBinOpExpr( | ||
| 994 | arena, | ||
| 995 | it, | ||
| 996 | tree, | ||
| 997 | SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr), | ||
| 998 | parseBoolAndExpr, | ||
| 999 | .Infinitely, | ||
| 1000 | ); | ||
| 1001 | } | ||
| 1002 | 935 | ||
| 1003 | /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* | 936 | return node; |
| 1004 | fn parseBoolAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 937 | } |
| 1005 | return parseBinOpExpr( | ||
| 1006 | arena, | ||
| 1007 | it, | ||
| 1008 | tree, | ||
| 1009 | SimpleBinOpParseFn(.Keyword_and, .BoolAnd), | ||
| 1010 | parseCompareExpr, | ||
| 1011 | .Infinitely, | ||
| 1012 | ); | ||
| 1013 | } | ||
| 1014 | 938 | ||
| 1015 | /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? | 939 | if (try p.parseAssignExpr()) |assign_expr_node| { |
| 1016 | fn parseCompareExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 940 | while_prefix.body = assign_expr_node; |
| 1017 | return parseBinOpExpr(arena, it, tree, parseCompareOp, parseBitwiseExpr, .Once); | ||
| 1018 | } | ||
| 1019 | 941 | ||
| 1020 | /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* | 942 | if (p.eatToken(.Semicolon) != null) return node; |
| 1021 | fn parseBitwiseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 1022 | return parseBinOpExpr(arena, it, tree, parseBitwiseOp, parseBitShiftExpr, .Infinitely); | ||
| 1023 | } | ||
| 1024 | 943 | ||
| 1025 | /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* | 944 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 1026 | fn parseBitShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 945 | const payload = try p.parsePayload(); |
| 1027 | return parseBinOpExpr(arena, it, tree, parseBitShiftOp, parseAdditionExpr, .Infinitely); | ||
| 1028 | } | ||
| 1029 | 946 | ||
| 1030 | /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* | 947 | const statement_node = try p.expectNode(parseStatement, .{ |
| 1031 | fn parseAdditionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 948 | .ExpectedStatement = .{ .token = p.tok_i }, |
| 1032 | return parseBinOpExpr(arena, it, tree, parseAdditionOp, parseMultiplyExpr, .Infinitely); | 949 | }); |
| 1033 | } | ||
| 1034 | 950 | ||
| 1035 | /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* | 951 | const else_node = try p.arena.allocator.create(Node.Else); |
| 1036 | fn parseMultiplyExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 952 | else_node.* = .{ |
| 1037 | return parseBinOpExpr(arena, it, tree, parseMultiplyOp, parsePrefixExpr, .Infinitely); | 953 | .else_token = else_token, |
| 1038 | } | 954 | .payload = payload, |
| 955 | .body = statement_node, | ||
| 956 | }; | ||
| 957 | while_prefix.@"else" = else_node; | ||
| 958 | return node; | ||
| 959 | } | ||
| 1039 | 960 | ||
| 1040 | /// PrefixExpr <- PrefixOp* PrimaryExpr | 961 | try p.errors.append(p.gpa, .{ |
| 1041 | fn parsePrefixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 962 | .ExpectedSemiOrElse = .{ .token = p.tok_i }, |
| 1042 | return parsePrefixOpExpr(arena, it, tree, parsePrefixOp, parsePrimaryExpr); | 963 | }); |
| 1043 | } | ||
| 1044 | 964 | ||
| 1045 | /// PrimaryExpr | 965 | return node; |
| 1046 | /// <- AsmExpr | 966 | } |
| 1047 | /// / IfExpr | ||
| 1048 | /// / KEYWORD_break BreakLabel? Expr? | ||
| 1049 | /// / KEYWORD_comptime Expr | ||
| 1050 | /// / KEYWORD_nosuspend Expr | ||
| 1051 | /// / KEYWORD_continue BreakLabel? | ||
| 1052 | /// / KEYWORD_resume Expr | ||
| 1053 | /// / KEYWORD_return Expr? | ||
| 1054 | /// / BlockLabel? LoopExpr | ||
| 1055 | /// / Block | ||
| 1056 | /// / CurlySuffixExpr | ||
| 1057 | fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 1058 | if (try parseAsmExpr(arena, it, tree)) |node| return node; | ||
| 1059 | if (try parseIfExpr(arena, it, tree)) |node| return node; | ||
| 1060 | |||
| 1061 | if (eatToken(it, .Keyword_break)) |token| { | ||
| 1062 | const label = try parseBreakLabel(arena, it, tree); | ||
| 1063 | const expr_node = try parseExpr(arena, it, tree); | ||
| 1064 | const node = try arena.create(Node.ControlFlowExpression); | ||
| 1065 | node.* = .{ | ||
| 1066 | .ltoken = token, | ||
| 1067 | .kind = .{ .Break = label }, | ||
| 1068 | .rhs = expr_node, | ||
| 1069 | }; | ||
| 1070 | return &node.base; | ||
| 1071 | } | ||
| 1072 | 967 | ||
| 1073 | if (eatToken(it, .Keyword_comptime)) |token| { | 968 | return null; |
| 1074 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1075 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1076 | }); | ||
| 1077 | const node = try arena.create(Node.Comptime); | ||
| 1078 | node.* = .{ | ||
| 1079 | .doc_comments = null, | ||
| 1080 | .comptime_token = token, | ||
| 1081 | .expr = expr_node, | ||
| 1082 | }; | ||
| 1083 | return &node.base; | ||
| 1084 | } | 969 | } |
| 1085 | 970 | ||
| 1086 | if (eatToken(it, .Keyword_nosuspend)) |token| { | 971 | /// BlockExprStatement |
| 1087 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | 972 | /// <- BlockExpr |
| 1088 | .ExpectedExpr = .{ .token = it.index }, | 973 | /// / AssignExpr SEMICOLON |
| 1089 | }); | 974 | fn parseBlockExprStatement(p: *Parser) !?*Node { |
| 1090 | const node = try arena.create(Node.Nosuspend); | 975 | if (try p.parseBlockExpr()) |node| return node; |
| 1091 | node.* = .{ | 976 | if (try p.parseAssignExpr()) |node| { |
| 1092 | .nosuspend_token = token, | 977 | _ = try p.expectTokenRecoverable(.Semicolon); |
| 1093 | .expr = expr_node, | 978 | return node; |
| 1094 | }; | 979 | } |
| 1095 | return &node.base; | 980 | return null; |
| 1096 | } | 981 | } |
| 1097 | 982 | ||
| 1098 | if (eatToken(it, .Keyword_continue)) |token| { | 983 | /// BlockExpr <- BlockLabel? Block |
| 1099 | const label = try parseBreakLabel(arena, it, tree); | 984 | fn parseBlockExpr(p: *Parser) Error!?*Node { |
| 1100 | const node = try arena.create(Node.ControlFlowExpression); | 985 | var colon: TokenIndex = undefined; |
| 1101 | node.* = .{ | 986 | const label_token = p.parseBlockLabel(&colon); |
| 1102 | .ltoken = token, | 987 | const block_node = (try p.parseBlock()) orelse { |
| 1103 | .kind = .{ .Continue = label }, | 988 | if (label_token) |label| { |
| 1104 | .rhs = null, | 989 | p.putBackToken(label + 1); // ":" |
| 990 | p.putBackToken(label); // IDENTIFIER | ||
| 991 | } | ||
| 992 | return null; | ||
| 1105 | }; | 993 | }; |
| 1106 | return &node.base; | 994 | block_node.cast(Node.Block).?.label = label_token; |
| 995 | return block_node; | ||
| 1107 | } | 996 | } |
| 1108 | 997 | ||
| 1109 | if (eatToken(it, .Keyword_resume)) |token| { | 998 | /// AssignExpr <- Expr (AssignOp Expr)? |
| 1110 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | 999 | fn parseAssignExpr(p: *Parser) !?*Node { |
| 1111 | .ExpectedExpr = .{ .token = it.index }, | 1000 | return p.parseBinOpExpr(parseAssignOp, parseExpr, .Once); |
| 1112 | }); | ||
| 1113 | const node = try arena.create(Node.PrefixOp); | ||
| 1114 | node.* = .{ | ||
| 1115 | .op_token = token, | ||
| 1116 | .op = .Resume, | ||
| 1117 | .rhs = expr_node, | ||
| 1118 | }; | ||
| 1119 | return &node.base; | ||
| 1120 | } | 1001 | } |
| 1121 | 1002 | ||
| 1122 | if (eatToken(it, .Keyword_return)) |token| { | 1003 | /// Expr <- KEYWORD_try* BoolOrExpr |
| 1123 | const expr_node = try parseExpr(arena, it, tree); | 1004 | fn parseExpr(p: *Parser) Error!?*Node { |
| 1124 | const node = try arena.create(Node.ControlFlowExpression); | 1005 | return p.parsePrefixOpExpr(parseTry, parseBoolOrExpr); |
| 1125 | node.* = .{ | ||
| 1126 | .ltoken = token, | ||
| 1127 | .kind = .Return, | ||
| 1128 | .rhs = expr_node, | ||
| 1129 | }; | ||
| 1130 | return &node.base; | ||
| 1131 | } | 1006 | } |
| 1132 | 1007 | ||
| 1133 | var colon: TokenIndex = undefined; | 1008 | /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* |
| 1134 | const label = parseBlockLabel(arena, it, tree, &colon); | 1009 | fn parseBoolOrExpr(p: *Parser) !?*Node { |
| 1135 | if (try parseLoopExpr(arena, it, tree)) |node| { | 1010 | return p.parseBinOpExpr( |
| 1136 | if (node.cast(Node.For)) |for_node| { | 1011 | SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr), |
| 1137 | for_node.label = label; | 1012 | parseBoolAndExpr, |
| 1138 | } else if (node.cast(Node.While)) |while_node| { | 1013 | .Infinitely, |
| 1139 | while_node.label = label; | 1014 | ); |
| 1140 | } else unreachable; | ||
| 1141 | return node; | ||
| 1142 | } | ||
| 1143 | if (label) |token| { | ||
| 1144 | putBackToken(it, token + 1); // ":" | ||
| 1145 | putBackToken(it, token); // IDENTIFIER | ||
| 1146 | } | 1015 | } |
| 1147 | 1016 | ||
| 1148 | if (try parseBlock(arena, it, tree)) |node| return node; | 1017 | /// BoolAndExpr <- CompareExpr (KEYWORD_and CompareExpr)* |
| 1149 | if (try parseCurlySuffixExpr(arena, it, tree)) |node| return node; | 1018 | fn parseBoolAndExpr(p: *Parser) !?*Node { |
| 1019 | return p.parseBinOpExpr( | ||
| 1020 | SimpleBinOpParseFn(.Keyword_and, .BoolAnd), | ||
| 1021 | parseCompareExpr, | ||
| 1022 | .Infinitely, | ||
| 1023 | ); | ||
| 1024 | } | ||
| 1150 | 1025 | ||
| 1151 | return null; | 1026 | /// CompareExpr <- BitwiseExpr (CompareOp BitwiseExpr)? |
| 1152 | } | 1027 | fn parseCompareExpr(p: *Parser) !?*Node { |
| 1028 | return p.parseBinOpExpr(parseCompareOp, parseBitwiseExpr, .Once); | ||
| 1029 | } | ||
| 1153 | 1030 | ||
| 1154 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? | 1031 | /// BitwiseExpr <- BitShiftExpr (BitwiseOp BitShiftExpr)* |
| 1155 | fn parseIfExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1032 | fn parseBitwiseExpr(p: *Parser) !?*Node { |
| 1156 | return parseIf(arena, it, tree, parseExpr); | 1033 | return p.parseBinOpExpr(parseBitwiseOp, parseBitShiftExpr, .Infinitely); |
| 1157 | } | 1034 | } |
| 1158 | 1035 | ||
| 1159 | /// Block <- LBRACE Statement* RBRACE | 1036 | /// BitShiftExpr <- AdditionExpr (BitShiftOp AdditionExpr)* |
| 1160 | fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1037 | fn parseBitShiftExpr(p: *Parser) !?*Node { |
| 1161 | const lbrace = eatToken(it, .LBrace) orelse return null; | 1038 | return p.parseBinOpExpr(parseBitShiftOp, parseAdditionExpr, .Infinitely); |
| 1039 | } | ||
| 1162 | 1040 | ||
| 1163 | var statements = Node.Block.StatementList.init(arena); | 1041 | /// AdditionExpr <- MultiplyExpr (AdditionOp MultiplyExpr)* |
| 1164 | while (true) { | 1042 | fn parseAdditionExpr(p: *Parser) !?*Node { |
| 1165 | const statement = (parseStatement(arena, it, tree) catch |err| switch (err) { | 1043 | return p.parseBinOpExpr(parseAdditionOp, parseMultiplyExpr, .Infinitely); |
| 1166 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1167 | error.ParseError => { | ||
| 1168 | // try to skip to the next statement | ||
| 1169 | findNextStmt(it); | ||
| 1170 | continue; | ||
| 1171 | }, | ||
| 1172 | }) orelse break; | ||
| 1173 | try statements.push(statement); | ||
| 1174 | } | 1044 | } |
| 1175 | 1045 | ||
| 1176 | const rbrace = try expectToken(it, tree, .RBrace); | 1046 | /// MultiplyExpr <- PrefixExpr (MultiplyOp PrefixExpr)* |
| 1047 | fn parseMultiplyExpr(p: *Parser) !?*Node { | ||
| 1048 | return p.parseBinOpExpr(parseMultiplyOp, parsePrefixExpr, .Infinitely); | ||
| 1049 | } | ||
| 1177 | 1050 | ||
| 1178 | const block_node = try arena.create(Node.Block); | 1051 | /// PrefixExpr <- PrefixOp* PrimaryExpr |
| 1179 | block_node.* = .{ | 1052 | fn parsePrefixExpr(p: *Parser) !?*Node { |
| 1180 | .label = null, | 1053 | return p.parsePrefixOpExpr(parsePrefixOp, parsePrimaryExpr); |
| 1181 | .lbrace = lbrace, | 1054 | } |
| 1182 | .statements = statements, | ||
| 1183 | .rbrace = rbrace, | ||
| 1184 | }; | ||
| 1185 | 1055 | ||
| 1186 | return &block_node.base; | 1056 | /// PrimaryExpr |
| 1187 | } | 1057 | /// <- AsmExpr |
| 1058 | /// / IfExpr | ||
| 1059 | /// / KEYWORD_break BreakLabel? Expr? | ||
| 1060 | /// / KEYWORD_comptime Expr | ||
| 1061 | /// / KEYWORD_nosuspend Expr | ||
| 1062 | /// / KEYWORD_continue BreakLabel? | ||
| 1063 | /// / KEYWORD_resume Expr | ||
| 1064 | /// / KEYWORD_return Expr? | ||
| 1065 | /// / BlockLabel? LoopExpr | ||
| 1066 | /// / Block | ||
| 1067 | /// / CurlySuffixExpr | ||
| 1068 | fn parsePrimaryExpr(p: *Parser) !?*Node { | ||
| 1069 | if (try p.parseAsmExpr()) |node| return node; | ||
| 1070 | if (try p.parseIfExpr()) |node| return node; | ||
| 1188 | 1071 | ||
| 1189 | /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) | 1072 | if (p.eatToken(.Keyword_break)) |token| { |
| 1190 | fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1073 | const label = try p.parseBreakLabel(); |
| 1191 | const inline_token = eatToken(it, .Keyword_inline); | 1074 | const expr_node = try p.parseExpr(); |
| 1075 | const node = try p.arena.allocator.create(Node.ControlFlowExpression); | ||
| 1076 | node.* = .{ | ||
| 1077 | .ltoken = token, | ||
| 1078 | .kind = .{ .Break = label }, | ||
| 1079 | .rhs = expr_node, | ||
| 1080 | }; | ||
| 1081 | return &node.base; | ||
| 1082 | } | ||
| 1192 | 1083 | ||
| 1193 | if (try parseForExpr(arena, it, tree)) |node| { | 1084 | if (p.eatToken(.Keyword_comptime)) |token| { |
| 1194 | node.cast(Node.For).?.inline_token = inline_token; | 1085 | const expr_node = try p.expectNode(parseExpr, .{ |
| 1195 | return node; | 1086 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1196 | } | 1087 | }); |
| 1088 | const node = try p.arena.allocator.create(Node.Comptime); | ||
| 1089 | node.* = .{ | ||
| 1090 | .doc_comments = null, | ||
| 1091 | .comptime_token = token, | ||
| 1092 | .expr = expr_node, | ||
| 1093 | }; | ||
| 1094 | return &node.base; | ||
| 1095 | } | ||
| 1197 | 1096 | ||
| 1198 | if (try parseWhileExpr(arena, it, tree)) |node| { | 1097 | if (p.eatToken(.Keyword_nosuspend)) |token| { |
| 1199 | node.cast(Node.While).?.inline_token = inline_token; | 1098 | const expr_node = try p.expectNode(parseExpr, .{ |
| 1200 | return node; | 1099 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1201 | } | 1100 | }); |
| 1101 | const node = try p.arena.allocator.create(Node.Nosuspend); | ||
| 1102 | node.* = .{ | ||
| 1103 | .nosuspend_token = token, | ||
| 1104 | .expr = expr_node, | ||
| 1105 | }; | ||
| 1106 | return &node.base; | ||
| 1107 | } | ||
| 1202 | 1108 | ||
| 1203 | if (inline_token == null) return null; | 1109 | if (p.eatToken(.Keyword_continue)) |token| { |
| 1110 | const label = try p.parseBreakLabel(); | ||
| 1111 | const node = try p.arena.allocator.create(Node.ControlFlowExpression); | ||
| 1112 | node.* = .{ | ||
| 1113 | .ltoken = token, | ||
| 1114 | .kind = .{ .Continue = label }, | ||
| 1115 | .rhs = null, | ||
| 1116 | }; | ||
| 1117 | return &node.base; | ||
| 1118 | } | ||
| 1204 | 1119 | ||
| 1205 | // If we've seen "inline", there should have been a "for" or "while" | 1120 | if (p.eatToken(.Keyword_resume)) |token| { |
| 1206 | try tree.errors.push(.{ | 1121 | const expr_node = try p.expectNode(parseExpr, .{ |
| 1207 | .ExpectedInlinable = .{ .token = it.index }, | 1122 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1208 | }); | 1123 | }); |
| 1209 | return error.ParseError; | 1124 | const node = try p.arena.allocator.create(Node.PrefixOp); |
| 1210 | } | 1125 | node.* = .{ |
| 1126 | .op_token = token, | ||
| 1127 | .op = .Resume, | ||
| 1128 | .rhs = expr_node, | ||
| 1129 | }; | ||
| 1130 | return &node.base; | ||
| 1131 | } | ||
| 1211 | 1132 | ||
| 1212 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? | 1133 | if (p.eatToken(.Keyword_return)) |token| { |
| 1213 | fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1134 | const expr_node = try p.parseExpr(); |
| 1214 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; | 1135 | const node = try p.arena.allocator.create(Node.ControlFlowExpression); |
| 1215 | const for_prefix = node.cast(Node.For).?; | 1136 | node.* = .{ |
| 1137 | .ltoken = token, | ||
| 1138 | .kind = .Return, | ||
| 1139 | .rhs = expr_node, | ||
| 1140 | }; | ||
| 1141 | return &node.base; | ||
| 1142 | } | ||
| 1216 | 1143 | ||
| 1217 | const body_node = try expectNode(arena, it, tree, parseExpr, .{ | 1144 | var colon: TokenIndex = undefined; |
| 1218 | .ExpectedExpr = .{ .token = it.index }, | 1145 | const label = p.parseBlockLabel(&colon); |
| 1219 | }); | 1146 | if (try p.parseLoopExpr()) |node| { |
| 1220 | for_prefix.body = body_node; | 1147 | if (node.cast(Node.For)) |for_node| { |
| 1148 | for_node.label = label; | ||
| 1149 | } else if (node.cast(Node.While)) |while_node| { | ||
| 1150 | while_node.label = label; | ||
| 1151 | } else unreachable; | ||
| 1152 | return node; | ||
| 1153 | } | ||
| 1154 | if (label) |token| { | ||
| 1155 | p.putBackToken(token + 1); // ":" | ||
| 1156 | p.putBackToken(token); // IDENTIFIER | ||
| 1157 | } | ||
| 1221 | 1158 | ||
| 1222 | if (eatToken(it, .Keyword_else)) |else_token| { | 1159 | if (try p.parseBlock()) |node| return node; |
| 1223 | const body = try expectNode(arena, it, tree, parseExpr, .{ | 1160 | if (try p.parseCurlySuffixExpr()) |node| return node; |
| 1224 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1225 | }); | ||
| 1226 | 1161 | ||
| 1227 | const else_node = try arena.create(Node.Else); | 1162 | return null; |
| 1228 | else_node.* = .{ | 1163 | } |
| 1229 | .else_token = else_token, | ||
| 1230 | .payload = null, | ||
| 1231 | .body = body, | ||
| 1232 | }; | ||
| 1233 | 1164 | ||
| 1234 | for_prefix.@"else" = else_node; | 1165 | /// IfExpr <- IfPrefix Expr (KEYWORD_else Payload? Expr)? |
| 1166 | fn parseIfExpr(p: *Parser) !?*Node { | ||
| 1167 | return p.parseIf(parseExpr); | ||
| 1235 | } | 1168 | } |
| 1236 | 1169 | ||
| 1237 | return node; | 1170 | /// Block <- LBRACE Statement* RBRACE |
| 1238 | } | 1171 | fn parseBlock(p: *Parser) !?*Node { |
| 1172 | const lbrace = p.eatToken(.LBrace) orelse return null; | ||
| 1173 | |||
| 1174 | var statements = std.ArrayList(*Node).init(p.gpa); | ||
| 1175 | defer statements.deinit(); | ||
| 1239 | 1176 | ||
| 1240 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? | 1177 | while (true) { |
| 1241 | fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1178 | const statement = (p.parseStatement() catch |err| switch (err) { |
| 1242 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; | 1179 | error.OutOfMemory => return error.OutOfMemory, |
| 1243 | const while_prefix = node.cast(Node.While).?; | 1180 | error.ParseError => { |
| 1181 | // try to skip to the next statement | ||
| 1182 | p.findNextStmt(); | ||
| 1183 | continue; | ||
| 1184 | }, | ||
| 1185 | }) orelse break; | ||
| 1186 | try statements.append(statement); | ||
| 1187 | } | ||
| 1244 | 1188 | ||
| 1245 | const body_node = try expectNode(arena, it, tree, parseExpr, .{ | 1189 | const rbrace = try p.expectToken(.RBrace); |
| 1246 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1247 | }); | ||
| 1248 | while_prefix.body = body_node; | ||
| 1249 | 1190 | ||
| 1250 | if (eatToken(it, .Keyword_else)) |else_token| { | 1191 | const statements_len = @intCast(NodeIndex, statements.items.len); |
| 1251 | const payload = try parsePayload(arena, it, tree); | ||
| 1252 | const body = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1253 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1254 | }); | ||
| 1255 | 1192 | ||
| 1256 | const else_node = try arena.create(Node.Else); | 1193 | const block_node = try Node.Block.alloc(&p.arena.allocator, statements_len); |
| 1257 | else_node.* = .{ | 1194 | block_node.* = .{ |
| 1258 | .else_token = else_token, | 1195 | .label = null, |
| 1259 | .payload = payload, | 1196 | .lbrace = lbrace, |
| 1260 | .body = body, | 1197 | .statements_len = statements_len, |
| 1198 | .rbrace = rbrace, | ||
| 1261 | }; | 1199 | }; |
| 1200 | std.mem.copy(*Node, block_node.statements(), statements.items); | ||
| 1262 | 1201 | ||
| 1263 | while_prefix.@"else" = else_node; | 1202 | return &block_node.base; |
| 1264 | } | 1203 | } |
| 1265 | 1204 | ||
| 1266 | return node; | 1205 | /// LoopExpr <- KEYWORD_inline? (ForExpr / WhileExpr) |
| 1267 | } | 1206 | fn parseLoopExpr(p: *Parser) !?*Node { |
| 1268 | 1207 | const inline_token = p.eatToken(.Keyword_inline); | |
| 1269 | /// CurlySuffixExpr <- TypeExpr InitList? | ||
| 1270 | fn parseCurlySuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 1271 | const type_expr = (try parseTypeExpr(arena, it, tree)) orelse return null; | ||
| 1272 | const suffix_op = (try parseInitList(arena, it, tree)) orelse return type_expr; | ||
| 1273 | suffix_op.lhs.node = type_expr; | ||
| 1274 | return &suffix_op.base; | ||
| 1275 | } | ||
| 1276 | 1208 | ||
| 1277 | /// InitList | 1209 | if (try p.parseForExpr()) |node| { |
| 1278 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | 1210 | node.cast(Node.For).?.inline_token = inline_token; |
| 1279 | /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | 1211 | return node; |
| 1280 | /// / LBRACE RBRACE | ||
| 1281 | fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.SuffixOp { | ||
| 1282 | const lbrace = eatToken(it, .LBrace) orelse return null; | ||
| 1283 | var init_list = Node.SuffixOp.Op.InitList.init(arena); | ||
| 1284 | |||
| 1285 | const op: Node.SuffixOp.Op = blk: { | ||
| 1286 | if (try parseFieldInit(arena, it, tree)) |field_init| { | ||
| 1287 | try init_list.push(field_init); | ||
| 1288 | while (eatToken(it, .Comma)) |_| { | ||
| 1289 | const next = (try parseFieldInit(arena, it, tree)) orelse break; | ||
| 1290 | try init_list.push(next); | ||
| 1291 | } | ||
| 1292 | break :blk .{ .StructInitializer = init_list }; | ||
| 1293 | } | 1212 | } |
| 1294 | 1213 | ||
| 1295 | if (try parseExpr(arena, it, tree)) |expr| { | 1214 | if (try p.parseWhileExpr()) |node| { |
| 1296 | try init_list.push(expr); | 1215 | node.cast(Node.While).?.inline_token = inline_token; |
| 1297 | while (eatToken(it, .Comma)) |_| { | 1216 | return node; |
| 1298 | const next = (try parseExpr(arena, it, tree)) orelse break; | ||
| 1299 | try init_list.push(next); | ||
| 1300 | } | ||
| 1301 | break :blk .{ .ArrayInitializer = init_list }; | ||
| 1302 | } | 1217 | } |
| 1303 | 1218 | ||
| 1304 | break :blk .{ .StructInitializer = init_list }; | 1219 | if (inline_token == null) return null; |
| 1305 | }; | ||
| 1306 | |||
| 1307 | const node = try arena.create(Node.SuffixOp); | ||
| 1308 | node.* = .{ | ||
| 1309 | .lhs = .{ .node = undefined }, // set by caller | ||
| 1310 | .op = op, | ||
| 1311 | .rtoken = try expectToken(it, tree, .RBrace), | ||
| 1312 | }; | ||
| 1313 | return node; | ||
| 1314 | } | ||
| 1315 | 1220 | ||
| 1316 | /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr | 1221 | // If we've seen "inline", there should have been a "for" or "while" |
| 1317 | fn parseTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { | 1222 | try p.errors.append(p.gpa, .{ |
| 1318 | return parsePrefixOpExpr(arena, it, tree, parsePrefixTypeOp, parseErrorUnionExpr); | 1223 | .ExpectedInlinable = .{ .token = p.tok_i }, |
| 1319 | } | 1224 | }); |
| 1225 | return error.ParseError; | ||
| 1226 | } | ||
| 1320 | 1227 | ||
| 1321 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | 1228 | /// ForExpr <- ForPrefix Expr (KEYWORD_else Expr)? |
| 1322 | fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1229 | fn parseForExpr(p: *Parser) !?*Node { |
| 1323 | const suffix_expr = (try parseSuffixExpr(arena, it, tree)) orelse return null; | 1230 | const node = (try p.parseForPrefix()) orelse return null; |
| 1231 | const for_prefix = node.cast(Node.For).?; | ||
| 1324 | 1232 | ||
| 1325 | if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| { | 1233 | const body_node = try p.expectNode(parseExpr, .{ |
| 1326 | const error_union = node.cast(Node.InfixOp).?; | 1234 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1327 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | ||
| 1328 | .ExpectedTypeExpr = .{ .token = it.index }, | ||
| 1329 | }); | 1235 | }); |
| 1330 | error_union.lhs = suffix_expr; | 1236 | for_prefix.body = body_node; |
| 1331 | error_union.rhs = type_expr; | 1237 | |
| 1238 | if (p.eatToken(.Keyword_else)) |else_token| { | ||
| 1239 | const body = try p.expectNode(parseExpr, .{ | ||
| 1240 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 1241 | }); | ||
| 1242 | |||
| 1243 | const else_node = try p.arena.allocator.create(Node.Else); | ||
| 1244 | else_node.* = .{ | ||
| 1245 | .else_token = else_token, | ||
| 1246 | .payload = null, | ||
| 1247 | .body = body, | ||
| 1248 | }; | ||
| 1249 | |||
| 1250 | for_prefix.@"else" = else_node; | ||
| 1251 | } | ||
| 1252 | |||
| 1332 | return node; | 1253 | return node; |
| 1333 | } | 1254 | } |
| 1334 | 1255 | ||
| 1335 | return suffix_expr; | 1256 | /// WhileExpr <- WhilePrefix Expr (KEYWORD_else Payload? Expr)? |
| 1336 | } | 1257 | fn parseWhileExpr(p: *Parser) !?*Node { |
| 1258 | const node = (try p.parseWhilePrefix()) orelse return null; | ||
| 1259 | const while_prefix = node.cast(Node.While).?; | ||
| 1337 | 1260 | ||
| 1338 | /// SuffixExpr | 1261 | const body_node = try p.expectNode(parseExpr, .{ |
| 1339 | /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments | 1262 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1340 | /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 1341 | fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 1342 | const maybe_async = eatToken(it, .Keyword_async); | ||
| 1343 | if (maybe_async) |async_token| { | ||
| 1344 | const token_fn = eatToken(it, .Keyword_fn); | ||
| 1345 | if (token_fn != null) { | ||
| 1346 | // TODO: remove this hack when async fn rewriting is | ||
| 1347 | // HACK: If we see the keyword `fn`, then we assume that | ||
| 1348 | // we are parsing an async fn proto, and not a call. | ||
| 1349 | // We therefore put back all tokens consumed by the async | ||
| 1350 | // prefix... | ||
| 1351 | putBackToken(it, token_fn.?); | ||
| 1352 | putBackToken(it, async_token); | ||
| 1353 | return parsePrimaryTypeExpr(arena, it, tree); | ||
| 1354 | } | ||
| 1355 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ | ||
| 1356 | .ExpectedPrimaryTypeExpr = .{ .token = it.index }, | ||
| 1357 | }); | 1263 | }); |
| 1264 | while_prefix.body = body_node; | ||
| 1358 | 1265 | ||
| 1359 | while (try parseSuffixOp(arena, it, tree)) |node| { | 1266 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 1360 | switch (node.id) { | 1267 | const payload = try p.parsePayload(); |
| 1361 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res }, | 1268 | const body = try p.expectNode(parseExpr, .{ |
| 1362 | .InfixOp => node.cast(Node.InfixOp).?.lhs = res, | 1269 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1363 | else => unreachable, | ||
| 1364 | } | ||
| 1365 | res = node; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { | ||
| 1369 | try tree.errors.push(.{ | ||
| 1370 | .ExpectedParamList = .{ .token = it.index }, | ||
| 1371 | }); | 1270 | }); |
| 1372 | // ignore this, continue parsing | 1271 | |
| 1373 | return res; | 1272 | const else_node = try p.arena.allocator.create(Node.Else); |
| 1273 | else_node.* = .{ | ||
| 1274 | .else_token = else_token, | ||
| 1275 | .payload = payload, | ||
| 1276 | .body = body, | ||
| 1277 | }; | ||
| 1278 | |||
| 1279 | while_prefix.@"else" = else_node; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | return node; | ||
| 1283 | } | ||
| 1284 | |||
| 1285 | /// CurlySuffixExpr <- TypeExpr InitList? | ||
| 1286 | fn parseCurlySuffixExpr(p: *Parser) !?*Node { | ||
| 1287 | const lhs = (try p.parseTypeExpr()) orelse return null; | ||
| 1288 | const suffix_op = (try p.parseInitList(lhs)) orelse return lhs; | ||
| 1289 | return suffix_op; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | /// InitList | ||
| 1293 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | ||
| 1294 | /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | ||
| 1295 | /// / LBRACE RBRACE | ||
| 1296 | fn parseInitList(p: *Parser, lhs: *Node) !?*Node { | ||
| 1297 | const lbrace = p.eatToken(.LBrace) orelse return null; | ||
| 1298 | var init_list = std.ArrayList(*Node).init(p.gpa); | ||
| 1299 | defer init_list.deinit(); | ||
| 1300 | |||
| 1301 | if (try p.parseFieldInit()) |field_init| { | ||
| 1302 | try init_list.append(field_init); | ||
| 1303 | while (p.eatToken(.Comma)) |_| { | ||
| 1304 | const next = (try p.parseFieldInit()) orelse break; | ||
| 1305 | try init_list.append(next); | ||
| 1306 | } | ||
| 1307 | const node = try Node.StructInitializer.alloc(&p.arena.allocator, init_list.items.len); | ||
| 1308 | node.* = .{ | ||
| 1309 | .lhs = lhs, | ||
| 1310 | .rtoken = try p.expectToken(.RBrace), | ||
| 1311 | .list_len = init_list.items.len, | ||
| 1312 | }; | ||
| 1313 | std.mem.copy(*Node, node.list(), init_list.items); | ||
| 1314 | return &node.base; | ||
| 1315 | } | ||
| 1316 | |||
| 1317 | if (try p.parseExpr()) |expr| { | ||
| 1318 | try init_list.append(expr); | ||
| 1319 | while (p.eatToken(.Comma)) |_| { | ||
| 1320 | const next = (try p.parseExpr()) orelse break; | ||
| 1321 | try init_list.append(next); | ||
| 1322 | } | ||
| 1323 | const node = try Node.ArrayInitializer.alloc(&p.arena.allocator, init_list.items.len); | ||
| 1324 | node.* = .{ | ||
| 1325 | .lhs = lhs, | ||
| 1326 | .rtoken = try p.expectToken(.RBrace), | ||
| 1327 | .list_len = init_list.items.len, | ||
| 1328 | }; | ||
| 1329 | std.mem.copy(*Node, node.list(), init_list.items); | ||
| 1330 | return &node.base; | ||
| 1331 | } | ||
| 1332 | |||
| 1333 | const node = try p.arena.allocator.create(Node.StructInitializer); | ||
| 1334 | node.* = .{ | ||
| 1335 | .lhs = lhs, | ||
| 1336 | .rtoken = try p.expectToken(.RBrace), | ||
| 1337 | .list_len = 0, | ||
| 1374 | }; | 1338 | }; |
| 1375 | const node = try arena.create(Node.SuffixOp); | 1339 | return &node.base; |
| 1340 | } | ||
| 1341 | |||
| 1342 | /// InitList | ||
| 1343 | /// <- LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE | ||
| 1344 | /// / LBRACE Expr (COMMA Expr)* COMMA? RBRACE | ||
| 1345 | /// / LBRACE RBRACE | ||
| 1346 | fn parseAnonInitList(p: *Parser, dot: TokenIndex) !?*Node { | ||
| 1347 | const lbrace = p.eatToken(.LBrace) orelse return null; | ||
| 1348 | var init_list = std.ArrayList(*Node).init(p.gpa); | ||
| 1349 | defer init_list.deinit(); | ||
| 1350 | |||
| 1351 | if (try p.parseFieldInit()) |field_init| { | ||
| 1352 | try init_list.append(field_init); | ||
| 1353 | while (p.eatToken(.Comma)) |_| { | ||
| 1354 | const next = (try p.parseFieldInit()) orelse break; | ||
| 1355 | try init_list.append(next); | ||
| 1356 | } | ||
| 1357 | const node = try Node.StructInitializerDot.alloc(&p.arena.allocator, init_list.items.len); | ||
| 1358 | node.* = .{ | ||
| 1359 | .dot = dot, | ||
| 1360 | .rtoken = try p.expectToken(.RBrace), | ||
| 1361 | .list_len = init_list.items.len, | ||
| 1362 | }; | ||
| 1363 | std.mem.copy(*Node, node.list(), init_list.items); | ||
| 1364 | return &node.base; | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | if (try p.parseExpr()) |expr| { | ||
| 1368 | try init_list.append(expr); | ||
| 1369 | while (p.eatToken(.Comma)) |_| { | ||
| 1370 | const next = (try p.parseExpr()) orelse break; | ||
| 1371 | try init_list.append(next); | ||
| 1372 | } | ||
| 1373 | const node = try Node.ArrayInitializerDot.alloc(&p.arena.allocator, init_list.items.len); | ||
| 1374 | node.* = .{ | ||
| 1375 | .dot = dot, | ||
| 1376 | .rtoken = try p.expectToken(.RBrace), | ||
| 1377 | .list_len = init_list.items.len, | ||
| 1378 | }; | ||
| 1379 | std.mem.copy(*Node, node.list(), init_list.items); | ||
| 1380 | return &node.base; | ||
| 1381 | } | ||
| 1382 | |||
| 1383 | const node = try p.arena.allocator.create(Node.StructInitializerDot); | ||
| 1376 | node.* = .{ | 1384 | node.* = .{ |
| 1377 | .lhs = .{ .node = res }, | 1385 | .dot = dot, |
| 1378 | .op = .{ | 1386 | .rtoken = try p.expectToken(.RBrace), |
| 1379 | .Call = .{ | 1387 | .list_len = 0, |
| 1380 | .params = params.list, | ||
| 1381 | .async_token = async_token, | ||
| 1382 | }, | ||
| 1383 | }, | ||
| 1384 | .rtoken = params.rparen, | ||
| 1385 | }; | 1388 | }; |
| 1386 | return &node.base; | 1389 | return &node.base; |
| 1387 | } | 1390 | } |
| 1388 | if (try parsePrimaryTypeExpr(arena, it, tree)) |expr| { | ||
| 1389 | var res = expr; | ||
| 1390 | 1391 | ||
| 1391 | while (true) { | 1392 | /// TypeExpr <- PrefixTypeOp* ErrorUnionExpr |
| 1392 | if (try parseSuffixOp(arena, it, tree)) |node| { | 1393 | fn parseTypeExpr(p: *Parser) Error!?*Node { |
| 1394 | return p.parsePrefixOpExpr(parsePrefixTypeOp, parseErrorUnionExpr); | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | /// ErrorUnionExpr <- SuffixExpr (EXCLAMATIONMARK TypeExpr)? | ||
| 1398 | fn parseErrorUnionExpr(p: *Parser) !?*Node { | ||
| 1399 | const suffix_expr = (try p.parseSuffixExpr()) orelse return null; | ||
| 1400 | |||
| 1401 | if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(p)) |node| { | ||
| 1402 | const error_union = node.cast(Node.InfixOp).?; | ||
| 1403 | const type_expr = try p.expectNode(parseTypeExpr, .{ | ||
| 1404 | .ExpectedTypeExpr = .{ .token = p.tok_i }, | ||
| 1405 | }); | ||
| 1406 | error_union.lhs = suffix_expr; | ||
| 1407 | error_union.rhs = type_expr; | ||
| 1408 | return node; | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | return suffix_expr; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | /// SuffixExpr | ||
| 1415 | /// <- KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments | ||
| 1416 | /// / PrimaryTypeExpr (SuffixOp / FnCallArguments)* | ||
| 1417 | fn parseSuffixExpr(p: *Parser) !?*Node { | ||
| 1418 | const maybe_async = p.eatToken(.Keyword_async); | ||
| 1419 | if (maybe_async) |async_token| { | ||
| 1420 | const token_fn = p.eatToken(.Keyword_fn); | ||
| 1421 | if (token_fn != null) { | ||
| 1422 | // TODO: remove this hack when async fn rewriting is | ||
| 1423 | // HACK: If we see the keyword `fn`, then we assume that | ||
| 1424 | // we are parsing an async fn proto, and not a call. | ||
| 1425 | // We therefore put back all tokens consumed by the async | ||
| 1426 | // prefix... | ||
| 1427 | p.putBackToken(token_fn.?); | ||
| 1428 | p.putBackToken(async_token); | ||
| 1429 | return p.parsePrimaryTypeExpr(); | ||
| 1430 | } | ||
| 1431 | var res = try p.expectNode(parsePrimaryTypeExpr, .{ | ||
| 1432 | .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i }, | ||
| 1433 | }); | ||
| 1434 | |||
| 1435 | while (try p.parseSuffixOp()) |node| { | ||
| 1393 | switch (node.id) { | 1436 | switch (node.id) { |
| 1394 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res }, | 1437 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, |
| 1395 | .InfixOp => node.cast(Node.InfixOp).?.lhs = res, | 1438 | .InfixOp => node.cast(Node.InfixOp).?.lhs = res, |
| 1396 | else => unreachable, | 1439 | else => unreachable, |
| 1397 | } | 1440 | } |
| 1398 | res = node; | 1441 | res = node; |
| 1399 | continue; | ||
| 1400 | } | 1442 | } |
| 1401 | if (try parseFnCallArguments(arena, it, tree)) |params| { | 1443 | |
| 1402 | const call = try arena.create(Node.SuffixOp); | 1444 | const params = (try p.parseFnCallArguments()) orelse { |
| 1403 | call.* = .{ | 1445 | try p.errors.append(p.gpa, .{ |
| 1404 | .lhs = .{ .node = res }, | 1446 | .ExpectedParamList = .{ .token = p.tok_i }, |
| 1405 | .op = .{ | 1447 | }); |
| 1406 | .Call = .{ | 1448 | // ignore this, continue parsing |
| 1407 | .params = params.list, | 1449 | return res; |
| 1408 | .async_token = null, | 1450 | }; |
| 1409 | }, | 1451 | defer p.gpa.free(params.list); |
| 1410 | }, | 1452 | const node = try Node.Call.alloc(&p.arena.allocator, params.list.len); |
| 1411 | .rtoken = params.rparen, | 1453 | node.* = .{ |
| 1412 | }; | 1454 | .lhs = res, |
| 1413 | res = &call.base; | 1455 | .params_len = params.list.len, |
| 1414 | continue; | 1456 | .async_token = async_token, |
| 1457 | .rtoken = params.rparen, | ||
| 1458 | }; | ||
| 1459 | std.mem.copy(*Node, node.params(), params.list); | ||
| 1460 | return &node.base; | ||
| 1461 | } | ||
| 1462 | if (try p.parsePrimaryTypeExpr()) |expr| { | ||
| 1463 | var res = expr; | ||
| 1464 | |||
| 1465 | while (true) { | ||
| 1466 | if (try p.parseSuffixOp()) |node| { | ||
| 1467 | switch (node.id) { | ||
| 1468 | .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, | ||
| 1469 | .InfixOp => node.cast(Node.InfixOp).?.lhs = res, | ||
| 1470 | else => unreachable, | ||
| 1471 | } | ||
| 1472 | res = node; | ||
| 1473 | continue; | ||
| 1474 | } | ||
| 1475 | if (try p.parseFnCallArguments()) |params| { | ||
| 1476 | defer p.gpa.free(params.list); | ||
| 1477 | const call = try Node.Call.alloc(&p.arena.allocator, params.list.len); | ||
| 1478 | call.* = .{ | ||
| 1479 | .lhs = res, | ||
| 1480 | .params_len = params.list.len, | ||
| 1481 | .async_token = null, | ||
| 1482 | .rtoken = params.rparen, | ||
| 1483 | }; | ||
| 1484 | std.mem.copy(*Node, call.params(), params.list); | ||
| 1485 | res = &call.base; | ||
| 1486 | continue; | ||
| 1487 | } | ||
| 1488 | break; | ||
| 1415 | } | 1489 | } |
| 1416 | break; | 1490 | return res; |
| 1417 | } | 1491 | } |
| 1418 | return res; | 1492 | |
| 1493 | return null; | ||
| 1419 | } | 1494 | } |
| 1420 | 1495 | ||
| 1421 | return null; | 1496 | /// PrimaryTypeExpr |
| 1422 | } | 1497 | /// <- BUILTINIDENTIFIER FnCallArguments |
| 1498 | /// / CHAR_LITERAL | ||
| 1499 | /// / ContainerDecl | ||
| 1500 | /// / DOT IDENTIFIER | ||
| 1501 | /// / ErrorSetDecl | ||
| 1502 | /// / FLOAT | ||
| 1503 | /// / FnProto | ||
| 1504 | /// / GroupedExpr | ||
| 1505 | /// / LabeledTypeExpr | ||
| 1506 | /// / IDENTIFIER | ||
| 1507 | /// / IfTypeExpr | ||
| 1508 | /// / INTEGER | ||
| 1509 | /// / KEYWORD_comptime TypeExpr | ||
| 1510 | /// / KEYWORD_error DOT IDENTIFIER | ||
| 1511 | /// / KEYWORD_false | ||
| 1512 | /// / KEYWORD_null | ||
| 1513 | /// / KEYWORD_anyframe | ||
| 1514 | /// / KEYWORD_true | ||
| 1515 | /// / KEYWORD_undefined | ||
| 1516 | /// / KEYWORD_unreachable | ||
| 1517 | /// / STRINGLITERAL | ||
| 1518 | /// / SwitchExpr | ||
| 1519 | fn parsePrimaryTypeExpr(p: *Parser) !?*Node { | ||
| 1520 | if (try p.parseBuiltinCall()) |node| return node; | ||
| 1521 | if (p.eatToken(.CharLiteral)) |token| { | ||
| 1522 | const node = try p.arena.allocator.create(Node.CharLiteral); | ||
| 1523 | node.* = .{ | ||
| 1524 | .token = token, | ||
| 1525 | }; | ||
| 1526 | return &node.base; | ||
| 1527 | } | ||
| 1528 | if (try p.parseContainerDecl()) |node| return node; | ||
| 1529 | if (try p.parseAnonLiteral()) |node| return node; | ||
| 1530 | if (try p.parseErrorSetDecl()) |node| return node; | ||
| 1531 | if (try p.parseFloatLiteral()) |node| return node; | ||
| 1532 | if (try p.parseFnProto()) |node| return node; | ||
| 1533 | if (try p.parseGroupedExpr()) |node| return node; | ||
| 1534 | if (try p.parseLabeledTypeExpr()) |node| return node; | ||
| 1535 | if (try p.parseIdentifier()) |node| return node; | ||
| 1536 | if (try p.parseIfTypeExpr()) |node| return node; | ||
| 1537 | if (try p.parseIntegerLiteral()) |node| return node; | ||
| 1538 | if (p.eatToken(.Keyword_comptime)) |token| { | ||
| 1539 | const expr = (try p.parseTypeExpr()) orelse return null; | ||
| 1540 | const node = try p.arena.allocator.create(Node.Comptime); | ||
| 1541 | node.* = .{ | ||
| 1542 | .doc_comments = null, | ||
| 1543 | .comptime_token = token, | ||
| 1544 | .expr = expr, | ||
| 1545 | }; | ||
| 1546 | return &node.base; | ||
| 1547 | } | ||
| 1548 | if (p.eatToken(.Keyword_error)) |token| { | ||
| 1549 | const period = try p.expectTokenRecoverable(.Period); | ||
| 1550 | const identifier = try p.expectNodeRecoverable(parseIdentifier, .{ | ||
| 1551 | .ExpectedIdentifier = .{ .token = p.tok_i }, | ||
| 1552 | }); | ||
| 1553 | const global_error_set = try p.createLiteral(Node.ErrorType, token); | ||
| 1554 | if (period == null or identifier == null) return global_error_set; | ||
| 1423 | 1555 | ||
| 1424 | /// PrimaryTypeExpr | 1556 | const node = try p.arena.allocator.create(Node.InfixOp); |
| 1425 | /// <- BUILTINIDENTIFIER FnCallArguments | 1557 | node.* = .{ |
| 1426 | /// / CHAR_LITERAL | 1558 | .op_token = period.?, |
| 1427 | /// / ContainerDecl | 1559 | .lhs = global_error_set, |
| 1428 | /// / DOT IDENTIFIER | 1560 | .op = .Period, |
| 1429 | /// / ErrorSetDecl | 1561 | .rhs = identifier.?, |
| 1430 | /// / FLOAT | 1562 | }; |
| 1431 | /// / FnProto | 1563 | return &node.base; |
| 1432 | /// / GroupedExpr | 1564 | } |
| 1433 | /// / LabeledTypeExpr | 1565 | if (p.eatToken(.Keyword_false)) |token| return p.createLiteral(Node.BoolLiteral, token); |
| 1434 | /// / IDENTIFIER | 1566 | if (p.eatToken(.Keyword_null)) |token| return p.createLiteral(Node.NullLiteral, token); |
| 1435 | /// / IfTypeExpr | 1567 | if (p.eatToken(.Keyword_anyframe)) |token| { |
| 1436 | /// / INTEGER | 1568 | const node = try p.arena.allocator.create(Node.AnyFrameType); |
| 1437 | /// / KEYWORD_comptime TypeExpr | 1569 | node.* = .{ |
| 1438 | /// / KEYWORD_error DOT IDENTIFIER | 1570 | .anyframe_token = token, |
| 1439 | /// / KEYWORD_false | 1571 | .result = null, |
| 1440 | /// / KEYWORD_null | 1572 | }; |
| 1441 | /// / KEYWORD_anyframe | 1573 | return &node.base; |
| 1442 | /// / KEYWORD_true | 1574 | } |
| 1443 | /// / KEYWORD_undefined | 1575 | if (p.eatToken(.Keyword_true)) |token| return p.createLiteral(Node.BoolLiteral, token); |
| 1444 | /// / KEYWORD_unreachable | 1576 | if (p.eatToken(.Keyword_undefined)) |token| return p.createLiteral(Node.UndefinedLiteral, token); |
| 1445 | /// / STRINGLITERAL | 1577 | if (p.eatToken(.Keyword_unreachable)) |token| return p.createLiteral(Node.Unreachable, token); |
| 1446 | /// / SwitchExpr | 1578 | if (try p.parseStringLiteral()) |node| return node; |
| 1447 | fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1579 | if (try p.parseSwitchExpr()) |node| return node; |
| 1448 | if (try parseBuiltinCall(arena, it, tree)) |node| return node; | 1580 | |
| 1449 | if (eatToken(it, .CharLiteral)) |token| { | 1581 | return null; |
| 1450 | const node = try arena.create(Node.CharLiteral); | 1582 | } |
| 1451 | node.* = .{ | 1583 | |
| 1452 | .token = token, | 1584 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto |
| 1585 | fn parseContainerDecl(p: *Parser) !?*Node { | ||
| 1586 | const layout_token = p.eatToken(.Keyword_extern) orelse | ||
| 1587 | p.eatToken(.Keyword_packed); | ||
| 1588 | |||
| 1589 | const node = (try p.parseContainerDeclAuto()) orelse { | ||
| 1590 | if (layout_token) |token| | ||
| 1591 | p.putBackToken(token); | ||
| 1592 | return null; | ||
| 1453 | }; | 1593 | }; |
| 1454 | return &node.base; | 1594 | node.cast(Node.ContainerDecl).?.*.layout_token = layout_token; |
| 1595 | return node; | ||
| 1455 | } | 1596 | } |
| 1456 | if (try parseContainerDecl(arena, it, tree)) |node| return node; | 1597 | |
| 1457 | if (try parseAnonLiteral(arena, it, tree)) |node| return node; | 1598 | /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE |
| 1458 | if (try parseErrorSetDecl(arena, it, tree)) |node| return node; | 1599 | fn parseErrorSetDecl(p: *Parser) !?*Node { |
| 1459 | if (try parseFloatLiteral(arena, it, tree)) |node| return node; | 1600 | const error_token = p.eatToken(.Keyword_error) orelse return null; |
| 1460 | if (try parseFnProto(arena, it, tree)) |node| return node; | 1601 | if (p.eatToken(.LBrace) == null) { |
| 1461 | if (try parseGroupedExpr(arena, it, tree)) |node| return node; | 1602 | // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error |
| 1462 | if (try parseLabeledTypeExpr(arena, it, tree)) |node| return node; | 1603 | p.putBackToken(error_token); |
| 1463 | if (try parseIdentifier(arena, it, tree)) |node| return node; | 1604 | return null; |
| 1464 | if (try parseIfTypeExpr(arena, it, tree)) |node| return node; | 1605 | } |
| 1465 | if (try parseIntegerLiteral(arena, it, tree)) |node| return node; | 1606 | const decls = try p.parseErrorTagList(); |
| 1466 | if (eatToken(it, .Keyword_comptime)) |token| { | 1607 | defer p.gpa.free(decls); |
| 1467 | const expr = (try parseTypeExpr(arena, it, tree)) orelse return null; | 1608 | const rbrace = try p.expectToken(.RBrace); |
| 1468 | const node = try arena.create(Node.Comptime); | 1609 | |
| 1610 | const node = try Node.ErrorSetDecl.alloc(&p.arena.allocator, decls.len); | ||
| 1469 | node.* = .{ | 1611 | node.* = .{ |
| 1470 | .doc_comments = null, | 1612 | .error_token = error_token, |
| 1471 | .comptime_token = token, | 1613 | .decls_len = decls.len, |
| 1472 | .expr = expr, | 1614 | .rbrace_token = rbrace, |
| 1473 | }; | 1615 | }; |
| 1616 | std.mem.copy(*Node, node.decls(), decls); | ||
| 1474 | return &node.base; | 1617 | return &node.base; |
| 1475 | } | 1618 | } |
| 1476 | if (eatToken(it, .Keyword_error)) |token| { | 1619 | |
| 1477 | const period = try expectTokenRecoverable(it, tree, .Period); | 1620 | /// GroupedExpr <- LPAREN Expr RPAREN |
| 1478 | const identifier = try expectNodeRecoverable(arena, it, tree, parseIdentifier, .{ | 1621 | fn parseGroupedExpr(p: *Parser) !?*Node { |
| 1479 | .ExpectedIdentifier = .{ .token = it.index }, | 1622 | const lparen = p.eatToken(.LParen) orelse return null; |
| 1623 | const expr = try p.expectNode(parseExpr, .{ | ||
| 1624 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 1480 | }); | 1625 | }); |
| 1481 | const global_error_set = try createLiteral(arena, Node.ErrorType, token); | 1626 | const rparen = try p.expectToken(.RParen); |
| 1482 | if (period == null or identifier == null) return global_error_set; | ||
| 1483 | 1627 | ||
| 1484 | const node = try arena.create(Node.InfixOp); | 1628 | const node = try p.arena.allocator.create(Node.GroupedExpression); |
| 1485 | node.* = .{ | 1629 | node.* = .{ |
| 1486 | .op_token = period.?, | 1630 | .lparen = lparen, |
| 1487 | .lhs = global_error_set, | 1631 | .expr = expr, |
| 1488 | .op = .Period, | 1632 | .rparen = rparen, |
| 1489 | .rhs = identifier.?, | ||
| 1490 | }; | 1633 | }; |
| 1491 | return &node.base; | 1634 | return &node.base; |
| 1492 | } | 1635 | } |
| 1493 | if (eatToken(it, .Keyword_false)) |token| return createLiteral(arena, Node.BoolLiteral, token); | 1636 | |
| 1494 | if (eatToken(it, .Keyword_null)) |token| return createLiteral(arena, Node.NullLiteral, token); | 1637 | /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? |
| 1495 | if (eatToken(it, .Keyword_anyframe)) |token| { | 1638 | fn parseIfTypeExpr(p: *Parser) !?*Node { |
| 1496 | const node = try arena.create(Node.AnyFrameType); | 1639 | return p.parseIf(parseTypeExpr); |
| 1497 | node.* = .{ | ||
| 1498 | .anyframe_token = token, | ||
| 1499 | .result = null, | ||
| 1500 | }; | ||
| 1501 | return &node.base; | ||
| 1502 | } | 1640 | } |
| 1503 | if (eatToken(it, .Keyword_true)) |token| return createLiteral(arena, Node.BoolLiteral, token); | ||
| 1504 | if (eatToken(it, .Keyword_undefined)) |token| return createLiteral(arena, Node.UndefinedLiteral, token); | ||
| 1505 | if (eatToken(it, .Keyword_unreachable)) |token| return createLiteral(arena, Node.Unreachable, token); | ||
| 1506 | if (try parseStringLiteral(arena, it, tree)) |node| return node; | ||
| 1507 | if (try parseSwitchExpr(arena, it, tree)) |node| return node; | ||
| 1508 | 1641 | ||
| 1509 | return null; | 1642 | /// LabeledTypeExpr |
| 1510 | } | 1643 | /// <- BlockLabel Block |
| 1644 | /// / BlockLabel? LoopTypeExpr | ||
| 1645 | fn parseLabeledTypeExpr(p: *Parser) !?*Node { | ||
| 1646 | var colon: TokenIndex = undefined; | ||
| 1647 | const label = p.parseBlockLabel(&colon); | ||
| 1511 | 1648 | ||
| 1512 | /// ContainerDecl <- (KEYWORD_extern / KEYWORD_packed)? ContainerDeclAuto | 1649 | if (label) |token| { |
| 1513 | fn parseContainerDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1650 | if (try p.parseBlock()) |node| { |
| 1514 | const layout_token = eatToken(it, .Keyword_extern) orelse | 1651 | node.cast(Node.Block).?.label = token; |
| 1515 | eatToken(it, .Keyword_packed); | 1652 | return node; |
| 1653 | } | ||
| 1654 | } | ||
| 1516 | 1655 | ||
| 1517 | const node = (try parseContainerDeclAuto(arena, it, tree)) orelse { | 1656 | if (try p.parseLoopTypeExpr()) |node| { |
| 1518 | if (layout_token) |token| | 1657 | switch (node.id) { |
| 1519 | putBackToken(it, token); | 1658 | .For => node.cast(Node.For).?.label = label, |
| 1520 | return null; | 1659 | .While => node.cast(Node.While).?.label = label, |
| 1521 | }; | 1660 | else => unreachable, |
| 1522 | node.cast(Node.ContainerDecl).?.*.layout_token = layout_token; | 1661 | } |
| 1523 | return node; | 1662 | return node; |
| 1524 | } | 1663 | } |
| 1525 | 1664 | ||
| 1526 | /// ErrorSetDecl <- KEYWORD_error LBRACE IdentifierList RBRACE | 1665 | if (label) |token| { |
| 1527 | fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1666 | p.putBackToken(colon); |
| 1528 | const error_token = eatToken(it, .Keyword_error) orelse return null; | 1667 | p.putBackToken(token); |
| 1529 | if (eatToken(it, .LBrace) == null) { | 1668 | } |
| 1530 | // Might parse as `KEYWORD_error DOT IDENTIFIER` later in PrimaryTypeExpr, so don't error | ||
| 1531 | putBackToken(it, error_token); | ||
| 1532 | return null; | 1669 | return null; |
| 1533 | } | 1670 | } |
| 1534 | const decls = try parseErrorTagList(arena, it, tree); | ||
| 1535 | const rbrace = try expectToken(it, tree, .RBrace); | ||
| 1536 | |||
| 1537 | const node = try arena.create(Node.ErrorSetDecl); | ||
| 1538 | node.* = .{ | ||
| 1539 | .error_token = error_token, | ||
| 1540 | .decls = decls, | ||
| 1541 | .rbrace_token = rbrace, | ||
| 1542 | }; | ||
| 1543 | return &node.base; | ||
| 1544 | } | ||
| 1545 | 1671 | ||
| 1546 | /// GroupedExpr <- LPAREN Expr RPAREN | 1672 | /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) |
| 1547 | fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1673 | fn parseLoopTypeExpr(p: *Parser) !?*Node { |
| 1548 | const lparen = eatToken(it, .LParen) orelse return null; | 1674 | const inline_token = p.eatToken(.Keyword_inline); |
| 1549 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1550 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1551 | }); | ||
| 1552 | const rparen = try expectToken(it, tree, .RParen); | ||
| 1553 | |||
| 1554 | const node = try arena.create(Node.GroupedExpression); | ||
| 1555 | node.* = .{ | ||
| 1556 | .lparen = lparen, | ||
| 1557 | .expr = expr, | ||
| 1558 | .rparen = rparen, | ||
| 1559 | }; | ||
| 1560 | return &node.base; | ||
| 1561 | } | ||
| 1562 | |||
| 1563 | /// IfTypeExpr <- IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? | ||
| 1564 | fn parseIfTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 1565 | return parseIf(arena, it, tree, parseTypeExpr); | ||
| 1566 | } | ||
| 1567 | 1675 | ||
| 1568 | /// LabeledTypeExpr | 1676 | if (try p.parseForTypeExpr()) |node| { |
| 1569 | /// <- BlockLabel Block | 1677 | node.cast(Node.For).?.inline_token = inline_token; |
| 1570 | /// / BlockLabel? LoopTypeExpr | ||
| 1571 | fn parseLabeledTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 1572 | var colon: TokenIndex = undefined; | ||
| 1573 | const label = parseBlockLabel(arena, it, tree, &colon); | ||
| 1574 | |||
| 1575 | if (label) |token| { | ||
| 1576 | if (try parseBlock(arena, it, tree)) |node| { | ||
| 1577 | node.cast(Node.Block).?.label = token; | ||
| 1578 | return node; | 1678 | return node; |
| 1579 | } | 1679 | } |
| 1580 | } | ||
| 1581 | 1680 | ||
| 1582 | if (try parseLoopTypeExpr(arena, it, tree)) |node| { | 1681 | if (try p.parseWhileTypeExpr()) |node| { |
| 1583 | switch (node.id) { | 1682 | node.cast(Node.While).?.inline_token = inline_token; |
| 1584 | .For => node.cast(Node.For).?.label = label, | 1683 | return node; |
| 1585 | .While => node.cast(Node.While).?.label = label, | ||
| 1586 | else => unreachable, | ||
| 1587 | } | 1684 | } |
| 1588 | return node; | ||
| 1589 | } | ||
| 1590 | 1685 | ||
| 1591 | if (label) |token| { | 1686 | if (inline_token == null) return null; |
| 1592 | putBackToken(it, colon); | 1687 | |
| 1593 | putBackToken(it, token); | 1688 | // If we've seen "inline", there should have been a "for" or "while" |
| 1689 | try p.errors.append(p.gpa, .{ | ||
| 1690 | .ExpectedInlinable = .{ .token = p.tok_i }, | ||
| 1691 | }); | ||
| 1692 | return error.ParseError; | ||
| 1594 | } | 1693 | } |
| 1595 | return null; | ||
| 1596 | } | ||
| 1597 | 1694 | ||
| 1598 | /// LoopTypeExpr <- KEYWORD_inline? (ForTypeExpr / WhileTypeExpr) | 1695 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? |
| 1599 | fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1696 | fn parseForTypeExpr(p: *Parser) !?*Node { |
| 1600 | const inline_token = eatToken(it, .Keyword_inline); | 1697 | const node = (try p.parseForPrefix()) orelse return null; |
| 1698 | const for_prefix = node.cast(Node.For).?; | ||
| 1601 | 1699 | ||
| 1602 | if (try parseForTypeExpr(arena, it, tree)) |node| { | 1700 | const type_expr = try p.expectNode(parseTypeExpr, .{ |
| 1603 | node.cast(Node.For).?.inline_token = inline_token; | 1701 | .ExpectedTypeExpr = .{ .token = p.tok_i }, |
| 1604 | return node; | 1702 | }); |
| 1605 | } | 1703 | for_prefix.body = type_expr; |
| 1606 | 1704 | ||
| 1607 | if (try parseWhileTypeExpr(arena, it, tree)) |node| { | 1705 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 1608 | node.cast(Node.While).?.inline_token = inline_token; | 1706 | const else_expr = try p.expectNode(parseTypeExpr, .{ |
| 1609 | return node; | 1707 | .ExpectedTypeExpr = .{ .token = p.tok_i }, |
| 1610 | } | 1708 | }); |
| 1611 | 1709 | ||
| 1612 | if (inline_token == null) return null; | 1710 | const else_node = try p.arena.allocator.create(Node.Else); |
| 1711 | else_node.* = .{ | ||
| 1712 | .else_token = else_token, | ||
| 1713 | .payload = null, | ||
| 1714 | .body = else_expr, | ||
| 1715 | }; | ||
| 1613 | 1716 | ||
| 1614 | // If we've seen "inline", there should have been a "for" or "while" | 1717 | for_prefix.@"else" = else_node; |
| 1615 | try tree.errors.push(.{ | 1718 | } |
| 1616 | .ExpectedInlinable = .{ .token = it.index }, | ||
| 1617 | }); | ||
| 1618 | return error.ParseError; | ||
| 1619 | } | ||
| 1620 | 1719 | ||
| 1621 | /// ForTypeExpr <- ForPrefix TypeExpr (KEYWORD_else TypeExpr)? | 1720 | return node; |
| 1622 | fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1721 | } |
| 1623 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; | ||
| 1624 | const for_prefix = node.cast(Node.For).?; | ||
| 1625 | 1722 | ||
| 1626 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | 1723 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? |
| 1627 | .ExpectedTypeExpr = .{ .token = it.index }, | 1724 | fn parseWhileTypeExpr(p: *Parser) !?*Node { |
| 1628 | }); | 1725 | const node = (try p.parseWhilePrefix()) orelse return null; |
| 1629 | for_prefix.body = type_expr; | 1726 | const while_prefix = node.cast(Node.While).?; |
| 1630 | 1727 | ||
| 1631 | if (eatToken(it, .Keyword_else)) |else_token| { | 1728 | const type_expr = try p.expectNode(parseTypeExpr, .{ |
| 1632 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | 1729 | .ExpectedTypeExpr = .{ .token = p.tok_i }, |
| 1633 | .ExpectedTypeExpr = .{ .token = it.index }, | ||
| 1634 | }); | 1730 | }); |
| 1731 | while_prefix.body = type_expr; | ||
| 1635 | 1732 | ||
| 1636 | const else_node = try arena.create(Node.Else); | 1733 | if (p.eatToken(.Keyword_else)) |else_token| { |
| 1637 | else_node.* = .{ | 1734 | const payload = try p.parsePayload(); |
| 1638 | .else_token = else_token, | ||
| 1639 | .payload = null, | ||
| 1640 | .body = else_expr, | ||
| 1641 | }; | ||
| 1642 | |||
| 1643 | for_prefix.@"else" = else_node; | ||
| 1644 | } | ||
| 1645 | 1735 | ||
| 1646 | return node; | 1736 | const else_expr = try p.expectNode(parseTypeExpr, .{ |
| 1647 | } | 1737 | .ExpectedTypeExpr = .{ .token = p.tok_i }, |
| 1738 | }); | ||
| 1648 | 1739 | ||
| 1649 | /// WhileTypeExpr <- WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)? | 1740 | const else_node = try p.arena.allocator.create(Node.Else); |
| 1650 | fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1741 | else_node.* = .{ |
| 1651 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; | 1742 | .else_token = else_token, |
| 1652 | const while_prefix = node.cast(Node.While).?; | 1743 | .payload = null, |
| 1744 | .body = else_expr, | ||
| 1745 | }; | ||
| 1653 | 1746 | ||
| 1654 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | 1747 | while_prefix.@"else" = else_node; |
| 1655 | .ExpectedTypeExpr = .{ .token = it.index }, | 1748 | } |
| 1656 | }); | ||
| 1657 | while_prefix.body = type_expr; | ||
| 1658 | 1749 | ||
| 1659 | if (eatToken(it, .Keyword_else)) |else_token| { | 1750 | return node; |
| 1660 | const payload = try parsePayload(arena, it, tree); | 1751 | } |
| 1661 | 1752 | ||
| 1662 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | 1753 | /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE |
| 1663 | .ExpectedTypeExpr = .{ .token = it.index }, | 1754 | fn parseSwitchExpr(p: *Parser) !?*Node { |
| 1755 | const switch_token = p.eatToken(.Keyword_switch) orelse return null; | ||
| 1756 | _ = try p.expectToken(.LParen); | ||
| 1757 | const expr_node = try p.expectNode(parseExpr, .{ | ||
| 1758 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 1664 | }); | 1759 | }); |
| 1760 | _ = try p.expectToken(.RParen); | ||
| 1761 | _ = try p.expectToken(.LBrace); | ||
| 1762 | const cases = try p.parseSwitchProngList(); | ||
| 1763 | defer p.gpa.free(cases); | ||
| 1764 | const rbrace = try p.expectToken(.RBrace); | ||
| 1665 | 1765 | ||
| 1666 | const else_node = try arena.create(Node.Else); | 1766 | const node = try Node.Switch.alloc(&p.arena.allocator, cases.len); |
| 1667 | else_node.* = .{ | 1767 | node.* = .{ |
| 1668 | .else_token = else_token, | 1768 | .switch_token = switch_token, |
| 1669 | .payload = null, | 1769 | .expr = expr_node, |
| 1670 | .body = else_expr, | 1770 | .cases_len = cases.len, |
| 1771 | .rbrace = rbrace, | ||
| 1671 | }; | 1772 | }; |
| 1672 | 1773 | std.mem.copy(*Node, node.cases(), cases); | |
| 1673 | while_prefix.@"else" = else_node; | 1774 | return &node.base; |
| 1674 | } | 1775 | } |
| 1675 | 1776 | ||
| 1676 | return node; | 1777 | /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN |
| 1677 | } | 1778 | /// AsmOutput <- COLON AsmOutputList AsmInput? |
| 1779 | /// AsmInput <- COLON AsmInputList AsmClobbers? | ||
| 1780 | /// AsmClobbers <- COLON StringList | ||
| 1781 | /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL? | ||
| 1782 | fn parseAsmExpr(p: *Parser) !?*Node { | ||
| 1783 | const asm_token = p.eatToken(.Keyword_asm) orelse return null; | ||
| 1784 | const volatile_token = p.eatToken(.Keyword_volatile); | ||
| 1785 | _ = try p.expectToken(.LParen); | ||
| 1786 | const template = try p.expectNode(parseExpr, .{ | ||
| 1787 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 1788 | }); | ||
| 1678 | 1789 | ||
| 1679 | /// SwitchExpr <- KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE | 1790 | var arena_outputs: []Node.Asm.Output = &[0]Node.Asm.Output{}; |
| 1680 | fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1791 | var arena_inputs: []Node.Asm.Input = &[0]Node.Asm.Input{}; |
| 1681 | const switch_token = eatToken(it, .Keyword_switch) orelse return null; | 1792 | var arena_clobbers: []*Node = &[0]*Node{}; |
| 1682 | _ = try expectToken(it, tree, .LParen); | ||
| 1683 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1684 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1685 | }); | ||
| 1686 | _ = try expectToken(it, tree, .RParen); | ||
| 1687 | _ = try expectToken(it, tree, .LBrace); | ||
| 1688 | const cases = try parseSwitchProngList(arena, it, tree); | ||
| 1689 | const rbrace = try expectToken(it, tree, .RBrace); | ||
| 1690 | |||
| 1691 | const node = try arena.create(Node.Switch); | ||
| 1692 | node.* = .{ | ||
| 1693 | .switch_token = switch_token, | ||
| 1694 | .expr = expr_node, | ||
| 1695 | .cases = cases, | ||
| 1696 | .rbrace = rbrace, | ||
| 1697 | }; | ||
| 1698 | return &node.base; | ||
| 1699 | } | ||
| 1700 | 1793 | ||
| 1701 | /// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN | 1794 | if (p.eatToken(.Colon) != null) { |
| 1702 | fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1795 | const outputs = try p.parseAsmOutputList(); |
| 1703 | const asm_token = eatToken(it, .Keyword_asm) orelse return null; | 1796 | defer p.gpa.free(outputs); |
| 1704 | const volatile_token = eatToken(it, .Keyword_volatile); | 1797 | arena_outputs = try p.arena.allocator.dupe(Node.Asm.Output, outputs); |
| 1705 | _ = try expectToken(it, tree, .LParen); | ||
| 1706 | const template = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1707 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1708 | }); | ||
| 1709 | |||
| 1710 | const node = try arena.create(Node.Asm); | ||
| 1711 | node.* = .{ | ||
| 1712 | .asm_token = asm_token, | ||
| 1713 | .volatile_token = volatile_token, | ||
| 1714 | .template = template, | ||
| 1715 | .outputs = Node.Asm.OutputList.init(arena), | ||
| 1716 | .inputs = Node.Asm.InputList.init(arena), | ||
| 1717 | .clobbers = Node.Asm.ClobberList.init(arena), | ||
| 1718 | .rparen = undefined, | ||
| 1719 | }; | ||
| 1720 | 1798 | ||
| 1721 | try parseAsmOutput(arena, it, tree, node); | 1799 | if (p.eatToken(.Colon) != null) { |
| 1722 | node.rparen = try expectToken(it, tree, .RParen); | 1800 | const inputs = try p.parseAsmInputList(); |
| 1723 | return &node.base; | 1801 | defer p.gpa.free(inputs); |
| 1724 | } | 1802 | arena_inputs = try p.arena.allocator.dupe(Node.Asm.Input, inputs); |
| 1725 | 1803 | ||
| 1726 | /// DOT IDENTIFIER | 1804 | if (p.eatToken(.Colon) != null) { |
| 1727 | fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1805 | const clobbers = try ListParseFn(*Node, parseStringLiteral)(p); |
| 1728 | const dot = eatToken(it, .Period) orelse return null; | 1806 | defer p.gpa.free(clobbers); |
| 1807 | arena_clobbers = try p.arena.allocator.dupe(*Node, clobbers); | ||
| 1808 | } | ||
| 1809 | } | ||
| 1810 | } | ||
| 1729 | 1811 | ||
| 1730 | // anon enum literal | 1812 | const node = try p.arena.allocator.create(Node.Asm); |
| 1731 | if (eatToken(it, .Identifier)) |name| { | ||
| 1732 | const node = try arena.create(Node.EnumLiteral); | ||
| 1733 | node.* = .{ | 1813 | node.* = .{ |
| 1734 | .dot = dot, | 1814 | .asm_token = asm_token, |
| 1735 | .name = name, | 1815 | .volatile_token = volatile_token, |
| 1816 | .template = template, | ||
| 1817 | .outputs = arena_outputs, | ||
| 1818 | .inputs = arena_inputs, | ||
| 1819 | .clobbers = arena_clobbers, | ||
| 1820 | .rparen = try p.expectToken(.RParen), | ||
| 1736 | }; | 1821 | }; |
| 1737 | return &node.base; | ||
| 1738 | } | ||
| 1739 | 1822 | ||
| 1740 | // anon container literal | ||
| 1741 | if (try parseInitList(arena, it, tree)) |node| { | ||
| 1742 | node.lhs = .{ .dot = dot }; | ||
| 1743 | return &node.base; | 1823 | return &node.base; |
| 1744 | } | 1824 | } |
| 1745 | 1825 | ||
| 1746 | putBackToken(it, dot); | 1826 | /// DOT IDENTIFIER |
| 1747 | return null; | 1827 | fn parseAnonLiteral(p: *Parser) !?*Node { |
| 1748 | } | 1828 | const dot = p.eatToken(.Period) orelse return null; |
| 1749 | |||
| 1750 | /// AsmOutput <- COLON AsmOutputList AsmInput? | ||
| 1751 | fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void { | ||
| 1752 | if (eatToken(it, .Colon) == null) return; | ||
| 1753 | asm_node.outputs = try parseAsmOutputList(arena, it, tree); | ||
| 1754 | try parseAsmInput(arena, it, tree, asm_node); | ||
| 1755 | } | ||
| 1756 | 1829 | ||
| 1757 | /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN | 1830 | // anon enum literal |
| 1758 | fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput { | 1831 | if (p.eatToken(.Identifier)) |name| { |
| 1759 | const lbracket = eatToken(it, .LBracket) orelse return null; | 1832 | const node = try p.arena.allocator.create(Node.EnumLiteral); |
| 1760 | const name = try expectNode(arena, it, tree, parseIdentifier, .{ | 1833 | node.* = .{ |
| 1761 | .ExpectedIdentifier = .{ .token = it.index }, | 1834 | .dot = dot, |
| 1762 | }); | 1835 | .name = name, |
| 1763 | _ = try expectToken(it, tree, .RBracket); | 1836 | }; |
| 1764 | 1837 | return &node.base; | |
| 1765 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ | ||
| 1766 | .ExpectedStringLiteral = .{ .token = it.index }, | ||
| 1767 | }); | ||
| 1768 | |||
| 1769 | _ = try expectToken(it, tree, .LParen); | ||
| 1770 | const kind: Node.AsmOutput.Kind = blk: { | ||
| 1771 | if (eatToken(it, .Arrow) != null) { | ||
| 1772 | const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{ | ||
| 1773 | .ExpectedTypeExpr = .{ .token = it.index }, | ||
| 1774 | }); | ||
| 1775 | break :blk .{ .Return = return_ident }; | ||
| 1776 | } | 1838 | } |
| 1777 | const variable = try expectNode(arena, it, tree, parseIdentifier, .{ | ||
| 1778 | .ExpectedIdentifier = .{ .token = it.index }, | ||
| 1779 | }); | ||
| 1780 | break :blk .{ .Variable = variable.cast(Node.Identifier).? }; | ||
| 1781 | }; | ||
| 1782 | const rparen = try expectToken(it, tree, .RParen); | ||
| 1783 | |||
| 1784 | const node = try arena.create(Node.AsmOutput); | ||
| 1785 | node.* = .{ | ||
| 1786 | .lbracket = lbracket, | ||
| 1787 | .symbolic_name = name, | ||
| 1788 | .constraint = constraint, | ||
| 1789 | .kind = kind, | ||
| 1790 | .rparen = rparen, | ||
| 1791 | }; | ||
| 1792 | return node; | ||
| 1793 | } | ||
| 1794 | 1839 | ||
| 1795 | /// AsmInput <- COLON AsmInputList AsmClobbers? | 1840 | if (try p.parseAnonInitList(dot)) |node| { |
| 1796 | fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void { | 1841 | return node; |
| 1797 | if (eatToken(it, .Colon) == null) return; | 1842 | } |
| 1798 | asm_node.inputs = try parseAsmInputList(arena, it, tree); | ||
| 1799 | try parseAsmClobbers(arena, it, tree, asm_node); | ||
| 1800 | } | ||
| 1801 | 1843 | ||
| 1802 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN | 1844 | p.putBackToken(dot); |
| 1803 | fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput { | 1845 | return null; |
| 1804 | const lbracket = eatToken(it, .LBracket) orelse return null; | 1846 | } |
| 1805 | const name = try expectNode(arena, it, tree, parseIdentifier, .{ | ||
| 1806 | .ExpectedIdentifier = .{ .token = it.index }, | ||
| 1807 | }); | ||
| 1808 | _ = try expectToken(it, tree, .RBracket); | ||
| 1809 | |||
| 1810 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ | ||
| 1811 | .ExpectedStringLiteral = .{ .token = it.index }, | ||
| 1812 | }); | ||
| 1813 | |||
| 1814 | _ = try expectToken(it, tree, .LParen); | ||
| 1815 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1816 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1817 | }); | ||
| 1818 | const rparen = try expectToken(it, tree, .RParen); | ||
| 1819 | |||
| 1820 | const node = try arena.create(Node.AsmInput); | ||
| 1821 | node.* = .{ | ||
| 1822 | .lbracket = lbracket, | ||
| 1823 | .symbolic_name = name, | ||
| 1824 | .constraint = constraint, | ||
| 1825 | .expr = expr, | ||
| 1826 | .rparen = rparen, | ||
| 1827 | }; | ||
| 1828 | return node; | ||
| 1829 | } | ||
| 1830 | 1847 | ||
| 1831 | /// AsmClobbers <- COLON StringList | 1848 | /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN |
| 1832 | /// StringList <- (STRINGLITERAL COMMA)* STRINGLITERAL? | 1849 | fn parseAsmOutputItem(p: *Parser) !?Node.Asm.Output { |
| 1833 | fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *Node.Asm) !void { | 1850 | const lbracket = p.eatToken(.LBracket) orelse return null; |
| 1834 | if (eatToken(it, .Colon) == null) return; | 1851 | const name = try p.expectNode(parseIdentifier, .{ |
| 1835 | asm_node.clobbers = try ListParseFn( | 1852 | .ExpectedIdentifier = .{ .token = p.tok_i }, |
| 1836 | Node.Asm.ClobberList, | 1853 | }); |
| 1837 | parseStringLiteral, | 1854 | _ = try p.expectToken(.RBracket); |
| 1838 | )(arena, it, tree); | ||
| 1839 | } | ||
| 1840 | 1855 | ||
| 1841 | /// BreakLabel <- COLON IDENTIFIER | 1856 | const constraint = try p.expectNode(parseStringLiteral, .{ |
| 1842 | fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1857 | .ExpectedStringLiteral = .{ .token = p.tok_i }, |
| 1843 | _ = eatToken(it, .Colon) orelse return null; | 1858 | }); |
| 1844 | return try expectNode(arena, it, tree, parseIdentifier, .{ | ||
| 1845 | .ExpectedIdentifier = .{ .token = it.index }, | ||
| 1846 | }); | ||
| 1847 | } | ||
| 1848 | 1859 | ||
| 1849 | /// BlockLabel <- IDENTIFIER COLON | 1860 | _ = try p.expectToken(.LParen); |
| 1850 | fn parseBlockLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree, colon_token: *TokenIndex) ?TokenIndex { | 1861 | const kind: Node.Asm.Output.Kind = blk: { |
| 1851 | const identifier = eatToken(it, .Identifier) orelse return null; | 1862 | if (p.eatToken(.Arrow) != null) { |
| 1852 | if (eatToken(it, .Colon)) |colon| { | 1863 | const return_ident = try p.expectNode(parseTypeExpr, .{ |
| 1853 | colon_token.* = colon; | 1864 | .ExpectedTypeExpr = .{ .token = p.tok_i }, |
| 1854 | return identifier; | 1865 | }); |
| 1866 | break :blk .{ .Return = return_ident }; | ||
| 1867 | } | ||
| 1868 | const variable = try p.expectNode(parseIdentifier, .{ | ||
| 1869 | .ExpectedIdentifier = .{ .token = p.tok_i }, | ||
| 1870 | }); | ||
| 1871 | break :blk .{ .Variable = variable.cast(Node.Identifier).? }; | ||
| 1872 | }; | ||
| 1873 | const rparen = try p.expectToken(.RParen); | ||
| 1874 | |||
| 1875 | return Node.Asm.Output{ | ||
| 1876 | .lbracket = lbracket, | ||
| 1877 | .symbolic_name = name, | ||
| 1878 | .constraint = constraint, | ||
| 1879 | .kind = kind, | ||
| 1880 | .rparen = rparen, | ||
| 1881 | }; | ||
| 1855 | } | 1882 | } |
| 1856 | putBackToken(it, identifier); | ||
| 1857 | return null; | ||
| 1858 | } | ||
| 1859 | 1883 | ||
| 1860 | /// FieldInit <- DOT IDENTIFIER EQUAL Expr | 1884 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN |
| 1861 | fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1885 | fn parseAsmInputItem(p: *Parser) !?Node.Asm.Input { |
| 1862 | const period_token = eatToken(it, .Period) orelse return null; | 1886 | const lbracket = p.eatToken(.LBracket) orelse return null; |
| 1863 | const name_token = eatToken(it, .Identifier) orelse { | 1887 | const name = try p.expectNode(parseIdentifier, .{ |
| 1864 | // Because of anon literals `.{` is also valid. | 1888 | .ExpectedIdentifier = .{ .token = p.tok_i }, |
| 1865 | putBackToken(it, period_token); | 1889 | }); |
| 1866 | return null; | 1890 | _ = try p.expectToken(.RBracket); |
| 1867 | }; | ||
| 1868 | const eq_token = eatToken(it, .Equal) orelse { | ||
| 1869 | // `.Name` may also be an enum literal, which is a later rule. | ||
| 1870 | putBackToken(it, name_token); | ||
| 1871 | putBackToken(it, period_token); | ||
| 1872 | return null; | ||
| 1873 | }; | ||
| 1874 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 1875 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1876 | }); | ||
| 1877 | |||
| 1878 | const node = try arena.create(Node.FieldInitializer); | ||
| 1879 | node.* = .{ | ||
| 1880 | .period_token = period_token, | ||
| 1881 | .name_token = name_token, | ||
| 1882 | .expr = expr_node, | ||
| 1883 | }; | ||
| 1884 | return &node.base; | ||
| 1885 | } | ||
| 1886 | 1891 | ||
| 1887 | /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN | 1892 | const constraint = try p.expectNode(parseStringLiteral, .{ |
| 1888 | fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1893 | .ExpectedStringLiteral = .{ .token = p.tok_i }, |
| 1889 | _ = eatToken(it, .Colon) orelse return null; | 1894 | }); |
| 1890 | _ = try expectToken(it, tree, .LParen); | ||
| 1891 | const node = try expectNode(arena, it, tree, parseAssignExpr, .{ | ||
| 1892 | .ExpectedExprOrAssignment = .{ .token = it.index }, | ||
| 1893 | }); | ||
| 1894 | _ = try expectToken(it, tree, .RParen); | ||
| 1895 | return node; | ||
| 1896 | } | ||
| 1897 | 1895 | ||
| 1898 | /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN | 1896 | _ = try p.expectToken(.LParen); |
| 1899 | fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1897 | const expr = try p.expectNode(parseExpr, .{ |
| 1900 | _ = eatToken(it, .Keyword_linksection) orelse return null; | 1898 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1901 | _ = try expectToken(it, tree, .LParen); | 1899 | }); |
| 1902 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | 1900 | const rparen = try p.expectToken(.RParen); |
| 1903 | .ExpectedExpr = .{ .token = it.index }, | ||
| 1904 | }); | ||
| 1905 | _ = try expectToken(it, tree, .RParen); | ||
| 1906 | return expr_node; | ||
| 1907 | } | ||
| 1908 | 1901 | ||
| 1909 | /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN | 1902 | return Node.Asm.Input{ |
| 1910 | fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1903 | .lbracket = lbracket, |
| 1911 | _ = eatToken(it, .Keyword_callconv) orelse return null; | 1904 | .symbolic_name = name, |
| 1912 | _ = try expectToken(it, tree, .LParen); | 1905 | .constraint = constraint, |
| 1913 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | 1906 | .expr = expr, |
| 1914 | .ExpectedExpr = .{ .token = it.index }, | 1907 | .rparen = rparen, |
| 1915 | }); | 1908 | }; |
| 1916 | _ = try expectToken(it, tree, .RParen); | 1909 | } |
| 1917 | return expr_node; | ||
| 1918 | } | ||
| 1919 | 1910 | ||
| 1920 | /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType | 1911 | /// BreakLabel <- COLON IDENTIFIER |
| 1921 | fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1912 | fn parseBreakLabel(p: *Parser) !?*Node { |
| 1922 | const doc_comments = try parseDocComment(arena, it, tree); | 1913 | _ = p.eatToken(.Colon) orelse return null; |
| 1923 | const noalias_token = eatToken(it, .Keyword_noalias); | 1914 | return p.expectNode(parseIdentifier, .{ |
| 1924 | const comptime_token = if (noalias_token == null) eatToken(it, .Keyword_comptime) else null; | 1915 | .ExpectedIdentifier = .{ .token = p.tok_i }, |
| 1925 | const name_token = blk: { | ||
| 1926 | const identifier = eatToken(it, .Identifier) orelse break :blk null; | ||
| 1927 | if (eatToken(it, .Colon) != null) break :blk identifier; | ||
| 1928 | putBackToken(it, identifier); // ParamType may also be an identifier | ||
| 1929 | break :blk null; | ||
| 1930 | }; | ||
| 1931 | const param_type = (try parseParamType(arena, it, tree)) orelse { | ||
| 1932 | // Only return cleanly if no keyword, identifier, or doc comment was found | ||
| 1933 | if (noalias_token == null and | ||
| 1934 | comptime_token == null and | ||
| 1935 | name_token == null and | ||
| 1936 | doc_comments == null) return null; | ||
| 1937 | try tree.errors.push(.{ | ||
| 1938 | .ExpectedParamType = .{ .token = it.index }, | ||
| 1939 | }); | 1916 | }); |
| 1940 | return error.ParseError; | 1917 | } |
| 1941 | }; | ||
| 1942 | |||
| 1943 | const param_decl = try arena.create(Node.ParamDecl); | ||
| 1944 | param_decl.* = .{ | ||
| 1945 | .doc_comments = doc_comments, | ||
| 1946 | .comptime_token = comptime_token, | ||
| 1947 | .noalias_token = noalias_token, | ||
| 1948 | .name_token = name_token, | ||
| 1949 | .param_type = param_type, | ||
| 1950 | }; | ||
| 1951 | return &param_decl.base; | ||
| 1952 | } | ||
| 1953 | 1918 | ||
| 1954 | /// ParamType | 1919 | /// BlockLabel <- IDENTIFIER COLON |
| 1955 | /// <- KEYWORD_var | 1920 | fn parseBlockLabel(p: *Parser, colon_token: *TokenIndex) ?TokenIndex { |
| 1956 | /// / DOT3 | 1921 | const identifier = p.eatToken(.Identifier) orelse return null; |
| 1957 | /// / TypeExpr | 1922 | if (p.eatToken(.Colon)) |colon| { |
| 1958 | fn parseParamType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?Node.ParamDecl.ParamType { | 1923 | colon_token.* = colon; |
| 1959 | // TODO cast from tuple to error union is broken | 1924 | return identifier; |
| 1960 | const P = Node.ParamDecl.ParamType; | 1925 | } |
| 1961 | if (try parseVarType(arena, it, tree)) |node| return P{ .var_type = node }; | 1926 | p.putBackToken(identifier); |
| 1962 | if (eatToken(it, .Ellipsis3)) |token| return P{ .var_args = token }; | 1927 | return null; |
| 1963 | if (try parseTypeExpr(arena, it, tree)) |node| return P{ .type_expr = node }; | 1928 | } |
| 1964 | return null; | ||
| 1965 | } | ||
| 1966 | 1929 | ||
| 1967 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | 1930 | /// FieldInit <- DOT IDENTIFIER EQUAL Expr |
| 1968 | fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1931 | fn parseFieldInit(p: *Parser) !?*Node { |
| 1969 | const if_token = eatToken(it, .Keyword_if) orelse return null; | 1932 | const period_token = p.eatToken(.Period) orelse return null; |
| 1970 | _ = try expectToken(it, tree, .LParen); | 1933 | const name_token = p.eatToken(.Identifier) orelse { |
| 1971 | const condition = try expectNode(arena, it, tree, parseExpr, .{ | 1934 | // Because of anon literals `.{` is also valid. |
| 1972 | .ExpectedExpr = .{ .token = it.index }, | 1935 | p.putBackToken(period_token); |
| 1973 | }); | 1936 | return null; |
| 1974 | _ = try expectToken(it, tree, .RParen); | 1937 | }; |
| 1975 | const payload = try parsePtrPayload(arena, it, tree); | 1938 | const eq_token = p.eatToken(.Equal) orelse { |
| 1976 | 1939 | // `.Name` may also be an enum literal, which is a later rule. | |
| 1977 | const node = try arena.create(Node.If); | 1940 | p.putBackToken(name_token); |
| 1978 | node.* = .{ | 1941 | p.putBackToken(period_token); |
| 1979 | .if_token = if_token, | 1942 | return null; |
| 1980 | .condition = condition, | 1943 | }; |
| 1981 | .payload = payload, | 1944 | const expr_node = try p.expectNode(parseExpr, .{ |
| 1982 | .body = undefined, // set by caller | 1945 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 1983 | .@"else" = null, | 1946 | }); |
| 1984 | }; | ||
| 1985 | return &node.base; | ||
| 1986 | } | ||
| 1987 | 1947 | ||
| 1988 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? | 1948 | const node = try p.arena.allocator.create(Node.FieldInitializer); |
| 1989 | fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1949 | node.* = .{ |
| 1990 | const while_token = eatToken(it, .Keyword_while) orelse return null; | 1950 | .period_token = period_token, |
| 1991 | 1951 | .name_token = name_token, | |
| 1992 | _ = try expectToken(it, tree, .LParen); | 1952 | .expr = expr_node, |
| 1993 | const condition = try expectNode(arena, it, tree, parseExpr, .{ | 1953 | }; |
| 1994 | .ExpectedExpr = .{ .token = it.index }, | 1954 | return &node.base; |
| 1995 | }); | 1955 | } |
| 1996 | _ = try expectToken(it, tree, .RParen); | ||
| 1997 | |||
| 1998 | const payload = try parsePtrPayload(arena, it, tree); | ||
| 1999 | const continue_expr = try parseWhileContinueExpr(arena, it, tree); | ||
| 2000 | |||
| 2001 | const node = try arena.create(Node.While); | ||
| 2002 | node.* = .{ | ||
| 2003 | .label = null, | ||
| 2004 | .inline_token = null, | ||
| 2005 | .while_token = while_token, | ||
| 2006 | .condition = condition, | ||
| 2007 | .payload = payload, | ||
| 2008 | .continue_expr = continue_expr, | ||
| 2009 | .body = undefined, // set by caller | ||
| 2010 | .@"else" = null, | ||
| 2011 | }; | ||
| 2012 | return &node.base; | ||
| 2013 | } | ||
| 2014 | 1956 | ||
| 2015 | /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload | 1957 | /// WhileContinueExpr <- COLON LPAREN AssignExpr RPAREN |
| 2016 | fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1958 | fn parseWhileContinueExpr(p: *Parser) !?*Node { |
| 2017 | const for_token = eatToken(it, .Keyword_for) orelse return null; | 1959 | _ = p.eatToken(.Colon) orelse return null; |
| 2018 | 1960 | _ = try p.expectToken(.LParen); | |
| 2019 | _ = try expectToken(it, tree, .LParen); | 1961 | const node = try p.expectNode(parseAssignExpr, .{ |
| 2020 | const array_expr = try expectNode(arena, it, tree, parseExpr, .{ | 1962 | .ExpectedExprOrAssignment = .{ .token = p.tok_i }, |
| 2021 | .ExpectedExpr = .{ .token = it.index }, | 1963 | }); |
| 2022 | }); | 1964 | _ = try p.expectToken(.RParen); |
| 2023 | _ = try expectToken(it, tree, .RParen); | 1965 | return node; |
| 2024 | 1966 | } | |
| 2025 | const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{ | ||
| 2026 | .ExpectedPayload = .{ .token = it.index }, | ||
| 2027 | }); | ||
| 2028 | |||
| 2029 | const node = try arena.create(Node.For); | ||
| 2030 | node.* = .{ | ||
| 2031 | .label = null, | ||
| 2032 | .inline_token = null, | ||
| 2033 | .for_token = for_token, | ||
| 2034 | .array_expr = array_expr, | ||
| 2035 | .payload = payload, | ||
| 2036 | .body = undefined, // set by caller | ||
| 2037 | .@"else" = null, | ||
| 2038 | }; | ||
| 2039 | return &node.base; | ||
| 2040 | } | ||
| 2041 | 1967 | ||
| 2042 | /// Payload <- PIPE IDENTIFIER PIPE | 1968 | /// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN |
| 2043 | fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1969 | fn parseLinkSection(p: *Parser) !?*Node { |
| 2044 | const lpipe = eatToken(it, .Pipe) orelse return null; | 1970 | _ = p.eatToken(.Keyword_linksection) orelse return null; |
| 2045 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | 1971 | _ = try p.expectToken(.LParen); |
| 2046 | .ExpectedIdentifier = .{ .token = it.index }, | 1972 | const expr_node = try p.expectNode(parseExpr, .{ |
| 2047 | }); | 1973 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 2048 | const rpipe = try expectToken(it, tree, .Pipe); | 1974 | }); |
| 2049 | 1975 | _ = try p.expectToken(.RParen); | |
| 2050 | const node = try arena.create(Node.Payload); | 1976 | return expr_node; |
| 2051 | node.* = .{ | 1977 | } |
| 2052 | .lpipe = lpipe, | ||
| 2053 | .error_symbol = identifier, | ||
| 2054 | .rpipe = rpipe, | ||
| 2055 | }; | ||
| 2056 | return &node.base; | ||
| 2057 | } | ||
| 2058 | 1978 | ||
| 2059 | /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE | 1979 | /// CallConv <- KEYWORD_callconv LPAREN Expr RPAREN |
| 2060 | fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1980 | fn parseCallconv(p: *Parser) !?*Node { |
| 2061 | const lpipe = eatToken(it, .Pipe) orelse return null; | 1981 | _ = p.eatToken(.Keyword_callconv) orelse return null; |
| 2062 | const asterisk = eatToken(it, .Asterisk); | 1982 | _ = try p.expectToken(.LParen); |
| 2063 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | 1983 | const expr_node = try p.expectNode(parseExpr, .{ |
| 2064 | .ExpectedIdentifier = .{ .token = it.index }, | 1984 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 2065 | }); | 1985 | }); |
| 2066 | const rpipe = try expectToken(it, tree, .Pipe); | 1986 | _ = try p.expectToken(.RParen); |
| 2067 | 1987 | return expr_node; | |
| 2068 | const node = try arena.create(Node.PointerPayload); | 1988 | } |
| 2069 | node.* = .{ | 1989 | |
| 2070 | .lpipe = lpipe, | 1990 | /// ParamDecl <- (KEYWORD_noalias / KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType |
| 2071 | .ptr_token = asterisk, | 1991 | fn parseParamDecl(p: *Parser) !?Node.FnProto.ParamDecl { |
| 2072 | .value_symbol = identifier, | 1992 | const doc_comments = try p.parseDocComment(); |
| 2073 | .rpipe = rpipe, | 1993 | const noalias_token = p.eatToken(.Keyword_noalias); |
| 2074 | }; | 1994 | const comptime_token = if (noalias_token == null) p.eatToken(.Keyword_comptime) else null; |
| 2075 | return &node.base; | 1995 | const name_token = blk: { |
| 2076 | } | 1996 | const identifier = p.eatToken(.Identifier) orelse break :blk null; |
| 1997 | if (p.eatToken(.Colon) != null) break :blk identifier; | ||
| 1998 | p.putBackToken(identifier); // ParamType may also be an identifier | ||
| 1999 | break :blk null; | ||
| 2000 | }; | ||
| 2001 | const param_type = (try p.parseParamType()) orelse { | ||
| 2002 | // Only return cleanly if no keyword, identifier, or doc comment was found | ||
| 2003 | if (noalias_token == null and | ||
| 2004 | comptime_token == null and | ||
| 2005 | name_token == null and | ||
| 2006 | doc_comments == null) | ||
| 2007 | { | ||
| 2008 | return null; | ||
| 2009 | } | ||
| 2010 | try p.errors.append(p.gpa, .{ | ||
| 2011 | .ExpectedParamType = .{ .token = p.tok_i }, | ||
| 2012 | }); | ||
| 2013 | return error.ParseError; | ||
| 2014 | }; | ||
| 2077 | 2015 | ||
| 2078 | /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE | 2016 | return Node.FnProto.ParamDecl{ |
| 2079 | fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2017 | .doc_comments = doc_comments, |
| 2080 | const lpipe = eatToken(it, .Pipe) orelse return null; | 2018 | .comptime_token = comptime_token, |
| 2081 | const asterisk = eatToken(it, .Asterisk); | 2019 | .noalias_token = noalias_token, |
| 2082 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | 2020 | .name_token = name_token, |
| 2083 | .ExpectedIdentifier = .{ .token = it.index }, | 2021 | .param_type = param_type, |
| 2084 | }); | 2022 | }; |
| 2085 | 2023 | } | |
| 2086 | const index = if (eatToken(it, .Comma) == null) | 2024 | |
| 2087 | null | 2025 | /// ParamType |
| 2088 | else | 2026 | /// <- KEYWORD_var |
| 2089 | try expectNode(arena, it, tree, parseIdentifier, .{ | 2027 | /// / DOT3 |
| 2090 | .ExpectedIdentifier = .{ .token = it.index }, | 2028 | /// / TypeExpr |
| 2029 | fn parseParamType(p: *Parser) !?Node.FnProto.ParamDecl.ParamType { | ||
| 2030 | // TODO cast from tuple to error union is broken | ||
| 2031 | const P = Node.FnProto.ParamDecl.ParamType; | ||
| 2032 | if (try p.parseVarType()) |node| return P{ .var_type = node }; | ||
| 2033 | if (p.eatToken(.Ellipsis3)) |token| return P{ .var_args = token }; | ||
| 2034 | if (try p.parseTypeExpr()) |node| return P{ .type_expr = node }; | ||
| 2035 | return null; | ||
| 2036 | } | ||
| 2037 | |||
| 2038 | /// IfPrefix <- KEYWORD_if LPAREN Expr RPAREN PtrPayload? | ||
| 2039 | fn parseIfPrefix(p: *Parser) !?*Node { | ||
| 2040 | const if_token = p.eatToken(.Keyword_if) orelse return null; | ||
| 2041 | _ = try p.expectToken(.LParen); | ||
| 2042 | const condition = try p.expectNode(parseExpr, .{ | ||
| 2043 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2091 | }); | 2044 | }); |
| 2045 | _ = try p.expectToken(.RParen); | ||
| 2046 | const payload = try p.parsePtrPayload(); | ||
| 2092 | 2047 | ||
| 2093 | const rpipe = try expectToken(it, tree, .Pipe); | 2048 | const node = try p.arena.allocator.create(Node.If); |
| 2049 | node.* = .{ | ||
| 2050 | .if_token = if_token, | ||
| 2051 | .condition = condition, | ||
| 2052 | .payload = payload, | ||
| 2053 | .body = undefined, // set by caller | ||
| 2054 | .@"else" = null, | ||
| 2055 | }; | ||
| 2056 | return &node.base; | ||
| 2057 | } | ||
| 2094 | 2058 | ||
| 2095 | const node = try arena.create(Node.PointerIndexPayload); | 2059 | /// WhilePrefix <- KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr? |
| 2096 | node.* = .{ | 2060 | fn parseWhilePrefix(p: *Parser) !?*Node { |
| 2097 | .lpipe = lpipe, | 2061 | const while_token = p.eatToken(.Keyword_while) orelse return null; |
| 2098 | .ptr_token = asterisk, | ||
| 2099 | .value_symbol = identifier, | ||
| 2100 | .index_symbol = index, | ||
| 2101 | .rpipe = rpipe, | ||
| 2102 | }; | ||
| 2103 | return &node.base; | ||
| 2104 | } | ||
| 2105 | 2062 | ||
| 2106 | /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr | 2063 | _ = try p.expectToken(.LParen); |
| 2107 | fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2064 | const condition = try p.expectNode(parseExpr, .{ |
| 2108 | const node = (try parseSwitchCase(arena, it, tree)) orelse return null; | 2065 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 2109 | const arrow = try expectToken(it, tree, .EqualAngleBracketRight); | 2066 | }); |
| 2110 | const payload = try parsePtrPayload(arena, it, tree); | 2067 | _ = try p.expectToken(.RParen); |
| 2111 | const expr = try expectNode(arena, it, tree, parseAssignExpr, .{ | ||
| 2112 | .ExpectedExprOrAssignment = .{ .token = it.index }, | ||
| 2113 | }); | ||
| 2114 | |||
| 2115 | const switch_case = node.cast(Node.SwitchCase).?; | ||
| 2116 | switch_case.arrow_token = arrow; | ||
| 2117 | switch_case.payload = payload; | ||
| 2118 | switch_case.expr = expr; | ||
| 2119 | |||
| 2120 | return node; | ||
| 2121 | } | ||
| 2122 | 2068 | ||
| 2123 | /// SwitchCase | 2069 | const payload = try p.parsePtrPayload(); |
| 2124 | /// <- SwitchItem (COMMA SwitchItem)* COMMA? | 2070 | const continue_expr = try p.parseWhileContinueExpr(); |
| 2125 | /// / KEYWORD_else | ||
| 2126 | fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2127 | var list = Node.SwitchCase.ItemList.init(arena); | ||
| 2128 | 2071 | ||
| 2129 | if (try parseSwitchItem(arena, it, tree)) |first_item| { | 2072 | const node = try p.arena.allocator.create(Node.While); |
| 2130 | try list.push(first_item); | 2073 | node.* = .{ |
| 2131 | while (eatToken(it, .Comma) != null) { | 2074 | .label = null, |
| 2132 | const next_item = (try parseSwitchItem(arena, it, tree)) orelse break; | 2075 | .inline_token = null, |
| 2133 | try list.push(next_item); | 2076 | .while_token = while_token, |
| 2134 | } | 2077 | .condition = condition, |
| 2135 | } else if (eatToken(it, .Keyword_else)) |else_token| { | 2078 | .payload = payload, |
| 2136 | const else_node = try arena.create(Node.SwitchElse); | 2079 | .continue_expr = continue_expr, |
| 2137 | else_node.* = .{ | 2080 | .body = undefined, // set by caller |
| 2138 | .token = else_token, | 2081 | .@"else" = null, |
| 2139 | }; | 2082 | }; |
| 2140 | try list.push(&else_node.base); | 2083 | return &node.base; |
| 2141 | } else return null; | 2084 | } |
| 2142 | 2085 | ||
| 2143 | const node = try arena.create(Node.SwitchCase); | 2086 | /// ForPrefix <- KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload |
| 2144 | node.* = .{ | 2087 | fn parseForPrefix(p: *Parser) !?*Node { |
| 2145 | .items = list, | 2088 | const for_token = p.eatToken(.Keyword_for) orelse return null; |
| 2146 | .arrow_token = undefined, // set by caller | ||
| 2147 | .payload = null, | ||
| 2148 | .expr = undefined, // set by caller | ||
| 2149 | }; | ||
| 2150 | return &node.base; | ||
| 2151 | } | ||
| 2152 | 2089 | ||
| 2153 | /// SwitchItem <- Expr (DOT3 Expr)? | 2090 | _ = try p.expectToken(.LParen); |
| 2154 | fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2091 | const array_expr = try p.expectNode(parseExpr, .{ |
| 2155 | const expr = (try parseExpr(arena, it, tree)) orelse return null; | 2092 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 2156 | if (eatToken(it, .Ellipsis3)) |token| { | ||
| 2157 | const range_end = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2158 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2159 | }); | 2093 | }); |
| 2094 | _ = try p.expectToken(.RParen); | ||
| 2160 | 2095 | ||
| 2161 | const node = try arena.create(Node.InfixOp); | 2096 | const payload = try p.expectNode(parsePtrIndexPayload, .{ |
| 2097 | .ExpectedPayload = .{ .token = p.tok_i }, | ||
| 2098 | }); | ||
| 2099 | |||
| 2100 | const node = try p.arena.allocator.create(Node.For); | ||
| 2162 | node.* = .{ | 2101 | node.* = .{ |
| 2163 | .op_token = token, | 2102 | .label = null, |
| 2164 | .lhs = expr, | 2103 | .inline_token = null, |
| 2165 | .op = .Range, | 2104 | .for_token = for_token, |
| 2166 | .rhs = range_end, | 2105 | .array_expr = array_expr, |
| 2106 | .payload = payload, | ||
| 2107 | .body = undefined, // set by caller | ||
| 2108 | .@"else" = null, | ||
| 2167 | }; | 2109 | }; |
| 2168 | return &node.base; | 2110 | return &node.base; |
| 2169 | } | 2111 | } |
| 2170 | return expr; | ||
| 2171 | } | ||
| 2172 | 2112 | ||
| 2173 | /// AssignOp | 2113 | /// Payload <- PIPE IDENTIFIER PIPE |
| 2174 | /// <- ASTERISKEQUAL | 2114 | fn parsePayload(p: *Parser) !?*Node { |
| 2175 | /// / SLASHEQUAL | 2115 | const lpipe = p.eatToken(.Pipe) orelse return null; |
| 2176 | /// / PERCENTEQUAL | 2116 | const identifier = try p.expectNode(parseIdentifier, .{ |
| 2177 | /// / PLUSEQUAL | 2117 | .ExpectedIdentifier = .{ .token = p.tok_i }, |
| 2178 | /// / MINUSEQUAL | 2118 | }); |
| 2179 | /// / LARROW2EQUAL | 2119 | const rpipe = try p.expectToken(.Pipe); |
| 2180 | /// / RARROW2EQUAL | ||
| 2181 | /// / AMPERSANDEQUAL | ||
| 2182 | /// / CARETEQUAL | ||
| 2183 | /// / PIPEEQUAL | ||
| 2184 | /// / ASTERISKPERCENTEQUAL | ||
| 2185 | /// / PLUSPERCENTEQUAL | ||
| 2186 | /// / MINUSPERCENTEQUAL | ||
| 2187 | /// / EQUAL | ||
| 2188 | fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2189 | const token = nextToken(it); | ||
| 2190 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | ||
| 2191 | .AsteriskEqual => .AssignMul, | ||
| 2192 | .SlashEqual => .AssignDiv, | ||
| 2193 | .PercentEqual => .AssignMod, | ||
| 2194 | .PlusEqual => .AssignAdd, | ||
| 2195 | .MinusEqual => .AssignSub, | ||
| 2196 | .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft, | ||
| 2197 | .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight, | ||
| 2198 | .AmpersandEqual => .AssignBitAnd, | ||
| 2199 | .CaretEqual => .AssignBitXor, | ||
| 2200 | .PipeEqual => .AssignBitOr, | ||
| 2201 | .AsteriskPercentEqual => .AssignMulWrap, | ||
| 2202 | .PlusPercentEqual => .AssignAddWrap, | ||
| 2203 | .MinusPercentEqual => .AssignSubWrap, | ||
| 2204 | .Equal => .Assign, | ||
| 2205 | else => { | ||
| 2206 | putBackToken(it, token.index); | ||
| 2207 | return null; | ||
| 2208 | }, | ||
| 2209 | }; | ||
| 2210 | 2120 | ||
| 2211 | const node = try arena.create(Node.InfixOp); | 2121 | const node = try p.arena.allocator.create(Node.Payload); |
| 2212 | node.* = .{ | 2122 | node.* = .{ |
| 2213 | .op_token = token.index, | 2123 | .lpipe = lpipe, |
| 2214 | .lhs = undefined, // set by caller | 2124 | .error_symbol = identifier, |
| 2215 | .op = op, | 2125 | .rpipe = rpipe, |
| 2216 | .rhs = undefined, // set by caller | 2126 | }; |
| 2217 | }; | 2127 | return &node.base; |
| 2218 | return &node.base; | 2128 | } |
| 2219 | } | ||
| 2220 | 2129 | ||
| 2221 | /// CompareOp | 2130 | /// PtrPayload <- PIPE ASTERISK? IDENTIFIER PIPE |
| 2222 | /// <- EQUALEQUAL | 2131 | fn parsePtrPayload(p: *Parser) !?*Node { |
| 2223 | /// / EXCLAMATIONMARKEQUAL | 2132 | const lpipe = p.eatToken(.Pipe) orelse return null; |
| 2224 | /// / LARROW | 2133 | const asterisk = p.eatToken(.Asterisk); |
| 2225 | /// / RARROW | 2134 | const identifier = try p.expectNode(parseIdentifier, .{ |
| 2226 | /// / LARROWEQUAL | 2135 | .ExpectedIdentifier = .{ .token = p.tok_i }, |
| 2227 | /// / RARROWEQUAL | 2136 | }); |
| 2228 | fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2137 | const rpipe = try p.expectToken(.Pipe); |
| 2229 | const token = nextToken(it); | ||
| 2230 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | ||
| 2231 | .EqualEqual => .EqualEqual, | ||
| 2232 | .BangEqual => .BangEqual, | ||
| 2233 | .AngleBracketLeft => .LessThan, | ||
| 2234 | .AngleBracketRight => .GreaterThan, | ||
| 2235 | .AngleBracketLeftEqual => .LessOrEqual, | ||
| 2236 | .AngleBracketRightEqual => .GreaterOrEqual, | ||
| 2237 | else => { | ||
| 2238 | putBackToken(it, token.index); | ||
| 2239 | return null; | ||
| 2240 | }, | ||
| 2241 | }; | ||
| 2242 | 2138 | ||
| 2243 | return try createInfixOp(arena, token.index, op); | 2139 | const node = try p.arena.allocator.create(Node.PointerPayload); |
| 2244 | } | 2140 | node.* = .{ |
| 2141 | .lpipe = lpipe, | ||
| 2142 | .ptr_token = asterisk, | ||
| 2143 | .value_symbol = identifier, | ||
| 2144 | .rpipe = rpipe, | ||
| 2145 | }; | ||
| 2146 | return &node.base; | ||
| 2147 | } | ||
| 2245 | 2148 | ||
| 2246 | /// BitwiseOp | 2149 | /// PtrIndexPayload <- PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE |
| 2247 | /// <- AMPERSAND | 2150 | fn parsePtrIndexPayload(p: *Parser) !?*Node { |
| 2248 | /// / CARET | 2151 | const lpipe = p.eatToken(.Pipe) orelse return null; |
| 2249 | /// / PIPE | 2152 | const asterisk = p.eatToken(.Asterisk); |
| 2250 | /// / KEYWORD_orelse | 2153 | const identifier = try p.expectNode(parseIdentifier, .{ |
| 2251 | /// / KEYWORD_catch Payload? | 2154 | .ExpectedIdentifier = .{ .token = p.tok_i }, |
| 2252 | fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2155 | }); |
| 2253 | const token = nextToken(it); | ||
| 2254 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | ||
| 2255 | .Ampersand => .BitAnd, | ||
| 2256 | .Caret => .BitXor, | ||
| 2257 | .Pipe => .BitOr, | ||
| 2258 | .Keyword_orelse => .UnwrapOptional, | ||
| 2259 | .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) }, | ||
| 2260 | else => { | ||
| 2261 | putBackToken(it, token.index); | ||
| 2262 | return null; | ||
| 2263 | }, | ||
| 2264 | }; | ||
| 2265 | 2156 | ||
| 2266 | return try createInfixOp(arena, token.index, op); | 2157 | const index = if (p.eatToken(.Comma) == null) |
| 2267 | } | 2158 | null |
| 2159 | else | ||
| 2160 | try p.expectNode(parseIdentifier, .{ | ||
| 2161 | .ExpectedIdentifier = .{ .token = p.tok_i }, | ||
| 2162 | }); | ||
| 2268 | 2163 | ||
| 2269 | /// BitShiftOp | 2164 | const rpipe = try p.expectToken(.Pipe); |
| 2270 | /// <- LARROW2 | ||
| 2271 | /// / RARROW2 | ||
| 2272 | fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2273 | const token = nextToken(it); | ||
| 2274 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | ||
| 2275 | .AngleBracketAngleBracketLeft => .BitShiftLeft, | ||
| 2276 | .AngleBracketAngleBracketRight => .BitShiftRight, | ||
| 2277 | else => { | ||
| 2278 | putBackToken(it, token.index); | ||
| 2279 | return null; | ||
| 2280 | }, | ||
| 2281 | }; | ||
| 2282 | 2165 | ||
| 2283 | return try createInfixOp(arena, token.index, op); | 2166 | const node = try p.arena.allocator.create(Node.PointerIndexPayload); |
| 2284 | } | 2167 | node.* = .{ |
| 2168 | .lpipe = lpipe, | ||
| 2169 | .ptr_token = asterisk, | ||
| 2170 | .value_symbol = identifier, | ||
| 2171 | .index_symbol = index, | ||
| 2172 | .rpipe = rpipe, | ||
| 2173 | }; | ||
| 2174 | return &node.base; | ||
| 2175 | } | ||
| 2285 | 2176 | ||
| 2286 | /// AdditionOp | 2177 | /// SwitchProng <- SwitchCase EQUALRARROW PtrPayload? AssignExpr |
| 2287 | /// <- PLUS | 2178 | fn parseSwitchProng(p: *Parser) !?*Node { |
| 2288 | /// / MINUS | 2179 | const node = (try p.parseSwitchCase()) orelse return null; |
| 2289 | /// / PLUS2 | 2180 | const arrow = try p.expectToken(.EqualAngleBracketRight); |
| 2290 | /// / PLUSPERCENT | 2181 | const payload = try p.parsePtrPayload(); |
| 2291 | /// / MINUSPERCENT | 2182 | const expr = try p.expectNode(parseAssignExpr, .{ |
| 2292 | fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2183 | .ExpectedExprOrAssignment = .{ .token = p.tok_i }, |
| 2293 | const token = nextToken(it); | 2184 | }); |
| 2294 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | ||
| 2295 | .Plus => .Add, | ||
| 2296 | .Minus => .Sub, | ||
| 2297 | .PlusPlus => .ArrayCat, | ||
| 2298 | .PlusPercent => .AddWrap, | ||
| 2299 | .MinusPercent => .SubWrap, | ||
| 2300 | else => { | ||
| 2301 | putBackToken(it, token.index); | ||
| 2302 | return null; | ||
| 2303 | }, | ||
| 2304 | }; | ||
| 2305 | 2185 | ||
| 2306 | return try createInfixOp(arena, token.index, op); | 2186 | const switch_case = node.cast(Node.SwitchCase).?; |
| 2307 | } | 2187 | switch_case.arrow_token = arrow; |
| 2188 | switch_case.payload = payload; | ||
| 2189 | switch_case.expr = expr; | ||
| 2308 | 2190 | ||
| 2309 | /// MultiplyOp | 2191 | return node; |
| 2310 | /// <- PIPE2 | 2192 | } |
| 2311 | /// / ASTERISK | ||
| 2312 | /// / SLASH | ||
| 2313 | /// / PERCENT | ||
| 2314 | /// / ASTERISK2 | ||
| 2315 | /// / ASTERISKPERCENT | ||
| 2316 | fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2317 | const token = nextToken(it); | ||
| 2318 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | ||
| 2319 | .PipePipe => .MergeErrorSets, | ||
| 2320 | .Asterisk => .Mul, | ||
| 2321 | .Slash => .Div, | ||
| 2322 | .Percent => .Mod, | ||
| 2323 | .AsteriskAsterisk => .ArrayMult, | ||
| 2324 | .AsteriskPercent => .MulWrap, | ||
| 2325 | else => { | ||
| 2326 | putBackToken(it, token.index); | ||
| 2327 | return null; | ||
| 2328 | }, | ||
| 2329 | }; | ||
| 2330 | 2193 | ||
| 2331 | return try createInfixOp(arena, token.index, op); | 2194 | /// SwitchCase |
| 2332 | } | 2195 | /// <- SwitchItem (COMMA SwitchItem)* COMMA? |
| 2196 | /// / KEYWORD_else | ||
| 2197 | fn parseSwitchCase(p: *Parser) !?*Node { | ||
| 2198 | var list = std.ArrayList(*Node).init(p.gpa); | ||
| 2199 | defer list.deinit(); | ||
| 2333 | 2200 | ||
| 2334 | /// PrefixOp | 2201 | if (try p.parseSwitchItem()) |first_item| { |
| 2335 | /// <- EXCLAMATIONMARK | 2202 | try list.append(first_item); |
| 2336 | /// / MINUS | 2203 | while (p.eatToken(.Comma) != null) { |
| 2337 | /// / TILDE | 2204 | const next_item = (try p.parseSwitchItem()) orelse break; |
| 2338 | /// / MINUSPERCENT | 2205 | try list.append(next_item); |
| 2339 | /// / AMPERSAND | 2206 | } |
| 2340 | /// / KEYWORD_try | 2207 | } else if (p.eatToken(.Keyword_else)) |else_token| { |
| 2341 | /// / KEYWORD_await | 2208 | const else_node = try p.arena.allocator.create(Node.SwitchElse); |
| 2342 | fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2209 | else_node.* = .{ |
| 2343 | const token = nextToken(it); | 2210 | .token = else_token, |
| 2344 | const op: Node.PrefixOp.Op = switch (token.ptr.id) { | 2211 | }; |
| 2345 | .Bang => .BoolNot, | 2212 | try list.append(&else_node.base); |
| 2346 | .Minus => .Negation, | 2213 | } else return null; |
| 2347 | .Tilde => .BitNot, | ||
| 2348 | .MinusPercent => .NegationWrap, | ||
| 2349 | .Ampersand => .AddressOf, | ||
| 2350 | .Keyword_try => .Try, | ||
| 2351 | .Keyword_await => .Await, | ||
| 2352 | else => { | ||
| 2353 | putBackToken(it, token.index); | ||
| 2354 | return null; | ||
| 2355 | }, | ||
| 2356 | }; | ||
| 2357 | 2214 | ||
| 2358 | const node = try arena.create(Node.PrefixOp); | 2215 | const node = try Node.SwitchCase.alloc(&p.arena.allocator, list.items.len); |
| 2359 | node.* = .{ | 2216 | node.* = .{ |
| 2360 | .op_token = token.index, | 2217 | .items_len = list.items.len, |
| 2361 | .op = op, | 2218 | .arrow_token = undefined, // set by caller |
| 2362 | .rhs = undefined, // set by caller | 2219 | .payload = null, |
| 2363 | }; | 2220 | .expr = undefined, // set by caller |
| 2364 | return &node.base; | 2221 | }; |
| 2365 | } | 2222 | std.mem.copy(*Node, node.items(), list.items); |
| 2223 | return &node.base; | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | /// SwitchItem <- Expr (DOT3 Expr)? | ||
| 2227 | fn parseSwitchItem(p: *Parser) !?*Node { | ||
| 2228 | const expr = (try p.parseExpr()) orelse return null; | ||
| 2229 | if (p.eatToken(.Ellipsis3)) |token| { | ||
| 2230 | const range_end = try p.expectNode(parseExpr, .{ | ||
| 2231 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2232 | }); | ||
| 2233 | |||
| 2234 | const node = try p.arena.allocator.create(Node.InfixOp); | ||
| 2235 | node.* = .{ | ||
| 2236 | .op_token = token, | ||
| 2237 | .lhs = expr, | ||
| 2238 | .op = .Range, | ||
| 2239 | .rhs = range_end, | ||
| 2240 | }; | ||
| 2241 | return &node.base; | ||
| 2242 | } | ||
| 2243 | return expr; | ||
| 2244 | } | ||
| 2245 | |||
| 2246 | /// AssignOp | ||
| 2247 | /// <- ASTERISKEQUAL | ||
| 2248 | /// / SLASHEQUAL | ||
| 2249 | /// / PERCENTEQUAL | ||
| 2250 | /// / PLUSEQUAL | ||
| 2251 | /// / MINUSEQUAL | ||
| 2252 | /// / LARROW2EQUAL | ||
| 2253 | /// / RARROW2EQUAL | ||
| 2254 | /// / AMPERSANDEQUAL | ||
| 2255 | /// / CARETEQUAL | ||
| 2256 | /// / PIPEEQUAL | ||
| 2257 | /// / ASTERISKPERCENTEQUAL | ||
| 2258 | /// / PLUSPERCENTEQUAL | ||
| 2259 | /// / MINUSPERCENTEQUAL | ||
| 2260 | /// / EQUAL | ||
| 2261 | fn parseAssignOp(p: *Parser) !?*Node { | ||
| 2262 | const token = p.nextToken(); | ||
| 2263 | const op: Node.InfixOp.Op = switch (p.token_ids[token]) { | ||
| 2264 | .AsteriskEqual => .AssignMul, | ||
| 2265 | .SlashEqual => .AssignDiv, | ||
| 2266 | .PercentEqual => .AssignMod, | ||
| 2267 | .PlusEqual => .AssignAdd, | ||
| 2268 | .MinusEqual => .AssignSub, | ||
| 2269 | .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft, | ||
| 2270 | .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight, | ||
| 2271 | .AmpersandEqual => .AssignBitAnd, | ||
| 2272 | .CaretEqual => .AssignBitXor, | ||
| 2273 | .PipeEqual => .AssignBitOr, | ||
| 2274 | .AsteriskPercentEqual => .AssignMulWrap, | ||
| 2275 | .PlusPercentEqual => .AssignAddWrap, | ||
| 2276 | .MinusPercentEqual => .AssignSubWrap, | ||
| 2277 | .Equal => .Assign, | ||
| 2278 | else => { | ||
| 2279 | p.putBackToken(token); | ||
| 2280 | return null; | ||
| 2281 | }, | ||
| 2282 | }; | ||
| 2366 | 2283 | ||
| 2367 | // TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on | 2284 | const node = try p.arena.allocator.create(Node.InfixOp); |
| 2368 | // pointers. Consider updating this rule: | ||
| 2369 | // ... | ||
| 2370 | // / ArrayTypeStart | ||
| 2371 | // / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* | ||
| 2372 | // / PtrTypeStart ... | ||
| 2373 | |||
| 2374 | /// PrefixTypeOp | ||
| 2375 | /// <- QUESTIONMARK | ||
| 2376 | /// / KEYWORD_anyframe MINUSRARROW | ||
| 2377 | /// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* | ||
| 2378 | /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* | ||
| 2379 | fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2380 | if (eatToken(it, .QuestionMark)) |token| { | ||
| 2381 | const node = try arena.create(Node.PrefixOp); | ||
| 2382 | node.* = .{ | 2285 | node.* = .{ |
| 2383 | .op_token = token, | 2286 | .op_token = token, |
| 2384 | .op = .OptionalType, | 2287 | .lhs = undefined, // set by caller |
| 2288 | .op = op, | ||
| 2385 | .rhs = undefined, // set by caller | 2289 | .rhs = undefined, // set by caller |
| 2386 | }; | 2290 | }; |
| 2387 | return &node.base; | 2291 | return &node.base; |
| 2388 | } | 2292 | } |
| 2389 | 2293 | ||
| 2390 | // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or | 2294 | /// CompareOp |
| 2391 | // .return_type more difficult for the caller (see parsePrefixOpExpr helper). | 2295 | /// <- EQUALEQUAL |
| 2392 | // Consider making the AnyFrameType a member of PrefixOp and add a | 2296 | /// / EXCLAMATIONMARKEQUAL |
| 2393 | // PrefixOp.AnyFrameType variant? | 2297 | /// / LARROW |
| 2394 | if (eatToken(it, .Keyword_anyframe)) |token| { | 2298 | /// / RARROW |
| 2395 | const arrow = eatToken(it, .Arrow) orelse { | 2299 | /// / LARROWEQUAL |
| 2396 | putBackToken(it, token); | 2300 | /// / RARROWEQUAL |
| 2397 | return null; | 2301 | fn parseCompareOp(p: *Parser) !?*Node { |
| 2302 | const token = p.nextToken(); | ||
| 2303 | const op: Node.InfixOp.Op = switch (p.token_ids[token]) { | ||
| 2304 | .EqualEqual => .EqualEqual, | ||
| 2305 | .BangEqual => .BangEqual, | ||
| 2306 | .AngleBracketLeft => .LessThan, | ||
| 2307 | .AngleBracketRight => .GreaterThan, | ||
| 2308 | .AngleBracketLeftEqual => .LessOrEqual, | ||
| 2309 | .AngleBracketRightEqual => .GreaterOrEqual, | ||
| 2310 | else => { | ||
| 2311 | p.putBackToken(token); | ||
| 2312 | return null; | ||
| 2313 | }, | ||
| 2398 | }; | 2314 | }; |
| 2399 | const node = try arena.create(Node.AnyFrameType); | 2315 | |
| 2400 | node.* = .{ | 2316 | return p.createInfixOp(token, op); |
| 2401 | .anyframe_token = token, | 2317 | } |
| 2402 | .result = .{ | 2318 | |
| 2403 | .arrow_token = arrow, | 2319 | /// BitwiseOp |
| 2404 | .return_type = undefined, // set by caller | 2320 | /// <- AMPERSAND |
| 2321 | /// / CARET | ||
| 2322 | /// / PIPE | ||
| 2323 | /// / KEYWORD_orelse | ||
| 2324 | /// / KEYWORD_catch Payload? | ||
| 2325 | fn parseBitwiseOp(p: *Parser) !?*Node { | ||
| 2326 | const token = p.nextToken(); | ||
| 2327 | const op: Node.InfixOp.Op = switch (p.token_ids[token]) { | ||
| 2328 | .Ampersand => .BitAnd, | ||
| 2329 | .Caret => .BitXor, | ||
| 2330 | .Pipe => .BitOr, | ||
| 2331 | .Keyword_orelse => .UnwrapOptional, | ||
| 2332 | .Keyword_catch => .{ .Catch = try p.parsePayload() }, | ||
| 2333 | else => { | ||
| 2334 | p.putBackToken(token); | ||
| 2335 | return null; | ||
| 2405 | }, | 2336 | }, |
| 2406 | }; | 2337 | }; |
| 2338 | |||
| 2339 | return p.createInfixOp(token, op); | ||
| 2340 | } | ||
| 2341 | |||
| 2342 | /// BitShiftOp | ||
| 2343 | /// <- LARROW2 | ||
| 2344 | /// / RARROW2 | ||
| 2345 | fn parseBitShiftOp(p: *Parser) !?*Node { | ||
| 2346 | const token = p.nextToken(); | ||
| 2347 | const op: Node.InfixOp.Op = switch (p.token_ids[token]) { | ||
| 2348 | .AngleBracketAngleBracketLeft => .BitShiftLeft, | ||
| 2349 | .AngleBracketAngleBracketRight => .BitShiftRight, | ||
| 2350 | else => { | ||
| 2351 | p.putBackToken(token); | ||
| 2352 | return null; | ||
| 2353 | }, | ||
| 2354 | }; | ||
| 2355 | |||
| 2356 | return p.createInfixOp(token, op); | ||
| 2357 | } | ||
| 2358 | |||
| 2359 | /// AdditionOp | ||
| 2360 | /// <- PLUS | ||
| 2361 | /// / MINUS | ||
| 2362 | /// / PLUS2 | ||
| 2363 | /// / PLUSPERCENT | ||
| 2364 | /// / MINUSPERCENT | ||
| 2365 | fn parseAdditionOp(p: *Parser) !?*Node { | ||
| 2366 | const token = p.nextToken(); | ||
| 2367 | const op: Node.InfixOp.Op = switch (p.token_ids[token]) { | ||
| 2368 | .Plus => .Add, | ||
| 2369 | .Minus => .Sub, | ||
| 2370 | .PlusPlus => .ArrayCat, | ||
| 2371 | .PlusPercent => .AddWrap, | ||
| 2372 | .MinusPercent => .SubWrap, | ||
| 2373 | else => { | ||
| 2374 | p.putBackToken(token); | ||
| 2375 | return null; | ||
| 2376 | }, | ||
| 2377 | }; | ||
| 2378 | |||
| 2379 | return p.createInfixOp(token, op); | ||
| 2380 | } | ||
| 2381 | |||
| 2382 | /// MultiplyOp | ||
| 2383 | /// <- PIPE2 | ||
| 2384 | /// / ASTERISK | ||
| 2385 | /// / SLASH | ||
| 2386 | /// / PERCENT | ||
| 2387 | /// / ASTERISK2 | ||
| 2388 | /// / ASTERISKPERCENT | ||
| 2389 | fn parseMultiplyOp(p: *Parser) !?*Node { | ||
| 2390 | const token = p.nextToken(); | ||
| 2391 | const op: Node.InfixOp.Op = switch (p.token_ids[token]) { | ||
| 2392 | .PipePipe => .MergeErrorSets, | ||
| 2393 | .Asterisk => .Mul, | ||
| 2394 | .Slash => .Div, | ||
| 2395 | .Percent => .Mod, | ||
| 2396 | .AsteriskAsterisk => .ArrayMult, | ||
| 2397 | .AsteriskPercent => .MulWrap, | ||
| 2398 | else => { | ||
| 2399 | p.putBackToken(token); | ||
| 2400 | return null; | ||
| 2401 | }, | ||
| 2402 | }; | ||
| 2403 | |||
| 2404 | return p.createInfixOp(token, op); | ||
| 2405 | } | ||
| 2406 | |||
| 2407 | /// PrefixOp | ||
| 2408 | /// <- EXCLAMATIONMARK | ||
| 2409 | /// / MINUS | ||
| 2410 | /// / TILDE | ||
| 2411 | /// / MINUSPERCENT | ||
| 2412 | /// / AMPERSAND | ||
| 2413 | /// / KEYWORD_try | ||
| 2414 | /// / KEYWORD_await | ||
| 2415 | fn parsePrefixOp(p: *Parser) !?*Node { | ||
| 2416 | const token = p.nextToken(); | ||
| 2417 | const op: Node.PrefixOp.Op = switch (p.token_ids[token]) { | ||
| 2418 | .Bang => .BoolNot, | ||
| 2419 | .Minus => .Negation, | ||
| 2420 | .Tilde => .BitNot, | ||
| 2421 | .MinusPercent => .NegationWrap, | ||
| 2422 | .Ampersand => .AddressOf, | ||
| 2423 | .Keyword_try => .Try, | ||
| 2424 | .Keyword_await => .Await, | ||
| 2425 | else => { | ||
| 2426 | p.putBackToken(token); | ||
| 2427 | return null; | ||
| 2428 | }, | ||
| 2429 | }; | ||
| 2430 | |||
| 2431 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2432 | node.* = .{ | ||
| 2433 | .op_token = token, | ||
| 2434 | .op = op, | ||
| 2435 | .rhs = undefined, // set by caller | ||
| 2436 | }; | ||
| 2407 | return &node.base; | 2437 | return &node.base; |
| 2408 | } | 2438 | } |
| 2409 | 2439 | ||
| 2410 | if (try parsePtrTypeStart(arena, it, tree)) |node| { | 2440 | // TODO: ArrayTypeStart is either an array or a slice, but const/allowzero only work on |
| 2411 | // If the token encountered was **, there will be two nodes instead of one. | 2441 | // pointers. Consider updating this rule: |
| 2412 | // The attributes should be applied to the rightmost operator. | 2442 | // ... |
| 2413 | const prefix_op = node.cast(Node.PrefixOp).?; | 2443 | // / ArrayTypeStart |
| 2414 | var ptr_info = if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk) | 2444 | // / SliceTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* |
| 2415 | &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType | 2445 | // / PtrTypeStart ... |
| 2416 | else | 2446 | |
| 2417 | &prefix_op.op.PtrType; | 2447 | /// PrefixTypeOp |
| 2448 | /// <- QUESTIONMARK | ||
| 2449 | /// / KEYWORD_anyframe MINUSRARROW | ||
| 2450 | /// / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* | ||
| 2451 | /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)* | ||
| 2452 | fn parsePrefixTypeOp(p: *Parser) !?*Node { | ||
| 2453 | if (p.eatToken(.QuestionMark)) |token| { | ||
| 2454 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2455 | node.* = .{ | ||
| 2456 | .op_token = token, | ||
| 2457 | .op = .OptionalType, | ||
| 2458 | .rhs = undefined, // set by caller | ||
| 2459 | }; | ||
| 2460 | return &node.base; | ||
| 2461 | } | ||
| 2418 | 2462 | ||
| 2419 | while (true) { | 2463 | // TODO: Returning a AnyFrameType instead of PrefixOp makes casting and setting .rhs or |
| 2420 | if (eatToken(it, .Keyword_align)) |align_token| { | 2464 | // .return_type more difficult for the caller (see parsePrefixOpExpr helper). |
| 2421 | const lparen = try expectToken(it, tree, .LParen); | 2465 | // Consider making the AnyFrameType a member of PrefixOp and add a |
| 2422 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | 2466 | // PrefixOp.AnyFrameType variant? |
| 2423 | .ExpectedExpr = .{ .token = it.index }, | 2467 | if (p.eatToken(.Keyword_anyframe)) |token| { |
| 2424 | }); | 2468 | const arrow = p.eatToken(.Arrow) orelse { |
| 2469 | p.putBackToken(token); | ||
| 2470 | return null; | ||
| 2471 | }; | ||
| 2472 | const node = try p.arena.allocator.create(Node.AnyFrameType); | ||
| 2473 | node.* = .{ | ||
| 2474 | .anyframe_token = token, | ||
| 2475 | .result = .{ | ||
| 2476 | .arrow_token = arrow, | ||
| 2477 | .return_type = undefined, // set by caller | ||
| 2478 | }, | ||
| 2479 | }; | ||
| 2480 | return &node.base; | ||
| 2481 | } | ||
| 2425 | 2482 | ||
| 2426 | // Optional bit range | 2483 | if (try p.parsePtrTypeStart()) |node| { |
| 2427 | const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: { | 2484 | // If the token encountered was **, there will be two nodes instead of one. |
| 2428 | const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{ | 2485 | // The attributes should be applied to the rightmost operator. |
| 2429 | .ExpectedIntegerLiteral = .{ .token = it.index }, | 2486 | const prefix_op = node.cast(Node.PrefixOp).?; |
| 2430 | }); | 2487 | var ptr_info = if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) |
| 2431 | _ = try expectToken(it, tree, .Colon); | 2488 | &prefix_op.rhs.cast(Node.PrefixOp).?.op.PtrType |
| 2432 | const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{ | 2489 | else |
| 2433 | .ExpectedIntegerLiteral = .{ .token = it.index }, | 2490 | &prefix_op.op.PtrType; |
| 2491 | |||
| 2492 | while (true) { | ||
| 2493 | if (p.eatToken(.Keyword_align)) |align_token| { | ||
| 2494 | const lparen = try p.expectToken(.LParen); | ||
| 2495 | const expr_node = try p.expectNode(parseExpr, .{ | ||
| 2496 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2434 | }); | 2497 | }); |
| 2435 | 2498 | ||
| 2436 | break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ | 2499 | // Optional bit range |
| 2437 | .start = range_start, | 2500 | const bit_range = if (p.eatToken(.Colon)) |_| bit_range_value: { |
| 2438 | .end = range_end, | 2501 | const range_start = try p.expectNode(parseIntegerLiteral, .{ |
| 2502 | .ExpectedIntegerLiteral = .{ .token = p.tok_i }, | ||
| 2503 | }); | ||
| 2504 | _ = try p.expectToken(.Colon); | ||
| 2505 | const range_end = try p.expectNode(parseIntegerLiteral, .{ | ||
| 2506 | .ExpectedIntegerLiteral = .{ .token = p.tok_i }, | ||
| 2507 | }); | ||
| 2508 | |||
| 2509 | break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ | ||
| 2510 | .start = range_start, | ||
| 2511 | .end = range_end, | ||
| 2512 | }; | ||
| 2513 | } else null; | ||
| 2514 | _ = try p.expectToken(.RParen); | ||
| 2515 | |||
| 2516 | if (ptr_info.align_info != null) { | ||
| 2517 | try p.errors.append(p.gpa, .{ | ||
| 2518 | .ExtraAlignQualifier = .{ .token = p.tok_i - 1 }, | ||
| 2519 | }); | ||
| 2520 | continue; | ||
| 2521 | } | ||
| 2522 | |||
| 2523 | ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{ | ||
| 2524 | .node = expr_node, | ||
| 2525 | .bit_range = bit_range, | ||
| 2439 | }; | 2526 | }; |
| 2440 | } else null; | ||
| 2441 | _ = try expectToken(it, tree, .RParen); | ||
| 2442 | 2527 | ||
| 2443 | if (ptr_info.align_info != null) { | ||
| 2444 | try tree.errors.push(.{ | ||
| 2445 | .ExtraAlignQualifier = .{ .token = it.index - 1 }, | ||
| 2446 | }); | ||
| 2447 | continue; | 2528 | continue; |
| 2448 | } | 2529 | } |
| 2449 | 2530 | if (p.eatToken(.Keyword_const)) |const_token| { | |
| 2450 | ptr_info.align_info = Node.PrefixOp.PtrInfo.Align{ | 2531 | if (ptr_info.const_token != null) { |
| 2451 | .node = expr_node, | 2532 | try p.errors.append(p.gpa, .{ |
| 2452 | .bit_range = bit_range, | 2533 | .ExtraConstQualifier = .{ .token = p.tok_i - 1 }, |
| 2453 | }; | 2534 | }); |
| 2454 | 2535 | continue; | |
| 2455 | continue; | 2536 | } |
| 2456 | } | 2537 | ptr_info.const_token = const_token; |
| 2457 | if (eatToken(it, .Keyword_const)) |const_token| { | ||
| 2458 | if (ptr_info.const_token != null) { | ||
| 2459 | try tree.errors.push(.{ | ||
| 2460 | .ExtraConstQualifier = .{ .token = it.index - 1 }, | ||
| 2461 | }); | ||
| 2462 | continue; | 2538 | continue; |
| 2463 | } | 2539 | } |
| 2464 | ptr_info.const_token = const_token; | 2540 | if (p.eatToken(.Keyword_volatile)) |volatile_token| { |
| 2465 | continue; | 2541 | if (ptr_info.volatile_token != null) { |
| 2466 | } | 2542 | try p.errors.append(p.gpa, .{ |
| 2467 | if (eatToken(it, .Keyword_volatile)) |volatile_token| { | 2543 | .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 }, |
| 2468 | if (ptr_info.volatile_token != null) { | 2544 | }); |
| 2469 | try tree.errors.push(.{ | 2545 | continue; |
| 2470 | .ExtraVolatileQualifier = .{ .token = it.index - 1 }, | 2546 | } |
| 2471 | }); | 2547 | ptr_info.volatile_token = volatile_token; |
| 2472 | continue; | 2548 | continue; |
| 2473 | } | 2549 | } |
| 2474 | ptr_info.volatile_token = volatile_token; | 2550 | if (p.eatToken(.Keyword_allowzero)) |allowzero_token| { |
| 2475 | continue; | 2551 | if (ptr_info.allowzero_token != null) { |
| 2476 | } | 2552 | try p.errors.append(p.gpa, .{ |
| 2477 | if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { | 2553 | .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 }, |
| 2478 | if (ptr_info.allowzero_token != null) { | 2554 | }); |
| 2479 | try tree.errors.push(.{ | 2555 | continue; |
| 2480 | .ExtraAllowZeroQualifier = .{ .token = it.index - 1 }, | 2556 | } |
| 2481 | }); | 2557 | ptr_info.allowzero_token = allowzero_token; |
| 2482 | continue; | 2558 | continue; |
| 2483 | } | 2559 | } |
| 2484 | ptr_info.allowzero_token = allowzero_token; | 2560 | break; |
| 2485 | continue; | ||
| 2486 | } | 2561 | } |
| 2487 | break; | ||
| 2488 | } | ||
| 2489 | 2562 | ||
| 2490 | return node; | 2563 | return node; |
| 2491 | } | 2564 | } |
| 2492 | 2565 | ||
| 2493 | if (try parseArrayTypeStart(arena, it, tree)) |node| { | 2566 | if (try p.parseArrayTypeStart()) |node| { |
| 2494 | switch (node.cast(Node.PrefixOp).?.op) { | 2567 | switch (node.cast(Node.PrefixOp).?.op) { |
| 2495 | .ArrayType => {}, | 2568 | .ArrayType => {}, |
| 2496 | .SliceType => |*slice_type| { | 2569 | .SliceType => |*slice_type| { |
| 2497 | // Collect pointer qualifiers in any order, but disallow duplicates | 2570 | // Collect pointer qualifiers in any order, but disallow duplicates |
| 2498 | while (true) { | 2571 | while (true) { |
| 2499 | if (try parseByteAlign(arena, it, tree)) |align_expr| { | 2572 | if (try p.parseByteAlign()) |align_expr| { |
| 2500 | if (slice_type.align_info != null) { | 2573 | if (slice_type.align_info != null) { |
| 2501 | try tree.errors.push(.{ | 2574 | try p.errors.append(p.gpa, .{ |
| 2502 | .ExtraAlignQualifier = .{ .token = it.index - 1 }, | 2575 | .ExtraAlignQualifier = .{ .token = p.tok_i - 1 }, |
| 2503 | }); | 2576 | }); |
| 2577 | continue; | ||
| 2578 | } | ||
| 2579 | slice_type.align_info = Node.PrefixOp.PtrInfo.Align{ | ||
| 2580 | .node = align_expr, | ||
| 2581 | .bit_range = null, | ||
| 2582 | }; | ||
| 2504 | continue; | 2583 | continue; |
| 2505 | } | 2584 | } |
| 2506 | slice_type.align_info = Node.PrefixOp.PtrInfo.Align{ | 2585 | if (p.eatToken(.Keyword_const)) |const_token| { |
| 2507 | .node = align_expr, | 2586 | if (slice_type.const_token != null) { |
| 2508 | .bit_range = null, | 2587 | try p.errors.append(p.gpa, .{ |
| 2509 | }; | 2588 | .ExtraConstQualifier = .{ .token = p.tok_i - 1 }, |
| 2510 | continue; | 2589 | }); |
| 2511 | } | 2590 | continue; |
| 2512 | if (eatToken(it, .Keyword_const)) |const_token| { | 2591 | } |
| 2513 | if (slice_type.const_token != null) { | 2592 | slice_type.const_token = const_token; |
| 2514 | try tree.errors.push(.{ | ||
| 2515 | .ExtraConstQualifier = .{ .token = it.index - 1 }, | ||
| 2516 | }); | ||
| 2517 | continue; | 2593 | continue; |
| 2518 | } | 2594 | } |
| 2519 | slice_type.const_token = const_token; | 2595 | if (p.eatToken(.Keyword_volatile)) |volatile_token| { |
| 2520 | continue; | 2596 | if (slice_type.volatile_token != null) { |
| 2521 | } | 2597 | try p.errors.append(p.gpa, .{ |
| 2522 | if (eatToken(it, .Keyword_volatile)) |volatile_token| { | 2598 | .ExtraVolatileQualifier = .{ .token = p.tok_i - 1 }, |
| 2523 | if (slice_type.volatile_token != null) { | 2599 | }); |
| 2524 | try tree.errors.push(.{ | 2600 | continue; |
| 2525 | .ExtraVolatileQualifier = .{ .token = it.index - 1 }, | 2601 | } |
| 2526 | }); | 2602 | slice_type.volatile_token = volatile_token; |
| 2527 | continue; | 2603 | continue; |
| 2528 | } | 2604 | } |
| 2529 | slice_type.volatile_token = volatile_token; | 2605 | if (p.eatToken(.Keyword_allowzero)) |allowzero_token| { |
| 2530 | continue; | 2606 | if (slice_type.allowzero_token != null) { |
| 2607 | try p.errors.append(p.gpa, .{ | ||
| 2608 | .ExtraAllowZeroQualifier = .{ .token = p.tok_i - 1 }, | ||
| 2609 | }); | ||
| 2610 | continue; | ||
| 2611 | } | ||
| 2612 | slice_type.allowzero_token = allowzero_token; | ||
| 2613 | continue; | ||
| 2614 | } | ||
| 2615 | break; | ||
| 2531 | } | 2616 | } |
| 2532 | if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { | 2617 | }, |
| 2533 | if (slice_type.allowzero_token != null) { | 2618 | else => unreachable, |
| 2534 | try tree.errors.push(.{ | 2619 | } |
| 2535 | .ExtraAllowZeroQualifier = .{ .token = it.index - 1 }, | 2620 | return node; |
| 2621 | } | ||
| 2622 | |||
| 2623 | return null; | ||
| 2624 | } | ||
| 2625 | |||
| 2626 | /// SuffixOp | ||
| 2627 | /// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET | ||
| 2628 | /// / DOT IDENTIFIER | ||
| 2629 | /// / DOTASTERISK | ||
| 2630 | /// / DOTQUESTIONMARK | ||
| 2631 | fn parseSuffixOp(p: *Parser) !?*Node { | ||
| 2632 | const OpAndToken = struct { | ||
| 2633 | op: Node.SuffixOp.Op, | ||
| 2634 | token: TokenIndex, | ||
| 2635 | }; | ||
| 2636 | const op_and_token: OpAndToken = blk: { | ||
| 2637 | if (p.eatToken(.LBracket)) |_| { | ||
| 2638 | const index_expr = try p.expectNode(parseExpr, .{ | ||
| 2639 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2640 | }); | ||
| 2641 | |||
| 2642 | if (p.eatToken(.Ellipsis2) != null) { | ||
| 2643 | const end_expr = try p.parseExpr(); | ||
| 2644 | const sentinel: ?*Node = if (p.eatToken(.Colon) != null) | ||
| 2645 | try p.parseExpr() | ||
| 2646 | else | ||
| 2647 | null; | ||
| 2648 | break :blk .{ | ||
| 2649 | .op = .{ | ||
| 2650 | .Slice = .{ | ||
| 2651 | .start = index_expr, | ||
| 2652 | .end = end_expr, | ||
| 2653 | .sentinel = sentinel, | ||
| 2654 | }, | ||
| 2655 | }, | ||
| 2656 | .token = try p.expectToken(.RBracket), | ||
| 2657 | }; | ||
| 2658 | } | ||
| 2659 | |||
| 2660 | break :blk .{ | ||
| 2661 | .op = .{ .ArrayAccess = index_expr }, | ||
| 2662 | .token = try p.expectToken(.RBracket), | ||
| 2663 | }; | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | if (p.eatToken(.PeriodAsterisk)) |period_asterisk| { | ||
| 2667 | break :blk .{ .op = .Deref, .token = period_asterisk }; | ||
| 2668 | } | ||
| 2669 | |||
| 2670 | if (p.eatToken(.Period)) |period| { | ||
| 2671 | if (try p.parseIdentifier()) |identifier| { | ||
| 2672 | // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser. | ||
| 2673 | // Should there be an Node.SuffixOp.FieldAccess variant? Or should | ||
| 2674 | // this grammar rule be altered? | ||
| 2675 | const node = try p.arena.allocator.create(Node.InfixOp); | ||
| 2676 | node.* = .{ | ||
| 2677 | .op_token = period, | ||
| 2678 | .lhs = undefined, // set by caller | ||
| 2679 | .op = .Period, | ||
| 2680 | .rhs = identifier, | ||
| 2681 | }; | ||
| 2682 | return &node.base; | ||
| 2683 | } | ||
| 2684 | if (p.eatToken(.QuestionMark)) |question_mark| { | ||
| 2685 | break :blk .{ .op = .UnwrapOptional, .token = question_mark }; | ||
| 2686 | } | ||
| 2687 | try p.errors.append(p.gpa, .{ | ||
| 2688 | .ExpectedSuffixOp = .{ .token = p.tok_i }, | ||
| 2689 | }); | ||
| 2690 | return null; | ||
| 2691 | } | ||
| 2692 | |||
| 2693 | return null; | ||
| 2694 | }; | ||
| 2695 | |||
| 2696 | const node = try p.arena.allocator.create(Node.SuffixOp); | ||
| 2697 | node.* = .{ | ||
| 2698 | .lhs = undefined, // set by caller | ||
| 2699 | .op = op_and_token.op, | ||
| 2700 | .rtoken = op_and_token.token, | ||
| 2701 | }; | ||
| 2702 | return &node.base; | ||
| 2703 | } | ||
| 2704 | |||
| 2705 | /// FnCallArguments <- LPAREN ExprList RPAREN | ||
| 2706 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 2707 | fn parseFnCallArguments(p: *Parser) !?AnnotatedParamList { | ||
| 2708 | if (p.eatToken(.LParen) == null) return null; | ||
| 2709 | const list = try ListParseFn(*Node, parseExpr)(p); | ||
| 2710 | errdefer p.gpa.free(list); | ||
| 2711 | const rparen = try p.expectToken(.RParen); | ||
| 2712 | return AnnotatedParamList{ .list = list, .rparen = rparen }; | ||
| 2713 | } | ||
| 2714 | |||
| 2715 | const AnnotatedParamList = struct { | ||
| 2716 | list: []*Node, | ||
| 2717 | rparen: TokenIndex, | ||
| 2718 | }; | ||
| 2719 | |||
| 2720 | /// ArrayTypeStart <- LBRACKET Expr? RBRACKET | ||
| 2721 | fn parseArrayTypeStart(p: *Parser) !?*Node { | ||
| 2722 | const lbracket = p.eatToken(.LBracket) orelse return null; | ||
| 2723 | const expr = try p.parseExpr(); | ||
| 2724 | const sentinel = if (p.eatToken(.Colon)) |_| | ||
| 2725 | try p.expectNode(parseExpr, .{ | ||
| 2726 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2727 | }) | ||
| 2728 | else | ||
| 2729 | null; | ||
| 2730 | const rbracket = try p.expectToken(.RBracket); | ||
| 2731 | |||
| 2732 | const op: Node.PrefixOp.Op = if (expr) |len_expr| | ||
| 2733 | .{ | ||
| 2734 | .ArrayType = .{ | ||
| 2735 | .len_expr = len_expr, | ||
| 2736 | .sentinel = sentinel, | ||
| 2737 | }, | ||
| 2738 | } | ||
| 2739 | else | ||
| 2740 | .{ | ||
| 2741 | .SliceType = Node.PrefixOp.PtrInfo{ | ||
| 2742 | .allowzero_token = null, | ||
| 2743 | .align_info = null, | ||
| 2744 | .const_token = null, | ||
| 2745 | .volatile_token = null, | ||
| 2746 | .sentinel = sentinel, | ||
| 2747 | }, | ||
| 2748 | }; | ||
| 2749 | |||
| 2750 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2751 | node.* = .{ | ||
| 2752 | .op_token = lbracket, | ||
| 2753 | .op = op, | ||
| 2754 | .rhs = undefined, // set by caller | ||
| 2755 | }; | ||
| 2756 | return &node.base; | ||
| 2757 | } | ||
| 2758 | |||
| 2759 | /// PtrTypeStart | ||
| 2760 | /// <- ASTERISK | ||
| 2761 | /// / ASTERISK2 | ||
| 2762 | /// / PTRUNKNOWN | ||
| 2763 | /// / PTRC | ||
| 2764 | fn parsePtrTypeStart(p: *Parser) !?*Node { | ||
| 2765 | if (p.eatToken(.Asterisk)) |asterisk| { | ||
| 2766 | const sentinel = if (p.eatToken(.Colon)) |_| | ||
| 2767 | try p.expectNode(parseExpr, .{ | ||
| 2768 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2769 | }) | ||
| 2770 | else | ||
| 2771 | null; | ||
| 2772 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2773 | node.* = .{ | ||
| 2774 | .op_token = asterisk, | ||
| 2775 | .op = .{ .PtrType = .{ .sentinel = sentinel } }, | ||
| 2776 | .rhs = undefined, // set by caller | ||
| 2777 | }; | ||
| 2778 | return &node.base; | ||
| 2779 | } | ||
| 2780 | |||
| 2781 | if (p.eatToken(.AsteriskAsterisk)) |double_asterisk| { | ||
| 2782 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2783 | node.* = .{ | ||
| 2784 | .op_token = double_asterisk, | ||
| 2785 | .op = .{ .PtrType = .{} }, | ||
| 2786 | .rhs = undefined, // set by caller | ||
| 2787 | }; | ||
| 2788 | |||
| 2789 | // Special case for **, which is its own token | ||
| 2790 | const child = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2791 | child.* = .{ | ||
| 2792 | .op_token = double_asterisk, | ||
| 2793 | .op = .{ .PtrType = .{} }, | ||
| 2794 | .rhs = undefined, // set by caller | ||
| 2795 | }; | ||
| 2796 | node.rhs = &child.base; | ||
| 2797 | |||
| 2798 | return &node.base; | ||
| 2799 | } | ||
| 2800 | if (p.eatToken(.LBracket)) |lbracket| { | ||
| 2801 | const asterisk = p.eatToken(.Asterisk) orelse { | ||
| 2802 | p.putBackToken(lbracket); | ||
| 2803 | return null; | ||
| 2804 | }; | ||
| 2805 | if (p.eatToken(.Identifier)) |ident| { | ||
| 2806 | const token_loc = p.token_locs[ident]; | ||
| 2807 | const token_slice = p.source[token_loc.start..token_loc.end]; | ||
| 2808 | if (!std.mem.eql(u8, token_slice, "c")) { | ||
| 2809 | p.putBackToken(ident); | ||
| 2810 | } else { | ||
| 2811 | _ = try p.expectToken(.RBracket); | ||
| 2812 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2813 | node.* = .{ | ||
| 2814 | .op_token = lbracket, | ||
| 2815 | .op = .{ .PtrType = .{} }, | ||
| 2816 | .rhs = undefined, // set by caller | ||
| 2817 | }; | ||
| 2818 | return &node.base; | ||
| 2819 | } | ||
| 2820 | } | ||
| 2821 | const sentinel = if (p.eatToken(.Colon)) |_| | ||
| 2822 | try p.expectNode(parseExpr, .{ | ||
| 2823 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2824 | }) | ||
| 2825 | else | ||
| 2826 | null; | ||
| 2827 | _ = try p.expectToken(.RBracket); | ||
| 2828 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 2829 | node.* = .{ | ||
| 2830 | .op_token = lbracket, | ||
| 2831 | .op = .{ .PtrType = .{ .sentinel = sentinel } }, | ||
| 2832 | .rhs = undefined, // set by caller | ||
| 2833 | }; | ||
| 2834 | return &node.base; | ||
| 2835 | } | ||
| 2836 | return null; | ||
| 2837 | } | ||
| 2838 | |||
| 2839 | /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE | ||
| 2840 | fn parseContainerDeclAuto(p: *Parser) !?*Node { | ||
| 2841 | const container_decl_type = (try p.parseContainerDeclType()) orelse return null; | ||
| 2842 | const lbrace = try p.expectToken(.LBrace); | ||
| 2843 | const members = try p.parseContainerMembers(false); | ||
| 2844 | defer p.gpa.free(members); | ||
| 2845 | const rbrace = try p.expectToken(.RBrace); | ||
| 2846 | |||
| 2847 | const members_len = @intCast(NodeIndex, members.len); | ||
| 2848 | const node = try Node.ContainerDecl.alloc(&p.arena.allocator, members_len); | ||
| 2849 | node.* = .{ | ||
| 2850 | .layout_token = null, | ||
| 2851 | .kind_token = container_decl_type.kind_token, | ||
| 2852 | .init_arg_expr = container_decl_type.init_arg_expr, | ||
| 2853 | .fields_and_decls_len = members_len, | ||
| 2854 | .lbrace_token = lbrace, | ||
| 2855 | .rbrace_token = rbrace, | ||
| 2856 | }; | ||
| 2857 | std.mem.copy(*Node, node.fieldsAndDecls(), members); | ||
| 2858 | return &node.base; | ||
| 2859 | } | ||
| 2860 | |||
| 2861 | /// Holds temporary data until we are ready to construct the full ContainerDecl AST node. | ||
| 2862 | const ContainerDeclType = struct { | ||
| 2863 | kind_token: TokenIndex, | ||
| 2864 | init_arg_expr: Node.ContainerDecl.InitArg, | ||
| 2865 | }; | ||
| 2866 | |||
| 2867 | /// ContainerDeclType | ||
| 2868 | /// <- KEYWORD_struct | ||
| 2869 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? | ||
| 2870 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? | ||
| 2871 | fn parseContainerDeclType(p: *Parser) !?ContainerDeclType { | ||
| 2872 | const kind_token = p.nextToken(); | ||
| 2873 | |||
| 2874 | const init_arg_expr = switch (p.token_ids[kind_token]) { | ||
| 2875 | .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, | ||
| 2876 | .Keyword_enum => blk: { | ||
| 2877 | if (p.eatToken(.LParen) != null) { | ||
| 2878 | const expr = try p.expectNode(parseExpr, .{ | ||
| 2879 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2880 | }); | ||
| 2881 | _ = try p.expectToken(.RParen); | ||
| 2882 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; | ||
| 2883 | } | ||
| 2884 | break :blk Node.ContainerDecl.InitArg{ .None = {} }; | ||
| 2885 | }, | ||
| 2886 | .Keyword_union => blk: { | ||
| 2887 | if (p.eatToken(.LParen) != null) { | ||
| 2888 | if (p.eatToken(.Keyword_enum) != null) { | ||
| 2889 | if (p.eatToken(.LParen) != null) { | ||
| 2890 | const expr = try p.expectNode(parseExpr, .{ | ||
| 2891 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2536 | }); | 2892 | }); |
| 2537 | continue; | 2893 | _ = try p.expectToken(.RParen); |
| 2894 | _ = try p.expectToken(.RParen); | ||
| 2895 | break :blk Node.ContainerDecl.InitArg{ .Enum = expr }; | ||
| 2538 | } | 2896 | } |
| 2539 | slice_type.allowzero_token = allowzero_token; | 2897 | _ = try p.expectToken(.RParen); |
| 2540 | continue; | 2898 | break :blk Node.ContainerDecl.InitArg{ .Enum = null }; |
| 2541 | } | 2899 | } |
| 2542 | break; | 2900 | const expr = try p.expectNode(parseExpr, .{ |
| 2901 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2902 | }); | ||
| 2903 | _ = try p.expectToken(.RParen); | ||
| 2904 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; | ||
| 2543 | } | 2905 | } |
| 2906 | break :blk Node.ContainerDecl.InitArg{ .None = {} }; | ||
| 2544 | }, | 2907 | }, |
| 2545 | else => unreachable, | 2908 | else => { |
| 2546 | } | 2909 | p.putBackToken(kind_token); |
| 2547 | return node; | 2910 | return null; |
| 2911 | }, | ||
| 2912 | }; | ||
| 2913 | |||
| 2914 | return ContainerDeclType{ | ||
| 2915 | .kind_token = kind_token, | ||
| 2916 | .init_arg_expr = init_arg_expr, | ||
| 2917 | }; | ||
| 2918 | } | ||
| 2919 | |||
| 2920 | /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN | ||
| 2921 | fn parseByteAlign(p: *Parser) !?*Node { | ||
| 2922 | _ = p.eatToken(.Keyword_align) orelse return null; | ||
| 2923 | _ = try p.expectToken(.LParen); | ||
| 2924 | const expr = try p.expectNode(parseExpr, .{ | ||
| 2925 | .ExpectedExpr = .{ .token = p.tok_i }, | ||
| 2926 | }); | ||
| 2927 | _ = try p.expectToken(.RParen); | ||
| 2928 | return expr; | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER? | ||
| 2932 | /// Only ErrorSetDecl parses an IdentifierList | ||
| 2933 | fn parseErrorTagList(p: *Parser) ![]*Node { | ||
| 2934 | return ListParseFn(*Node, parseErrorTag)(p); | ||
| 2548 | } | 2935 | } |
| 2549 | 2936 | ||
| 2550 | return null; | 2937 | /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng? |
| 2551 | } | 2938 | fn parseSwitchProngList(p: *Parser) ![]*Node { |
| 2939 | return ListParseFn(*Node, parseSwitchProng)(p); | ||
| 2940 | } | ||
| 2552 | 2941 | ||
| 2553 | /// SuffixOp | 2942 | /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? |
| 2554 | /// <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET | 2943 | fn parseAsmOutputList(p: *Parser) Error![]Node.Asm.Output { |
| 2555 | /// / DOT IDENTIFIER | 2944 | return ListParseFn(Node.Asm.Output, parseAsmOutputItem)(p); |
| 2556 | /// / DOTASTERISK | 2945 | } |
| 2557 | /// / DOTQUESTIONMARK | ||
| 2558 | fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2559 | const OpAndToken = struct { | ||
| 2560 | op: Node.SuffixOp.Op, | ||
| 2561 | token: TokenIndex, | ||
| 2562 | }; | ||
| 2563 | const op_and_token: OpAndToken = blk: { | ||
| 2564 | if (eatToken(it, .LBracket)) |_| { | ||
| 2565 | const index_expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2566 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2567 | }); | ||
| 2568 | 2946 | ||
| 2569 | if (eatToken(it, .Ellipsis2) != null) { | 2947 | /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? |
| 2570 | const end_expr = try parseExpr(arena, it, tree); | 2948 | fn parseAsmInputList(p: *Parser) Error![]Node.Asm.Input { |
| 2571 | const sentinel: ?*ast.Node = if (eatToken(it, .Colon) != null) | 2949 | return ListParseFn(Node.Asm.Input, parseAsmInputItem)(p); |
| 2572 | try parseExpr(arena, it, tree) | 2950 | } |
| 2573 | else | 2951 | |
| 2574 | null; | 2952 | /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl? |
| 2575 | break :blk .{ | 2953 | fn parseParamDeclList(p: *Parser) ![]Node.FnProto.ParamDecl { |
| 2576 | .op = .{ | 2954 | return ListParseFn(Node.FnProto.ParamDecl, parseParamDecl)(p); |
| 2577 | .Slice = .{ | 2955 | } |
| 2578 | .start = index_expr, | 2956 | |
| 2579 | .end = end_expr, | 2957 | const NodeParseFn = fn (p: *Parser) Error!?*Node; |
| 2580 | .sentinel = sentinel, | 2958 | |
| 2959 | fn ListParseFn(comptime E: type, comptime nodeParseFn: var) ParseFn([]E) { | ||
| 2960 | return struct { | ||
| 2961 | pub fn parse(p: *Parser) ![]E { | ||
| 2962 | var list = std.ArrayList(E).init(p.gpa); | ||
| 2963 | defer list.deinit(); | ||
| 2964 | |||
| 2965 | while (try nodeParseFn(p)) |item| { | ||
| 2966 | try list.append(item); | ||
| 2967 | |||
| 2968 | switch (p.token_ids[p.tok_i]) { | ||
| 2969 | .Comma => _ = p.nextToken(), | ||
| 2970 | // all possible delimiters | ||
| 2971 | .Colon, .RParen, .RBrace, .RBracket => break, | ||
| 2972 | else => { | ||
| 2973 | // this is likely just a missing comma, | ||
| 2974 | // continue parsing this list and give an error | ||
| 2975 | try p.errors.append(p.gpa, .{ | ||
| 2976 | .ExpectedToken = .{ .token = p.tok_i, .expected_id = .Comma }, | ||
| 2977 | }); | ||
| 2581 | }, | 2978 | }, |
| 2582 | }, | 2979 | } |
| 2583 | .token = try expectToken(it, tree, .RBracket), | 2980 | } |
| 2584 | }; | 2981 | return list.toOwnedSlice(); |
| 2585 | } | 2982 | } |
| 2983 | }.parse; | ||
| 2984 | } | ||
| 2586 | 2985 | ||
| 2587 | break :blk .{ | 2986 | fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn { |
| 2588 | .op = .{ .ArrayAccess = index_expr }, | 2987 | return struct { |
| 2589 | .token = try expectToken(it, tree, .RBracket), | 2988 | pub fn parse(p: *Parser) Error!?*Node { |
| 2590 | }; | 2989 | const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) { |
| 2591 | } | 2990 | .Keyword_and => p.nextToken(), |
| 2592 | 2991 | .Invalid_ampersands => blk: { | |
| 2593 | if (eatToken(it, .PeriodAsterisk)) |period_asterisk| { | 2992 | try p.errors.append(p.gpa, .{ |
| 2594 | break :blk .{ .op = .Deref, .token = period_asterisk }; | 2993 | .InvalidAnd = .{ .token = p.tok_i }, |
| 2595 | } | 2994 | }); |
| 2995 | break :blk p.nextToken(); | ||
| 2996 | }, | ||
| 2997 | else => return null, | ||
| 2998 | } else p.eatToken(token) orelse return null; | ||
| 2596 | 2999 | ||
| 2597 | if (eatToken(it, .Period)) |period| { | 3000 | const node = try p.arena.allocator.create(Node.InfixOp); |
| 2598 | if (try parseIdentifier(arena, it, tree)) |identifier| { | ||
| 2599 | // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser. | ||
| 2600 | // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should | ||
| 2601 | // this grammar rule be altered? | ||
| 2602 | const node = try arena.create(Node.InfixOp); | ||
| 2603 | node.* = .{ | 3001 | node.* = .{ |
| 2604 | .op_token = period, | 3002 | .op_token = op_token, |
| 2605 | .lhs = undefined, // set by caller | 3003 | .lhs = undefined, // set by caller |
| 2606 | .op = .Period, | 3004 | .op = op, |
| 2607 | .rhs = identifier, | 3005 | .rhs = undefined, // set by caller |
| 2608 | }; | 3006 | }; |
| 2609 | return &node.base; | 3007 | return &node.base; |
| 2610 | } | 3008 | } |
| 2611 | if (eatToken(it, .QuestionMark)) |question_mark| { | 3009 | }.parse; |
| 2612 | break :blk .{ .op = .UnwrapOptional, .token = question_mark }; | 3010 | } |
| 2613 | } | ||
| 2614 | try tree.errors.push(.{ | ||
| 2615 | .ExpectedSuffixOp = .{ .token = it.index }, | ||
| 2616 | }); | ||
| 2617 | return null; | ||
| 2618 | } | ||
| 2619 | |||
| 2620 | return null; | ||
| 2621 | }; | ||
| 2622 | |||
| 2623 | const node = try arena.create(Node.SuffixOp); | ||
| 2624 | node.* = .{ | ||
| 2625 | .lhs = undefined, // set by caller | ||
| 2626 | .op = op_and_token.op, | ||
| 2627 | .rtoken = op_and_token.token, | ||
| 2628 | }; | ||
| 2629 | return &node.base; | ||
| 2630 | } | ||
| 2631 | 3011 | ||
| 2632 | /// FnCallArguments <- LPAREN ExprList RPAREN | 3012 | // Helper parsers not included in the grammar |
| 2633 | /// ExprList <- (Expr COMMA)* Expr? | ||
| 2634 | fn parseFnCallArguments(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?AnnotatedParamList { | ||
| 2635 | if (eatToken(it, .LParen) == null) return null; | ||
| 2636 | const list = try ListParseFn(Node.FnProto.ParamList, parseExpr)(arena, it, tree); | ||
| 2637 | const rparen = try expectToken(it, tree, .RParen); | ||
| 2638 | return AnnotatedParamList{ .list = list, .rparen = rparen }; | ||
| 2639 | } | ||
| 2640 | 3013 | ||
| 2641 | const AnnotatedParamList = struct { | 3014 | fn parseBuiltinCall(p: *Parser) !?*Node { |
| 2642 | list: Node.FnProto.ParamList, // NOTE: may also be any other type SegmentedList(*Node, 2) | 3015 | const token = p.eatToken(.Builtin) orelse return null; |
| 2643 | rparen: TokenIndex, | 3016 | const params = (try p.parseFnCallArguments()) orelse { |
| 2644 | }; | 3017 | try p.errors.append(p.gpa, .{ |
| 3018 | .ExpectedParamList = .{ .token = p.tok_i }, | ||
| 3019 | }); | ||
| 2645 | 3020 | ||
| 2646 | /// ArrayTypeStart <- LBRACKET Expr? RBRACKET | 3021 | // lets pretend this was an identifier so we can continue parsing |
| 2647 | fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3022 | const node = try p.arena.allocator.create(Node.Identifier); |
| 2648 | const lbracket = eatToken(it, .LBracket) orelse return null; | 3023 | node.* = .{ |
| 2649 | const expr = try parseExpr(arena, it, tree); | 3024 | .token = token, |
| 2650 | const sentinel = if (eatToken(it, .Colon)) |_| | 3025 | }; |
| 2651 | try expectNode(arena, it, tree, parseExpr, .{ | 3026 | return &node.base; |
| 2652 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2653 | }) | ||
| 2654 | else | ||
| 2655 | null; | ||
| 2656 | const rbracket = try expectToken(it, tree, .RBracket); | ||
| 2657 | |||
| 2658 | const op: Node.PrefixOp.Op = if (expr) |len_expr| | ||
| 2659 | .{ | ||
| 2660 | .ArrayType = .{ | ||
| 2661 | .len_expr = len_expr, | ||
| 2662 | .sentinel = sentinel, | ||
| 2663 | }, | ||
| 2664 | } | ||
| 2665 | else | ||
| 2666 | .{ | ||
| 2667 | .SliceType = Node.PrefixOp.PtrInfo{ | ||
| 2668 | .allowzero_token = null, | ||
| 2669 | .align_info = null, | ||
| 2670 | .const_token = null, | ||
| 2671 | .volatile_token = null, | ||
| 2672 | .sentinel = sentinel, | ||
| 2673 | }, | ||
| 2674 | }; | 3027 | }; |
| 3028 | defer p.gpa.free(params.list); | ||
| 2675 | 3029 | ||
| 2676 | const node = try arena.create(Node.PrefixOp); | 3030 | const node = try Node.BuiltinCall.alloc(&p.arena.allocator, params.list.len); |
| 2677 | node.* = .{ | ||
| 2678 | .op_token = lbracket, | ||
| 2679 | .op = op, | ||
| 2680 | .rhs = undefined, // set by caller | ||
| 2681 | }; | ||
| 2682 | return &node.base; | ||
| 2683 | } | ||
| 2684 | |||
| 2685 | /// PtrTypeStart | ||
| 2686 | /// <- ASTERISK | ||
| 2687 | /// / ASTERISK2 | ||
| 2688 | /// / PTRUNKNOWN | ||
| 2689 | /// / PTRC | ||
| 2690 | fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2691 | if (eatToken(it, .Asterisk)) |asterisk| { | ||
| 2692 | const sentinel = if (eatToken(it, .Colon)) |_| | ||
| 2693 | try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2694 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2695 | }) | ||
| 2696 | else | ||
| 2697 | null; | ||
| 2698 | const node = try arena.create(Node.PrefixOp); | ||
| 2699 | node.* = .{ | 3031 | node.* = .{ |
| 2700 | .op_token = asterisk, | 3032 | .builtin_token = token, |
| 2701 | .op = .{ .PtrType = .{ .sentinel = sentinel } }, | 3033 | .params_len = params.list.len, |
| 2702 | .rhs = undefined, // set by caller | 3034 | .rparen_token = params.rparen, |
| 2703 | }; | 3035 | }; |
| 3036 | std.mem.copy(*Node, node.params(), params.list); | ||
| 2704 | return &node.base; | 3037 | return &node.base; |
| 2705 | } | 3038 | } |
| 2706 | 3039 | ||
| 2707 | if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { | 3040 | fn parseErrorTag(p: *Parser) !?*Node { |
| 2708 | const node = try arena.create(Node.PrefixOp); | 3041 | const doc_comments = try p.parseDocComment(); // no need to rewind on failure |
| 3042 | const token = p.eatToken(.Identifier) orelse return null; | ||
| 3043 | |||
| 3044 | const node = try p.arena.allocator.create(Node.ErrorTag); | ||
| 2709 | node.* = .{ | 3045 | node.* = .{ |
| 2710 | .op_token = double_asterisk, | 3046 | .doc_comments = doc_comments, |
| 2711 | .op = .{ .PtrType = .{} }, | 3047 | .name_token = token, |
| 2712 | .rhs = undefined, // set by caller | ||
| 2713 | }; | 3048 | }; |
| 3049 | return &node.base; | ||
| 3050 | } | ||
| 2714 | 3051 | ||
| 2715 | // Special case for **, which is its own token | 3052 | fn parseIdentifier(p: *Parser) !?*Node { |
| 2716 | const child = try arena.create(Node.PrefixOp); | 3053 | const token = p.eatToken(.Identifier) orelse return null; |
| 2717 | child.* = .{ | 3054 | const node = try p.arena.allocator.create(Node.Identifier); |
| 2718 | .op_token = double_asterisk, | 3055 | node.* = .{ |
| 2719 | .op = .{ .PtrType = .{} }, | 3056 | .token = token, |
| 2720 | .rhs = undefined, // set by caller | ||
| 2721 | }; | 3057 | }; |
| 2722 | node.rhs = &child.base; | ||
| 2723 | |||
| 2724 | return &node.base; | 3058 | return &node.base; |
| 2725 | } | 3059 | } |
| 2726 | if (eatToken(it, .LBracket)) |lbracket| { | 3060 | |
| 2727 | const asterisk = eatToken(it, .Asterisk) orelse { | 3061 | fn parseVarType(p: *Parser) !?*Node { |
| 2728 | putBackToken(it, lbracket); | 3062 | const token = p.eatToken(.Keyword_var) orelse return null; |
| 2729 | return null; | 3063 | const node = try p.arena.allocator.create(Node.VarType); |
| 2730 | }; | ||
| 2731 | if (eatToken(it, .Identifier)) |ident| { | ||
| 2732 | if (!std.mem.eql(u8, tree.tokenSlice(ident), "c")) { | ||
| 2733 | putBackToken(it, ident); | ||
| 2734 | } else { | ||
| 2735 | _ = try expectToken(it, tree, .RBracket); | ||
| 2736 | const node = try arena.create(Node.PrefixOp); | ||
| 2737 | node.* = .{ | ||
| 2738 | .op_token = lbracket, | ||
| 2739 | .op = .{ .PtrType = .{} }, | ||
| 2740 | .rhs = undefined, // set by caller | ||
| 2741 | }; | ||
| 2742 | return &node.base; | ||
| 2743 | } | ||
| 2744 | } | ||
| 2745 | const sentinel = if (eatToken(it, .Colon)) |_| | ||
| 2746 | try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2747 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2748 | }) | ||
| 2749 | else | ||
| 2750 | null; | ||
| 2751 | _ = try expectToken(it, tree, .RBracket); | ||
| 2752 | const node = try arena.create(Node.PrefixOp); | ||
| 2753 | node.* = .{ | 3064 | node.* = .{ |
| 2754 | .op_token = lbracket, | 3065 | .token = token, |
| 2755 | .op = .{ .PtrType = .{ .sentinel = sentinel } }, | ||
| 2756 | .rhs = undefined, // set by caller | ||
| 2757 | }; | 3066 | }; |
| 2758 | return &node.base; | 3067 | return &node.base; |
| 2759 | } | 3068 | } |
| 2760 | return null; | ||
| 2761 | } | ||
| 2762 | 3069 | ||
| 2763 | /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE | 3070 | fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node { |
| 2764 | fn parseContainerDeclAuto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3071 | const result = try p.arena.allocator.create(T); |
| 2765 | const node = (try parseContainerDeclType(arena, it, tree)) orelse return null; | 3072 | result.* = T{ |
| 2766 | const lbrace = try expectToken(it, tree, .LBrace); | 3073 | .base = Node{ .id = Node.typeToId(T) }, |
| 2767 | const members = try parseContainerMembers(arena, it, tree, false); | 3074 | .token = token, |
| 2768 | const rbrace = try expectToken(it, tree, .RBrace); | 3075 | }; |
| 3076 | return &result.base; | ||
| 3077 | } | ||
| 2769 | 3078 | ||
| 2770 | const decl_type = node.cast(Node.ContainerDecl).?; | 3079 | fn parseStringLiteralSingle(p: *Parser) !?*Node { |
| 2771 | decl_type.fields_and_decls = members; | 3080 | if (p.eatToken(.StringLiteral)) |token| { |
| 2772 | decl_type.lbrace_token = lbrace; | 3081 | const node = try p.arena.allocator.create(Node.StringLiteral); |
| 2773 | decl_type.rbrace_token = rbrace; | 3082 | node.* = .{ |
| 3083 | .token = token, | ||
| 3084 | }; | ||
| 3085 | return &node.base; | ||
| 3086 | } | ||
| 3087 | return null; | ||
| 3088 | } | ||
| 2774 | 3089 | ||
| 2775 | return node; | 3090 | // string literal or multiline string literal |
| 2776 | } | 3091 | fn parseStringLiteral(p: *Parser) !?*Node { |
| 3092 | if (try p.parseStringLiteralSingle()) |node| return node; | ||
| 2777 | 3093 | ||
| 2778 | /// ContainerDeclType | 3094 | if (p.eatToken(.MultilineStringLiteralLine)) |first_line| { |
| 2779 | /// <- KEYWORD_struct | 3095 | const start_tok_i = p.tok_i; |
| 2780 | /// / KEYWORD_enum (LPAREN Expr RPAREN)? | 3096 | var tok_i = start_tok_i; |
| 2781 | /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)? | 3097 | var count: usize = 1; // including first_line |
| 2782 | fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3098 | while (true) : (tok_i += 1) { |
| 2783 | const kind_token = nextToken(it); | 3099 | switch (p.token_ids[tok_i]) { |
| 2784 | 3100 | .LineComment => continue, | |
| 2785 | const init_arg_expr = switch (kind_token.ptr.id) { | 3101 | .MultilineStringLiteralLine => count += 1, |
| 2786 | .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, | 3102 | else => break, |
| 2787 | .Keyword_enum => blk: { | ||
| 2788 | if (eatToken(it, .LParen) != null) { | ||
| 2789 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2790 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2791 | }); | ||
| 2792 | _ = try expectToken(it, tree, .RParen); | ||
| 2793 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; | ||
| 2794 | } | ||
| 2795 | break :blk Node.ContainerDecl.InitArg{ .None = {} }; | ||
| 2796 | }, | ||
| 2797 | .Keyword_union => blk: { | ||
| 2798 | if (eatToken(it, .LParen) != null) { | ||
| 2799 | if (eatToken(it, .Keyword_enum) != null) { | ||
| 2800 | if (eatToken(it, .LParen) != null) { | ||
| 2801 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2802 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2803 | }); | ||
| 2804 | _ = try expectToken(it, tree, .RParen); | ||
| 2805 | _ = try expectToken(it, tree, .RParen); | ||
| 2806 | break :blk Node.ContainerDecl.InitArg{ .Enum = expr }; | ||
| 2807 | } | ||
| 2808 | _ = try expectToken(it, tree, .RParen); | ||
| 2809 | break :blk Node.ContainerDecl.InitArg{ .Enum = null }; | ||
| 2810 | } | 3103 | } |
| 2811 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2812 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2813 | }); | ||
| 2814 | _ = try expectToken(it, tree, .RParen); | ||
| 2815 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; | ||
| 2816 | } | 3104 | } |
| 2817 | break :blk Node.ContainerDecl.InitArg{ .None = {} }; | ||
| 2818 | }, | ||
| 2819 | else => { | ||
| 2820 | putBackToken(it, kind_token.index); | ||
| 2821 | return null; | ||
| 2822 | }, | ||
| 2823 | }; | ||
| 2824 | |||
| 2825 | const node = try arena.create(Node.ContainerDecl); | ||
| 2826 | node.* = .{ | ||
| 2827 | .layout_token = null, | ||
| 2828 | .kind_token = kind_token.index, | ||
| 2829 | .init_arg_expr = init_arg_expr, | ||
| 2830 | .fields_and_decls = undefined, // set by caller | ||
| 2831 | .lbrace_token = undefined, // set by caller | ||
| 2832 | .rbrace_token = undefined, // set by caller | ||
| 2833 | }; | ||
| 2834 | return &node.base; | ||
| 2835 | } | ||
| 2836 | |||
| 2837 | /// ByteAlign <- KEYWORD_align LPAREN Expr RPAREN | ||
| 2838 | fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2839 | _ = eatToken(it, .Keyword_align) orelse return null; | ||
| 2840 | _ = try expectToken(it, tree, .LParen); | ||
| 2841 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 2842 | .ExpectedExpr = .{ .token = it.index }, | ||
| 2843 | }); | ||
| 2844 | _ = try expectToken(it, tree, .RParen); | ||
| 2845 | return expr; | ||
| 2846 | } | ||
| 2847 | |||
| 2848 | /// IdentifierList <- (IDENTIFIER COMMA)* IDENTIFIER? | ||
| 2849 | /// Only ErrorSetDecl parses an IdentifierList | ||
| 2850 | fn parseErrorTagList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.ErrorSetDecl.DeclList { | ||
| 2851 | return try ListParseFn(Node.ErrorSetDecl.DeclList, parseErrorTag)(arena, it, tree); | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | /// SwitchProngList <- (SwitchProng COMMA)* SwitchProng? | ||
| 2855 | fn parseSwitchProngList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.Switch.CaseList { | ||
| 2856 | return try ListParseFn(Node.Switch.CaseList, parseSwitchProng)(arena, it, tree); | ||
| 2857 | } | ||
| 2858 | |||
| 2859 | /// AsmOutputList <- (AsmOutputItem COMMA)* AsmOutputItem? | ||
| 2860 | fn parseAsmOutputList(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!Node.Asm.OutputList { | ||
| 2861 | return try ListParseFn(Node.Asm.OutputList, parseAsmOutputItem)(arena, it, tree); | ||
| 2862 | } | ||
| 2863 | |||
| 2864 | /// AsmInputList <- (AsmInputItem COMMA)* AsmInputItem? | ||
| 2865 | fn parseAsmInputList(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!Node.Asm.InputList { | ||
| 2866 | return try ListParseFn(Node.Asm.InputList, parseAsmInputItem)(arena, it, tree); | ||
| 2867 | } | ||
| 2868 | |||
| 2869 | /// ParamDeclList <- (ParamDecl COMMA)* ParamDecl? | ||
| 2870 | fn parseParamDeclList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !Node.FnProto.ParamList { | ||
| 2871 | return try ListParseFn(Node.FnProto.ParamList, parseParamDecl)(arena, it, tree); | ||
| 2872 | } | ||
| 2873 | |||
| 2874 | fn ParseFn(comptime T: type) type { | ||
| 2875 | return fn (*Allocator, *TokenIterator, *Tree) Error!T; | ||
| 2876 | } | ||
| 2877 | 3105 | ||
| 2878 | const NodeParseFn = fn (*Allocator, *TokenIterator, *Tree) Error!?*Node; | 3106 | const node = try Node.MultilineStringLiteral.alloc(&p.arena.allocator, count); |
| 2879 | 3107 | node.* = .{ .lines_len = count }; | |
| 2880 | fn ListParseFn(comptime L: type, comptime nodeParseFn: var) ParseFn(L) { | 3108 | const lines = node.lines(); |
| 2881 | return struct { | 3109 | tok_i = start_tok_i; |
| 2882 | pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !L { | 3110 | lines[0] = first_line; |
| 2883 | var list = L.init(arena); | 3111 | count = 1; |
| 2884 | while (try nodeParseFn(arena, it, tree)) |node| { | 3112 | while (true) : (tok_i += 1) { |
| 2885 | try list.push(node); | 3113 | switch (p.token_ids[tok_i]) { |
| 2886 | 3114 | .LineComment => continue, | |
| 2887 | switch (it.peek().?.id) { | 3115 | .MultilineStringLiteralLine => { |
| 2888 | .Comma => _ = nextToken(it), | 3116 | lines[count] = tok_i; |
| 2889 | // all possible delimiters | 3117 | count += 1; |
| 2890 | .Colon, .RParen, .RBrace, .RBracket => break, | ||
| 2891 | else => { | ||
| 2892 | // this is likely just a missing comma, | ||
| 2893 | // continue parsing this list and give an error | ||
| 2894 | try tree.errors.push(.{ | ||
| 2895 | .ExpectedToken = .{ .token = it.index, .expected_id = .Comma }, | ||
| 2896 | }); | ||
| 2897 | }, | 3118 | }, |
| 3119 | else => break, | ||
| 2898 | } | 3120 | } |
| 2899 | } | 3121 | } |
| 2900 | return list; | 3122 | p.tok_i = tok_i; |
| 2901 | } | ||
| 2902 | }.parse; | ||
| 2903 | } | ||
| 2904 | |||
| 2905 | fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn { | ||
| 2906 | return struct { | ||
| 2907 | pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { | ||
| 2908 | const op_token = if (token == .Keyword_and) switch (it.peek().?.id) { | ||
| 2909 | .Keyword_and => nextToken(it).index, | ||
| 2910 | .Invalid_ampersands => blk: { | ||
| 2911 | try tree.errors.push(.{ | ||
| 2912 | .InvalidAnd = .{ .token = it.index }, | ||
| 2913 | }); | ||
| 2914 | break :blk nextToken(it).index; | ||
| 2915 | }, | ||
| 2916 | else => return null, | ||
| 2917 | } else eatToken(it, token) orelse return null; | ||
| 2918 | |||
| 2919 | const node = try arena.create(Node.InfixOp); | ||
| 2920 | node.* = .{ | ||
| 2921 | .op_token = op_token, | ||
| 2922 | .lhs = undefined, // set by caller | ||
| 2923 | .op = op, | ||
| 2924 | .rhs = undefined, // set by caller | ||
| 2925 | }; | ||
| 2926 | return &node.base; | 3123 | return &node.base; |
| 2927 | } | 3124 | } |
| 2928 | }.parse; | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | // Helper parsers not included in the grammar | ||
| 2932 | 3125 | ||
| 2933 | fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3126 | return null; |
| 2934 | const token = eatToken(it, .Builtin) orelse return null; | 3127 | } |
| 2935 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { | ||
| 2936 | try tree.errors.push(.{ | ||
| 2937 | .ExpectedParamList = .{ .token = it.index }, | ||
| 2938 | }); | ||
| 2939 | 3128 | ||
| 2940 | // lets pretend this was an identifier so we can continue parsing | 3129 | fn parseIntegerLiteral(p: *Parser) !?*Node { |
| 2941 | const node = try arena.create(Node.Identifier); | 3130 | const token = p.eatToken(.IntegerLiteral) orelse return null; |
| 3131 | const node = try p.arena.allocator.create(Node.IntegerLiteral); | ||
| 2942 | node.* = .{ | 3132 | node.* = .{ |
| 2943 | .token = token, | 3133 | .token = token, |
| 2944 | }; | 3134 | }; |
| 2945 | return &node.base; | 3135 | return &node.base; |
| 2946 | }; | 3136 | } |
| 2947 | const node = try arena.create(Node.BuiltinCall); | ||
| 2948 | node.* = .{ | ||
| 2949 | .builtin_token = token, | ||
| 2950 | .params = params.list, | ||
| 2951 | .rparen_token = params.rparen, | ||
| 2952 | }; | ||
| 2953 | return &node.base; | ||
| 2954 | } | ||
| 2955 | |||
| 2956 | fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2957 | const doc_comments = try parseDocComment(arena, it, tree); // no need to rewind on failure | ||
| 2958 | const token = eatToken(it, .Identifier) orelse return null; | ||
| 2959 | |||
| 2960 | const node = try arena.create(Node.ErrorTag); | ||
| 2961 | node.* = .{ | ||
| 2962 | .doc_comments = doc_comments, | ||
| 2963 | .name_token = token, | ||
| 2964 | }; | ||
| 2965 | return &node.base; | ||
| 2966 | } | ||
| 2967 | |||
| 2968 | fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2969 | const token = eatToken(it, .Identifier) orelse return null; | ||
| 2970 | const node = try arena.create(Node.Identifier); | ||
| 2971 | node.* = .{ | ||
| 2972 | .token = token, | ||
| 2973 | }; | ||
| 2974 | return &node.base; | ||
| 2975 | } | ||
| 2976 | |||
| 2977 | fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 2978 | const token = eatToken(it, .Keyword_var) orelse return null; | ||
| 2979 | const node = try arena.create(Node.VarType); | ||
| 2980 | node.* = .{ | ||
| 2981 | .token = token, | ||
| 2982 | }; | ||
| 2983 | return &node.base; | ||
| 2984 | } | ||
| 2985 | |||
| 2986 | fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node { | ||
| 2987 | const result = try arena.create(T); | ||
| 2988 | result.* = T{ | ||
| 2989 | .base = Node{ .id = Node.typeToId(T) }, | ||
| 2990 | .token = token, | ||
| 2991 | }; | ||
| 2992 | return &result.base; | ||
| 2993 | } | ||
| 2994 | 3137 | ||
| 2995 | fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3138 | fn parseFloatLiteral(p: *Parser) !?*Node { |
| 2996 | if (eatToken(it, .StringLiteral)) |token| { | 3139 | const token = p.eatToken(.FloatLiteral) orelse return null; |
| 2997 | const node = try arena.create(Node.StringLiteral); | 3140 | const node = try p.arena.allocator.create(Node.FloatLiteral); |
| 2998 | node.* = .{ | 3141 | node.* = .{ |
| 2999 | .token = token, | 3142 | .token = token, |
| 3000 | }; | 3143 | }; |
| 3001 | return &node.base; | 3144 | return &node.base; |
| 3002 | } | 3145 | } |
| 3003 | return null; | ||
| 3004 | } | ||
| 3005 | |||
| 3006 | // string literal or multiline string literal | ||
| 3007 | fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 3008 | if (try parseStringLiteralSingle(arena, it, tree)) |node| return node; | ||
| 3009 | 3146 | ||
| 3010 | if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { | 3147 | fn parseTry(p: *Parser) !?*Node { |
| 3011 | const node = try arena.create(Node.MultilineStringLiteral); | 3148 | const token = p.eatToken(.Keyword_try) orelse return null; |
| 3149 | const node = try p.arena.allocator.create(Node.PrefixOp); | ||
| 3012 | node.* = .{ | 3150 | node.* = .{ |
| 3013 | .lines = Node.MultilineStringLiteral.LineList.init(arena), | 3151 | .op_token = token, |
| 3152 | .op = .Try, | ||
| 3153 | .rhs = undefined, // set by caller | ||
| 3014 | }; | 3154 | }; |
| 3015 | try node.lines.push(first_line); | ||
| 3016 | while (eatToken(it, .MultilineStringLiteralLine)) |line| | ||
| 3017 | try node.lines.push(line); | ||
| 3018 | |||
| 3019 | return &node.base; | 3155 | return &node.base; |
| 3020 | } | 3156 | } |
| 3021 | 3157 | ||
| 3022 | return null; | 3158 | fn parseUse(p: *Parser) !?*Node { |
| 3023 | } | 3159 | const token = p.eatToken(.Keyword_usingnamespace) orelse return null; |
| 3024 | 3160 | const node = try p.arena.allocator.create(Node.Use); | |
| 3025 | fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3161 | node.* = .{ |
| 3026 | const token = eatToken(it, .IntegerLiteral) orelse return null; | 3162 | .doc_comments = null, |
| 3027 | const node = try arena.create(Node.IntegerLiteral); | 3163 | .visib_token = null, |
| 3028 | node.* = .{ | 3164 | .use_token = token, |
| 3029 | .token = token, | 3165 | .expr = try p.expectNode(parseExpr, .{ |
| 3030 | }; | 3166 | .ExpectedExpr = .{ .token = p.tok_i }, |
| 3031 | return &node.base; | 3167 | }), |
| 3032 | } | 3168 | .semicolon_token = try p.expectToken(.Semicolon), |
| 3033 | 3169 | }; | |
| 3034 | fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3170 | return &node.base; |
| 3035 | const token = eatToken(it, .FloatLiteral) orelse return null; | 3171 | } |
| 3036 | const node = try arena.create(Node.FloatLiteral); | ||
| 3037 | node.* = .{ | ||
| 3038 | .token = token, | ||
| 3039 | }; | ||
| 3040 | return &node.base; | ||
| 3041 | } | ||
| 3042 | |||
| 3043 | fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ||
| 3044 | const token = eatToken(it, .Keyword_try) orelse return null; | ||
| 3045 | const node = try arena.create(Node.PrefixOp); | ||
| 3046 | node.* = .{ | ||
| 3047 | .op_token = token, | ||
| 3048 | .op = .Try, | ||
| 3049 | .rhs = undefined, // set by caller | ||
| 3050 | }; | ||
| 3051 | return &node.base; | ||
| 3052 | } | ||
| 3053 | 3172 | ||
| 3054 | fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 3173 | /// IfPrefix Body (KEYWORD_else Payload? Body)? |
| 3055 | const token = eatToken(it, .Keyword_usingnamespace) orelse return null; | 3174 | fn parseIf(p: *Parser, bodyParseFn: NodeParseFn) !?*Node { |
| 3056 | const node = try arena.create(Node.Use); | 3175 | const node = (try p.parseIfPrefix()) orelse return null; |
| 3057 | node.* = .{ | 3176 | const if_prefix = node.cast(Node.If).?; |
| 3058 | .doc_comments = null, | ||
| 3059 | .visib_token = null, | ||
| 3060 | .use_token = token, | ||
| 3061 | .expr = try expectNode(arena, it, tree, parseExpr, .{ | ||
| 3062 | .ExpectedExpr = .{ .token = it.index }, | ||
| 3063 | }), | ||
| 3064 | .semicolon_token = try expectToken(it, tree, .Semicolon), | ||
| 3065 | }; | ||
| 3066 | return &node.base; | ||
| 3067 | } | ||
| 3068 | 3177 | ||
| 3069 | /// IfPrefix Body (KEYWORD_else Payload? Body)? | 3178 | if_prefix.body = try p.expectNode(bodyParseFn, .{ |
| 3070 | fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: NodeParseFn) !?*Node { | 3179 | .InvalidToken = .{ .token = p.tok_i }, |
| 3071 | const node = (try parseIfPrefix(arena, it, tree)) orelse return null; | 3180 | }); |
| 3072 | const if_prefix = node.cast(Node.If).?; | ||
| 3073 | |||
| 3074 | if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{ | ||
| 3075 | .InvalidToken = .{ .token = it.index }, | ||
| 3076 | }); | ||
| 3077 | |||
| 3078 | const else_token = eatToken(it, .Keyword_else) orelse return node; | ||
| 3079 | const payload = try parsePayload(arena, it, tree); | ||
| 3080 | const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{ | ||
| 3081 | .InvalidToken = .{ .token = it.index }, | ||
| 3082 | }); | ||
| 3083 | const else_node = try arena.create(Node.Else); | ||
| 3084 | else_node.* = .{ | ||
| 3085 | .else_token = else_token, | ||
| 3086 | .payload = payload, | ||
| 3087 | .body = else_expr, | ||
| 3088 | }; | ||
| 3089 | if_prefix.@"else" = else_node; | ||
| 3090 | 3181 | ||
| 3091 | return node; | 3182 | const else_token = p.eatToken(.Keyword_else) orelse return node; |
| 3092 | } | 3183 | const payload = try p.parsePayload(); |
| 3184 | const else_expr = try p.expectNode(bodyParseFn, .{ | ||
| 3185 | .InvalidToken = .{ .token = p.tok_i }, | ||
| 3186 | }); | ||
| 3187 | const else_node = try p.arena.allocator.create(Node.Else); | ||
| 3188 | else_node.* = .{ | ||
| 3189 | .else_token = else_token, | ||
| 3190 | .payload = payload, | ||
| 3191 | .body = else_expr, | ||
| 3192 | }; | ||
| 3193 | if_prefix.@"else" = else_node; | ||
| 3093 | 3194 | ||
| 3094 | /// Eat a multiline doc comment | 3195 | return node; |
| 3095 | fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.DocComment { | ||
| 3096 | var lines = Node.DocComment.LineList.init(arena); | ||
| 3097 | while (eatToken(it, .DocComment)) |line| { | ||
| 3098 | try lines.push(line); | ||
| 3099 | } | 3196 | } |
| 3100 | 3197 | ||
| 3101 | if (lines.len == 0) return null; | 3198 | /// Eat a multiline doc comment |
| 3199 | fn parseDocComment(p: *Parser) !?*Node.DocComment { | ||
| 3200 | if (p.eatToken(.DocComment)) |first_line| { | ||
| 3201 | while (p.eatToken(.DocComment)) |_| {} | ||
| 3202 | const node = try p.arena.allocator.create(Node.DocComment); | ||
| 3203 | node.* = .{ .first_line = first_line }; | ||
| 3204 | return node; | ||
| 3205 | } | ||
| 3206 | return null; | ||
| 3207 | } | ||
| 3102 | 3208 | ||
| 3103 | const node = try arena.create(Node.DocComment); | 3209 | fn tokensOnSameLine(p: *Parser, token1: TokenIndex, token2: TokenIndex) bool { |
| 3104 | node.* = .{ | 3210 | return std.mem.indexOfScalar(u8, p.source[p.token_locs[token1].end..p.token_locs[token2].start], '\n') == null; |
| 3105 | .lines = lines, | 3211 | } |
| 3106 | }; | ||
| 3107 | return node; | ||
| 3108 | } | ||
| 3109 | 3212 | ||
| 3110 | /// Eat a single-line doc comment on the same line as another node | 3213 | /// Eat a single-line doc comment on the same line as another node |
| 3111 | fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, after_token: TokenIndex) !?*Node.DocComment { | 3214 | fn parseAppendedDocComment(p: *Parser, after_token: TokenIndex) !?*Node.DocComment { |
| 3112 | const comment_token = eatToken(it, .DocComment) orelse return null; | 3215 | const comment_token = p.eatToken(.DocComment) orelse return null; |
| 3113 | if (tree.tokensOnSameLine(after_token, comment_token)) { | 3216 | if (p.tokensOnSameLine(after_token, comment_token)) { |
| 3114 | const node = try arena.create(Node.DocComment); | 3217 | const node = try p.arena.allocator.create(Node.DocComment); |
| 3115 | node.* = .{ | 3218 | node.* = .{ .first_line = comment_token }; |
| 3116 | .lines = Node.DocComment.LineList.init(arena), | 3219 | return node; |
| 3117 | }; | 3220 | } |
| 3118 | try node.lines.push(comment_token); | 3221 | p.putBackToken(comment_token); |
| 3119 | return node; | 3222 | return null; |
| 3120 | } | 3223 | } |
| 3121 | putBackToken(it, comment_token); | ||
| 3122 | return null; | ||
| 3123 | } | ||
| 3124 | 3224 | ||
| 3125 | /// Op* Child | 3225 | /// Op* Child |
| 3126 | fn parsePrefixOpExpr( | 3226 | fn parsePrefixOpExpr(p: *Parser, opParseFn: NodeParseFn, childParseFn: NodeParseFn) Error!?*Node { |
| 3127 | arena: *Allocator, | 3227 | if (try opParseFn(p)) |first_op| { |
| 3128 | it: *TokenIterator, | 3228 | var rightmost_op = first_op; |
| 3129 | tree: *Tree, | 3229 | while (true) { |
| 3130 | opParseFn: NodeParseFn, | 3230 | switch (rightmost_op.id) { |
| 3131 | childParseFn: NodeParseFn, | 3231 | .PrefixOp => { |
| 3132 | ) Error!?*Node { | 3232 | var prefix_op = rightmost_op.cast(Node.PrefixOp).?; |
| 3133 | if (try opParseFn(arena, it, tree)) |first_op| { | 3233 | // If the token encountered was **, there will be two nodes |
| 3134 | var rightmost_op = first_op; | 3234 | if (p.token_ids[prefix_op.op_token] == .AsteriskAsterisk) { |
| 3135 | while (true) { | 3235 | rightmost_op = prefix_op.rhs; |
| 3236 | prefix_op = rightmost_op.cast(Node.PrefixOp).?; | ||
| 3237 | } | ||
| 3238 | if (try opParseFn(p)) |rhs| { | ||
| 3239 | prefix_op.rhs = rhs; | ||
| 3240 | rightmost_op = rhs; | ||
| 3241 | } else break; | ||
| 3242 | }, | ||
| 3243 | .AnyFrameType => { | ||
| 3244 | const prom = rightmost_op.cast(Node.AnyFrameType).?; | ||
| 3245 | if (try opParseFn(p)) |rhs| { | ||
| 3246 | prom.result.?.return_type = rhs; | ||
| 3247 | rightmost_op = rhs; | ||
| 3248 | } else break; | ||
| 3249 | }, | ||
| 3250 | else => unreachable, | ||
| 3251 | } | ||
| 3252 | } | ||
| 3253 | |||
| 3254 | // If any prefix op existed, a child node on the RHS is required | ||
| 3136 | switch (rightmost_op.id) { | 3255 | switch (rightmost_op.id) { |
| 3137 | .PrefixOp => { | 3256 | .PrefixOp => { |
| 3138 | var prefix_op = rightmost_op.cast(Node.PrefixOp).?; | 3257 | const prefix_op = rightmost_op.cast(Node.PrefixOp).?; |
| 3139 | // If the token encountered was **, there will be two nodes | 3258 | prefix_op.rhs = try p.expectNode(childParseFn, .{ |
| 3140 | if (tree.tokens.at(prefix_op.op_token).id == .AsteriskAsterisk) { | 3259 | .InvalidToken = .{ .token = p.tok_i }, |
| 3141 | rightmost_op = prefix_op.rhs; | 3260 | }); |
| 3142 | prefix_op = rightmost_op.cast(Node.PrefixOp).?; | ||
| 3143 | } | ||
| 3144 | if (try opParseFn(arena, it, tree)) |rhs| { | ||
| 3145 | prefix_op.rhs = rhs; | ||
| 3146 | rightmost_op = rhs; | ||
| 3147 | } else break; | ||
| 3148 | }, | 3261 | }, |
| 3149 | .AnyFrameType => { | 3262 | .AnyFrameType => { |
| 3150 | const prom = rightmost_op.cast(Node.AnyFrameType).?; | 3263 | const prom = rightmost_op.cast(Node.AnyFrameType).?; |
| 3151 | if (try opParseFn(arena, it, tree)) |rhs| { | 3264 | prom.result.?.return_type = try p.expectNode(childParseFn, .{ |
| 3152 | prom.result.?.return_type = rhs; | 3265 | .InvalidToken = .{ .token = p.tok_i }, |
| 3153 | rightmost_op = rhs; | 3266 | }); |
| 3154 | } else break; | ||
| 3155 | }, | 3267 | }, |
| 3156 | else => unreachable, | 3268 | else => unreachable, |
| 3157 | } | 3269 | } |
| 3158 | } | ||
| 3159 | 3270 | ||
| 3160 | // If any prefix op existed, a child node on the RHS is required | 3271 | return first_op; |
| 3161 | switch (rightmost_op.id) { | ||
| 3162 | .PrefixOp => { | ||
| 3163 | const prefix_op = rightmost_op.cast(Node.PrefixOp).?; | ||
| 3164 | prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{ | ||
| 3165 | .InvalidToken = .{ .token = it.index }, | ||
| 3166 | }); | ||
| 3167 | }, | ||
| 3168 | .AnyFrameType => { | ||
| 3169 | const prom = rightmost_op.cast(Node.AnyFrameType).?; | ||
| 3170 | prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{ | ||
| 3171 | .InvalidToken = .{ .token = it.index }, | ||
| 3172 | }); | ||
| 3173 | }, | ||
| 3174 | else => unreachable, | ||
| 3175 | } | 3272 | } |
| 3176 | 3273 | ||
| 3177 | return first_op; | 3274 | // Otherwise, the child node is optional |
| 3275 | return childParseFn(p); | ||
| 3178 | } | 3276 | } |
| 3179 | 3277 | ||
| 3180 | // Otherwise, the child node is optional | 3278 | /// Child (Op Child)* |
| 3181 | return try childParseFn(arena, it, tree); | 3279 | /// Child (Op Child)? |
| 3182 | } | 3280 | fn parseBinOpExpr( |
| 3281 | p: *Parser, | ||
| 3282 | opParseFn: NodeParseFn, | ||
| 3283 | childParseFn: NodeParseFn, | ||
| 3284 | chain: enum { | ||
| 3285 | Once, | ||
| 3286 | Infinitely, | ||
| 3287 | }, | ||
| 3288 | ) Error!?*Node { | ||
| 3289 | var res = (try childParseFn(p)) orelse return null; | ||
| 3183 | 3290 | ||
| 3184 | /// Child (Op Child)* | 3291 | while (try opParseFn(p)) |node| { |
| 3185 | /// Child (Op Child)? | 3292 | const right = try p.expectNode(childParseFn, .{ |
| 3186 | fn parseBinOpExpr( | 3293 | .InvalidToken = .{ .token = p.tok_i }, |
| 3187 | arena: *Allocator, | 3294 | }); |
| 3188 | it: *TokenIterator, | 3295 | const left = res; |
| 3189 | tree: *Tree, | 3296 | res = node; |
| 3190 | opParseFn: NodeParseFn, | ||
| 3191 | childParseFn: NodeParseFn, | ||
| 3192 | chain: enum { | ||
| 3193 | Once, | ||
| 3194 | Infinitely, | ||
| 3195 | }, | ||
| 3196 | ) Error!?*Node { | ||
| 3197 | var res = (try childParseFn(arena, it, tree)) orelse return null; | ||
| 3198 | |||
| 3199 | while (try opParseFn(arena, it, tree)) |node| { | ||
| 3200 | const right = try expectNode(arena, it, tree, childParseFn, .{ | ||
| 3201 | .InvalidToken = .{ .token = it.index }, | ||
| 3202 | }); | ||
| 3203 | const left = res; | ||
| 3204 | res = node; | ||
| 3205 | 3297 | ||
| 3206 | const op = node.cast(Node.InfixOp).?; | 3298 | const op = node.cast(Node.InfixOp).?; |
| 3207 | op.*.lhs = left; | 3299 | op.*.lhs = left; |
| 3208 | op.*.rhs = right; | 3300 | op.*.rhs = right; |
| 3209 | 3301 | ||
| 3210 | switch (chain) { | 3302 | switch (chain) { |
| 3211 | .Once => break, | 3303 | .Once => break, |
| 3212 | .Infinitely => continue, | 3304 | .Infinitely => continue, |
| 3305 | } | ||
| 3213 | } | 3306 | } |
| 3307 | |||
| 3308 | return res; | ||
| 3214 | } | 3309 | } |
| 3215 | 3310 | ||
| 3216 | return res; | 3311 | fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node { |
| 3217 | } | 3312 | const node = try p.arena.allocator.create(Node.InfixOp); |
| 3313 | node.* = .{ | ||
| 3314 | .op_token = index, | ||
| 3315 | .lhs = undefined, // set by caller | ||
| 3316 | .op = op, | ||
| 3317 | .rhs = undefined, // set by caller | ||
| 3318 | }; | ||
| 3319 | return &node.base; | ||
| 3320 | } | ||
| 3218 | 3321 | ||
| 3219 | fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { | 3322 | fn eatToken(p: *Parser, id: Token.Id) ?TokenIndex { |
| 3220 | const node = try arena.create(Node.InfixOp); | 3323 | return if (p.token_ids[p.tok_i] == id) p.nextToken() else null; |
| 3221 | node.* = .{ | 3324 | } |
| 3222 | .op_token = index, | ||
| 3223 | .lhs = undefined, // set by caller | ||
| 3224 | .op = op, | ||
| 3225 | .rhs = undefined, // set by caller | ||
| 3226 | }; | ||
| 3227 | return &node.base; | ||
| 3228 | } | ||
| 3229 | 3325 | ||
| 3230 | fn eatToken(it: *TokenIterator, id: Token.Id) ?TokenIndex { | 3326 | fn expectToken(p: *Parser, id: Token.Id) Error!TokenIndex { |
| 3231 | return if (eatAnnotatedToken(it, id)) |token| token.index else null; | 3327 | return (try p.expectTokenRecoverable(id)) orelse error.ParseError; |
| 3232 | } | 3328 | } |
| 3233 | 3329 | ||
| 3234 | fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken { | 3330 | fn expectTokenRecoverable(p: *Parser, id: Token.Id) !?TokenIndex { |
| 3235 | return if (it.peek().?.id == id) nextToken(it) else null; | 3331 | const token = p.nextToken(); |
| 3236 | } | 3332 | if (p.token_ids[token] != id) { |
| 3333 | try p.errors.append(p.gpa, .{ | ||
| 3334 | .ExpectedToken = .{ .token = token, .expected_id = id }, | ||
| 3335 | }); | ||
| 3336 | // go back so that we can recover properly | ||
| 3337 | p.putBackToken(token); | ||
| 3338 | return null; | ||
| 3339 | } | ||
| 3340 | return token; | ||
| 3341 | } | ||
| 3237 | 3342 | ||
| 3238 | fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { | 3343 | fn nextToken(p: *Parser) TokenIndex { |
| 3239 | return (try expectTokenRecoverable(it, tree, id)) orelse | 3344 | const result = p.tok_i; |
| 3240 | error.ParseError; | 3345 | p.tok_i += 1; |
| 3241 | } | 3346 | assert(p.token_ids[result] != .LineComment); |
| 3347 | if (p.tok_i >= p.token_ids.len) return result; | ||
| 3242 | 3348 | ||
| 3243 | fn expectTokenRecoverable(it: *TokenIterator, tree: *Tree, id: Token.Id) !?TokenIndex { | 3349 | while (true) { |
| 3244 | const token = nextToken(it); | 3350 | if (p.token_ids[p.tok_i] != .LineComment) return result; |
| 3245 | if (token.ptr.id != id) { | 3351 | p.tok_i += 1; |
| 3246 | try tree.errors.push(.{ | 3352 | } |
| 3247 | .ExpectedToken = .{ .token = token.index, .expected_id = id }, | ||
| 3248 | }); | ||
| 3249 | // go back so that we can recover properly | ||
| 3250 | putBackToken(it, token.index); | ||
| 3251 | return null; | ||
| 3252 | } | 3353 | } |
| 3253 | return token.index; | ||
| 3254 | } | ||
| 3255 | |||
| 3256 | fn nextToken(it: *TokenIterator) AnnotatedToken { | ||
| 3257 | const result = AnnotatedToken{ | ||
| 3258 | .index = it.index, | ||
| 3259 | .ptr = it.next().?, | ||
| 3260 | }; | ||
| 3261 | assert(result.ptr.id != .LineComment); | ||
| 3262 | 3354 | ||
| 3263 | while (true) { | 3355 | fn putBackToken(p: *Parser, putting_back: TokenIndex) void { |
| 3264 | const next_tok = it.peek() orelse return result; | 3356 | while (p.tok_i > 0) { |
| 3265 | if (next_tok.id != .LineComment) return result; | 3357 | p.tok_i -= 1; |
| 3266 | _ = it.next(); | 3358 | if (p.token_ids[p.tok_i] == .LineComment) continue; |
| 3359 | assert(putting_back == p.tok_i); | ||
| 3360 | return; | ||
| 3361 | } | ||
| 3267 | } | 3362 | } |
| 3268 | } | ||
| 3269 | 3363 | ||
| 3270 | fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void { | 3364 | fn expectNode( |
| 3271 | while (true) { | 3365 | p: *Parser, |
| 3272 | const prev_tok = it.prev() orelse return; | 3366 | parseFn: NodeParseFn, |
| 3273 | if (prev_tok.id == .LineComment) continue; | 3367 | /// if parsing fails |
| 3274 | assert(it.list.at(putting_back) == prev_tok); | 3368 | err: AstError, |
| 3275 | return; | 3369 | ) Error!*Node { |
| 3370 | return (try p.expectNodeRecoverable(parseFn, err)) orelse return error.ParseError; | ||
| 3276 | } | 3371 | } |
| 3277 | } | ||
| 3278 | 3372 | ||
| 3279 | const AnnotatedToken = struct { | 3373 | fn expectNodeRecoverable( |
| 3280 | index: TokenIndex, | 3374 | p: *Parser, |
| 3281 | ptr: *Token, | 3375 | parseFn: NodeParseFn, |
| 3376 | /// if parsing fails | ||
| 3377 | err: AstError, | ||
| 3378 | ) !?*Node { | ||
| 3379 | return (try parseFn(p)) orelse { | ||
| 3380 | try p.errors.append(p.gpa, err); | ||
| 3381 | return null; | ||
| 3382 | }; | ||
| 3383 | } | ||
| 3282 | }; | 3384 | }; |
| 3283 | 3385 | ||
| 3284 | fn expectNode( | 3386 | fn ParseFn(comptime T: type) type { |
| 3285 | arena: *Allocator, | 3387 | return fn (p: *Parser) Error!T; |
| 3286 | it: *TokenIterator, | ||
| 3287 | tree: *Tree, | ||
| 3288 | parseFn: NodeParseFn, | ||
| 3289 | err: AstError, // if parsing fails | ||
| 3290 | ) Error!*Node { | ||
| 3291 | return (try expectNodeRecoverable(arena, it, tree, parseFn, err)) orelse | ||
| 3292 | return error.ParseError; | ||
| 3293 | } | 3388 | } |
| 3294 | 3389 | ||
| 3295 | fn expectNodeRecoverable( | ||
| 3296 | arena: *Allocator, | ||
| 3297 | it: *TokenIterator, | ||
| 3298 | tree: *Tree, | ||
| 3299 | parseFn: NodeParseFn, | ||
| 3300 | err: AstError, // if parsing fails | ||
| 3301 | ) !?*Node { | ||
| 3302 | return (try parseFn(arena, it, tree)) orelse { | ||
| 3303 | try tree.errors.push(err); | ||
| 3304 | return null; | ||
| 3305 | }; | ||
| 3306 | } | ||
| 3307 | 3390 | ||
| 3308 | test "std.zig.parser" { | 3391 | test "std.zig.parser" { |
| 3309 | _ = @import("parser_test.zig"); | 3392 | _ = @import("parser_test.zig"); |
lib/std/zig/parser_test.zig+3-6| ... | @@ -3180,9 +3180,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b | ... | @@ -3180,9 +3180,8 @@ fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *b |
| 3180 | const tree = try std.zig.parse(allocator, source); | 3180 | const tree = try std.zig.parse(allocator, source); |
| 3181 | defer tree.deinit(); | 3181 | defer tree.deinit(); |
| 3182 | 3182 | ||
| 3183 | var error_it = tree.errors.iterator(0); | 3183 | for (tree.errors) |*parse_error| { |
| 3184 | while (error_it.next()) |parse_error| { | 3184 | const token = tree.token_locs[parse_error.loc()]; |
| 3185 | const token = tree.tokens.at(parse_error.loc()); | ||
| 3186 | const loc = tree.tokenLocation(0, parse_error.loc()); | 3185 | const loc = tree.tokenLocation(0, parse_error.loc()); |
| 3187 | try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 }); | 3186 | try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 }); |
| 3188 | try tree.renderError(parse_error, stderr); | 3187 | try tree.renderError(parse_error, stderr); |
| ... | @@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void { | ... | @@ -3271,8 +3270,6 @@ fn testError(source: []const u8, expected_errors: []const Error) !void { |
| 3271 | 3270 | ||
| 3272 | std.testing.expect(tree.errors.len == expected_errors.len); | 3271 | std.testing.expect(tree.errors.len == expected_errors.len); |
| 3273 | for (expected_errors) |expected, i| { | 3272 | for (expected_errors) |expected, i| { |
| 3274 | const err = tree.errors.at(i); | 3273 | std.testing.expect(expected == tree.errors[i]); |
| 3275 | |||
| 3276 | std.testing.expect(expected == err.*); | ||
| 3277 | } | 3274 | } |
| 3278 | } | 3275 | } |
lib/std/zig/render.zig+630-573| ... | @@ -67,24 +67,23 @@ fn renderRoot( | ... | @@ -67,24 +67,23 @@ fn renderRoot( |
| 67 | stream: var, | 67 | stream: var, |
| 68 | tree: *ast.Tree, | 68 | tree: *ast.Tree, |
| 69 | ) (@TypeOf(stream).Error || Error)!void { | 69 | ) (@TypeOf(stream).Error || Error)!void { |
| 70 | var tok_it = tree.tokens.iterator(0); | ||
| 71 | |||
| 72 | // render all the line comments at the beginning of the file | 70 | // render all the line comments at the beginning of the file |
| 73 | while (tok_it.next()) |token| { | 71 | for (tree.token_ids) |token_id, i| { |
| 74 | if (token.id != .LineComment) break; | 72 | if (token_id != .LineComment) break; |
| 75 | try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSlicePtr(token), " ")}); | 73 | const token_loc = tree.token_locs[i]; |
| 76 | if (tok_it.peek()) |next_token| { | 74 | try stream.print("{}\n", .{mem.trimRight(u8, tree.tokenSliceLoc(token_loc), " ")}); |
| 77 | const loc = tree.tokenLocationPtr(token.end, next_token); | 75 | const next_token = tree.token_locs[i + 1]; |
| 78 | if (loc.line >= 2) { | 76 | const loc = tree.tokenLocationLoc(token_loc.end, next_token); |
| 79 | try stream.writeByte('\n'); | 77 | if (loc.line >= 2) { |
| 80 | } | 78 | try stream.writeByte('\n'); |
| 81 | } | 79 | } |
| 82 | } | 80 | } |
| 83 | 81 | ||
| 84 | var start_col: usize = 0; | 82 | var start_col: usize = 0; |
| 85 | var it = tree.root_node.decls.iterator(0); | 83 | var decl_i: ast.NodeIndex = 0; |
| 84 | const root_decls = tree.root_node.decls(); | ||
| 86 | while (true) { | 85 | while (true) { |
| 87 | var decl = (it.next() orelse return).*; | 86 | var decl = root_decls[decl_i]; |
| 88 | 87 | ||
| 89 | // This loop does the following: | 88 | // This loop does the following: |
| 90 | // | 89 | // |
| ... | @@ -103,8 +102,8 @@ fn renderRoot( | ... | @@ -103,8 +102,8 @@ fn renderRoot( |
| 103 | 102 | ||
| 104 | while (token_index != 0) { | 103 | while (token_index != 0) { |
| 105 | token_index -= 1; | 104 | token_index -= 1; |
| 106 | const token = tree.tokens.at(token_index); | 105 | const token_id = tree.token_ids[token_index]; |
| 107 | switch (token.id) { | 106 | switch (token_id) { |
| 108 | .LineComment => {}, | 107 | .LineComment => {}, |
| 109 | .DocComment => { | 108 | .DocComment => { |
| 110 | copy_start_token_index = token_index; | 109 | copy_start_token_index = token_index; |
| ... | @@ -113,12 +112,13 @@ fn renderRoot( | ... | @@ -113,12 +112,13 @@ fn renderRoot( |
| 113 | else => break, | 112 | else => break, |
| 114 | } | 113 | } |
| 115 | 114 | ||
| 116 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { | 115 | const token_loc = tree.token_locs[token_index]; |
| 116 | if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) { | ||
| 117 | if (!found_fmt_directive) { | 117 | if (!found_fmt_directive) { |
| 118 | fmt_active = false; | 118 | fmt_active = false; |
| 119 | found_fmt_directive = true; | 119 | found_fmt_directive = true; |
| 120 | } | 120 | } |
| 121 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { | 121 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) { |
| 122 | if (!found_fmt_directive) { | 122 | if (!found_fmt_directive) { |
| 123 | fmt_active = true; | 123 | fmt_active = true; |
| 124 | found_fmt_directive = true; | 124 | found_fmt_directive = true; |
| ... | @@ -133,25 +133,28 @@ fn renderRoot( | ... | @@ -133,25 +133,28 @@ fn renderRoot( |
| 133 | token_index = decl.firstToken(); | 133 | token_index = decl.firstToken(); |
| 134 | 134 | ||
| 135 | while (!fmt_active) { | 135 | while (!fmt_active) { |
| 136 | decl = (it.next() orelse { | 136 | decl_i += 1; |
| 137 | if (decl_i >= root_decls.len) { | ||
| 137 | // If there's no next reformatted `decl`, just copy the | 138 | // If there's no next reformatted `decl`, just copy the |
| 138 | // remaining input tokens and bail out. | 139 | // remaining input tokens and bail out. |
| 139 | const start = tree.tokens.at(copy_start_token_index).start; | 140 | const start = tree.token_locs[copy_start_token_index].start; |
| 140 | try copyFixingWhitespace(stream, tree.source[start..]); | 141 | try copyFixingWhitespace(stream, tree.source[start..]); |
| 141 | return; | 142 | return; |
| 142 | }).*; | 143 | } |
| 144 | decl = root_decls[decl_i]; | ||
| 143 | var decl_first_token_index = decl.firstToken(); | 145 | var decl_first_token_index = decl.firstToken(); |
| 144 | 146 | ||
| 145 | while (token_index < decl_first_token_index) : (token_index += 1) { | 147 | while (token_index < decl_first_token_index) : (token_index += 1) { |
| 146 | const token = tree.tokens.at(token_index); | 148 | const token_id = tree.token_ids[token_index]; |
| 147 | switch (token.id) { | 149 | switch (token_id) { |
| 148 | .LineComment => {}, | 150 | .LineComment => {}, |
| 149 | .Eof => unreachable, | 151 | .Eof => unreachable, |
| 150 | else => continue, | 152 | else => continue, |
| 151 | } | 153 | } |
| 152 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { | 154 | const token_loc = tree.token_locs[token_index]; |
| 155 | if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: on")) { | ||
| 153 | fmt_active = true; | 156 | fmt_active = true; |
| 154 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { | 157 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSliceLoc(token_loc)[2..], " "), "zig fmt: off")) { |
| 155 | fmt_active = false; | 158 | fmt_active = false; |
| 156 | } | 159 | } |
| 157 | } | 160 | } |
| ... | @@ -163,8 +166,8 @@ fn renderRoot( | ... | @@ -163,8 +166,8 @@ fn renderRoot( |
| 163 | token_index = copy_end_token_index; | 166 | token_index = copy_end_token_index; |
| 164 | while (token_index != 0) { | 167 | while (token_index != 0) { |
| 165 | token_index -= 1; | 168 | token_index -= 1; |
| 166 | const token = tree.tokens.at(token_index); | 169 | const token_id = tree.token_ids[token_index]; |
| 167 | switch (token.id) { | 170 | switch (token_id) { |
| 168 | .LineComment => {}, | 171 | .LineComment => {}, |
| 169 | .DocComment => { | 172 | .DocComment => { |
| 170 | copy_end_token_index = token_index; | 173 | copy_end_token_index = token_index; |
| ... | @@ -174,30 +177,33 @@ fn renderRoot( | ... | @@ -174,30 +177,33 @@ fn renderRoot( |
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| 176 | 179 | ||
| 177 | const start = tree.tokens.at(copy_start_token_index).start; | 180 | const start = tree.token_locs[copy_start_token_index].start; |
| 178 | const end = tree.tokens.at(copy_end_token_index).start; | 181 | const end = tree.token_locs[copy_end_token_index].start; |
| 179 | try copyFixingWhitespace(stream, tree.source[start..end]); | 182 | try copyFixingWhitespace(stream, tree.source[start..end]); |
| 180 | } | 183 | } |
| 181 | 184 | ||
| 182 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); | 185 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); |
| 183 | if (it.peek()) |next_decl| { | 186 | decl_i += 1; |
| 184 | try renderExtraNewline(tree, stream, &start_col, next_decl.*); | 187 | if (decl_i >= root_decls.len) return; |
| 185 | } | 188 | try renderExtraNewline(tree, stream, &start_col, root_decls[decl_i]); |
| 186 | } | 189 | } |
| 187 | } | 190 | } |
| 188 | 191 | ||
| 189 | fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void { | 192 | fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Error!void { |
| 190 | const first_token = node.firstToken(); | 193 | return renderExtraNewlineToken(tree, stream, start_col, node.firstToken()); |
| 194 | } | ||
| 195 | |||
| 196 | fn renderExtraNewlineToken(tree: *ast.Tree, stream: var, start_col: *usize, first_token: ast.TokenIndex,) @TypeOf(stream).Error!void { | ||
| 191 | var prev_token = first_token; | 197 | var prev_token = first_token; |
| 192 | if (prev_token == 0) return; | 198 | if (prev_token == 0) return; |
| 193 | var newline_threshold: usize = 2; | 199 | var newline_threshold: usize = 2; |
| 194 | while (tree.tokens.at(prev_token - 1).id == .DocComment) { | 200 | while (tree.token_ids[prev_token - 1] == .DocComment) { |
| 195 | if (tree.tokenLocation(tree.tokens.at(prev_token - 1).end, prev_token).line == 1) { | 201 | if (tree.tokenLocation(tree.token_locs[prev_token - 1].end, prev_token).line == 1) { |
| 196 | newline_threshold += 1; | 202 | newline_threshold += 1; |
| 197 | } | 203 | } |
| 198 | prev_token -= 1; | 204 | prev_token -= 1; |
| 199 | } | 205 | } |
| 200 | const prev_token_end = tree.tokens.at(prev_token - 1).end; | 206 | const prev_token_end = tree.token_locs[prev_token - 1].end; |
| 201 | const loc = tree.tokenLocation(prev_token_end, first_token); | 207 | const loc = tree.tokenLocation(prev_token_end, first_token); |
| 202 | if (loc.line >= newline_threshold) { | 208 | if (loc.line >= newline_threshold) { |
| 203 | try stream.writeByte('\n'); | 209 | try stream.writeByte('\n'); |
| ... | @@ -262,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, | ... | @@ -262,7 +268,7 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, |
| 262 | 268 | ||
| 263 | const src_has_trailing_comma = blk: { | 269 | const src_has_trailing_comma = blk: { |
| 264 | const maybe_comma = tree.nextToken(field.lastToken()); | 270 | const maybe_comma = tree.nextToken(field.lastToken()); |
| 265 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | 271 | break :blk tree.token_ids[maybe_comma] == .Comma; |
| 266 | }; | 272 | }; |
| 267 | 273 | ||
| 268 | // The trailing comma is emitted at the end, but if it's not present | 274 | // The trailing comma is emitted at the end, but if it's not present |
| ... | @@ -324,11 +330,18 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, | ... | @@ -324,11 +330,18 @@ fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, |
| 324 | 330 | ||
| 325 | .DocComment => { | 331 | .DocComment => { |
| 326 | const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); | 332 | const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); |
| 327 | var it = comment.lines.iterator(0); | 333 | const kind = tree.token_ids[comment.first_line]; |
| 328 | while (it.next()) |line_token_index| { | 334 | try renderToken(tree, stream, comment.first_line, indent, start_col, .Newline); |
| 329 | try renderToken(tree, stream, line_token_index.*, indent, start_col, .Newline); | 335 | var tok_i = comment.first_line + 1; |
| 330 | if (it.peek()) |_| { | 336 | while (true) : (tok_i += 1) { |
| 337 | const tok_id = tree.token_ids[tok_i]; | ||
| 338 | if (tok_id == kind) { | ||
| 331 | try stream.writeByteNTimes(' ', indent); | 339 | try stream.writeByteNTimes(' ', indent); |
| 340 | try renderToken(tree, stream, tok_i, indent, start_col, .Newline); | ||
| 341 | } else if (tok_id == .LineComment) { | ||
| 342 | continue; | ||
| 343 | } else { | ||
| 344 | break; | ||
| 332 | } | 345 | } |
| 333 | } | 346 | } |
| 334 | }, | 347 | }, |
| ... | @@ -358,20 +371,20 @@ fn renderExpression( | ... | @@ -358,20 +371,20 @@ fn renderExpression( |
| 358 | try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); | 371 | try renderToken(tree, stream, tree.nextToken(label), indent, start_col, Space.Space); |
| 359 | } | 372 | } |
| 360 | 373 | ||
| 361 | if (block.statements.len == 0) { | 374 | if (block.statements_len == 0) { |
| 362 | try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None); | 375 | try renderToken(tree, stream, block.lbrace, indent + indent_delta, start_col, Space.None); |
| 363 | return renderToken(tree, stream, block.rbrace, indent, start_col, space); | 376 | return renderToken(tree, stream, block.rbrace, indent, start_col, space); |
| 364 | } else { | 377 | } else { |
| 365 | const block_indent = indent + indent_delta; | 378 | const block_indent = indent + indent_delta; |
| 366 | try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline); | 379 | try renderToken(tree, stream, block.lbrace, block_indent, start_col, Space.Newline); |
| 367 | 380 | ||
| 368 | var it = block.statements.iterator(0); | 381 | const block_statements = block.statements(); |
| 369 | while (it.next()) |statement| { | 382 | for (block_statements) |statement, i| { |
| 370 | try stream.writeByteNTimes(' ', block_indent); | 383 | try stream.writeByteNTimes(' ', block_indent); |
| 371 | try renderStatement(allocator, stream, tree, block_indent, start_col, statement.*); | 384 | try renderStatement(allocator, stream, tree, block_indent, start_col, statement); |
| 372 | 385 | ||
| 373 | if (it.peek()) |next_statement| { | 386 | if (i + 1 < block_statements.len) { |
| 374 | try renderExtraNewline(tree, stream, start_col, next_statement.*); | 387 | try renderExtraNewline(tree, stream, start_col, block_statements[i + 1]); |
| 375 | } | 388 | } |
| 376 | } | 389 | } |
| 377 | 390 | ||
| ... | @@ -426,13 +439,13 @@ fn renderExpression( | ... | @@ -426,13 +439,13 @@ fn renderExpression( |
| 426 | try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space); | 439 | try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space); |
| 427 | 440 | ||
| 428 | const after_op_space = blk: { | 441 | const after_op_space = blk: { |
| 429 | const loc = tree.tokenLocation(tree.tokens.at(infix_op_node.op_token).end, tree.nextToken(infix_op_node.op_token)); | 442 | const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token)); |
| 430 | break :blk if (loc.line == 0) op_space else Space.Newline; | 443 | break :blk if (loc.line == 0) op_space else Space.Newline; |
| 431 | }; | 444 | }; |
| 432 | 445 | ||
| 433 | try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space); | 446 | try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space); |
| 434 | if (after_op_space == Space.Newline and | 447 | if (after_op_space == Space.Newline and |
| 435 | tree.tokens.at(tree.nextToken(infix_op_node.op_token)).id != .MultilineStringLiteralLine) | 448 | tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine) |
| 436 | { | 449 | { |
| 437 | try stream.writeByteNTimes(' ', indent + indent_delta); | 450 | try stream.writeByteNTimes(' ', indent + indent_delta); |
| 438 | start_col.* = indent + indent_delta; | 451 | start_col.* = indent + indent_delta; |
| ... | @@ -453,10 +466,10 @@ fn renderExpression( | ... | @@ -453,10 +466,10 @@ fn renderExpression( |
| 453 | 466 | ||
| 454 | switch (prefix_op_node.op) { | 467 | switch (prefix_op_node.op) { |
| 455 | .PtrType => |ptr_info| { | 468 | .PtrType => |ptr_info| { |
| 456 | const op_tok_id = tree.tokens.at(prefix_op_node.op_token).id; | 469 | const op_tok_id = tree.token_ids[prefix_op_node.op_token]; |
| 457 | switch (op_tok_id) { | 470 | switch (op_tok_id) { |
| 458 | .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'), | 471 | .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'), |
| 459 | .LBracket => if (tree.tokens.at(prefix_op_node.op_token + 2).id == .Identifier) | 472 | .LBracket => if (tree.token_ids[prefix_op_node.op_token + 2] == .Identifier) |
| 460 | try stream.writeAll("[*c") | 473 | try stream.writeAll("[*c") |
| 461 | else | 474 | else |
| 462 | try stream.writeAll("[*"), | 475 | try stream.writeAll("[*"), |
| ... | @@ -568,8 +581,8 @@ fn renderExpression( | ... | @@ -568,8 +581,8 @@ fn renderExpression( |
| 568 | 581 | ||
| 569 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ | 582 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ |
| 570 | 583 | ||
| 571 | const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; | 584 | const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment; |
| 572 | const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; | 585 | const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment; |
| 573 | const new_indent = if (ends_with_comment) indent + indent_delta else indent; | 586 | const new_indent = if (ends_with_comment) indent + indent_delta else indent; |
| 574 | const new_space = if (ends_with_comment) Space.Newline else Space.None; | 587 | const new_space = if (ends_with_comment) Space.Newline else Space.None; |
| 575 | try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space); | 588 | try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space); |
| ... | @@ -610,80 +623,371 @@ fn renderExpression( | ... | @@ -610,80 +623,371 @@ fn renderExpression( |
| 610 | return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space); | 623 | return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space); |
| 611 | }, | 624 | }, |
| 612 | 625 | ||
| 613 | .SuffixOp => { | 626 | .ArrayInitializer, .ArrayInitializerDot => { |
| 614 | const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base); | 627 | var rtoken: ast.TokenIndex = undefined; |
| 615 | 628 | var exprs: []*ast.Node = undefined; | |
| 616 | switch (suffix_op.op) { | 629 | const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){ |
| 617 | .Call => |*call_info| { | 630 | .ArrayInitializerDot => blk: { |
| 618 | if (call_info.async_token) |async_token| { | 631 | const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base); |
| 619 | try renderToken(tree, stream, async_token, indent, start_col, Space.Space); | 632 | rtoken = casted.rtoken; |
| 620 | } | 633 | exprs = casted.list(); |
| 621 | 634 | break :blk .{ .dot = casted.dot }; | |
| 622 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 635 | }, |
| 623 | 636 | .ArrayInitializer => blk: { | |
| 624 | const lparen = tree.nextToken(suffix_op.lhs.node.lastToken()); | 637 | const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base); |
| 638 | rtoken = casted.rtoken; | ||
| 639 | exprs = casted.list(); | ||
| 640 | break :blk .{ .node = casted.lhs }; | ||
| 641 | }, | ||
| 642 | else => unreachable, | ||
| 643 | }; | ||
| 625 | 644 | ||
| 626 | if (call_info.params.len == 0) { | 645 | const lbrace = switch (lhs) { |
| 627 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); | 646 | .dot => |dot| tree.nextToken(dot), |
| 628 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | 647 | .node => |node| tree.nextToken(node.lastToken()), |
| 629 | } | 648 | }; |
| 630 | 649 | ||
| 631 | const src_has_trailing_comma = blk: { | 650 | if (exprs.len == 0) { |
| 632 | const maybe_comma = tree.prevToken(suffix_op.rtoken); | 651 | switch (lhs) { |
| 633 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | 652 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| 634 | }; | 653 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| 654 | } | ||
| 655 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | ||
| 656 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 657 | } | ||
| 635 | 658 | ||
| 636 | if (src_has_trailing_comma) { | 659 | if (exprs.len == 1 and tree.token_ids[exprs[0].lastToken() + 1] == .RBrace) { |
| 637 | const new_indent = indent + indent_delta; | 660 | const expr = exprs[0]; |
| 638 | try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); | 661 | switch (lhs) { |
| 662 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 663 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 664 | } | ||
| 665 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | ||
| 666 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); | ||
| 667 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 668 | } | ||
| 639 | 669 | ||
| 640 | var it = call_info.params.iterator(0); | 670 | switch (lhs) { |
| 641 | while (true) { | 671 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| 642 | const param_node = it.next().?; | 672 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| 673 | } | ||
| 643 | 674 | ||
| 644 | const param_node_new_indent = if (param_node.*.id == .MultilineStringLiteral) blk: { | 675 | // scan to find row size |
| 645 | break :blk indent; | 676 | const maybe_row_size: ?usize = blk: { |
| 646 | } else blk: { | 677 | var count: usize = 1; |
| 647 | try stream.writeByteNTimes(' ', new_indent); | 678 | for (exprs) |expr, i| { |
| 648 | break :blk new_indent; | 679 | if (i + 1 < exprs.len) { |
| 680 | const expr_last_token = expr.lastToken() + 1; | ||
| 681 | const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, exprs[i+1].firstToken()); | ||
| 682 | if (loc.line != 0) break :blk count; | ||
| 683 | count += 1; | ||
| 684 | } else { | ||
| 685 | const expr_last_token = expr.lastToken(); | ||
| 686 | const loc = tree.tokenLocation(tree.token_locs[expr_last_token].end, rtoken); | ||
| 687 | if (loc.line == 0) { | ||
| 688 | // all on one line | ||
| 689 | const src_has_trailing_comma = trailblk: { | ||
| 690 | const maybe_comma = tree.prevToken(rtoken); | ||
| 691 | break :trailblk tree.token_ids[maybe_comma] == .Comma; | ||
| 649 | }; | 692 | }; |
| 650 | 693 | if (src_has_trailing_comma) { | |
| 651 | if (it.peek()) |next_node| { | 694 | break :blk 1; // force row size 1 |
| 652 | try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.None); | ||
| 653 | const comma = tree.nextToken(param_node.*.lastToken()); | ||
| 654 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // , | ||
| 655 | try renderExtraNewline(tree, stream, start_col, next_node.*); | ||
| 656 | } else { | 695 | } else { |
| 657 | try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node.*, Space.Comma); | 696 | break :blk null; // no newlines |
| 658 | try stream.writeByteNTimes(' ', indent); | ||
| 659 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 660 | } | 697 | } |
| 661 | } | 698 | } |
| 699 | break :blk count; | ||
| 662 | } | 700 | } |
| 701 | } | ||
| 702 | unreachable; | ||
| 703 | }; | ||
| 663 | 704 | ||
| 664 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( | 705 | if (maybe_row_size) |row_size| { |
| 706 | // A place to store the width of each expression and its column's maximum | ||
| 707 | var widths = try allocator.alloc(usize, exprs.len + row_size); | ||
| 708 | defer allocator.free(widths); | ||
| 709 | mem.set(usize, widths, 0); | ||
| 710 | |||
| 711 | var expr_widths = widths[0 .. widths.len - row_size]; | ||
| 712 | var column_widths = widths[widths.len - row_size ..]; | ||
| 713 | |||
| 714 | // Null stream for counting the printed length of each expression | ||
| 715 | var counting_stream = std.io.countingOutStream(std.io.null_out_stream); | ||
| 716 | |||
| 717 | for (exprs) |expr, i| { | ||
| 718 | counting_stream.bytes_written = 0; | ||
| 719 | var dummy_col: usize = 0; | ||
| 720 | try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr, Space.None); | ||
| 721 | const width = @intCast(usize, counting_stream.bytes_written); | ||
| 722 | const col = i % row_size; | ||
| 723 | column_widths[col] = std.math.max(column_widths[col], width); | ||
| 724 | expr_widths[i] = width; | ||
| 725 | } | ||
| 726 | |||
| 727 | var new_indent = indent + indent_delta; | ||
| 728 | |||
| 729 | if (tree.token_ids[tree.nextToken(lbrace)] != .MultilineStringLiteralLine) { | ||
| 730 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); | ||
| 731 | try stream.writeByteNTimes(' ', new_indent); | ||
| 732 | } else { | ||
| 733 | new_indent -= indent_delta; | ||
| 734 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None); | ||
| 735 | } | ||
| 736 | |||
| 737 | var col: usize = 1; | ||
| 738 | for (exprs) |expr, i| { | ||
| 739 | if (i + 1 < exprs.len) { | ||
| 740 | const next_expr = exprs[i + 1]; | ||
| 741 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.None); | ||
| 742 | |||
| 743 | const comma = tree.nextToken(expr.lastToken()); | ||
| 744 | |||
| 745 | if (col != row_size) { | ||
| 746 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // , | ||
| 747 | |||
| 748 | const padding = column_widths[i % row_size] - expr_widths[i]; | ||
| 749 | try stream.writeByteNTimes(' ', padding); | ||
| 750 | |||
| 751 | col += 1; | ||
| 752 | continue; | ||
| 753 | } | ||
| 754 | col = 1; | ||
| 665 | 755 | ||
| 666 | var it = call_info.params.iterator(0); | 756 | if (tree.token_ids[tree.nextToken(comma)] != .MultilineStringLiteralLine) { |
| 667 | while (it.next()) |param_node| { | 757 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // , |
| 668 | try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None); | 758 | } else { |
| 759 | try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // , | ||
| 760 | } | ||
| 669 | 761 | ||
| 670 | if (it.peek() != null) { | 762 | try renderExtraNewline(tree, stream, start_col, next_expr); |
| 671 | const comma = tree.nextToken(param_node.*.lastToken()); | 763 | if (next_expr.id != .MultilineStringLiteral) { |
| 672 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); | 764 | try stream.writeByteNTimes(' ', new_indent); |
| 673 | } | 765 | } |
| 766 | } else { | ||
| 767 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // , | ||
| 768 | } | ||
| 769 | } | ||
| 770 | if (exprs[exprs.len - 1].id != .MultilineStringLiteral) { | ||
| 771 | try stream.writeByteNTimes(' ', indent); | ||
| 772 | } | ||
| 773 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 774 | } else { | ||
| 775 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | ||
| 776 | for (exprs) |expr, i| { | ||
| 777 | if (i + 1 < exprs.len) { | ||
| 778 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); | ||
| 779 | const comma = tree.nextToken(expr.lastToken()); | ||
| 780 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , | ||
| 781 | } else { | ||
| 782 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space); | ||
| 674 | } | 783 | } |
| 675 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | 784 | } |
| 785 | |||
| 786 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 787 | } | ||
| 788 | }, | ||
| 789 | |||
| 790 | .StructInitializer, .StructInitializerDot => { | ||
| 791 | var rtoken: ast.TokenIndex = undefined; | ||
| 792 | var field_inits: []*ast.Node = undefined; | ||
| 793 | const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){ | ||
| 794 | .StructInitializerDot => blk: { | ||
| 795 | const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base); | ||
| 796 | rtoken = casted.rtoken; | ||
| 797 | field_inits = casted.list(); | ||
| 798 | break :blk .{ .dot = casted.dot }; | ||
| 676 | }, | 799 | }, |
| 800 | .StructInitializer => blk: { | ||
| 801 | const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base); | ||
| 802 | rtoken = casted.rtoken; | ||
| 803 | field_inits = casted.list(); | ||
| 804 | break :blk .{ .node = casted.lhs }; | ||
| 805 | }, | ||
| 806 | else => unreachable, | ||
| 807 | }; | ||
| 808 | |||
| 809 | const lbrace = switch (lhs) { | ||
| 810 | .dot => |dot| tree.nextToken(dot), | ||
| 811 | .node => |node| tree.nextToken(node.lastToken()), | ||
| 812 | }; | ||
| 813 | |||
| 814 | if (field_inits.len == 0) { | ||
| 815 | switch (lhs) { | ||
| 816 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 817 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 818 | } | ||
| 819 | try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); | ||
| 820 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 821 | } | ||
| 822 | |||
| 823 | const src_has_trailing_comma = blk: { | ||
| 824 | const maybe_comma = tree.prevToken(rtoken); | ||
| 825 | break :blk tree.token_ids[maybe_comma] == .Comma; | ||
| 826 | }; | ||
| 827 | |||
| 828 | const src_same_line = blk: { | ||
| 829 | const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken); | ||
| 830 | break :blk loc.line == 0; | ||
| 831 | }; | ||
| 832 | |||
| 833 | const expr_outputs_one_line = blk: { | ||
| 834 | // render field expressions until a LF is found | ||
| 835 | for (field_inits) |field_init| { | ||
| 836 | var find_stream = FindByteOutStream.init('\n'); | ||
| 837 | var dummy_col: usize = 0; | ||
| 838 | try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init, Space.None); | ||
| 839 | if (find_stream.byte_found) break :blk false; | ||
| 840 | } | ||
| 841 | break :blk true; | ||
| 842 | }; | ||
| 843 | |||
| 844 | if (field_inits.len == 1) blk: { | ||
| 845 | const field_init = field_inits[0].cast(ast.Node.FieldInitializer).?; | ||
| 846 | |||
| 847 | switch (field_init.expr.id) { | ||
| 848 | .StructInitializer, | ||
| 849 | .StructInitializerDot, | ||
| 850 | => break :blk, | ||
| 851 | |||
| 852 | else => {}, | ||
| 853 | } | ||
| 854 | |||
| 855 | // if the expression outputs to multiline, make this struct multiline | ||
| 856 | if (!expr_outputs_one_line or src_has_trailing_comma) { | ||
| 857 | break :blk; | ||
| 858 | } | ||
| 859 | |||
| 860 | switch (lhs) { | ||
| 861 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 862 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 863 | } | ||
| 864 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | ||
| 865 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); | ||
| 866 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 867 | } | ||
| 868 | |||
| 869 | if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { | ||
| 870 | // render all on one line, no trailing comma | ||
| 871 | switch (lhs) { | ||
| 872 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 873 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 874 | } | ||
| 875 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | ||
| 876 | |||
| 877 | for (field_inits) |field_init, i| { | ||
| 878 | if (i + 1 < field_inits.len) { | ||
| 879 | try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.None); | ||
| 880 | |||
| 881 | const comma = tree.nextToken(field_init.lastToken()); | ||
| 882 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); | ||
| 883 | } else { | ||
| 884 | try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space); | ||
| 885 | } | ||
| 886 | } | ||
| 887 | |||
| 888 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 889 | } | ||
| 890 | |||
| 891 | const new_indent = indent + indent_delta; | ||
| 892 | |||
| 893 | switch (lhs) { | ||
| 894 | .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None), | ||
| 895 | .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None), | ||
| 896 | } | ||
| 897 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); | ||
| 898 | |||
| 899 | for (field_inits) |field_init, i| { | ||
| 900 | try stream.writeByteNTimes(' ', new_indent); | ||
| 901 | |||
| 902 | if (i + 1 < field_inits.len) { | ||
| 903 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.None); | ||
| 904 | |||
| 905 | const comma = tree.nextToken(field_init.lastToken()); | ||
| 906 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); | ||
| 907 | |||
| 908 | try renderExtraNewline(tree, stream, start_col, field_inits[i + 1]); | ||
| 909 | } else { | ||
| 910 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.Comma); | ||
| 911 | } | ||
| 912 | } | ||
| 913 | |||
| 914 | try stream.writeByteNTimes(' ', indent); | ||
| 915 | return renderToken(tree, stream, rtoken, indent, start_col, space); | ||
| 916 | }, | ||
| 917 | |||
| 918 | .Call => { | ||
| 919 | const call = @fieldParentPtr(ast.Node.Call, "base", base); | ||
| 920 | if (call.async_token) |async_token| { | ||
| 921 | try renderToken(tree, stream, async_token, indent, start_col, Space.Space); | ||
| 922 | } | ||
| 923 | |||
| 924 | try renderExpression(allocator, stream, tree, indent, start_col, call.lhs, Space.None); | ||
| 925 | |||
| 926 | const lparen = tree.nextToken(call.lhs.lastToken()); | ||
| 927 | |||
| 928 | if (call.params_len == 0) { | ||
| 929 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); | ||
| 930 | return renderToken(tree, stream, call.rtoken, indent, start_col, space); | ||
| 931 | } | ||
| 932 | |||
| 933 | const src_has_trailing_comma = blk: { | ||
| 934 | const maybe_comma = tree.prevToken(call.rtoken); | ||
| 935 | break :blk tree.token_ids[maybe_comma] == .Comma; | ||
| 936 | }; | ||
| 937 | |||
| 938 | if (src_has_trailing_comma) { | ||
| 939 | const new_indent = indent + indent_delta; | ||
| 940 | try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); | ||
| 677 | 941 | ||
| 942 | const params = call.params(); | ||
| 943 | for (params) |param_node, i| { | ||
| 944 | const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: { | ||
| 945 | break :blk indent; | ||
| 946 | } else blk: { | ||
| 947 | try stream.writeByteNTimes(' ', new_indent); | ||
| 948 | break :blk new_indent; | ||
| 949 | }; | ||
| 950 | |||
| 951 | if (i + 1 < params.len) { | ||
| 952 | try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.None); | ||
| 953 | const comma = tree.nextToken(param_node.lastToken()); | ||
| 954 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // , | ||
| 955 | try renderExtraNewline(tree, stream, start_col, params[i + 1]); | ||
| 956 | } else { | ||
| 957 | try renderExpression(allocator, stream, tree, param_node_new_indent, start_col, param_node, Space.Comma); | ||
| 958 | try stream.writeByteNTimes(' ', indent); | ||
| 959 | return renderToken(tree, stream, call.rtoken, indent, start_col, space); | ||
| 960 | } | ||
| 961 | } | ||
| 962 | } | ||
| 963 | |||
| 964 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( | ||
| 965 | |||
| 966 | const params = call.params(); | ||
| 967 | for (params) |param_node, i| { | ||
| 968 | try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None); | ||
| 969 | |||
| 970 | if (i + 1 < params.len) { | ||
| 971 | const comma = tree.nextToken(param_node.lastToken()); | ||
| 972 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); | ||
| 973 | } | ||
| 974 | } | ||
| 975 | return renderToken(tree, stream, call.rtoken, indent, start_col, space); | ||
| 976 | }, | ||
| 977 | |||
| 978 | .SuffixOp => { | ||
| 979 | const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base); | ||
| 980 | |||
| 981 | switch (suffix_op.op) { | ||
| 678 | .ArrayAccess => |index_expr| { | 982 | .ArrayAccess => |index_expr| { |
| 679 | const lbracket = tree.nextToken(suffix_op.lhs.node.lastToken()); | 983 | const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); |
| 680 | const rbracket = tree.nextToken(index_expr.lastToken()); | 984 | const rbracket = tree.nextToken(index_expr.lastToken()); |
| 681 | 985 | ||
| 682 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 986 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 683 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ | 987 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ |
| 684 | 988 | ||
| 685 | const starts_with_comment = tree.tokens.at(lbracket + 1).id == .LineComment; | 989 | const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment; |
| 686 | const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; | 990 | const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment; |
| 687 | const new_indent = if (ends_with_comment) indent + indent_delta else indent; | 991 | const new_indent = if (ends_with_comment) indent + indent_delta else indent; |
| 688 | const new_space = if (ends_with_comment) Space.Newline else Space.None; | 992 | const new_space = if (ends_with_comment) Space.Newline else Space.None; |
| 689 | try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space); | 993 | try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space); |
| ... | @@ -697,18 +1001,18 @@ fn renderExpression( | ... | @@ -697,18 +1001,18 @@ fn renderExpression( |
| 697 | }, | 1001 | }, |
| 698 | 1002 | ||
| 699 | .Deref => { | 1003 | .Deref => { |
| 700 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 1004 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 701 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* | 1005 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* |
| 702 | }, | 1006 | }, |
| 703 | 1007 | ||
| 704 | .UnwrapOptional => { | 1008 | .UnwrapOptional => { |
| 705 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 1009 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 706 | try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . | 1010 | try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . |
| 707 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? | 1011 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? |
| 708 | }, | 1012 | }, |
| 709 | 1013 | ||
| 710 | .Slice => |range| { | 1014 | .Slice => |range| { |
| 711 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 1015 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 712 | 1016 | ||
| 713 | const lbracket = tree.prevToken(range.start.firstToken()); | 1017 | const lbracket = tree.prevToken(range.start.firstToken()); |
| 714 | const dotdot = tree.nextToken(range.start.lastToken()); | 1018 | const dotdot = tree.nextToken(range.start.lastToken()); |
| ... | @@ -733,269 +1037,6 @@ fn renderExpression( | ... | @@ -733,269 +1037,6 @@ fn renderExpression( |
| 733 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ] | 1037 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ] |
| 734 | }, | 1038 | }, |
| 735 | 1039 | ||
| 736 | .StructInitializer => |*field_inits| { | ||
| 737 | const lbrace = switch (suffix_op.lhs) { | ||
| 738 | .dot => |dot| tree.nextToken(dot), | ||
| 739 | .node => |node| tree.nextToken(node.lastToken()), | ||
| 740 | }; | ||
| 741 | |||
| 742 | if (field_inits.len == 0) { | ||
| 743 | switch (suffix_op.lhs) { | ||
| 744 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 745 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 746 | } | ||
| 747 | try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); | ||
| 748 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 749 | } | ||
| 750 | |||
| 751 | const src_has_trailing_comma = blk: { | ||
| 752 | const maybe_comma = tree.prevToken(suffix_op.rtoken); | ||
| 753 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | ||
| 754 | }; | ||
| 755 | |||
| 756 | const src_same_line = blk: { | ||
| 757 | const loc = tree.tokenLocation(tree.tokens.at(lbrace).end, suffix_op.rtoken); | ||
| 758 | break :blk loc.line == 0; | ||
| 759 | }; | ||
| 760 | |||
| 761 | const expr_outputs_one_line = blk: { | ||
| 762 | // render field expressions until a LF is found | ||
| 763 | var it = field_inits.iterator(0); | ||
| 764 | while (it.next()) |field_init| { | ||
| 765 | var find_stream = FindByteOutStream.init('\n'); | ||
| 766 | var dummy_col: usize = 0; | ||
| 767 | try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init.*, Space.None); | ||
| 768 | if (find_stream.byte_found) break :blk false; | ||
| 769 | } | ||
| 770 | break :blk true; | ||
| 771 | }; | ||
| 772 | |||
| 773 | if (field_inits.len == 1) blk: { | ||
| 774 | const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?; | ||
| 775 | |||
| 776 | if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| { | ||
| 777 | if (nested_suffix_op.op == .StructInitializer) { | ||
| 778 | break :blk; | ||
| 779 | } | ||
| 780 | } | ||
| 781 | |||
| 782 | // if the expression outputs to multiline, make this struct multiline | ||
| 783 | if (!expr_outputs_one_line or src_has_trailing_comma) { | ||
| 784 | break :blk; | ||
| 785 | } | ||
| 786 | |||
| 787 | switch (suffix_op.lhs) { | ||
| 788 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 789 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 790 | } | ||
| 791 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | ||
| 792 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); | ||
| 793 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 794 | } | ||
| 795 | |||
| 796 | if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { | ||
| 797 | // render all on one line, no trailing comma | ||
| 798 | switch (suffix_op.lhs) { | ||
| 799 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 800 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 801 | } | ||
| 802 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | ||
| 803 | |||
| 804 | var it = field_inits.iterator(0); | ||
| 805 | while (it.next()) |field_init| { | ||
| 806 | if (it.peek() != null) { | ||
| 807 | try renderExpression(allocator, stream, tree, indent, start_col, field_init.*, Space.None); | ||
| 808 | |||
| 809 | const comma = tree.nextToken(field_init.*.lastToken()); | ||
| 810 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); | ||
| 811 | } else { | ||
| 812 | try renderExpression(allocator, stream, tree, indent, start_col, field_init.*, Space.Space); | ||
| 813 | } | ||
| 814 | } | ||
| 815 | |||
| 816 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 817 | } | ||
| 818 | |||
| 819 | const new_indent = indent + indent_delta; | ||
| 820 | |||
| 821 | switch (suffix_op.lhs) { | ||
| 822 | .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None), | ||
| 823 | .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None), | ||
| 824 | } | ||
| 825 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); | ||
| 826 | |||
| 827 | var it = field_inits.iterator(0); | ||
| 828 | while (it.next()) |field_init| { | ||
| 829 | try stream.writeByteNTimes(' ', new_indent); | ||
| 830 | |||
| 831 | if (it.peek()) |next_field_init| { | ||
| 832 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init.*, Space.None); | ||
| 833 | |||
| 834 | const comma = tree.nextToken(field_init.*.lastToken()); | ||
| 835 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); | ||
| 836 | |||
| 837 | try renderExtraNewline(tree, stream, start_col, next_field_init.*); | ||
| 838 | } else { | ||
| 839 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init.*, Space.Comma); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | try stream.writeByteNTimes(' ', indent); | ||
| 844 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 845 | }, | ||
| 846 | |||
| 847 | .ArrayInitializer => |*exprs| { | ||
| 848 | const lbrace = switch (suffix_op.lhs) { | ||
| 849 | .dot => |dot| tree.nextToken(dot), | ||
| 850 | .node => |node| tree.nextToken(node.lastToken()), | ||
| 851 | }; | ||
| 852 | |||
| 853 | if (exprs.len == 0) { | ||
| 854 | switch (suffix_op.lhs) { | ||
| 855 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 856 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 857 | } | ||
| 858 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | ||
| 859 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 860 | } | ||
| 861 | if (exprs.len == 1 and tree.tokens.at(exprs.at(0).*.lastToken() + 1).id == .RBrace) { | ||
| 862 | const expr = exprs.at(0).*; | ||
| 863 | |||
| 864 | switch (suffix_op.lhs) { | ||
| 865 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 866 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 867 | } | ||
| 868 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | ||
| 869 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); | ||
| 870 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 871 | } | ||
| 872 | |||
| 873 | switch (suffix_op.lhs) { | ||
| 874 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | ||
| 875 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | ||
| 876 | } | ||
| 877 | |||
| 878 | // scan to find row size | ||
| 879 | const maybe_row_size: ?usize = blk: { | ||
| 880 | var count: usize = 1; | ||
| 881 | var it = exprs.iterator(0); | ||
| 882 | while (true) { | ||
| 883 | const expr = it.next().?.*; | ||
| 884 | if (it.peek()) |next_expr| { | ||
| 885 | const expr_last_token = expr.*.lastToken() + 1; | ||
| 886 | const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken()); | ||
| 887 | if (loc.line != 0) break :blk count; | ||
| 888 | count += 1; | ||
| 889 | } else { | ||
| 890 | const expr_last_token = expr.*.lastToken(); | ||
| 891 | const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, suffix_op.rtoken); | ||
| 892 | if (loc.line == 0) { | ||
| 893 | // all on one line | ||
| 894 | const src_has_trailing_comma = trailblk: { | ||
| 895 | const maybe_comma = tree.prevToken(suffix_op.rtoken); | ||
| 896 | break :trailblk tree.tokens.at(maybe_comma).id == .Comma; | ||
| 897 | }; | ||
| 898 | if (src_has_trailing_comma) { | ||
| 899 | break :blk 1; // force row size 1 | ||
| 900 | } else { | ||
| 901 | break :blk null; // no newlines | ||
| 902 | } | ||
| 903 | } | ||
| 904 | break :blk count; | ||
| 905 | } | ||
| 906 | } | ||
| 907 | }; | ||
| 908 | |||
| 909 | if (maybe_row_size) |row_size| { | ||
| 910 | // A place to store the width of each expression and its column's maximum | ||
| 911 | var widths = try allocator.alloc(usize, exprs.len + row_size); | ||
| 912 | defer allocator.free(widths); | ||
| 913 | mem.set(usize, widths, 0); | ||
| 914 | |||
| 915 | var expr_widths = widths[0 .. widths.len - row_size]; | ||
| 916 | var column_widths = widths[widths.len - row_size ..]; | ||
| 917 | |||
| 918 | // Null stream for counting the printed length of each expression | ||
| 919 | var counting_stream = std.io.countingOutStream(std.io.null_out_stream); | ||
| 920 | |||
| 921 | var it = exprs.iterator(0); | ||
| 922 | var i: usize = 0; | ||
| 923 | |||
| 924 | while (it.next()) |expr| : (i += 1) { | ||
| 925 | counting_stream.bytes_written = 0; | ||
| 926 | var dummy_col: usize = 0; | ||
| 927 | try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr.*, Space.None); | ||
| 928 | const width = @intCast(usize, counting_stream.bytes_written); | ||
| 929 | const col = i % row_size; | ||
| 930 | column_widths[col] = std.math.max(column_widths[col], width); | ||
| 931 | expr_widths[i] = width; | ||
| 932 | } | ||
| 933 | |||
| 934 | var new_indent = indent + indent_delta; | ||
| 935 | |||
| 936 | if (tree.tokens.at(tree.nextToken(lbrace)).id != .MultilineStringLiteralLine) { | ||
| 937 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); | ||
| 938 | try stream.writeByteNTimes(' ', new_indent); | ||
| 939 | } else { | ||
| 940 | new_indent -= indent_delta; | ||
| 941 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None); | ||
| 942 | } | ||
| 943 | |||
| 944 | it.set(0); | ||
| 945 | i = 0; | ||
| 946 | var col: usize = 1; | ||
| 947 | while (it.next()) |expr| : (i += 1) { | ||
| 948 | if (it.peek()) |next_expr| { | ||
| 949 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr.*, Space.None); | ||
| 950 | |||
| 951 | const comma = tree.nextToken(expr.*.lastToken()); | ||
| 952 | |||
| 953 | if (col != row_size) { | ||
| 954 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // , | ||
| 955 | |||
| 956 | const padding = column_widths[i % row_size] - expr_widths[i]; | ||
| 957 | try stream.writeByteNTimes(' ', padding); | ||
| 958 | |||
| 959 | col += 1; | ||
| 960 | continue; | ||
| 961 | } | ||
| 962 | col = 1; | ||
| 963 | |||
| 964 | if (tree.tokens.at(tree.nextToken(comma)).id != .MultilineStringLiteralLine) { | ||
| 965 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // , | ||
| 966 | } else { | ||
| 967 | try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // , | ||
| 968 | } | ||
| 969 | |||
| 970 | try renderExtraNewline(tree, stream, start_col, next_expr.*); | ||
| 971 | if (next_expr.*.id != .MultilineStringLiteral) { | ||
| 972 | try stream.writeByteNTimes(' ', new_indent); | ||
| 973 | } | ||
| 974 | } else { | ||
| 975 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr.*, Space.Comma); // , | ||
| 976 | } | ||
| 977 | } | ||
| 978 | const last_node = it.prev().?; | ||
| 979 | if (last_node.*.id != .MultilineStringLiteral) { | ||
| 980 | try stream.writeByteNTimes(' ', indent); | ||
| 981 | } | ||
| 982 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 983 | } else { | ||
| 984 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | ||
| 985 | var it = exprs.iterator(0); | ||
| 986 | while (it.next()) |expr| { | ||
| 987 | if (it.peek()) |next_expr| { | ||
| 988 | try renderExpression(allocator, stream, tree, indent, start_col, expr.*, Space.None); | ||
| 989 | const comma = tree.nextToken(expr.*.lastToken()); | ||
| 990 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , | ||
| 991 | } else { | ||
| 992 | try renderExpression(allocator, stream, tree, indent, start_col, expr.*, Space.Space); | ||
| 993 | } | ||
| 994 | } | ||
| 995 | |||
| 996 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | ||
| 997 | } | ||
| 998 | }, | ||
| 999 | } | 1040 | } |
| 1000 | }, | 1041 | }, |
| 1001 | 1042 | ||
| ... | @@ -1179,7 +1220,7 @@ fn renderExpression( | ... | @@ -1179,7 +1220,7 @@ fn renderExpression( |
| 1179 | }, | 1220 | }, |
| 1180 | } | 1221 | } |
| 1181 | 1222 | ||
| 1182 | if (container_decl.fields_and_decls.len == 0) { | 1223 | if (container_decl.fields_and_decls_len == 0) { |
| 1183 | try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // { | 1224 | try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // { |
| 1184 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } | 1225 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } |
| 1185 | } | 1226 | } |
| ... | @@ -1188,23 +1229,24 @@ fn renderExpression( | ... | @@ -1188,23 +1229,24 @@ fn renderExpression( |
| 1188 | var maybe_comma = tree.prevToken(container_decl.lastToken()); | 1229 | var maybe_comma = tree.prevToken(container_decl.lastToken()); |
| 1189 | // Doc comments for a field may also appear after the comma, eg. | 1230 | // Doc comments for a field may also appear after the comma, eg. |
| 1190 | // field_name: T, // comment attached to field_name | 1231 | // field_name: T, // comment attached to field_name |
| 1191 | if (tree.tokens.at(maybe_comma).id == .DocComment) | 1232 | if (tree.token_ids[maybe_comma] == .DocComment) |
| 1192 | maybe_comma = tree.prevToken(maybe_comma); | 1233 | maybe_comma = tree.prevToken(maybe_comma); |
| 1193 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | 1234 | break :blk tree.token_ids[maybe_comma] == .Comma; |
| 1194 | }; | 1235 | }; |
| 1195 | 1236 | ||
| 1237 | const fields_and_decls = container_decl.fieldsAndDecls(); | ||
| 1238 | |||
| 1196 | // Check if the first declaration and the { are on the same line | 1239 | // Check if the first declaration and the { are on the same line |
| 1197 | const src_has_newline = !tree.tokensOnSameLine( | 1240 | const src_has_newline = !tree.tokensOnSameLine( |
| 1198 | container_decl.lbrace_token, | 1241 | container_decl.lbrace_token, |
| 1199 | container_decl.fields_and_decls.at(0).*.firstToken(), | 1242 | fields_and_decls[0].firstToken(), |
| 1200 | ); | 1243 | ); |
| 1201 | 1244 | ||
| 1202 | // We can only print all the elements in-line if all the | 1245 | // We can only print all the elements in-line if all the |
| 1203 | // declarations inside are fields | 1246 | // declarations inside are fields |
| 1204 | const src_has_only_fields = blk: { | 1247 | const src_has_only_fields = blk: { |
| 1205 | var it = container_decl.fields_and_decls.iterator(0); | 1248 | for (fields_and_decls) |decl| { |
| 1206 | while (it.next()) |decl| { | 1249 | if (decl.id != .ContainerField) break :blk false; |
| 1207 | if (decl.*.id != .ContainerField) break :blk false; | ||
| 1208 | } | 1250 | } |
| 1209 | break :blk true; | 1251 | break :blk true; |
| 1210 | }; | 1252 | }; |
| ... | @@ -1214,13 +1256,12 @@ fn renderExpression( | ... | @@ -1214,13 +1256,12 @@ fn renderExpression( |
| 1214 | const new_indent = indent + indent_delta; | 1256 | const new_indent = indent + indent_delta; |
| 1215 | try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // { | 1257 | try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // { |
| 1216 | 1258 | ||
| 1217 | var it = container_decl.fields_and_decls.iterator(0); | 1259 | for (fields_and_decls) |decl, i| { |
| 1218 | while (it.next()) |decl| { | ||
| 1219 | try stream.writeByteNTimes(' ', new_indent); | 1260 | try stream.writeByteNTimes(' ', new_indent); |
| 1220 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, .Newline); | 1261 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, .Newline); |
| 1221 | 1262 | ||
| 1222 | if (it.peek()) |next_decl| { | 1263 | if (i + 1 < fields_and_decls.len) { |
| 1223 | try renderExtraNewline(tree, stream, start_col, next_decl.*); | 1264 | try renderExtraNewline(tree, stream, start_col, fields_and_decls[i + 1]); |
| 1224 | } | 1265 | } |
| 1225 | } | 1266 | } |
| 1226 | 1267 | ||
| ... | @@ -1233,10 +1274,9 @@ fn renderExpression( | ... | @@ -1233,10 +1274,9 @@ fn renderExpression( |
| 1233 | const new_indent = indent + indent_delta; | 1274 | const new_indent = indent + indent_delta; |
| 1234 | try stream.writeByteNTimes(' ', new_indent); | 1275 | try stream.writeByteNTimes(' ', new_indent); |
| 1235 | 1276 | ||
| 1236 | var it = container_decl.fields_and_decls.iterator(0); | 1277 | for (fields_and_decls) |decl, i| { |
| 1237 | while (it.next()) |decl| { | 1278 | const space_after_decl: Space = if (i + 1 >= fields_and_decls.len) .Newline else .Space; |
| 1238 | const space_after_decl: Space = if (it.peek() == null) .Newline else .Space; | 1279 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl, space_after_decl); |
| 1239 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, space_after_decl); | ||
| 1240 | } | 1280 | } |
| 1241 | 1281 | ||
| 1242 | try stream.writeByteNTimes(' ', indent); | 1282 | try stream.writeByteNTimes(' ', indent); |
| ... | @@ -1244,9 +1284,8 @@ fn renderExpression( | ... | @@ -1244,9 +1284,8 @@ fn renderExpression( |
| 1244 | // All the declarations on the same line | 1284 | // All the declarations on the same line |
| 1245 | try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // { | 1285 | try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // { |
| 1246 | 1286 | ||
| 1247 | var it = container_decl.fields_and_decls.iterator(0); | 1287 | for (fields_and_decls) |decl| { |
| 1248 | while (it.next()) |decl| { | 1288 | try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Space); |
| 1249 | try renderContainerDecl(allocator, stream, tree, indent, start_col, decl.*, .Space); | ||
| 1250 | } | 1289 | } |
| 1251 | } | 1290 | } |
| 1252 | 1291 | ||
| ... | @@ -1258,14 +1297,14 @@ fn renderExpression( | ... | @@ -1258,14 +1297,14 @@ fn renderExpression( |
| 1258 | 1297 | ||
| 1259 | const lbrace = tree.nextToken(err_set_decl.error_token); | 1298 | const lbrace = tree.nextToken(err_set_decl.error_token); |
| 1260 | 1299 | ||
| 1261 | if (err_set_decl.decls.len == 0) { | 1300 | if (err_set_decl.decls_len == 0) { |
| 1262 | try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); | 1301 | try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); |
| 1263 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | 1302 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); |
| 1264 | return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); | 1303 | return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); |
| 1265 | } | 1304 | } |
| 1266 | 1305 | ||
| 1267 | if (err_set_decl.decls.len == 1) blk: { | 1306 | if (err_set_decl.decls_len == 1) blk: { |
| 1268 | const node = err_set_decl.decls.at(0).*; | 1307 | const node = err_set_decl.decls()[0]; |
| 1269 | 1308 | ||
| 1270 | // if there are any doc comments or same line comments | 1309 | // if there are any doc comments or same line comments |
| 1271 | // don't try to put it all on one line | 1310 | // don't try to put it all on one line |
| ... | @@ -1285,24 +1324,24 @@ fn renderExpression( | ... | @@ -1285,24 +1324,24 @@ fn renderExpression( |
| 1285 | 1324 | ||
| 1286 | const src_has_trailing_comma = blk: { | 1325 | const src_has_trailing_comma = blk: { |
| 1287 | const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); | 1326 | const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); |
| 1288 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | 1327 | break :blk tree.token_ids[maybe_comma] == .Comma; |
| 1289 | }; | 1328 | }; |
| 1290 | 1329 | ||
| 1291 | if (src_has_trailing_comma) { | 1330 | if (src_has_trailing_comma) { |
| 1292 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { | 1331 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { |
| 1293 | const new_indent = indent + indent_delta; | 1332 | const new_indent = indent + indent_delta; |
| 1294 | 1333 | ||
| 1295 | var it = err_set_decl.decls.iterator(0); | 1334 | const decls = err_set_decl.decls(); |
| 1296 | while (it.next()) |node| { | 1335 | for (decls) |node, i| { |
| 1297 | try stream.writeByteNTimes(' ', new_indent); | 1336 | try stream.writeByteNTimes(' ', new_indent); |
| 1298 | 1337 | ||
| 1299 | if (it.peek()) |next_node| { | 1338 | if (i + 1 < decls.len) { |
| 1300 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); | 1339 | try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None); |
| 1301 | try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , | 1340 | try renderToken(tree, stream, tree.nextToken(node.lastToken()), new_indent, start_col, Space.Newline); // , |
| 1302 | 1341 | ||
| 1303 | try renderExtraNewline(tree, stream, start_col, next_node.*); | 1342 | try renderExtraNewline(tree, stream, start_col, decls[i + 1]); |
| 1304 | } else { | 1343 | } else { |
| 1305 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); | 1344 | try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma); |
| 1306 | } | 1345 | } |
| 1307 | } | 1346 | } |
| 1308 | 1347 | ||
| ... | @@ -1311,17 +1350,17 @@ fn renderExpression( | ... | @@ -1311,17 +1350,17 @@ fn renderExpression( |
| 1311 | } else { | 1350 | } else { |
| 1312 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // { | 1351 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // { |
| 1313 | 1352 | ||
| 1314 | var it = err_set_decl.decls.iterator(0); | 1353 | const decls = err_set_decl.decls(); |
| 1315 | while (it.next()) |node| { | 1354 | for (decls) |node, i| { |
| 1316 | if (it.peek()) |next_node| { | 1355 | if (i + 1 < decls.len) { |
| 1317 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); | 1356 | try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None); |
| 1318 | 1357 | ||
| 1319 | const comma_token = tree.nextToken(node.*.lastToken()); | 1358 | const comma_token = tree.nextToken(node.lastToken()); |
| 1320 | assert(tree.tokens.at(comma_token).id == .Comma); | 1359 | assert(tree.token_ids[comma_token] == .Comma); |
| 1321 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , | 1360 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , |
| 1322 | try renderExtraNewline(tree, stream, start_col, next_node.*); | 1361 | try renderExtraNewline(tree, stream, start_col, decls[i + 1]); |
| 1323 | } else { | 1362 | } else { |
| 1324 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space); | 1363 | try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space); |
| 1325 | } | 1364 | } |
| 1326 | } | 1365 | } |
| 1327 | 1366 | ||
| ... | @@ -1342,14 +1381,12 @@ fn renderExpression( | ... | @@ -1342,14 +1381,12 @@ fn renderExpression( |
| 1342 | const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base); | 1381 | const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base); |
| 1343 | 1382 | ||
| 1344 | var skip_first_indent = true; | 1383 | var skip_first_indent = true; |
| 1345 | if (tree.tokens.at(multiline_str_literal.firstToken() - 1).id != .LineComment) { | 1384 | if (tree.token_ids[multiline_str_literal.firstToken() - 1] != .LineComment) { |
| 1346 | try stream.print("\n", .{}); | 1385 | try stream.print("\n", .{}); |
| 1347 | skip_first_indent = false; | 1386 | skip_first_indent = false; |
| 1348 | } | 1387 | } |
| 1349 | 1388 | ||
| 1350 | var i: usize = 0; | 1389 | for (multiline_str_literal.lines()) |t| { |
| 1351 | while (i < multiline_str_literal.lines.len) : (i += 1) { | ||
| 1352 | const t = multiline_str_literal.lines.at(i).*; | ||
| 1353 | if (!skip_first_indent) { | 1390 | if (!skip_first_indent) { |
| 1354 | try stream.writeByteNTimes(' ', indent + indent_delta); | 1391 | try stream.writeByteNTimes(' ', indent + indent_delta); |
| 1355 | } | 1392 | } |
| ... | @@ -1369,10 +1406,10 @@ fn renderExpression( | ... | @@ -1369,10 +1406,10 @@ fn renderExpression( |
| 1369 | try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name | 1406 | try renderToken(tree, stream, builtin_call.builtin_token, indent, start_col, Space.None); // @name |
| 1370 | 1407 | ||
| 1371 | const src_params_trailing_comma = blk: { | 1408 | const src_params_trailing_comma = blk: { |
| 1372 | if (builtin_call.params.len < 2) break :blk false; | 1409 | if (builtin_call.params_len < 2) break :blk false; |
| 1373 | const last_node = builtin_call.params.at(builtin_call.params.len - 1).*; | 1410 | const last_node = builtin_call.params()[builtin_call.params_len - 1]; |
| 1374 | const maybe_comma = tree.nextToken(last_node.lastToken()); | 1411 | const maybe_comma = tree.nextToken(last_node.lastToken()); |
| 1375 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | 1412 | break :blk tree.token_ids[maybe_comma] == .Comma; |
| 1376 | }; | 1413 | }; |
| 1377 | 1414 | ||
| 1378 | const lparen = tree.nextToken(builtin_call.builtin_token); | 1415 | const lparen = tree.nextToken(builtin_call.builtin_token); |
| ... | @@ -1381,12 +1418,12 @@ fn renderExpression( | ... | @@ -1381,12 +1418,12 @@ fn renderExpression( |
| 1381 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( | 1418 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( |
| 1382 | 1419 | ||
| 1383 | // render all on one line, no trailing comma | 1420 | // render all on one line, no trailing comma |
| 1384 | var it = builtin_call.params.iterator(0); | 1421 | const params = builtin_call.params(); |
| 1385 | while (it.next()) |param_node| { | 1422 | for (params) |param_node, i| { |
| 1386 | try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.None); | 1423 | try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.None); |
| 1387 | 1424 | ||
| 1388 | if (it.peek() != null) { | 1425 | if (i + 1 < params.len) { |
| 1389 | const comma_token = tree.nextToken(param_node.*.lastToken()); | 1426 | const comma_token = tree.nextToken(param_node.lastToken()); |
| 1390 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , | 1427 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , |
| 1391 | } | 1428 | } |
| 1392 | } | 1429 | } |
| ... | @@ -1395,10 +1432,9 @@ fn renderExpression( | ... | @@ -1395,10 +1432,9 @@ fn renderExpression( |
| 1395 | const new_indent = indent + indent_delta; | 1432 | const new_indent = indent + indent_delta; |
| 1396 | try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // ( | 1433 | try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // ( |
| 1397 | 1434 | ||
| 1398 | var it = builtin_call.params.iterator(0); | 1435 | for (builtin_call.params()) |param_node| { |
| 1399 | while (it.next()) |param_node| { | ||
| 1400 | try stream.writeByteNTimes(' ', new_indent); | 1436 | try stream.writeByteNTimes(' ', new_indent); |
| 1401 | try renderExpression(allocator, stream, tree, indent, start_col, param_node.*, Space.Comma); | 1437 | try renderExpression(allocator, stream, tree, indent, start_col, param_node, Space.Comma); |
| 1402 | } | 1438 | } |
| 1403 | try stream.writeByteNTimes(' ', indent); | 1439 | try stream.writeByteNTimes(' ', indent); |
| 1404 | } | 1440 | } |
| ... | @@ -1410,8 +1446,8 @@ fn renderExpression( | ... | @@ -1410,8 +1446,8 @@ fn renderExpression( |
| 1410 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base); | 1446 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base); |
| 1411 | 1447 | ||
| 1412 | if (fn_proto.visib_token) |visib_token_index| { | 1448 | if (fn_proto.visib_token) |visib_token_index| { |
| 1413 | const visib_token = tree.tokens.at(visib_token_index); | 1449 | const visib_token = tree.token_ids[visib_token_index]; |
| 1414 | assert(visib_token.id == .Keyword_pub or visib_token.id == .Keyword_export); | 1450 | assert(visib_token == .Keyword_pub or visib_token == .Keyword_export); |
| 1415 | 1451 | ||
| 1416 | try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub | 1452 | try renderToken(tree, stream, visib_token_index, indent, start_col, Space.Space); // pub |
| 1417 | } | 1453 | } |
| ... | @@ -1433,7 +1469,7 @@ fn renderExpression( | ... | @@ -1433,7 +1469,7 @@ fn renderExpression( |
| 1433 | try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn | 1469 | try renderToken(tree, stream, fn_proto.fn_token, indent, start_col, Space.Space); // fn |
| 1434 | break :blk tree.nextToken(fn_proto.fn_token); | 1470 | break :blk tree.nextToken(fn_proto.fn_token); |
| 1435 | }; | 1471 | }; |
| 1436 | assert(tree.tokens.at(lparen).id == .LParen); | 1472 | assert(tree.token_ids[lparen] == .LParen); |
| 1437 | 1473 | ||
| 1438 | const rparen = tree.prevToken( | 1474 | const rparen = tree.prevToken( |
| 1439 | // the first token for the annotation expressions is the left | 1475 | // the first token for the annotation expressions is the left |
| ... | @@ -1449,10 +1485,10 @@ fn renderExpression( | ... | @@ -1449,10 +1485,10 @@ fn renderExpression( |
| 1449 | .InferErrorSet => |node| tree.prevToken(node.firstToken()), | 1485 | .InferErrorSet => |node| tree.prevToken(node.firstToken()), |
| 1450 | .Invalid => unreachable, | 1486 | .Invalid => unreachable, |
| 1451 | }); | 1487 | }); |
| 1452 | assert(tree.tokens.at(rparen).id == .RParen); | 1488 | assert(tree.token_ids[rparen] == .RParen); |
| 1453 | 1489 | ||
| 1454 | const src_params_trailing_comma = blk: { | 1490 | const src_params_trailing_comma = blk: { |
| 1455 | const maybe_comma = tree.tokens.at(rparen - 1).id; | 1491 | const maybe_comma = tree.token_ids[rparen - 1]; |
| 1456 | break :blk maybe_comma == .Comma or maybe_comma == .LineComment; | 1492 | break :blk maybe_comma == .Comma or maybe_comma == .LineComment; |
| 1457 | }; | 1493 | }; |
| 1458 | 1494 | ||
| ... | @@ -1460,12 +1496,11 @@ fn renderExpression( | ... | @@ -1460,12 +1496,11 @@ fn renderExpression( |
| 1460 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( | 1496 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); // ( |
| 1461 | 1497 | ||
| 1462 | // render all on one line, no trailing comma | 1498 | // render all on one line, no trailing comma |
| 1463 | var it = fn_proto.params.iterator(0); | 1499 | for (fn_proto.params()) |param_decl, i| { |
| 1464 | while (it.next()) |param_decl_node| { | 1500 | try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl, Space.None); |
| 1465 | try renderParamDecl(allocator, stream, tree, indent, start_col, param_decl_node.*, Space.None); | ||
| 1466 | 1501 | ||
| 1467 | if (it.peek() != null) { | 1502 | if (i + 1 < fn_proto.params_len) { |
| 1468 | const comma = tree.nextToken(param_decl_node.*.lastToken()); | 1503 | const comma = tree.nextToken(param_decl.lastToken()); |
| 1469 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , | 1504 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , |
| 1470 | } | 1505 | } |
| 1471 | } | 1506 | } |
| ... | @@ -1474,10 +1509,9 @@ fn renderExpression( | ... | @@ -1474,10 +1509,9 @@ fn renderExpression( |
| 1474 | const new_indent = indent + indent_delta; | 1509 | const new_indent = indent + indent_delta; |
| 1475 | try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // ( | 1510 | try renderToken(tree, stream, lparen, new_indent, start_col, Space.Newline); // ( |
| 1476 | 1511 | ||
| 1477 | var it = fn_proto.params.iterator(0); | 1512 | for (fn_proto.params()) |param_decl| { |
| 1478 | while (it.next()) |param_decl_node| { | ||
| 1479 | try stream.writeByteNTimes(' ', new_indent); | 1513 | try stream.writeByteNTimes(' ', new_indent); |
| 1480 | try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl_node.*, Space.Comma); | 1514 | try renderParamDecl(allocator, stream, tree, new_indent, start_col, param_decl, Space.Comma); |
| 1481 | } | 1515 | } |
| 1482 | try stream.writeByteNTimes(' ', indent); | 1516 | try stream.writeByteNTimes(' ', indent); |
| 1483 | } | 1517 | } |
| ... | @@ -1556,7 +1590,7 @@ fn renderExpression( | ... | @@ -1556,7 +1590,7 @@ fn renderExpression( |
| 1556 | const rparen = tree.nextToken(switch_node.expr.lastToken()); | 1590 | const rparen = tree.nextToken(switch_node.expr.lastToken()); |
| 1557 | const lbrace = tree.nextToken(rparen); | 1591 | const lbrace = tree.nextToken(rparen); |
| 1558 | 1592 | ||
| 1559 | if (switch_node.cases.len == 0) { | 1593 | if (switch_node.cases_len == 0) { |
| 1560 | try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None); | 1594 | try renderExpression(allocator, stream, tree, indent, start_col, switch_node.expr, Space.None); |
| 1561 | try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // ) | 1595 | try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // ) |
| 1562 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // { | 1596 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); // { |
| ... | @@ -1570,13 +1604,13 @@ fn renderExpression( | ... | @@ -1570,13 +1604,13 @@ fn renderExpression( |
| 1570 | try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // ) | 1604 | try renderToken(tree, stream, rparen, indent, start_col, Space.Space); // ) |
| 1571 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // { | 1605 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); // { |
| 1572 | 1606 | ||
| 1573 | var it = switch_node.cases.iterator(0); | 1607 | const cases = switch_node.cases(); |
| 1574 | while (it.next()) |node| { | 1608 | for (cases) |node, i| { |
| 1575 | try stream.writeByteNTimes(' ', new_indent); | 1609 | try stream.writeByteNTimes(' ', new_indent); |
| 1576 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); | 1610 | try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.Comma); |
| 1577 | 1611 | ||
| 1578 | if (it.peek()) |next_node| { | 1612 | if (i + 1 < cases.len) { |
| 1579 | try renderExtraNewline(tree, stream, start_col, next_node.*); | 1613 | try renderExtraNewline(tree, stream, start_col, cases[i + 1]); |
| 1580 | } | 1614 | } |
| 1581 | } | 1615 | } |
| 1582 | 1616 | ||
| ... | @@ -1587,38 +1621,38 @@ fn renderExpression( | ... | @@ -1587,38 +1621,38 @@ fn renderExpression( |
| 1587 | .SwitchCase => { | 1621 | .SwitchCase => { |
| 1588 | const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base); | 1622 | const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base); |
| 1589 | 1623 | ||
| 1590 | assert(switch_case.items.len != 0); | 1624 | assert(switch_case.items_len != 0); |
| 1591 | const src_has_trailing_comma = blk: { | 1625 | const src_has_trailing_comma = blk: { |
| 1592 | const last_node = switch_case.items.at(switch_case.items.len - 1).*; | 1626 | const last_node = switch_case.items()[switch_case.items_len - 1]; |
| 1593 | const maybe_comma = tree.nextToken(last_node.lastToken()); | 1627 | const maybe_comma = tree.nextToken(last_node.lastToken()); |
| 1594 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | 1628 | break :blk tree.token_ids[maybe_comma] == .Comma; |
| 1595 | }; | 1629 | }; |
| 1596 | 1630 | ||
| 1597 | if (switch_case.items.len == 1 or !src_has_trailing_comma) { | 1631 | if (switch_case.items_len == 1 or !src_has_trailing_comma) { |
| 1598 | var it = switch_case.items.iterator(0); | 1632 | const items = switch_case.items(); |
| 1599 | while (it.next()) |node| { | 1633 | for (items) |node, i| { |
| 1600 | if (it.peek()) |next_node| { | 1634 | if (i + 1 < items.len) { |
| 1601 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); | 1635 | try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None); |
| 1602 | 1636 | ||
| 1603 | const comma_token = tree.nextToken(node.*.lastToken()); | 1637 | const comma_token = tree.nextToken(node.lastToken()); |
| 1604 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , | 1638 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , |
| 1605 | try renderExtraNewline(tree, stream, start_col, next_node.*); | 1639 | try renderExtraNewline(tree, stream, start_col, items[i + 1]); |
| 1606 | } else { | 1640 | } else { |
| 1607 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space); | 1641 | try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Space); |
| 1608 | } | 1642 | } |
| 1609 | } | 1643 | } |
| 1610 | } else { | 1644 | } else { |
| 1611 | var it = switch_case.items.iterator(0); | 1645 | const items = switch_case.items(); |
| 1612 | while (it.next()) |node| { | 1646 | for (items) |node, i| { |
| 1613 | if (it.peek()) |next_node| { | 1647 | if (i + 1 < items.len) { |
| 1614 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); | 1648 | try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None); |
| 1615 | 1649 | ||
| 1616 | const comma_token = tree.nextToken(node.*.lastToken()); | 1650 | const comma_token = tree.nextToken(node.lastToken()); |
| 1617 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // , | 1651 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Newline); // , |
| 1618 | try renderExtraNewline(tree, stream, start_col, next_node.*); | 1652 | try renderExtraNewline(tree, stream, start_col, items[i + 1]); |
| 1619 | try stream.writeByteNTimes(' ', indent); | 1653 | try stream.writeByteNTimes(' ', indent); |
| 1620 | } else { | 1654 | } else { |
| 1621 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma); | 1655 | try renderExpression(allocator, stream, tree, indent, start_col, node, Space.Comma); |
| 1622 | try stream.writeByteNTimes(' ', indent); | 1656 | try stream.writeByteNTimes(' ', indent); |
| 1623 | } | 1657 | } |
| 1624 | } | 1658 | } |
| ... | @@ -1918,34 +1952,31 @@ fn renderExpression( | ... | @@ -1918,34 +1952,31 @@ fn renderExpression( |
| 1918 | } else blk: { | 1952 | } else blk: { |
| 1919 | try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // : | 1953 | try renderToken(tree, stream, colon1, indent, start_col, Space.Space); // : |
| 1920 | 1954 | ||
| 1921 | var it = asm_node.outputs.iterator(0); | 1955 | for (asm_node.outputs) |*asm_output, i| { |
| 1922 | while (true) { | 1956 | if (i + 1 < asm_node.outputs.len) { |
| 1923 | const asm_output = it.next().?; | 1957 | const next_asm_output = asm_node.outputs[i + 1]; |
| 1924 | const node = &(asm_output.*).base; | 1958 | try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.None); |
| 1925 | 1959 | ||
| 1926 | if (it.peek()) |next_asm_output| { | 1960 | const comma = tree.prevToken(next_asm_output.firstToken()); |
| 1927 | try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None); | ||
| 1928 | const next_node = &(next_asm_output.*).base; | ||
| 1929 | |||
| 1930 | const comma = tree.prevToken(next_asm_output.*.firstToken()); | ||
| 1931 | try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // , | 1961 | try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // , |
| 1932 | try renderExtraNewline(tree, stream, start_col, next_node); | 1962 | try renderExtraNewlineToken(tree, stream, start_col, next_asm_output.firstToken()); |
| 1933 | 1963 | ||
| 1934 | try stream.writeByteNTimes(' ', indent_extra); | 1964 | try stream.writeByteNTimes(' ', indent_extra); |
| 1935 | } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) { | 1965 | } else if (asm_node.inputs.len == 0 and asm_node.clobbers.len == 0) { |
| 1936 | try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline); | 1966 | try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline); |
| 1937 | try stream.writeByteNTimes(' ', indent); | 1967 | try stream.writeByteNTimes(' ', indent); |
| 1938 | return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); | 1968 | return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); |
| 1939 | } else { | 1969 | } else { |
| 1940 | try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline); | 1970 | try renderAsmOutput(allocator, stream, tree, indent_extra, start_col, asm_output, Space.Newline); |
| 1941 | try stream.writeByteNTimes(' ', indent_once); | 1971 | try stream.writeByteNTimes(' ', indent_once); |
| 1942 | const comma_or_colon = tree.nextToken(node.lastToken()); | 1972 | const comma_or_colon = tree.nextToken(asm_output.lastToken()); |
| 1943 | break :blk switch (tree.tokens.at(comma_or_colon).id) { | 1973 | break :blk switch (tree.token_ids[comma_or_colon]) { |
| 1944 | .Comma => tree.nextToken(comma_or_colon), | 1974 | .Comma => tree.nextToken(comma_or_colon), |
| 1945 | else => comma_or_colon, | 1975 | else => comma_or_colon, |
| 1946 | }; | 1976 | }; |
| 1947 | } | 1977 | } |
| 1948 | } | 1978 | } |
| 1979 | unreachable; | ||
| 1949 | }; | 1980 | }; |
| 1950 | 1981 | ||
| 1951 | const colon3 = if (asm_node.inputs.len == 0) blk: { | 1982 | const colon3 = if (asm_node.inputs.len == 0) blk: { |
| ... | @@ -1956,43 +1987,37 @@ fn renderExpression( | ... | @@ -1956,43 +1987,37 @@ fn renderExpression( |
| 1956 | } else blk: { | 1987 | } else blk: { |
| 1957 | try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // : | 1988 | try renderToken(tree, stream, colon2, indent, start_col, Space.Space); // : |
| 1958 | 1989 | ||
| 1959 | var it = asm_node.inputs.iterator(0); | 1990 | for (asm_node.inputs) |*asm_input, i| { |
| 1960 | while (true) { | 1991 | if (i + 1 < asm_node.inputs.len) { |
| 1961 | const asm_input = it.next().?; | 1992 | const next_asm_input = &asm_node.inputs[i + 1]; |
| 1962 | const node = &(asm_input.*).base; | 1993 | try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.None); |
| 1963 | |||
| 1964 | if (it.peek()) |next_asm_input| { | ||
| 1965 | try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.None); | ||
| 1966 | const next_node = &(next_asm_input.*).base; | ||
| 1967 | 1994 | ||
| 1968 | const comma = tree.prevToken(next_asm_input.*.firstToken()); | 1995 | const comma = tree.prevToken(next_asm_input.firstToken()); |
| 1969 | try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // , | 1996 | try renderToken(tree, stream, comma, indent_extra, start_col, Space.Newline); // , |
| 1970 | try renderExtraNewline(tree, stream, start_col, next_node); | 1997 | try renderExtraNewlineToken(tree, stream, start_col, next_asm_input.firstToken()); |
| 1971 | 1998 | ||
| 1972 | try stream.writeByteNTimes(' ', indent_extra); | 1999 | try stream.writeByteNTimes(' ', indent_extra); |
| 1973 | } else if (asm_node.clobbers.len == 0) { | 2000 | } else if (asm_node.clobbers.len == 0) { |
| 1974 | try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline); | 2001 | try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline); |
| 1975 | try stream.writeByteNTimes(' ', indent); | 2002 | try stream.writeByteNTimes(' ', indent); |
| 1976 | return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // ) | 2003 | return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); // ) |
| 1977 | } else { | 2004 | } else { |
| 1978 | try renderExpression(allocator, stream, tree, indent_extra, start_col, node, Space.Newline); | 2005 | try renderAsmInput(allocator, stream, tree, indent_extra, start_col, asm_input, Space.Newline); |
| 1979 | try stream.writeByteNTimes(' ', indent_once); | 2006 | try stream.writeByteNTimes(' ', indent_once); |
| 1980 | const comma_or_colon = tree.nextToken(node.lastToken()); | 2007 | const comma_or_colon = tree.nextToken(asm_input.lastToken()); |
| 1981 | break :blk switch (tree.tokens.at(comma_or_colon).id) { | 2008 | break :blk switch (tree.token_ids[comma_or_colon]) { |
| 1982 | .Comma => tree.nextToken(comma_or_colon), | 2009 | .Comma => tree.nextToken(comma_or_colon), |
| 1983 | else => comma_or_colon, | 2010 | else => comma_or_colon, |
| 1984 | }; | 2011 | }; |
| 1985 | } | 2012 | } |
| 1986 | } | 2013 | } |
| 2014 | unreachable; | ||
| 1987 | }; | 2015 | }; |
| 1988 | 2016 | ||
| 1989 | try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // : | 2017 | try renderToken(tree, stream, colon3, indent, start_col, Space.Space); // : |
| 1990 | 2018 | ||
| 1991 | var it = asm_node.clobbers.iterator(0); | 2019 | for (asm_node.clobbers) |clobber_node, i| { |
| 1992 | while (true) { | 2020 | if (i + 1 >= asm_node.clobbers.len) { |
| 1993 | const clobber_node = it.next().?.*; | ||
| 1994 | |||
| 1995 | if (it.peek() == null) { | ||
| 1996 | try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline); | 2021 | try renderExpression(allocator, stream, tree, indent_extra, start_col, clobber_node, Space.Newline); |
| 1997 | try stream.writeByteNTimes(' ', indent); | 2022 | try stream.writeByteNTimes(' ', indent); |
| 1998 | return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); | 2023 | return renderToken(tree, stream, asm_node.rparen, indent, start_col, space); |
| ... | @@ -2004,40 +2029,6 @@ fn renderExpression( | ... | @@ -2004,40 +2029,6 @@ fn renderExpression( |
| 2004 | } | 2029 | } |
| 2005 | }, | 2030 | }, |
| 2006 | 2031 | ||
| 2007 | .AsmInput => { | ||
| 2008 | const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base); | ||
| 2009 | |||
| 2010 | try stream.writeAll("["); | ||
| 2011 | try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None); | ||
| 2012 | try stream.writeAll("] "); | ||
| 2013 | try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None); | ||
| 2014 | try stream.writeAll(" ("); | ||
| 2015 | try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None); | ||
| 2016 | return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // ) | ||
| 2017 | }, | ||
| 2018 | |||
| 2019 | .AsmOutput => { | ||
| 2020 | const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base); | ||
| 2021 | |||
| 2022 | try stream.writeAll("["); | ||
| 2023 | try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None); | ||
| 2024 | try stream.writeAll("] "); | ||
| 2025 | try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None); | ||
| 2026 | try stream.writeAll(" ("); | ||
| 2027 | |||
| 2028 | switch (asm_output.kind) { | ||
| 2029 | ast.Node.AsmOutput.Kind.Variable => |variable_name| { | ||
| 2030 | try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None); | ||
| 2031 | }, | ||
| 2032 | ast.Node.AsmOutput.Kind.Return => |return_type| { | ||
| 2033 | try stream.writeAll("-> "); | ||
| 2034 | try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None); | ||
| 2035 | }, | ||
| 2036 | } | ||
| 2037 | |||
| 2038 | return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // ) | ||
| 2039 | }, | ||
| 2040 | |||
| 2041 | .EnumLiteral => { | 2032 | .EnumLiteral => { |
| 2042 | const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base); | 2033 | const enum_literal = @fieldParentPtr(ast.Node.EnumLiteral, "base", base); |
| 2043 | 2034 | ||
| ... | @@ -2050,11 +2041,56 @@ fn renderExpression( | ... | @@ -2050,11 +2041,56 @@ fn renderExpression( |
| 2050 | .VarDecl, | 2041 | .VarDecl, |
| 2051 | .Use, | 2042 | .Use, |
| 2052 | .TestDecl, | 2043 | .TestDecl, |
| 2053 | .ParamDecl, | ||
| 2054 | => unreachable, | 2044 | => unreachable, |
| 2055 | } | 2045 | } |
| 2056 | } | 2046 | } |
| 2057 | 2047 | ||
| 2048 | fn renderAsmOutput( | ||
| 2049 | allocator: *mem.Allocator, | ||
| 2050 | stream: var, | ||
| 2051 | tree: *ast.Tree, | ||
| 2052 | indent: usize, | ||
| 2053 | start_col: *usize, | ||
| 2054 | asm_output: *const ast.Node.Asm.Output, | ||
| 2055 | space: Space, | ||
| 2056 | ) (@TypeOf(stream).Error || Error)!void { | ||
| 2057 | try stream.writeAll("["); | ||
| 2058 | try renderExpression(allocator, stream, tree, indent, start_col, asm_output.symbolic_name, Space.None); | ||
| 2059 | try stream.writeAll("] "); | ||
| 2060 | try renderExpression(allocator, stream, tree, indent, start_col, asm_output.constraint, Space.None); | ||
| 2061 | try stream.writeAll(" ("); | ||
| 2062 | |||
| 2063 | switch (asm_output.kind) { | ||
| 2064 | ast.Node.Asm.Output.Kind.Variable => |variable_name| { | ||
| 2065 | try renderExpression(allocator, stream, tree, indent, start_col, &variable_name.base, Space.None); | ||
| 2066 | }, | ||
| 2067 | ast.Node.Asm.Output.Kind.Return => |return_type| { | ||
| 2068 | try stream.writeAll("-> "); | ||
| 2069 | try renderExpression(allocator, stream, tree, indent, start_col, return_type, Space.None); | ||
| 2070 | }, | ||
| 2071 | } | ||
| 2072 | |||
| 2073 | return renderToken(tree, stream, asm_output.lastToken(), indent, start_col, space); // ) | ||
| 2074 | } | ||
| 2075 | |||
| 2076 | fn renderAsmInput( | ||
| 2077 | allocator: *mem.Allocator, | ||
| 2078 | stream: var, | ||
| 2079 | tree: *ast.Tree, | ||
| 2080 | indent: usize, | ||
| 2081 | start_col: *usize, | ||
| 2082 | asm_input: *const ast.Node.Asm.Input, | ||
| 2083 | space: Space, | ||
| 2084 | ) (@TypeOf(stream).Error || Error)!void { | ||
| 2085 | try stream.writeAll("["); | ||
| 2086 | try renderExpression(allocator, stream, tree, indent, start_col, asm_input.symbolic_name, Space.None); | ||
| 2087 | try stream.writeAll("] "); | ||
| 2088 | try renderExpression(allocator, stream, tree, indent, start_col, asm_input.constraint, Space.None); | ||
| 2089 | try stream.writeAll(" ("); | ||
| 2090 | try renderExpression(allocator, stream, tree, indent, start_col, asm_input.expr, Space.None); | ||
| 2091 | return renderToken(tree, stream, asm_input.lastToken(), indent, start_col, space); // ) | ||
| 2092 | } | ||
| 2093 | |||
| 2058 | fn renderVarDecl( | 2094 | fn renderVarDecl( |
| 2059 | allocator: *mem.Allocator, | 2095 | allocator: *mem.Allocator, |
| 2060 | stream: var, | 2096 | stream: var, |
| ... | @@ -2133,11 +2169,9 @@ fn renderParamDecl( | ... | @@ -2133,11 +2169,9 @@ fn renderParamDecl( |
| 2133 | tree: *ast.Tree, | 2169 | tree: *ast.Tree, |
| 2134 | indent: usize, | 2170 | indent: usize, |
| 2135 | start_col: *usize, | 2171 | start_col: *usize, |
| 2136 | base: *ast.Node, | 2172 | param_decl: ast.Node.FnProto.ParamDecl, |
| 2137 | space: Space, | 2173 | space: Space, |
| 2138 | ) (@TypeOf(stream).Error || Error)!void { | 2174 | ) (@TypeOf(stream).Error || Error)!void { |
| 2139 | const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base); | ||
| 2140 | |||
| 2141 | try renderDocComments(tree, stream, param_decl, indent, start_col); | 2175 | try renderDocComments(tree, stream, param_decl, indent, start_col); |
| 2142 | 2176 | ||
| 2143 | if (param_decl.comptime_token) |comptime_token| { | 2177 | if (param_decl.comptime_token) |comptime_token| { |
| ... | @@ -2174,7 +2208,7 @@ fn renderStatement( | ... | @@ -2174,7 +2208,7 @@ fn renderStatement( |
| 2174 | try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None); | 2208 | try renderExpression(allocator, stream, tree, indent, start_col, base, Space.None); |
| 2175 | 2209 | ||
| 2176 | const semicolon_index = tree.nextToken(base.lastToken()); | 2210 | const semicolon_index = tree.nextToken(base.lastToken()); |
| 2177 | assert(tree.tokens.at(semicolon_index).id == .Semicolon); | 2211 | assert(tree.token_ids[semicolon_index] == .Semicolon); |
| 2178 | try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline); | 2212 | try renderToken(tree, stream, semicolon_index, indent, start_col, Space.Newline); |
| 2179 | } else { | 2213 | } else { |
| 2180 | try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline); | 2214 | try renderExpression(allocator, stream, tree, indent, start_col, base, Space.Newline); |
| ... | @@ -2212,22 +2246,25 @@ fn renderTokenOffset( | ... | @@ -2212,22 +2246,25 @@ fn renderTokenOffset( |
| 2212 | return; | 2246 | return; |
| 2213 | } | 2247 | } |
| 2214 | 2248 | ||
| 2215 | var token = tree.tokens.at(token_index); | 2249 | var token_loc = tree.token_locs[token_index]; |
| 2216 | try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(token)[token_skip_bytes..], " ")); | 2250 | try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(token_loc)[token_skip_bytes..], " ")); |
| 2217 | 2251 | ||
| 2218 | if (space == Space.NoComment) | 2252 | if (space == Space.NoComment) |
| 2219 | return; | 2253 | return; |
| 2220 | 2254 | ||
| 2221 | var next_token = tree.tokens.at(token_index + 1); | 2255 | var next_token_id = tree.token_ids[token_index + 1]; |
| 2256 | var next_token_loc = tree.token_locs[token_index + 1]; | ||
| 2222 | 2257 | ||
| 2223 | if (space == Space.Comma) switch (next_token.id) { | 2258 | if (space == Space.Comma) switch (next_token_id) { |
| 2224 | .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline), | 2259 | .Comma => return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline), |
| 2225 | .LineComment => { | 2260 | .LineComment => { |
| 2226 | try stream.writeAll(", "); | 2261 | try stream.writeAll(", "); |
| 2227 | return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline); | 2262 | return renderToken(tree, stream, token_index + 1, indent, start_col, Space.Newline); |
| 2228 | }, | 2263 | }, |
| 2229 | else => { | 2264 | else => { |
| 2230 | if (token_index + 2 < tree.tokens.len and tree.tokens.at(token_index + 2).id == .MultilineStringLiteralLine) { | 2265 | if (token_index + 2 < tree.token_ids.len and |
| 2266 | tree.token_ids[token_index + 2] == .MultilineStringLiteralLine) | ||
| 2267 | { | ||
| 2231 | try stream.writeAll(","); | 2268 | try stream.writeAll(","); |
| 2232 | return; | 2269 | return; |
| 2233 | } else { | 2270 | } else { |
| ... | @@ -2240,19 +2277,20 @@ fn renderTokenOffset( | ... | @@ -2240,19 +2277,20 @@ fn renderTokenOffset( |
| 2240 | 2277 | ||
| 2241 | // Skip over same line doc comments | 2278 | // Skip over same line doc comments |
| 2242 | var offset: usize = 1; | 2279 | var offset: usize = 1; |
| 2243 | if (next_token.id == .DocComment) { | 2280 | if (next_token_id == .DocComment) { |
| 2244 | const loc = tree.tokenLocationPtr(token.end, next_token); | 2281 | const loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); |
| 2245 | if (loc.line == 0) { | 2282 | if (loc.line == 0) { |
| 2246 | offset += 1; | 2283 | offset += 1; |
| 2247 | next_token = tree.tokens.at(token_index + offset); | 2284 | next_token_id = tree.token_ids[token_index + offset]; |
| 2285 | next_token_loc = tree.token_locs[token_index + offset]; | ||
| 2248 | } | 2286 | } |
| 2249 | } | 2287 | } |
| 2250 | 2288 | ||
| 2251 | if (next_token.id != .LineComment) blk: { | 2289 | if (next_token_id != .LineComment) blk: { |
| 2252 | switch (space) { | 2290 | switch (space) { |
| 2253 | Space.None, Space.NoNewline => return, | 2291 | Space.None, Space.NoNewline => return, |
| 2254 | Space.Newline => { | 2292 | Space.Newline => { |
| 2255 | if (next_token.id == .MultilineStringLiteralLine) { | 2293 | if (next_token_id == .MultilineStringLiteralLine) { |
| 2256 | return; | 2294 | return; |
| 2257 | } else { | 2295 | } else { |
| 2258 | try stream.writeAll("\n"); | 2296 | try stream.writeAll("\n"); |
| ... | @@ -2261,7 +2299,7 @@ fn renderTokenOffset( | ... | @@ -2261,7 +2299,7 @@ fn renderTokenOffset( |
| 2261 | } | 2299 | } |
| 2262 | }, | 2300 | }, |
| 2263 | Space.Space, Space.SpaceOrOutdent => { | 2301 | Space.Space, Space.SpaceOrOutdent => { |
| 2264 | if (next_token.id == .MultilineStringLiteralLine) | 2302 | if (next_token_id == .MultilineStringLiteralLine) |
| 2265 | return; | 2303 | return; |
| 2266 | try stream.writeByte(' '); | 2304 | try stream.writeByte(' '); |
| 2267 | return; | 2305 | return; |
| ... | @@ -2271,14 +2309,15 @@ fn renderTokenOffset( | ... | @@ -2271,14 +2309,15 @@ fn renderTokenOffset( |
| 2271 | } | 2309 | } |
| 2272 | 2310 | ||
| 2273 | while (true) { | 2311 | while (true) { |
| 2274 | const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2; | 2312 | const comment_is_empty = mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ").len == 2; |
| 2275 | if (comment_is_empty) { | 2313 | if (comment_is_empty) { |
| 2276 | switch (space) { | 2314 | switch (space) { |
| 2277 | Space.Newline => { | 2315 | Space.Newline => { |
| 2278 | offset += 1; | 2316 | offset += 1; |
| 2279 | token = next_token; | 2317 | token_loc = next_token_loc; |
| 2280 | next_token = tree.tokens.at(token_index + offset); | 2318 | next_token_id = tree.token_ids[token_index + offset]; |
| 2281 | if (next_token.id != .LineComment) { | 2319 | next_token_loc = tree.token_locs[token_index + offset]; |
| 2320 | if (next_token_id != .LineComment) { | ||
| 2282 | try stream.writeByte('\n'); | 2321 | try stream.writeByte('\n'); |
| 2283 | start_col.* = 0; | 2322 | start_col.* = 0; |
| 2284 | return; | 2323 | return; |
| ... | @@ -2291,18 +2330,19 @@ fn renderTokenOffset( | ... | @@ -2291,18 +2330,19 @@ fn renderTokenOffset( |
| 2291 | } | 2330 | } |
| 2292 | } | 2331 | } |
| 2293 | 2332 | ||
| 2294 | var loc = tree.tokenLocationPtr(token.end, next_token); | 2333 | var loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); |
| 2295 | if (loc.line == 0) { | 2334 | if (loc.line == 0) { |
| 2296 | try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")}); | 2335 | try stream.print(" {}", .{mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")}); |
| 2297 | offset = 2; | 2336 | offset = 2; |
| 2298 | token = next_token; | 2337 | token_loc = next_token_loc; |
| 2299 | next_token = tree.tokens.at(token_index + offset); | 2338 | next_token_loc = tree.token_locs[token_index + offset]; |
| 2300 | if (next_token.id != .LineComment) { | 2339 | next_token_id = tree.token_ids[token_index + offset]; |
| 2340 | if (next_token_id != .LineComment) { | ||
| 2301 | switch (space) { | 2341 | switch (space) { |
| 2302 | Space.None, Space.Space => { | 2342 | Space.None, Space.Space => { |
| 2303 | try stream.writeByte('\n'); | 2343 | try stream.writeByte('\n'); |
| 2304 | const after_comment_token = tree.tokens.at(token_index + offset); | 2344 | const after_comment_token = tree.token_ids[token_index + offset]; |
| 2305 | const next_line_indent = switch (after_comment_token.id) { | 2345 | const next_line_indent = switch (after_comment_token) { |
| 2306 | .RParen, .RBrace, .RBracket => indent, | 2346 | .RParen, .RBrace, .RBracket => indent, |
| 2307 | else => indent + indent_delta, | 2347 | else => indent + indent_delta, |
| 2308 | }; | 2348 | }; |
| ... | @@ -2315,7 +2355,7 @@ fn renderTokenOffset( | ... | @@ -2315,7 +2355,7 @@ fn renderTokenOffset( |
| 2315 | start_col.* = indent; | 2355 | start_col.* = indent; |
| 2316 | }, | 2356 | }, |
| 2317 | Space.Newline => { | 2357 | Space.Newline => { |
| 2318 | if (next_token.id == .MultilineStringLiteralLine) { | 2358 | if (next_token_id == .MultilineStringLiteralLine) { |
| 2319 | return; | 2359 | return; |
| 2320 | } else { | 2360 | } else { |
| 2321 | try stream.writeAll("\n"); | 2361 | try stream.writeAll("\n"); |
| ... | @@ -2328,7 +2368,7 @@ fn renderTokenOffset( | ... | @@ -2328,7 +2368,7 @@ fn renderTokenOffset( |
| 2328 | } | 2368 | } |
| 2329 | return; | 2369 | return; |
| 2330 | } | 2370 | } |
| 2331 | loc = tree.tokenLocationPtr(token.end, next_token); | 2371 | loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); |
| 2332 | } | 2372 | } |
| 2333 | 2373 | ||
| 2334 | while (true) { | 2374 | while (true) { |
| ... | @@ -2338,15 +2378,16 @@ fn renderTokenOffset( | ... | @@ -2338,15 +2378,16 @@ fn renderTokenOffset( |
| 2338 | const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2); | 2378 | const newline_count = if (loc.line <= 1) @as(u8, 1) else @as(u8, 2); |
| 2339 | try stream.writeByteNTimes('\n', newline_count); | 2379 | try stream.writeByteNTimes('\n', newline_count); |
| 2340 | try stream.writeByteNTimes(' ', indent); | 2380 | try stream.writeByteNTimes(' ', indent); |
| 2341 | try stream.writeAll(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")); | 2381 | try stream.writeAll(mem.trimRight(u8, tree.tokenSliceLoc(next_token_loc), " ")); |
| 2342 | 2382 | ||
| 2343 | offset += 1; | 2383 | offset += 1; |
| 2344 | token = next_token; | 2384 | token_loc = next_token_loc; |
| 2345 | next_token = tree.tokens.at(token_index + offset); | 2385 | next_token_loc = tree.token_locs[token_index + offset]; |
| 2346 | if (next_token.id != .LineComment) { | 2386 | next_token_id = tree.token_ids[token_index + offset]; |
| 2387 | if (next_token_id != .LineComment) { | ||
| 2347 | switch (space) { | 2388 | switch (space) { |
| 2348 | Space.Newline => { | 2389 | Space.Newline => { |
| 2349 | if (next_token.id == .MultilineStringLiteralLine) { | 2390 | if (next_token_id == .MultilineStringLiteralLine) { |
| 2350 | return; | 2391 | return; |
| 2351 | } else { | 2392 | } else { |
| 2352 | try stream.writeAll("\n"); | 2393 | try stream.writeAll("\n"); |
| ... | @@ -2357,8 +2398,8 @@ fn renderTokenOffset( | ... | @@ -2357,8 +2398,8 @@ fn renderTokenOffset( |
| 2357 | Space.None, Space.Space => { | 2398 | Space.None, Space.Space => { |
| 2358 | try stream.writeByte('\n'); | 2399 | try stream.writeByte('\n'); |
| 2359 | 2400 | ||
| 2360 | const after_comment_token = tree.tokens.at(token_index + offset); | 2401 | const after_comment_token = tree.token_ids[token_index + offset]; |
| 2361 | const next_line_indent = switch (after_comment_token.id) { | 2402 | const next_line_indent = switch (after_comment_token) { |
| 2362 | .RParen, .RBrace, .RBracket => blk: { | 2403 | .RParen, .RBrace, .RBracket => blk: { |
| 2363 | if (indent > indent_delta) { | 2404 | if (indent > indent_delta) { |
| 2364 | break :blk indent - indent_delta; | 2405 | break :blk indent - indent_delta; |
| ... | @@ -2381,7 +2422,7 @@ fn renderTokenOffset( | ... | @@ -2381,7 +2422,7 @@ fn renderTokenOffset( |
| 2381 | } | 2422 | } |
| 2382 | return; | 2423 | return; |
| 2383 | } | 2424 | } |
| 2384 | loc = tree.tokenLocationPtr(token.end, next_token); | 2425 | loc = tree.tokenLocationLoc(token_loc.end, next_token_loc); |
| 2385 | } | 2426 | } |
| 2386 | } | 2427 | } |
| 2387 | 2428 | ||
| ... | @@ -2404,16 +2445,32 @@ fn renderDocComments( | ... | @@ -2404,16 +2445,32 @@ fn renderDocComments( |
| 2404 | start_col: *usize, | 2445 | start_col: *usize, |
| 2405 | ) (@TypeOf(stream).Error || Error)!void { | 2446 | ) (@TypeOf(stream).Error || Error)!void { |
| 2406 | const comment = node.doc_comments orelse return; | 2447 | const comment = node.doc_comments orelse return; |
| 2407 | var it = comment.lines.iterator(0); | 2448 | return renderDocCommentsToken(tree, stream, comment, node.firstToken(), indent, start_col); |
| 2408 | const first_token = node.firstToken(); | 2449 | } |
| 2409 | while (it.next()) |line_token_index| { | 2450 | |
| 2410 | if (line_token_index.* < first_token) { | 2451 | fn renderDocCommentsToken( |
| 2411 | try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.Newline); | 2452 | tree: *ast.Tree, |
| 2412 | try stream.writeByteNTimes(' ', indent); | 2453 | stream: var, |
| 2413 | } else { | 2454 | comment: *ast.Node.DocComment, |
| 2414 | try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.NoComment); | 2455 | first_token: ast.TokenIndex, |
| 2415 | try stream.writeAll("\n"); | 2456 | indent: usize, |
| 2416 | try stream.writeByteNTimes(' ', indent); | 2457 | start_col: *usize, |
| 2458 | ) (@TypeOf(stream).Error || Error)!void { | ||
| 2459 | var tok_i = comment.first_line; | ||
| 2460 | while (true) : (tok_i += 1) { | ||
| 2461 | switch (tree.token_ids[tok_i]) { | ||
| 2462 | .DocComment, .ContainerDocComment => { | ||
| 2463 | if (comment.first_line < first_token) { | ||
| 2464 | try renderToken(tree, stream, tok_i, indent, start_col, Space.Newline); | ||
| 2465 | try stream.writeByteNTimes(' ', indent); | ||
| 2466 | } else { | ||
| 2467 | try renderToken(tree, stream, tok_i, indent, start_col, Space.NoComment); | ||
| 2468 | try stream.writeAll("\n"); | ||
| 2469 | try stream.writeByteNTimes(' ', indent); | ||
| 2470 | } | ||
| 2471 | }, | ||
| 2472 | .LineComment => continue, | ||
| 2473 | else => break, | ||
| 2417 | } | 2474 | } |
| 2418 | } | 2475 | } |
| 2419 | } | 2476 | } |
lib/std/zig/tokenizer.zig+18-10| ... | @@ -3,8 +3,12 @@ const mem = std.mem; | ... | @@ -3,8 +3,12 @@ const mem = std.mem; |
| 3 | 3 | ||
| 4 | pub const Token = struct { | 4 | pub const Token = struct { |
| 5 | id: Id, | 5 | id: Id, |
| 6 | start: usize, | 6 | loc: Loc, |
| 7 | end: usize, | 7 | |
| 8 | pub const Loc = struct { | ||
| 9 | start: usize, | ||
| 10 | end: usize, | ||
| 11 | }; | ||
| 8 | 12 | ||
| 9 | pub const Keyword = struct { | 13 | pub const Keyword = struct { |
| 10 | bytes: []const u8, | 14 | bytes: []const u8, |
| ... | @@ -426,8 +430,10 @@ pub const Tokenizer = struct { | ... | @@ -426,8 +430,10 @@ pub const Tokenizer = struct { |
| 426 | var state: State = .start; | 430 | var state: State = .start; |
| 427 | var result = Token{ | 431 | var result = Token{ |
| 428 | .id = .Eof, | 432 | .id = .Eof, |
| 429 | .start = self.index, | 433 | .loc = .{ |
| 430 | .end = undefined, | 434 | .start = self.index, |
| 435 | .end = undefined, | ||
| 436 | }, | ||
| 431 | }; | 437 | }; |
| 432 | var seen_escape_digits: usize = undefined; | 438 | var seen_escape_digits: usize = undefined; |
| 433 | var remaining_code_units: usize = undefined; | 439 | var remaining_code_units: usize = undefined; |
| ... | @@ -436,7 +442,7 @@ pub const Tokenizer = struct { | ... | @@ -436,7 +442,7 @@ pub const Tokenizer = struct { |
| 436 | switch (state) { | 442 | switch (state) { |
| 437 | .start => switch (c) { | 443 | .start => switch (c) { |
| 438 | ' ', '\n', '\t', '\r' => { | 444 | ' ', '\n', '\t', '\r' => { |
| 439 | result.start = self.index + 1; | 445 | result.loc.start = self.index + 1; |
| 440 | }, | 446 | }, |
| 441 | '"' => { | 447 | '"' => { |
| 442 | state = .string_literal; | 448 | state = .string_literal; |
| ... | @@ -686,7 +692,7 @@ pub const Tokenizer = struct { | ... | @@ -686,7 +692,7 @@ pub const Tokenizer = struct { |
| 686 | .identifier => switch (c) { | 692 | .identifier => switch (c) { |
| 687 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, | 693 | 'a'...'z', 'A'...'Z', '_', '0'...'9' => {}, |
| 688 | else => { | 694 | else => { |
| 689 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { | 695 | if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| { |
| 690 | result.id = id; | 696 | result.id = id; |
| 691 | } | 697 | } |
| 692 | break; | 698 | break; |
| ... | @@ -1313,7 +1319,7 @@ pub const Tokenizer = struct { | ... | @@ -1313,7 +1319,7 @@ pub const Tokenizer = struct { |
| 1313 | => {}, | 1319 | => {}, |
| 1314 | 1320 | ||
| 1315 | .identifier => { | 1321 | .identifier => { |
| 1316 | if (Token.getKeyword(self.buffer[result.start..self.index])) |id| { | 1322 | if (Token.getKeyword(self.buffer[result.loc.start..self.index])) |id| { |
| 1317 | result.id = id; | 1323 | result.id = id; |
| 1318 | } | 1324 | } |
| 1319 | }, | 1325 | }, |
| ... | @@ -1420,7 +1426,7 @@ pub const Tokenizer = struct { | ... | @@ -1420,7 +1426,7 @@ pub const Tokenizer = struct { |
| 1420 | } | 1426 | } |
| 1421 | } | 1427 | } |
| 1422 | 1428 | ||
| 1423 | result.end = self.index; | 1429 | result.loc.end = self.index; |
| 1424 | return result; | 1430 | return result; |
| 1425 | } | 1431 | } |
| 1426 | 1432 | ||
| ... | @@ -1430,8 +1436,10 @@ pub const Tokenizer = struct { | ... | @@ -1430,8 +1436,10 @@ pub const Tokenizer = struct { |
| 1430 | if (invalid_length == 0) return; | 1436 | if (invalid_length == 0) return; |
| 1431 | self.pending_invalid_token = .{ | 1437 | self.pending_invalid_token = .{ |
| 1432 | .id = .Invalid, | 1438 | .id = .Invalid, |
| 1433 | .start = self.index, | 1439 | .loc = .{ |
| 1434 | .end = self.index + invalid_length, | 1440 | .start = self.index, |
| 1441 | .end = self.index + invalid_length, | ||
| 1442 | }, | ||
| 1435 | }; | 1443 | }; |
| 1436 | } | 1444 | } |
| 1437 | 1445 |
src-self-hosted/clang.zig+11-13| ... | @@ -22,7 +22,7 @@ pub const struct_ZigClangCompoundStmt = @Type(.Opaque); | ... | @@ -22,7 +22,7 @@ pub const struct_ZigClangCompoundStmt = @Type(.Opaque); |
| 22 | pub const struct_ZigClangConstantArrayType = @Type(.Opaque); | 22 | pub const struct_ZigClangConstantArrayType = @Type(.Opaque); |
| 23 | pub const struct_ZigClangContinueStmt = @Type(.Opaque); | 23 | pub const struct_ZigClangContinueStmt = @Type(.Opaque); |
| 24 | pub const struct_ZigClangDecayedType = @Type(.Opaque); | 24 | pub const struct_ZigClangDecayedType = @Type(.Opaque); |
| 25 | pub const struct_ZigClangDecl = @Type(.Opaque); | 25 | pub const ZigClangDecl = @Type(.Opaque); |
| 26 | pub const struct_ZigClangDeclRefExpr = @Type(.Opaque); | 26 | pub const struct_ZigClangDeclRefExpr = @Type(.Opaque); |
| 27 | pub const struct_ZigClangDeclStmt = @Type(.Opaque); | 27 | pub const struct_ZigClangDeclStmt = @Type(.Opaque); |
| 28 | pub const struct_ZigClangDefaultStmt = @Type(.Opaque); | 28 | pub const struct_ZigClangDefaultStmt = @Type(.Opaque); |
| ... | @@ -63,7 +63,7 @@ pub const struct_ZigClangReturnStmt = @Type(.Opaque); | ... | @@ -63,7 +63,7 @@ pub const struct_ZigClangReturnStmt = @Type(.Opaque); |
| 63 | pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque); | 63 | pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque); |
| 64 | pub const struct_ZigClangSourceManager = @Type(.Opaque); | 64 | pub const struct_ZigClangSourceManager = @Type(.Opaque); |
| 65 | pub const struct_ZigClangSourceRange = @Type(.Opaque); | 65 | pub const struct_ZigClangSourceRange = @Type(.Opaque); |
| 66 | pub const struct_ZigClangStmt = @Type(.Opaque); | 66 | pub const ZigClangStmt = @Type(.Opaque); |
| 67 | pub const struct_ZigClangStringLiteral = @Type(.Opaque); | 67 | pub const struct_ZigClangStringLiteral = @Type(.Opaque); |
| 68 | pub const struct_ZigClangStringRef = @Type(.Opaque); | 68 | pub const struct_ZigClangStringRef = @Type(.Opaque); |
| 69 | pub const struct_ZigClangSwitchStmt = @Type(.Opaque); | 69 | pub const struct_ZigClangSwitchStmt = @Type(.Opaque); |
| ... | @@ -781,7 +781,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigCla | ... | @@ -781,7 +781,7 @@ pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigCla |
| 781 | pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType; | 781 | pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangASTContext, T: struct_ZigClangQualType) struct_ZigClangQualType; |
| 782 | pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext; | 782 | pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext; |
| 783 | pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; | 783 | pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; |
| 784 | pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?fn (?*c_void, *const struct_ZigClangDecl) callconv(.C) bool) bool; | 784 | pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?fn (?*c_void, *const ZigClangDecl) callconv(.C) bool) bool; |
| 785 | pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl; | 785 | pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl; |
| 786 | pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClangTagDecl) bool; | 786 | pub extern fn ZigClangTagDecl_isThisDeclarationADefinition(self: *const ZigClangTagDecl) bool; |
| 787 | pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl; | 787 | pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) *const struct_ZigClangEnumDecl; |
| ... | @@ -817,7 +817,7 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE | ... | @@ -817,7 +817,7 @@ pub extern fn ZigClangEnumDecl_enumerator_end(*const ZigClangEnumDecl) ZigClangE |
| 817 | pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator; | 817 | pub extern fn ZigClangEnumDecl_enumerator_iterator_next(ZigClangEnumDecl_enumerator_iterator) ZigClangEnumDecl_enumerator_iterator; |
| 818 | pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl; | 818 | pub extern fn ZigClangEnumDecl_enumerator_iterator_deref(ZigClangEnumDecl_enumerator_iterator) *const ZigClangEnumConstantDecl; |
| 819 | pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool; | 819 | pub extern fn ZigClangEnumDecl_enumerator_iterator_neq(ZigClangEnumDecl_enumerator_iterator, ZigClangEnumDecl_enumerator_iterator) bool; |
| 820 | pub extern fn ZigClangDecl_castToNamedDecl(decl: *const struct_ZigClangDecl) ?*const ZigClangNamedDecl; | 820 | pub extern fn ZigClangDecl_castToNamedDecl(decl: *const ZigClangDecl) ?*const ZigClangNamedDecl; |
| 821 | pub extern fn ZigClangNamedDecl_getName_bytes_begin(decl: ?*const struct_ZigClangNamedDecl) [*:0]const u8; | 821 | pub extern fn ZigClangNamedDecl_getName_bytes_begin(decl: ?*const struct_ZigClangNamedDecl) [*:0]const u8; |
| 822 | pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool; | 822 | pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool; |
| 823 | pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl; | 823 | pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl; |
| ... | @@ -842,9 +842,9 @@ pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [* | ... | @@ -842,9 +842,9 @@ pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [* |
| 842 | pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType; | 842 | pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType; |
| 843 | pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType; | 843 | pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType; |
| 844 | pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType; | 844 | pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType; |
| 845 | pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; | 845 | pub extern fn ZigClangStmt_getBeginLoc(self: *const ZigClangStmt) struct_ZigClangSourceLocation; |
| 846 | pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass; | 846 | pub extern fn ZigClangStmt_getStmtClass(self: ?*const ZigClangStmt) ZigClangStmtClass; |
| 847 | pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool; | 847 | pub extern fn ZigClangStmt_classof_Expr(self: ?*const ZigClangStmt) bool; |
| 848 | pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass; | 848 | pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass; |
| 849 | pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType; | 849 | pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType; |
| 850 | pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation; | 850 | pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation; |
| ... | @@ -873,7 +873,7 @@ pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl | ... | @@ -873,7 +873,7 @@ pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl |
| 873 | pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool; | 873 | pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool; |
| 874 | pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass; | 874 | pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass; |
| 875 | pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl; | 875 | pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl; |
| 876 | pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt; | 876 | pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const ZigClangStmt; |
| 877 | pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool; | 877 | pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool; |
| 878 | pub extern fn ZigClangFunctionDecl_isThisDeclarationADefinition(self: *const ZigClangFunctionDecl) bool; | 878 | pub extern fn ZigClangFunctionDecl_isThisDeclarationADefinition(self: *const ZigClangFunctionDecl) bool; |
| 879 | pub extern fn ZigClangFunctionDecl_doesThisDeclarationHaveABody(self: *const ZigClangFunctionDecl) bool; | 879 | pub extern fn ZigClangFunctionDecl_doesThisDeclarationHaveABody(self: *const ZigClangFunctionDecl) bool; |
| ... | @@ -918,7 +918,6 @@ pub const ZigClangCompoundStmt = struct_ZigClangCompoundStmt; | ... | @@ -918,7 +918,6 @@ pub const ZigClangCompoundStmt = struct_ZigClangCompoundStmt; |
| 918 | pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType; | 918 | pub const ZigClangConstantArrayType = struct_ZigClangConstantArrayType; |
| 919 | pub const ZigClangContinueStmt = struct_ZigClangContinueStmt; | 919 | pub const ZigClangContinueStmt = struct_ZigClangContinueStmt; |
| 920 | pub const ZigClangDecayedType = struct_ZigClangDecayedType; | 920 | pub const ZigClangDecayedType = struct_ZigClangDecayedType; |
| 921 | pub const ZigClangDecl = struct_ZigClangDecl; | ||
| 922 | pub const ZigClangDeclRefExpr = struct_ZigClangDeclRefExpr; | 921 | pub const ZigClangDeclRefExpr = struct_ZigClangDeclRefExpr; |
| 923 | pub const ZigClangDeclStmt = struct_ZigClangDeclStmt; | 922 | pub const ZigClangDeclStmt = struct_ZigClangDeclStmt; |
| 924 | pub const ZigClangDefaultStmt = struct_ZigClangDefaultStmt; | 923 | pub const ZigClangDefaultStmt = struct_ZigClangDefaultStmt; |
| ... | @@ -959,7 +958,6 @@ pub const ZigClangReturnStmt = struct_ZigClangReturnStmt; | ... | @@ -959,7 +958,6 @@ pub const ZigClangReturnStmt = struct_ZigClangReturnStmt; |
| 959 | pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope; | 958 | pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope; |
| 960 | pub const ZigClangSourceManager = struct_ZigClangSourceManager; | 959 | pub const ZigClangSourceManager = struct_ZigClangSourceManager; |
| 961 | pub const ZigClangSourceRange = struct_ZigClangSourceRange; | 960 | pub const ZigClangSourceRange = struct_ZigClangSourceRange; |
| 962 | pub const ZigClangStmt = struct_ZigClangStmt; | ||
| 963 | pub const ZigClangStringLiteral = struct_ZigClangStringLiteral; | 961 | pub const ZigClangStringLiteral = struct_ZigClangStringLiteral; |
| 964 | pub const ZigClangStringRef = struct_ZigClangStringRef; | 962 | pub const ZigClangStringRef = struct_ZigClangStringRef; |
| 965 | pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt; | 963 | pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt; |
| ... | @@ -1016,14 +1014,14 @@ pub extern fn ZigClangLoadFromCommandLine( | ... | @@ -1016,14 +1014,14 @@ pub extern fn ZigClangLoadFromCommandLine( |
| 1016 | ) ?*ZigClangASTUnit; | 1014 | ) ?*ZigClangASTUnit; |
| 1017 | 1015 | ||
| 1018 | pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind; | 1016 | pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind; |
| 1019 | pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8; | 1017 | pub extern fn ZigClangDecl_getDeclKindName(decl: *const ZigClangDecl) [*:0]const u8; |
| 1020 | 1018 | ||
| 1021 | pub const ZigClangCompoundStmt_const_body_iterator = [*]const *struct_ZigClangStmt; | 1019 | pub const ZigClangCompoundStmt_const_body_iterator = [*]const *ZigClangStmt; |
| 1022 | 1020 | ||
| 1023 | pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; | 1021 | pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; |
| 1024 | pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; | 1022 | pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; |
| 1025 | 1023 | ||
| 1026 | pub const ZigClangDeclStmt_const_decl_iterator = [*]const *struct_ZigClangDecl; | 1024 | pub const ZigClangDeclStmt_const_decl_iterator = [*]const *ZigClangDecl; |
| 1027 | 1025 | ||
| 1028 | pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; | 1026 | pub extern fn ZigClangDeclStmt_decl_begin(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; |
| 1029 | pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; | 1027 | pub extern fn ZigClangDeclStmt_decl_end(self: *const ZigClangDeclStmt) ZigClangDeclStmt_const_decl_iterator; |
src-self-hosted/main.zig+8-10| ... | @@ -600,8 +600,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { | ... | @@ -600,8 +600,7 @@ pub fn cmdFmt(gpa: *Allocator, args: []const []const u8) !void { |
| 600 | }; | 600 | }; |
| 601 | defer tree.deinit(); | 601 | defer tree.deinit(); |
| 602 | 602 | ||
| 603 | var error_it = tree.errors.iterator(0); | 603 | for (tree.errors) |parse_error| { |
| 604 | while (error_it.next()) |parse_error| { | ||
| 605 | try printErrMsgToFile(gpa, parse_error, tree, "<stdin>", stderr_file, color); | 604 | try printErrMsgToFile(gpa, parse_error, tree, "<stdin>", stderr_file, color); |
| 606 | } | 605 | } |
| 607 | if (tree.errors.len != 0) { | 606 | if (tree.errors.len != 0) { |
| ... | @@ -701,8 +700,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { | ... | @@ -701,8 +700,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 701 | }; | 700 | }; |
| 702 | defer tree.deinit(); | 701 | defer tree.deinit(); |
| 703 | 702 | ||
| 704 | var error_it = tree.errors.iterator(0); | 703 | for (tree.errors) |parse_error| { |
| 705 | while (error_it.next()) |parse_error| { | ||
| 706 | try printErrMsgToFile(fmt.gpa, parse_error, tree, file_path, std.io.getStdErr(), fmt.color); | 704 | try printErrMsgToFile(fmt.gpa, parse_error, tree, file_path, std.io.getStdErr(), fmt.color); |
| 707 | } | 705 | } |
| 708 | if (tree.errors.len != 0) { | 706 | if (tree.errors.len != 0) { |
| ... | @@ -730,7 +728,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { | ... | @@ -730,7 +728,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 730 | 728 | ||
| 731 | fn printErrMsgToFile( | 729 | fn printErrMsgToFile( |
| 732 | gpa: *mem.Allocator, | 730 | gpa: *mem.Allocator, |
| 733 | parse_error: *const ast.Error, | 731 | parse_error: ast.Error, |
| 734 | tree: *ast.Tree, | 732 | tree: *ast.Tree, |
| 735 | path: []const u8, | 733 | path: []const u8, |
| 736 | file: fs.File, | 734 | file: fs.File, |
| ... | @@ -745,15 +743,15 @@ fn printErrMsgToFile( | ... | @@ -745,15 +743,15 @@ fn printErrMsgToFile( |
| 745 | const span_first = lok_token; | 743 | const span_first = lok_token; |
| 746 | const span_last = lok_token; | 744 | const span_last = lok_token; |
| 747 | 745 | ||
| 748 | const first_token = tree.tokens.at(span_first); | 746 | const first_token = tree.token_locs[span_first]; |
| 749 | const last_token = tree.tokens.at(span_last); | 747 | const last_token = tree.token_locs[span_last]; |
| 750 | const start_loc = tree.tokenLocationPtr(0, first_token); | 748 | const start_loc = tree.tokenLocationLoc(0, first_token); |
| 751 | const end_loc = tree.tokenLocationPtr(first_token.end, last_token); | 749 | const end_loc = tree.tokenLocationLoc(first_token.end, last_token); |
| 752 | 750 | ||
| 753 | var text_buf = std.ArrayList(u8).init(gpa); | 751 | var text_buf = std.ArrayList(u8).init(gpa); |
| 754 | defer text_buf.deinit(); | 752 | defer text_buf.deinit(); |
| 755 | const out_stream = text_buf.outStream(); | 753 | const out_stream = text_buf.outStream(); |
| 756 | try parse_error.render(&tree.tokens, out_stream); | 754 | try parse_error.render(tree.token_ids, out_stream); |
| 757 | const text = text_buf.span(); | 755 | const text = text_buf.span(); |
| 758 | 756 | ||
| 759 | const stream = file.outStream(); | 757 | const stream = file.outStream(); |
src-self-hosted/translate_c.zig+877-778| ... | @@ -37,10 +37,10 @@ fn addrEql(a: usize, b: usize) bool { | ... | @@ -37,10 +37,10 @@ fn addrEql(a: usize, b: usize) bool { |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | const SymbolTable = std.StringHashMap(*ast.Node); | 39 | const SymbolTable = std.StringHashMap(*ast.Node); |
| 40 | const AliasList = std.SegmentedList(struct { | 40 | const AliasList = std.ArrayList(struct { |
| 41 | alias: []const u8, | 41 | alias: []const u8, |
| 42 | name: []const u8, | 42 | name: []const u8, |
| 43 | }, 4); | 43 | }); |
| 44 | 44 | ||
| 45 | const Scope = struct { | 45 | const Scope = struct { |
| 46 | id: Id, | 46 | id: Id, |
| ... | @@ -54,50 +54,99 @@ const Scope = struct { | ... | @@ -54,50 +54,99 @@ const Scope = struct { |
| 54 | Loop, | 54 | Loop, |
| 55 | }; | 55 | }; |
| 56 | 56 | ||
| 57 | /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated. | ||
| 58 | /// When it is deinitialized, it produces an ast.Node.Switch which is allocated | ||
| 59 | /// into the main arena. | ||
| 57 | const Switch = struct { | 60 | const Switch = struct { |
| 58 | base: Scope, | 61 | base: Scope, |
| 59 | pending_block: *ast.Node.Block, | 62 | pending_block: Block, |
| 60 | cases: *ast.Node.Switch.CaseList, | 63 | cases: []*ast.Node, |
| 64 | case_index: usize, | ||
| 61 | has_default: bool = false, | 65 | has_default: bool = false, |
| 62 | }; | 66 | }; |
| 63 | 67 | ||
| 68 | /// Used for the scope of condition expressions, for example `if (cond)`. | ||
| 69 | /// The block is lazily initialised because it is only needed for rare | ||
| 70 | /// cases of comma operators being used. | ||
| 71 | const Condition = struct { | ||
| 72 | base: Scope, | ||
| 73 | block: ?Block = null, | ||
| 74 | |||
| 75 | fn getBlockScope(self: *Condition, c: *Context) !*Block { | ||
| 76 | if (self.block) |*b| return b; | ||
| 77 | self.block = try Block.init(c, &self.base, "blk"); | ||
| 78 | return &self.block.?; | ||
| 79 | } | ||
| 80 | |||
| 81 | fn deinit(self: *Condition) void { | ||
| 82 | if (self.block) |*b| b.deinit(); | ||
| 83 | } | ||
| 84 | }; | ||
| 85 | |||
| 86 | /// Represents an in-progress ast.Node.Block. This struct is stack-allocated. | ||
| 87 | /// When it is deinitialized, it produces an ast.Node.Block which is allocated | ||
| 88 | /// into the main arena. | ||
| 64 | const Block = struct { | 89 | const Block = struct { |
| 65 | base: Scope, | 90 | base: Scope, |
| 66 | block_node: *ast.Node.Block, | 91 | statements: std.ArrayList(*ast.Node), |
| 67 | variables: AliasList, | 92 | variables: AliasList, |
| 68 | label: ?[]const u8, | 93 | label: ?ast.TokenIndex, |
| 69 | mangle_count: u32 = 0, | 94 | mangle_count: u32 = 0, |
| 95 | lbrace: ast.TokenIndex, | ||
| 70 | 96 | ||
| 71 | /// Don't forget to set rbrace token and block_node later | 97 | fn init(c: *Context, parent: *Scope, label: ?[]const u8) !Block { |
| 72 | fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block { | 98 | return Block{ |
| 73 | const block = try c.a().create(Block); | ||
| 74 | block.* = .{ | ||
| 75 | .base = .{ | 99 | .base = .{ |
| 76 | .id = .Block, | 100 | .id = .Block, |
| 77 | .parent = parent, | 101 | .parent = parent, |
| 78 | }, | 102 | }, |
| 79 | .block_node = undefined, | 103 | .statements = std.ArrayList(*ast.Node).init(c.gpa), |
| 80 | .variables = AliasList.init(c.a()), | 104 | .variables = AliasList.init(c.gpa), |
| 81 | .label = label, | 105 | .label = if (label) |l| blk: { |
| 106 | const ll = try appendIdentifier(c, l); | ||
| 107 | _ = try appendToken(c, .Colon, ":"); | ||
| 108 | break :blk ll; | ||
| 109 | } else null, | ||
| 110 | .lbrace = try appendToken(c, .LBrace, "{"), | ||
| 82 | }; | 111 | }; |
| 83 | return block; | 112 | } |
| 113 | |||
| 114 | fn deinit(self: *Block) void { | ||
| 115 | self.statements.deinit(); | ||
| 116 | self.variables.deinit(); | ||
| 117 | self.* = undefined; | ||
| 118 | } | ||
| 119 | |||
| 120 | fn complete(self: *Block, c: *Context) !*ast.Node.Block { | ||
| 121 | // We reserve 1 extra statement if the parent is a Loop. This is in case of | ||
| 122 | // do while, we want to put `if (cond) break;` at the end. | ||
| 123 | const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop); | ||
| 124 | const node = try ast.Node.Block.alloc(c.arena, alloc_len); | ||
| 125 | node.* = .{ | ||
| 126 | .statements_len = self.statements.items.len, | ||
| 127 | .lbrace = self.lbrace, | ||
| 128 | .rbrace = try appendToken(c, .RBrace, "}"), | ||
| 129 | .label = self.label, | ||
| 130 | }; | ||
| 131 | mem.copy(*ast.Node, node.statements(), self.statements.items); | ||
| 132 | return node; | ||
| 84 | } | 133 | } |
| 85 | 134 | ||
| 86 | /// Given the desired name, return a name that does not shadow anything from outer scopes. | 135 | /// Given the desired name, return a name that does not shadow anything from outer scopes. |
| 87 | /// Inserts the returned name into the scope. | 136 | /// Inserts the returned name into the scope. |
| 88 | fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 { | 137 | fn makeMangledName(scope: *Block, c: *Context, name: []const u8) ![]const u8 { |
| 89 | var proposed_name = name; | 138 | const name_copy = try c.arena.dupe(u8, name); |
| 139 | var proposed_name = name_copy; | ||
| 90 | while (scope.contains(proposed_name)) { | 140 | while (scope.contains(proposed_name)) { |
| 91 | scope.mangle_count += 1; | 141 | scope.mangle_count += 1; |
| 92 | proposed_name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, scope.mangle_count }); | 142 | proposed_name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ name, scope.mangle_count }); |
| 93 | } | 143 | } |
| 94 | try scope.variables.push(.{ .name = name, .alias = proposed_name }); | 144 | try scope.variables.append(.{ .name = name_copy, .alias = proposed_name }); |
| 95 | return proposed_name; | 145 | return proposed_name; |
| 96 | } | 146 | } |
| 97 | 147 | ||
| 98 | fn getAlias(scope: *Block, name: []const u8) []const u8 { | 148 | fn getAlias(scope: *Block, name: []const u8) []const u8 { |
| 99 | var it = scope.variables.iterator(0); | 149 | for (scope.variables.items) |p| { |
| 100 | while (it.next()) |p| { | ||
| 101 | if (mem.eql(u8, p.name, name)) | 150 | if (mem.eql(u8, p.name, name)) |
| 102 | return p.alias; | 151 | return p.alias; |
| 103 | } | 152 | } |
| ... | @@ -105,8 +154,7 @@ const Scope = struct { | ... | @@ -105,8 +154,7 @@ const Scope = struct { |
| 105 | } | 154 | } |
| 106 | 155 | ||
| 107 | fn localContains(scope: *Block, name: []const u8) bool { | 156 | fn localContains(scope: *Block, name: []const u8) bool { |
| 108 | var it = scope.variables.iterator(0); | 157 | for (scope.variables.items) |p| { |
| 109 | while (it.next()) |p| { | ||
| 110 | if (mem.eql(u8, p.name, name)) | 158 | if (mem.eql(u8, p.name, name)) |
| 111 | return true; | 159 | return true; |
| 112 | } | 160 | } |
| ... | @@ -132,8 +180,8 @@ const Scope = struct { | ... | @@ -132,8 +180,8 @@ const Scope = struct { |
| 132 | .id = .Root, | 180 | .id = .Root, |
| 133 | .parent = null, | 181 | .parent = null, |
| 134 | }, | 182 | }, |
| 135 | .sym_table = SymbolTable.init(c.a()), | 183 | .sym_table = SymbolTable.init(c.arena), |
| 136 | .macro_table = SymbolTable.init(c.a()), | 184 | .macro_table = SymbolTable.init(c.arena), |
| 137 | .context = c, | 185 | .context = c, |
| 138 | }; | 186 | }; |
| 139 | } | 187 | } |
| ... | @@ -158,10 +206,7 @@ const Scope = struct { | ... | @@ -158,10 +206,7 @@ const Scope = struct { |
| 158 | switch (scope.id) { | 206 | switch (scope.id) { |
| 159 | .Root => unreachable, | 207 | .Root => unreachable, |
| 160 | .Block => return @fieldParentPtr(Block, "base", scope), | 208 | .Block => return @fieldParentPtr(Block, "base", scope), |
| 161 | .Condition => { | 209 | .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c), |
| 162 | // comma operator used | ||
| 163 | return try Block.init(c, scope, "blk"); | ||
| 164 | }, | ||
| 165 | else => scope = scope.parent.?, | 210 | else => scope = scope.parent.?, |
| 166 | } | 211 | } |
| 167 | } | 212 | } |
| ... | @@ -208,7 +253,11 @@ const Scope = struct { | ... | @@ -208,7 +253,11 @@ const Scope = struct { |
| 208 | }; | 253 | }; |
| 209 | 254 | ||
| 210 | pub const Context = struct { | 255 | pub const Context = struct { |
| 211 | tree: *ast.Tree, | 256 | gpa: *mem.Allocator, |
| 257 | arena: *mem.Allocator, | ||
| 258 | token_ids: std.ArrayListUnmanaged(Token.Id), | ||
| 259 | token_locs: std.ArrayListUnmanaged(Token.Loc), | ||
| 260 | errors: std.ArrayListUnmanaged(ast.Error), | ||
| 212 | source_buffer: *std.ArrayList(u8), | 261 | source_buffer: *std.ArrayList(u8), |
| 213 | err: Error, | 262 | err: Error, |
| 214 | source_manager: *ZigClangSourceManager, | 263 | source_manager: *ZigClangSourceManager, |
| ... | @@ -217,6 +266,7 @@ pub const Context = struct { | ... | @@ -217,6 +266,7 @@ pub const Context = struct { |
| 217 | global_scope: *Scope.Root, | 266 | global_scope: *Scope.Root, |
| 218 | clang_context: *ZigClangASTContext, | 267 | clang_context: *ZigClangASTContext, |
| 219 | mangle_count: u32 = 0, | 268 | mangle_count: u32 = 0, |
| 269 | root_decls: std.ArrayListUnmanaged(*ast.Node), | ||
| 220 | 270 | ||
| 221 | /// This one is different than the root scope's name table. This contains | 271 | /// This one is different than the root scope's name table. This contains |
| 222 | /// a list of names that we found by visiting all the top level decls without | 272 | /// a list of names that we found by visiting all the top level decls without |
| ... | @@ -229,13 +279,9 @@ pub const Context = struct { | ... | @@ -229,13 +279,9 @@ pub const Context = struct { |
| 229 | return c.mangle_count; | 279 | return c.mangle_count; |
| 230 | } | 280 | } |
| 231 | 281 | ||
| 232 | fn a(c: *Context) *mem.Allocator { | ||
| 233 | return &c.tree.arena_allocator.allocator; | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Convert a null-terminated C string to a slice allocated in the arena | 282 | /// Convert a null-terminated C string to a slice allocated in the arena |
| 237 | fn str(c: *Context, s: [*:0]const u8) ![]u8 { | 283 | fn str(c: *Context, s: [*:0]const u8) ![]u8 { |
| 238 | return mem.dupe(c.a(), u8, mem.spanZ(s)); | 284 | return mem.dupe(c.arena, u8, mem.spanZ(s)); |
| 239 | } | 285 | } |
| 240 | 286 | ||
| 241 | /// Convert a clang source location to a file:line:column string | 287 | /// Convert a clang source location to a file:line:column string |
| ... | @@ -246,12 +292,52 @@ pub const Context = struct { | ... | @@ -246,12 +292,52 @@ pub const Context = struct { |
| 246 | 292 | ||
| 247 | const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc); | 293 | const line = ZigClangSourceManager_getSpellingLineNumber(c.source_manager, spelling_loc); |
| 248 | const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc); | 294 | const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc); |
| 249 | return std.fmt.allocPrint(c.a(), "{}:{}:{}", .{ filename, line, column }); | 295 | return std.fmt.allocPrint(c.arena, "{}:{}:{}", .{ filename, line, column }); |
| 296 | } | ||
| 297 | |||
| 298 | fn createCall(c: *Context, fn_expr: *ast.Node, params_len: ast.NodeIndex) !*ast.Node.Call { | ||
| 299 | _ = try appendToken(c, .LParen, "("); | ||
| 300 | const node = try ast.Node.Call.alloc(c.arena, params_len); | ||
| 301 | node.* = .{ | ||
| 302 | .lhs = fn_expr, | ||
| 303 | .params_len = params_len, | ||
| 304 | .async_token = null, | ||
| 305 | .rtoken = undefined, // set after appending args | ||
| 306 | }; | ||
| 307 | return node; | ||
| 308 | } | ||
| 309 | |||
| 310 | fn createBuiltinCall(c: *Context, name: []const u8, params_len: ast.NodeIndex) !*ast.Node.BuiltinCall { | ||
| 311 | const builtin_token = try appendToken(c, .Builtin, name); | ||
| 312 | _ = try appendToken(c, .LParen, "("); | ||
| 313 | const node = try ast.Node.BuiltinCall.alloc(c.arena, params_len); | ||
| 314 | node.* = .{ | ||
| 315 | .builtin_token = builtin_token, | ||
| 316 | .params_len = params_len, | ||
| 317 | .rparen_token = undefined, // set after appending args | ||
| 318 | }; | ||
| 319 | return node; | ||
| 320 | } | ||
| 321 | |||
| 322 | fn createBlock(c: *Context, label: ?[]const u8, statements_len: ast.NodeIndex) !*ast.Node.Block { | ||
| 323 | const label_node = if (label) |l| blk: { | ||
| 324 | const ll = try appendIdentifier(c, l); | ||
| 325 | _ = try appendToken(c, .Colon, ":"); | ||
| 326 | break :blk ll; | ||
| 327 | } else null; | ||
| 328 | const block_node = try ast.Node.Block.alloc(c.arena, statements_len); | ||
| 329 | block_node.* = .{ | ||
| 330 | .label = label_node, | ||
| 331 | .lbrace = try appendToken(c, .LBrace, "{"), | ||
| 332 | .statements_len = statements_len, | ||
| 333 | .rbrace = undefined, | ||
| 334 | }; | ||
| 335 | return block_node; | ||
| 250 | } | 336 | } |
| 251 | }; | 337 | }; |
| 252 | 338 | ||
| 253 | pub fn translate( | 339 | pub fn translate( |
| 254 | backing_allocator: *mem.Allocator, | 340 | gpa: *mem.Allocator, |
| 255 | args_begin: [*]?[*]const u8, | 341 | args_begin: [*]?[*]const u8, |
| 256 | args_end: [*]?[*]const u8, | 342 | args_end: [*]?[*]const u8, |
| 257 | errors: *[]ClangErrMsg, | 343 | errors: *[]ClangErrMsg, |
| ... | @@ -269,47 +355,38 @@ pub fn translate( | ... | @@ -269,47 +355,38 @@ pub fn translate( |
| 269 | }; | 355 | }; |
| 270 | defer ZigClangASTUnit_delete(ast_unit); | 356 | defer ZigClangASTUnit_delete(ast_unit); |
| 271 | 357 | ||
| 272 | const tree = blk: { | 358 | var source_buffer = std.ArrayList(u8).init(gpa); |
| 273 | var tree_arena = std.heap.ArenaAllocator.init(backing_allocator); | 359 | defer source_buffer.deinit(); |
| 274 | errdefer tree_arena.deinit(); | ||
| 275 | |||
| 276 | const tree = try tree_arena.allocator.create(ast.Tree); | ||
| 277 | tree.* = .{ | ||
| 278 | .source = undefined, // need to use toOwnedSlice later | ||
| 279 | .root_node = undefined, | ||
| 280 | .arena_allocator = tree_arena, | ||
| 281 | .tokens = undefined, // can't reference the allocator yet | ||
| 282 | .errors = undefined, // can't reference the allocator yet | ||
| 283 | .generated = true, | ||
| 284 | }; | ||
| 285 | break :blk tree; | ||
| 286 | }; | ||
| 287 | const arena = &tree.arena_allocator.allocator; // now we can reference the allocator | ||
| 288 | errdefer tree.arena_allocator.deinit(); | ||
| 289 | tree.tokens = ast.Tree.TokenList.init(arena); | ||
| 290 | tree.errors = ast.Tree.ErrorList.init(arena); | ||
| 291 | |||
| 292 | tree.root_node = try arena.create(ast.Node.Root); | ||
| 293 | tree.root_node.* = .{ | ||
| 294 | .decls = ast.Node.Root.DeclList.init(arena), | ||
| 295 | // initialized with the eof token at the end | ||
| 296 | .eof_token = undefined, | ||
| 297 | }; | ||
| 298 | 360 | ||
| 299 | var source_buffer = std.ArrayList(u8).init(arena); | 361 | // For memory that has the same lifetime as the Tree that we return |
| 362 | // from this function. | ||
| 363 | var arena = std.heap.ArenaAllocator.init(gpa); | ||
| 364 | errdefer arena.deinit(); | ||
| 300 | 365 | ||
| 301 | var context = Context{ | 366 | var context = Context{ |
| 302 | .tree = tree, | 367 | .gpa = gpa, |
| 368 | .arena = &arena.allocator, | ||
| 303 | .source_buffer = &source_buffer, | 369 | .source_buffer = &source_buffer, |
| 304 | .source_manager = ZigClangASTUnit_getSourceManager(ast_unit), | 370 | .source_manager = ZigClangASTUnit_getSourceManager(ast_unit), |
| 305 | .err = undefined, | 371 | .err = undefined, |
| 306 | .decl_table = DeclTable.init(arena), | 372 | .decl_table = DeclTable.init(gpa), |
| 307 | .alias_list = AliasList.init(arena), | 373 | .alias_list = AliasList.init(gpa), |
| 308 | .global_scope = try arena.create(Scope.Root), | 374 | .global_scope = try arena.allocator.create(Scope.Root), |
| 309 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, | 375 | .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, |
| 310 | .global_names = std.StringHashMap(void).init(arena), | 376 | .global_names = std.StringHashMap(void).init(gpa), |
| 377 | .token_ids = .{}, | ||
| 378 | .token_locs = .{}, | ||
| 379 | .errors = .{}, | ||
| 380 | .root_decls = .{}, | ||
| 311 | }; | 381 | }; |
| 312 | context.global_scope.* = Scope.Root.init(&context); | 382 | context.global_scope.* = Scope.Root.init(&context); |
| 383 | defer context.decl_table.deinit(); | ||
| 384 | defer context.alias_list.deinit(); | ||
| 385 | defer context.token_ids.deinit(gpa); | ||
| 386 | defer context.token_locs.deinit(gpa); | ||
| 387 | defer context.errors.deinit(gpa); | ||
| 388 | defer context.global_names.deinit(); | ||
| 389 | defer context.root_decls.deinit(gpa); | ||
| 313 | 390 | ||
| 314 | try prepopulateGlobalNameTable(ast_unit, &context); | 391 | try prepopulateGlobalNameTable(ast_unit, &context); |
| 315 | 392 | ||
| ... | @@ -320,23 +397,34 @@ pub fn translate( | ... | @@ -320,23 +397,34 @@ pub fn translate( |
| 320 | try transPreprocessorEntities(&context, ast_unit); | 397 | try transPreprocessorEntities(&context, ast_unit); |
| 321 | 398 | ||
| 322 | try addMacros(&context); | 399 | try addMacros(&context); |
| 323 | var it = context.alias_list.iterator(0); | 400 | for (context.alias_list.items) |alias| { |
| 324 | while (it.next()) |alias| { | ||
| 325 | if (!context.global_scope.sym_table.contains(alias.alias)) { | 401 | if (!context.global_scope.sym_table.contains(alias.alias)) { |
| 326 | try createAlias(&context, alias); | 402 | try createAlias(&context, alias); |
| 327 | } | 403 | } |
| 328 | } | 404 | } |
| 329 | 405 | ||
| 330 | tree.root_node.eof_token = try appendToken(&context, .Eof, ""); | 406 | const eof_token = try appendToken(&context, .Eof, ""); |
| 331 | tree.source = source_buffer.toOwnedSlice(); | 407 | const root_node = try ast.Node.Root.create(&arena.allocator, context.root_decls.items.len, eof_token); |
| 408 | mem.copy(*ast.Node, root_node.decls(), context.root_decls.items); | ||
| 409 | |||
| 332 | if (false) { | 410 | if (false) { |
| 333 | std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", .{tree.source}); | 411 | std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", .{source_buffer.items}); |
| 334 | var i: usize = 0; | 412 | for (context.token_ids.items) |token| { |
| 335 | while (i < tree.tokens.len) : (i += 1) { | ||
| 336 | const token = tree.tokens.at(i); | ||
| 337 | std.debug.warn("{}\n", .{token}); | 413 | std.debug.warn("{}\n", .{token}); |
| 338 | } | 414 | } |
| 339 | } | 415 | } |
| 416 | |||
| 417 | const tree = try arena.allocator.create(ast.Tree); | ||
| 418 | tree.* = .{ | ||
| 419 | .gpa = gpa, | ||
| 420 | .source = try arena.allocator.dupe(u8, source_buffer.items), | ||
| 421 | .token_ids = context.token_ids.toOwnedSlice(gpa), | ||
| 422 | .token_locs = context.token_locs.toOwnedSlice(gpa), | ||
| 423 | .errors = context.errors.toOwnedSlice(gpa), | ||
| 424 | .root_node = root_node, | ||
| 425 | .arena = arena.state, | ||
| 426 | .generated = true, | ||
| 427 | }; | ||
| 340 | return tree; | 428 | return tree; |
| 341 | } | 429 | } |
| 342 | 430 | ||
| ... | @@ -490,42 +578,35 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -490,42 +578,35 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 490 | 578 | ||
| 491 | // actual function definition with body | 579 | // actual function definition with body |
| 492 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); | 580 | const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); |
| 493 | const block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null); | 581 | var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null); |
| 582 | defer block_scope.deinit(); | ||
| 494 | var scope = &block_scope.base; | 583 | var scope = &block_scope.base; |
| 495 | const block_node = try transCreateNodeBlock(rp.c, null); | ||
| 496 | block_scope.block_node = block_node; | ||
| 497 | 584 | ||
| 498 | var it = proto_node.params.iterator(0); | ||
| 499 | var param_id: c_uint = 0; | 585 | var param_id: c_uint = 0; |
| 500 | while (it.next()) |p| { | 586 | for (proto_node.params()) |*param, i| { |
| 501 | const param = @fieldParentPtr(ast.Node.ParamDecl, "base", p.*); | ||
| 502 | const param_name = if (param.name_token) |name_tok| | 587 | const param_name = if (param.name_token) |name_tok| |
| 503 | tokenSlice(c, name_tok) | 588 | tokenSlice(c, name_tok) |
| 504 | else if (param.param_type == .var_args) { | 589 | else if (param.param_type == .var_args) { |
| 505 | assert(it.next() == null); | 590 | assert(i + 1 == proto_node.params_len); |
| 506 | _ = proto_node.params.pop(); | 591 | proto_node.params_len -= 1; |
| 507 | break; | 592 | break; |
| 508 | } else | 593 | } else |
| 509 | return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name}); | 594 | return failDecl(c, fn_decl_loc, fn_name, "function {} parameter has no name", .{fn_name}); |
| 510 | 595 | ||
| 511 | const mangled_param_name = try block_scope.makeMangledName(c, param_name); | ||
| 512 | |||
| 513 | const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id); | 596 | const c_param = ZigClangFunctionDecl_getParamDecl(fn_decl, param_id); |
| 514 | const qual_type = ZigClangParmVarDecl_getOriginalType(c_param); | 597 | const qual_type = ZigClangParmVarDecl_getOriginalType(c_param); |
| 515 | const is_const = ZigClangQualType_isConstQualified(qual_type); | 598 | const is_const = ZigClangQualType_isConstQualified(qual_type); |
| 516 | 599 | ||
| 517 | const arg_name = blk: { | 600 | const mangled_param_name = try block_scope.makeMangledName(c, param_name); |
| 518 | const param_prefix = if (is_const) "" else "arg_"; | ||
| 519 | const bare_arg_name = try std.fmt.allocPrint(c.a(), "{}{}", .{ param_prefix, mangled_param_name }); | ||
| 520 | break :blk try block_scope.makeMangledName(c, bare_arg_name); | ||
| 521 | }; | ||
| 522 | 601 | ||
| 523 | if (!is_const) { | 602 | if (!is_const) { |
| 603 | const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{}", .{ mangled_param_name }); | ||
| 604 | const arg_name = try block_scope.makeMangledName(c, bare_arg_name); | ||
| 524 | const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name); | 605 | const node = try transCreateNodeVarDecl(c, false, false, mangled_param_name); |
| 525 | node.eq_token = try appendToken(c, .Equal, "="); | 606 | node.eq_token = try appendToken(c, .Equal, "="); |
| 526 | node.init_node = try transCreateNodeIdentifier(c, arg_name); | 607 | node.init_node = try transCreateNodeIdentifier(c, arg_name); |
| 527 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | 608 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 528 | try block_node.statements.push(&node.base); | 609 | try block_scope.statements.append(&node.base); |
| 529 | param.name_token = try appendIdentifier(c, arg_name); | 610 | param.name_token = try appendIdentifier(c, arg_name); |
| 530 | _ = try appendToken(c, .Colon, ":"); | 611 | _ = try appendToken(c, .Colon, ":"); |
| 531 | } | 612 | } |
| ... | @@ -533,14 +614,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { | ... | @@ -533,14 +614,15 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 533 | param_id += 1; | 614 | param_id += 1; |
| 534 | } | 615 | } |
| 535 | 616 | ||
| 536 | transCompoundStmtInline(rp, &block_scope.base, @ptrCast(*const ZigClangCompoundStmt, body_stmt), block_node) catch |err| switch (err) { | 617 | const casted_body = @ptrCast(*const ZigClangCompoundStmt, body_stmt); |
| 618 | transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) { | ||
| 537 | error.OutOfMemory => |e| return e, | 619 | error.OutOfMemory => |e| return e, |
| 538 | error.UnsupportedTranslation, | 620 | error.UnsupportedTranslation, |
| 539 | error.UnsupportedType, | 621 | error.UnsupportedType, |
| 540 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), | 622 | => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), |
| 541 | }; | 623 | }; |
| 542 | block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 624 | const body_node = try block_scope.complete(rp.c); |
| 543 | proto_node.body_node = &block_node.base; | 625 | proto_node.body_node = &body_node.base; |
| 544 | return addTopLevelDecl(c, fn_name, &proto_node.base); | 626 | return addTopLevelDecl(c, fn_name, &proto_node.base); |
| 545 | } | 627 | } |
| 546 | 628 | ||
| ... | @@ -560,7 +642,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -560,7 +642,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 560 | 642 | ||
| 561 | // TODO https://github.com/ziglang/zig/issues/3756 | 643 | // TODO https://github.com/ziglang/zig/issues/3756 |
| 562 | // TODO https://github.com/ziglang/zig/issues/1802 | 644 | // TODO https://github.com/ziglang/zig/issues/1802 |
| 563 | const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ var_name, c.getMangle() }) else var_name; | 645 | const checked_name = if (isZigPrimitiveType(var_name)) try std.fmt.allocPrint(c.arena, "{}_{}", .{ var_name, c.getMangle() }) else var_name; |
| 564 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); | 646 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); |
| 565 | 647 | ||
| 566 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); | 648 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| ... | @@ -620,7 +702,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -620,7 +702,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 620 | _ = try appendToken(rp.c, .LParen, "("); | 702 | _ = try appendToken(rp.c, .LParen, "("); |
| 621 | const expr = try transCreateNodeStringLiteral( | 703 | const expr = try transCreateNodeStringLiteral( |
| 622 | rp.c, | 704 | rp.c, |
| 623 | try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}), | 705 | try std.fmt.allocPrint(rp.c.arena, "\"{}\"", .{str_ptr[0..str_len]}), |
| 624 | ); | 706 | ); |
| 625 | _ = try appendToken(rp.c, .RParen, ")"); | 707 | _ = try appendToken(rp.c, .RParen, ")"); |
| 626 | 708 | ||
| ... | @@ -643,7 +725,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { | ... | @@ -643,7 +725,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 643 | break :blk null; | 725 | break :blk null; |
| 644 | }; | 726 | }; |
| 645 | 727 | ||
| 646 | const node = try c.a().create(ast.Node.VarDecl); | 728 | const node = try c.arena.create(ast.Node.VarDecl); |
| 647 | node.* = .{ | 729 | node.* = .{ |
| 648 | .doc_comments = null, | 730 | .doc_comments = null, |
| 649 | .visib_token = visib_tok, | 731 | .visib_token = visib_tok, |
| ... | @@ -702,7 +784,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l | ... | @@ -702,7 +784,7 @@ fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl, top_l |
| 702 | 784 | ||
| 703 | // TODO https://github.com/ziglang/zig/issues/3756 | 785 | // TODO https://github.com/ziglang/zig/issues/3756 |
| 704 | // TODO https://github.com/ziglang/zig/issues/1802 | 786 | // TODO https://github.com/ziglang/zig/issues/1802 |
| 705 | const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name; | 787 | const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{}_{}", .{ typedef_name, c.getMangle() }) else typedef_name; |
| 706 | if (checkForBuiltinTypedef(checked_name)) |builtin| { | 788 | if (checkForBuiltinTypedef(checked_name)) |builtin| { |
| 707 | return transTypeDefAsBuiltin(c, typedef_decl, builtin); | 789 | return transTypeDefAsBuiltin(c, typedef_decl, builtin); |
| 708 | } | 790 | } |
| ... | @@ -745,7 +827,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -745,7 +827,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 745 | // Record declarations such as `struct {...} x` have no name but they're not | 827 | // Record declarations such as `struct {...} x` have no name but they're not |
| 746 | // anonymous hence here isAnonymousStructOrUnion is not needed | 828 | // anonymous hence here isAnonymousStructOrUnion is not needed |
| 747 | if (bare_name.len == 0) { | 829 | if (bare_name.len == 0) { |
| 748 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | 830 | bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{}", .{c.getMangle()}); |
| 749 | is_unnamed = true; | 831 | is_unnamed = true; |
| 750 | } | 832 | } |
| 751 | 833 | ||
| ... | @@ -762,7 +844,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -762,7 +844,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 762 | return null; | 844 | return null; |
| 763 | } | 845 | } |
| 764 | 846 | ||
| 765 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); | 847 | const name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ container_kind_name, bare_name }); |
| 766 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); | 848 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); |
| 767 | 849 | ||
| 768 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); | 850 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); |
| ... | @@ -785,15 +867,8 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -785,15 +867,8 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 785 | const container_tok = try appendToken(c, container_kind, container_kind_name); | 867 | const container_tok = try appendToken(c, container_kind, container_kind_name); |
| 786 | const lbrace_token = try appendToken(c, .LBrace, "{"); | 868 | const lbrace_token = try appendToken(c, .LBrace, "{"); |
| 787 | 869 | ||
| 788 | const container_node = try c.a().create(ast.Node.ContainerDecl); | 870 | var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa); |
| 789 | container_node.* = .{ | 871 | defer fields_and_decls.deinit(); |
| 790 | .layout_token = layout_tok, | ||
| 791 | .kind_token = container_tok, | ||
| 792 | .init_arg_expr = .None, | ||
| 793 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | ||
| 794 | .lbrace_token = lbrace_token, | ||
| 795 | .rbrace_token = undefined, | ||
| 796 | }; | ||
| 797 | 872 | ||
| 798 | var unnamed_field_count: u32 = 0; | 873 | var unnamed_field_count: u32 = 0; |
| 799 | var it = ZigClangRecordDecl_field_begin(record_def); | 874 | var it = ZigClangRecordDecl_field_begin(record_def); |
| ... | @@ -821,7 +896,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -821,7 +896,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 821 | var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl))); | 896 | var raw_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl))); |
| 822 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) { | 897 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl) or raw_name.len == 0) { |
| 823 | // Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields. | 898 | // Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields. |
| 824 | raw_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{unnamed_field_count}); | 899 | raw_name = try std.fmt.allocPrint(c.arena, "unnamed_{}", .{unnamed_field_count}); |
| 825 | unnamed_field_count += 1; | 900 | unnamed_field_count += 1; |
| 826 | is_anon = true; | 901 | is_anon = true; |
| 827 | } | 902 | } |
| ... | @@ -851,7 +926,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -851,7 +926,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 851 | break :blk null; | 926 | break :blk null; |
| 852 | }; | 927 | }; |
| 853 | 928 | ||
| 854 | const field_node = try c.a().create(ast.Node.ContainerField); | 929 | const field_node = try c.arena.create(ast.Node.ContainerField); |
| 855 | field_node.* = .{ | 930 | field_node.* = .{ |
| 856 | .doc_comments = null, | 931 | .doc_comments = null, |
| 857 | .comptime_token = null, | 932 | .comptime_token = null, |
| ... | @@ -868,10 +943,19 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -868,10 +943,19 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 868 | ); | 943 | ); |
| 869 | } | 944 | } |
| 870 | 945 | ||
| 871 | try container_node.fields_and_decls.push(&field_node.base); | 946 | try fields_and_decls.append(&field_node.base); |
| 872 | _ = try appendToken(c, .Comma, ","); | 947 | _ = try appendToken(c, .Comma, ","); |
| 873 | } | 948 | } |
| 874 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | 949 | const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len); |
| 950 | container_node.* = .{ | ||
| 951 | .layout_token = layout_tok, | ||
| 952 | .kind_token = container_tok, | ||
| 953 | .init_arg_expr = .None, | ||
| 954 | .fields_and_decls_len = fields_and_decls.items.len, | ||
| 955 | .lbrace_token = lbrace_token, | ||
| 956 | .rbrace_token = try appendToken(c, .RBrace, "}"), | ||
| 957 | }; | ||
| 958 | mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items); | ||
| 875 | semicolon = try appendToken(c, .Semicolon, ";"); | 959 | semicolon = try appendToken(c, .Semicolon, ";"); |
| 876 | break :blk &container_node.base; | 960 | break :blk &container_node.base; |
| 877 | }; | 961 | }; |
| ... | @@ -879,7 +963,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* | ... | @@ -879,7 +963,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* |
| 879 | 963 | ||
| 880 | try addTopLevelDecl(c, name, &node.base); | 964 | try addTopLevelDecl(c, name, &node.base); |
| 881 | if (!is_unnamed) | 965 | if (!is_unnamed) |
| 882 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | 966 | try c.alias_list.append(.{ .alias = bare_name, .name = name }); |
| 883 | return transCreateNodeIdentifier(c, name); | 967 | return transCreateNodeIdentifier(c, name); |
| 884 | } | 968 | } |
| 885 | 969 | ||
| ... | @@ -892,11 +976,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -892,11 +976,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 892 | var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl))); | 976 | var bare_name = try c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, enum_decl))); |
| 893 | var is_unnamed = false; | 977 | var is_unnamed = false; |
| 894 | if (bare_name.len == 0) { | 978 | if (bare_name.len == 0) { |
| 895 | bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); | 979 | bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{}", .{c.getMangle()}); |
| 896 | is_unnamed = true; | 980 | is_unnamed = true; |
| 897 | } | 981 | } |
| 898 | 982 | ||
| 899 | const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); | 983 | const name = try std.fmt.allocPrint(c.arena, "enum_{}", .{bare_name}); |
| 900 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); | 984 | _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); |
| 901 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); | 985 | const node = try transCreateNodeVarDecl(c, !is_unnamed, true, name); |
| 902 | node.eq_token = try appendToken(c, .Equal, "="); | 986 | node.eq_token = try appendToken(c, .Equal, "="); |
| ... | @@ -916,15 +1000,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -916,15 +1000,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 916 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); | 1000 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 917 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); | 1001 | const container_tok = try appendToken(c, .Keyword_enum, "enum"); |
| 918 | 1002 | ||
| 919 | const container_node = try c.a().create(ast.Node.ContainerDecl); | 1003 | var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa); |
| 920 | container_node.* = .{ | 1004 | defer fields_and_decls.deinit(); |
| 921 | .layout_token = extern_tok, | ||
| 922 | .kind_token = container_tok, | ||
| 923 | .init_arg_expr = .None, | ||
| 924 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), | ||
| 925 | .lbrace_token = undefined, | ||
| 926 | .rbrace_token = undefined, | ||
| 927 | }; | ||
| 928 | 1005 | ||
| 929 | const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); | 1006 | const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); |
| 930 | // The underlying type may be null in case of forward-declared enum | 1007 | // The underlying type may be null in case of forward-declared enum |
| ... | @@ -933,7 +1010,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -933,7 +1010,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 933 | 1010 | ||
| 934 | // default to c_int since msvc and gcc default to different types | 1011 | // default to c_int since msvc and gcc default to different types |
| 935 | _ = try appendToken(c, .LParen, "("); | 1012 | _ = try appendToken(c, .LParen, "("); |
| 936 | container_node.init_arg_expr = .{ | 1013 | const init_arg_expr = ast.Node.ContainerDecl.InitArg{ |
| 937 | .Type = if (int_type.ptr != null and | 1014 | .Type = if (int_type.ptr != null and |
| 938 | !isCBuiltinType(int_type, .UInt) and | 1015 | !isCBuiltinType(int_type, .UInt) and |
| 939 | !isCBuiltinType(int_type, .Int)) | 1016 | !isCBuiltinType(int_type, .Int)) |
| ... | @@ -949,7 +1026,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -949,7 +1026,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 949 | }; | 1026 | }; |
| 950 | _ = try appendToken(c, .RParen, ")"); | 1027 | _ = try appendToken(c, .RParen, ")"); |
| 951 | 1028 | ||
| 952 | container_node.lbrace_token = try appendToken(c, .LBrace, "{"); | 1029 | const lbrace_token = try appendToken(c, .LBrace, "{"); |
| 953 | 1030 | ||
| 954 | it = ZigClangEnumDecl_enumerator_begin(enum_def); | 1031 | it = ZigClangEnumDecl_enumerator_begin(enum_def); |
| 955 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); | 1032 | end_it = ZigClangEnumDecl_enumerator_end(enum_def); |
| ... | @@ -971,7 +1048,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -971,7 +1048,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 971 | } else | 1048 | } else |
| 972 | null; | 1049 | null; |
| 973 | 1050 | ||
| 974 | const field_node = try c.a().create(ast.Node.ContainerField); | 1051 | const field_node = try c.arena.create(ast.Node.ContainerField); |
| 975 | field_node.* = .{ | 1052 | field_node.* = .{ |
| 976 | .doc_comments = null, | 1053 | .doc_comments = null, |
| 977 | .comptime_token = null, | 1054 | .comptime_token = null, |
| ... | @@ -981,32 +1058,32 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -981,32 +1058,32 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 981 | .align_expr = null, | 1058 | .align_expr = null, |
| 982 | }; | 1059 | }; |
| 983 | 1060 | ||
| 984 | try container_node.fields_and_decls.push(&field_node.base); | 1061 | try fields_and_decls.append(&field_node.base); |
| 985 | _ = try appendToken(c, .Comma, ","); | 1062 | _ = try appendToken(c, .Comma, ","); |
| 986 | 1063 | ||
| 987 | // In C each enum value is in the global namespace. So we put them there too. | 1064 | // In C each enum value is in the global namespace. So we put them there too. |
| 988 | // At this point we can rely on the enum emitting successfully. | 1065 | // At this point we can rely on the enum emitting successfully. |
| 989 | const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name); | 1066 | const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name); |
| 990 | tld_node.eq_token = try appendToken(c, .Equal, "="); | 1067 | tld_node.eq_token = try appendToken(c, .Equal, "="); |
| 991 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt"); | 1068 | const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1); |
| 992 | const enum_ident = try transCreateNodeIdentifier(c, name); | 1069 | const enum_ident = try transCreateNodeIdentifier(c, name); |
| 993 | const period_tok = try appendToken(c, .Period, "."); | 1070 | const period_tok = try appendToken(c, .Period, "."); |
| 994 | const field_ident = try transCreateNodeIdentifier(c, field_name); | 1071 | const field_ident = try transCreateNodeIdentifier(c, field_name); |
| 995 | const field_access_node = try c.a().create(ast.Node.InfixOp); | 1072 | const field_access_node = try c.arena.create(ast.Node.InfixOp); |
| 996 | field_access_node.* = .{ | 1073 | field_access_node.* = .{ |
| 997 | .op_token = period_tok, | 1074 | .op_token = period_tok, |
| 998 | .lhs = enum_ident, | 1075 | .lhs = enum_ident, |
| 999 | .op = .Period, | 1076 | .op = .Period, |
| 1000 | .rhs = field_ident, | 1077 | .rhs = field_ident, |
| 1001 | }; | 1078 | }; |
| 1002 | try cast_node.params.push(&field_access_node.base); | 1079 | cast_node.params()[0] = &field_access_node.base; |
| 1003 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1080 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1004 | tld_node.init_node = &cast_node.base; | 1081 | tld_node.init_node = &cast_node.base; |
| 1005 | tld_node.semicolon_token = try appendToken(c, .Semicolon, ";"); | 1082 | tld_node.semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 1006 | try addTopLevelDecl(c, field_name, &tld_node.base); | 1083 | try addTopLevelDecl(c, field_name, &tld_node.base); |
| 1007 | } | 1084 | } |
| 1008 | // make non exhaustive | 1085 | // make non exhaustive |
| 1009 | const field_node = try c.a().create(ast.Node.ContainerField); | 1086 | const field_node = try c.arena.create(ast.Node.ContainerField); |
| 1010 | field_node.* = .{ | 1087 | field_node.* = .{ |
| 1011 | .doc_comments = null, | 1088 | .doc_comments = null, |
| 1012 | .comptime_token = null, | 1089 | .comptime_token = null, |
| ... | @@ -1016,10 +1093,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -1016,10 +1093,18 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 1016 | .align_expr = null, | 1093 | .align_expr = null, |
| 1017 | }; | 1094 | }; |
| 1018 | 1095 | ||
| 1019 | try container_node.fields_and_decls.push(&field_node.base); | 1096 | try fields_and_decls.append(&field_node.base); |
| 1020 | _ = try appendToken(c, .Comma, ","); | 1097 | _ = try appendToken(c, .Comma, ","); |
| 1021 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); | 1098 | const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len); |
| 1022 | 1099 | container_node.* = .{ | |
| 1100 | .layout_token = extern_tok, | ||
| 1101 | .kind_token = container_tok, | ||
| 1102 | .init_arg_expr = init_arg_expr, | ||
| 1103 | .fields_and_decls_len = fields_and_decls.items.len, | ||
| 1104 | .lbrace_token = lbrace_token, | ||
| 1105 | .rbrace_token = try appendToken(c, .RBrace, "}"), | ||
| 1106 | }; | ||
| 1107 | mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items); | ||
| 1023 | break :blk &container_node.base; | 1108 | break :blk &container_node.base; |
| 1024 | } else | 1109 | } else |
| 1025 | try transCreateNodeOpaqueType(c); | 1110 | try transCreateNodeOpaqueType(c); |
| ... | @@ -1028,7 +1113,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No | ... | @@ -1028,7 +1113,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No |
| 1028 | 1113 | ||
| 1029 | try addTopLevelDecl(c, name, &node.base); | 1114 | try addTopLevelDecl(c, name, &node.base); |
| 1030 | if (!is_unnamed) | 1115 | if (!is_unnamed) |
| 1031 | try c.alias_list.push(.{ .alias = bare_name, .name = name }); | 1116 | try c.alias_list.append(.{ .alias = bare_name, .name = name }); |
| 1032 | return transCreateNodeIdentifier(c, name); | 1117 | return transCreateNodeIdentifier(c, name); |
| 1033 | } | 1118 | } |
| 1034 | 1119 | ||
| ... | @@ -1071,7 +1156,7 @@ fn transStmt( | ... | @@ -1071,7 +1156,7 @@ fn transStmt( |
| 1071 | .ParenExprClass => { | 1156 | .ParenExprClass => { |
| 1072 | const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue); | 1157 | const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue); |
| 1073 | if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); | 1158 | if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); |
| 1074 | const node = try rp.c.a().create(ast.Node.GroupedExpression); | 1159 | const node = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 1075 | node.* = .{ | 1160 | node.* = .{ |
| 1076 | .lparen = try appendToken(rp.c, .LParen, "("), | 1161 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 1077 | .expr = expr, | 1162 | .expr = expr, |
| ... | @@ -1085,7 +1170,7 @@ fn transStmt( | ... | @@ -1085,7 +1170,7 @@ fn transStmt( |
| 1085 | .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)), | 1170 | .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)), |
| 1086 | .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)), | 1171 | .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)), |
| 1087 | .NullStmtClass => { | 1172 | .NullStmtClass => { |
| 1088 | const block = try transCreateNodeBlock(rp.c, null); | 1173 | const block = try rp.c.createBlock(null, 0); |
| 1089 | block.rbrace = try appendToken(rp.c, .RBrace, "}"); | 1174 | block.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 1090 | return &block.base; | 1175 | return &block.base; |
| 1091 | }, | 1176 | }, |
| ... | @@ -1116,7 +1201,7 @@ fn transStmt( | ... | @@ -1116,7 +1201,7 @@ fn transStmt( |
| 1116 | const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?; | 1201 | const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?; |
| 1117 | const expr = try transExpr(rp, scope, source_expr, .used, lrvalue); | 1202 | const expr = try transExpr(rp, scope, source_expr, .used, lrvalue); |
| 1118 | if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); | 1203 | if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr); |
| 1119 | const node = try rp.c.a().create(ast.Node.GroupedExpression); | 1204 | const node = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 1120 | node.* = .{ | 1205 | node.* = .{ |
| 1121 | .lparen = try appendToken(rp.c, .LParen, "("), | 1206 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 1122 | .expr = expr, | 1207 | .expr = expr, |
| ... | @@ -1147,31 +1232,27 @@ fn transBinaryOperator( | ... | @@ -1147,31 +1232,27 @@ fn transBinaryOperator( |
| 1147 | var op_token: ast.TokenIndex = undefined; | 1232 | var op_token: ast.TokenIndex = undefined; |
| 1148 | var op_id: ast.Node.InfixOp.Op = undefined; | 1233 | var op_id: ast.Node.InfixOp.Op = undefined; |
| 1149 | switch (op) { | 1234 | switch (op) { |
| 1150 | .Assign => return transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)), | 1235 | .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)), |
| 1151 | .Comma => { | 1236 | .Comma => { |
| 1152 | const block_scope = try scope.findBlockScope(rp.c); | 1237 | const block_scope = try scope.findBlockScope(rp.c); |
| 1153 | const expr = block_scope.base.parent == scope; | 1238 | const expr = block_scope.base.parent == scope; |
| 1154 | const lparen = if (expr) blk: { | 1239 | const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined; |
| 1155 | const l = try appendToken(rp.c, .LParen, "("); | ||
| 1156 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | ||
| 1157 | break :blk l; | ||
| 1158 | } else undefined; | ||
| 1159 | 1240 | ||
| 1160 | const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value); | 1241 | const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value); |
| 1161 | try block_scope.block_node.statements.push(lhs); | 1242 | try block_scope.statements.append(lhs); |
| 1162 | 1243 | ||
| 1163 | const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 1244 | const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 1164 | if (expr) { | 1245 | if (expr) { |
| 1165 | _ = try appendToken(rp.c, .Semicolon, ";"); | 1246 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1166 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 1247 | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label); |
| 1167 | break_node.rhs = rhs; | 1248 | break_node.rhs = rhs; |
| 1168 | try block_scope.block_node.statements.push(&break_node.base); | 1249 | try block_scope.statements.append(&break_node.base); |
| 1169 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 1250 | const block_node = try block_scope.complete(rp.c); |
| 1170 | const rparen = try appendToken(rp.c, .RParen, ")"); | 1251 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 1171 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 1252 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 1172 | grouped_expr.* = .{ | 1253 | grouped_expr.* = .{ |
| 1173 | .lparen = lparen, | 1254 | .lparen = lparen, |
| 1174 | .expr = &block_scope.block_node.base, | 1255 | .expr = &block_node.base, |
| 1175 | .rparen = rparen, | 1256 | .rparen = rparen, |
| 1176 | }; | 1257 | }; |
| 1177 | return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); | 1258 | return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); |
| ... | @@ -1182,11 +1263,11 @@ fn transBinaryOperator( | ... | @@ -1182,11 +1263,11 @@ fn transBinaryOperator( |
| 1182 | .Div => { | 1263 | .Div => { |
| 1183 | if (cIsSignedInteger(qt)) { | 1264 | if (cIsSignedInteger(qt)) { |
| 1184 | // signed integer division uses @divTrunc | 1265 | // signed integer division uses @divTrunc |
| 1185 | const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); | 1266 | const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2); |
| 1186 | try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); | 1267 | div_trunc_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); |
| 1187 | _ = try appendToken(rp.c, .Comma, ","); | 1268 | _ = try appendToken(rp.c, .Comma, ","); |
| 1188 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 1269 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 1189 | try div_trunc_node.params.push(rhs); | 1270 | div_trunc_node.params()[1] = rhs; |
| 1190 | div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1271 | div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1191 | return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); | 1272 | return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); |
| 1192 | } | 1273 | } |
| ... | @@ -1194,11 +1275,11 @@ fn transBinaryOperator( | ... | @@ -1194,11 +1275,11 @@ fn transBinaryOperator( |
| 1194 | .Rem => { | 1275 | .Rem => { |
| 1195 | if (cIsSignedInteger(qt)) { | 1276 | if (cIsSignedInteger(qt)) { |
| 1196 | // signed integer division uses @rem | 1277 | // signed integer division uses @rem |
| 1197 | const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); | 1278 | const rem_node = try rp.c.createBuiltinCall("@rem", 2); |
| 1198 | try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); | 1279 | rem_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); |
| 1199 | _ = try appendToken(rp.c, .Comma, ","); | 1280 | _ = try appendToken(rp.c, .Comma, ","); |
| 1200 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 1281 | const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 1201 | try rem_node.params.push(rhs); | 1282 | rem_node.params()[1] = rhs; |
| 1202 | rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1283 | rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1203 | return maybeSuppressResult(rp, scope, result_used, &rem_node.base); | 1284 | return maybeSuppressResult(rp, scope, result_used, &rem_node.base); |
| 1204 | } | 1285 | } |
| ... | @@ -1302,15 +1383,15 @@ fn transBinaryOperator( | ... | @@ -1302,15 +1383,15 @@ fn transBinaryOperator( |
| 1302 | const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); | 1383 | const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); |
| 1303 | 1384 | ||
| 1304 | const lhs = if (isBoolRes(lhs_node)) init: { | 1385 | const lhs = if (isBoolRes(lhs_node)) init: { |
| 1305 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | 1386 | const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 1306 | try cast_node.params.push(lhs_node); | 1387 | cast_node.params()[0] = lhs_node; |
| 1307 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1388 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1308 | break :init &cast_node.base; | 1389 | break :init &cast_node.base; |
| 1309 | } else lhs_node; | 1390 | } else lhs_node; |
| 1310 | 1391 | ||
| 1311 | const rhs = if (isBoolRes(rhs_node)) init: { | 1392 | const rhs = if (isBoolRes(rhs_node)) init: { |
| 1312 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | 1393 | const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 1313 | try cast_node.params.push(rhs_node); | 1394 | cast_node.params()[0] = rhs_node; |
| 1314 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1395 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1315 | break :init &cast_node.base; | 1396 | break :init &cast_node.base; |
| 1316 | } else rhs_node; | 1397 | } else rhs_node; |
| ... | @@ -1322,23 +1403,22 @@ fn transCompoundStmtInline( | ... | @@ -1322,23 +1403,22 @@ fn transCompoundStmtInline( |
| 1322 | rp: RestorePoint, | 1403 | rp: RestorePoint, |
| 1323 | parent_scope: *Scope, | 1404 | parent_scope: *Scope, |
| 1324 | stmt: *const ZigClangCompoundStmt, | 1405 | stmt: *const ZigClangCompoundStmt, |
| 1325 | block_node: *ast.Node.Block, | 1406 | block: *Scope.Block, |
| 1326 | ) TransError!void { | 1407 | ) TransError!void { |
| 1327 | var it = ZigClangCompoundStmt_body_begin(stmt); | 1408 | var it = ZigClangCompoundStmt_body_begin(stmt); |
| 1328 | const end_it = ZigClangCompoundStmt_body_end(stmt); | 1409 | const end_it = ZigClangCompoundStmt_body_end(stmt); |
| 1329 | while (it != end_it) : (it += 1) { | 1410 | while (it != end_it) : (it += 1) { |
| 1330 | const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value); | 1411 | const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value); |
| 1331 | if (result != &block_node.base) | 1412 | try block.statements.append(result); |
| 1332 | try block_node.statements.push(result); | ||
| 1333 | } | 1413 | } |
| 1334 | } | 1414 | } |
| 1335 | 1415 | ||
| 1336 | fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { | 1416 | fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { |
| 1337 | const block_scope = try Scope.Block.init(rp.c, scope, null); | 1417 | var block_scope = try Scope.Block.init(rp.c, scope, null); |
| 1338 | block_scope.block_node = try transCreateNodeBlock(rp.c, null); | 1418 | defer block_scope.deinit(); |
| 1339 | try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); | 1419 | try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope); |
| 1340 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 1420 | const node = try block_scope.complete(rp.c); |
| 1341 | return &block_scope.block_node.base; | 1421 | return &node.base; |
| 1342 | } | 1422 | } |
| 1343 | 1423 | ||
| 1344 | fn transCStyleCastExprClass( | 1424 | fn transCStyleCastExprClass( |
| ... | @@ -1360,77 +1440,83 @@ fn transCStyleCastExprClass( | ... | @@ -1360,77 +1440,83 @@ fn transCStyleCastExprClass( |
| 1360 | return maybeSuppressResult(rp, scope, result_used, cast_node); | 1440 | return maybeSuppressResult(rp, scope, result_used, cast_node); |
| 1361 | } | 1441 | } |
| 1362 | 1442 | ||
| 1363 | fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { | 1443 | fn transDeclStmtOne(rp: RestorePoint, scope: *Scope, decl: *const ZigClangDecl, block_scope: *Scope.Block,) TransError!*ast.Node { |
| 1364 | const c = rp.c; | 1444 | const c = rp.c; |
| 1365 | const block_scope = scope.findBlockScope(c) catch unreachable; | 1445 | |
| 1446 | switch (ZigClangDecl_getKind(decl)) { | ||
| 1447 | .Var => { | ||
| 1448 | const var_decl = @ptrCast(*const ZigClangVarDecl, decl); | ||
| 1449 | |||
| 1450 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) | ||
| 1451 | null | ||
| 1452 | else | ||
| 1453 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); | ||
| 1454 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); | ||
| 1455 | const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( | ||
| 1456 | @ptrCast(*const ZigClangNamedDecl, var_decl), | ||
| 1457 | )); | ||
| 1458 | const mangled_name = try block_scope.makeMangledName(c, name); | ||
| 1459 | const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name); | ||
| 1460 | |||
| 1461 | _ = try appendToken(c, .Colon, ":"); | ||
| 1462 | const loc = ZigClangDecl_getLocation(decl); | ||
| 1463 | node.type_node = try transQualType(rp, qual_type, loc); | ||
| 1464 | |||
| 1465 | node.eq_token = try appendToken(c, .Equal, "="); | ||
| 1466 | var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| | ||
| 1467 | try transExprCoercing(rp, scope, expr, .used, .r_value) | ||
| 1468 | else | ||
| 1469 | try transCreateNodeUndefinedLiteral(c); | ||
| 1470 | if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { | ||
| 1471 | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); | ||
| 1472 | builtin_node.params()[0] = init_node; | ||
| 1473 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1474 | init_node = &builtin_node.base; | ||
| 1475 | } | ||
| 1476 | node.init_node = init_node; | ||
| 1477 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 1478 | return &node.base; | ||
| 1479 | }, | ||
| 1480 | .Typedef => { | ||
| 1481 | const typedef_decl = @ptrCast(*const ZigClangTypedefNameDecl, decl); | ||
| 1482 | const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( | ||
| 1483 | @ptrCast(*const ZigClangNamedDecl, typedef_decl), | ||
| 1484 | )); | ||
| 1485 | |||
| 1486 | const underlying_qual = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); | ||
| 1487 | const underlying_type = ZigClangQualType_getTypePtr(underlying_qual); | ||
| 1488 | |||
| 1489 | const mangled_name = try block_scope.makeMangledName(c, name); | ||
| 1490 | const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse | ||
| 1491 | return error.UnsupportedTranslation; | ||
| 1492 | return &node.base; | ||
| 1493 | }, | ||
| 1494 | else => |kind| return revertAndWarn( | ||
| 1495 | rp, | ||
| 1496 | error.UnsupportedTranslation, | ||
| 1497 | ZigClangDecl_getLocation(decl), | ||
| 1498 | "TODO implement translation of DeclStmt kind {}", | ||
| 1499 | .{@tagName(kind)}, | ||
| 1500 | ), | ||
| 1501 | } | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) TransError!*ast.Node { | ||
| 1505 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | ||
| 1366 | 1506 | ||
| 1367 | var it = ZigClangDeclStmt_decl_begin(stmt); | 1507 | var it = ZigClangDeclStmt_decl_begin(stmt); |
| 1368 | const end_it = ZigClangDeclStmt_decl_end(stmt); | 1508 | const end_it = ZigClangDeclStmt_decl_end(stmt); |
| 1369 | while (it != end_it) : (it += 1) { | 1509 | assert(it != end_it); |
| 1370 | switch (ZigClangDecl_getKind(it[0])) { | 1510 | while (true) : (it += 1) { |
| 1371 | .Var => { | 1511 | const node = try transDeclStmtOne(rp, scope, it[0], block_scope); |
| 1372 | const var_decl = @ptrCast(*const ZigClangVarDecl, it[0]); | ||
| 1373 | 1512 | ||
| 1374 | const thread_local_token = if (ZigClangVarDecl_getTLSKind(var_decl) == .None) | 1513 | if (it + 1 == end_it) { |
| 1375 | null | 1514 | return node; |
| 1376 | else | 1515 | } else { |
| 1377 | try appendToken(c, .Keyword_threadlocal, "threadlocal"); | 1516 | try block_scope.statements.append(node); |
| 1378 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); | ||
| 1379 | const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( | ||
| 1380 | @ptrCast(*const ZigClangNamedDecl, var_decl), | ||
| 1381 | )); | ||
| 1382 | const mangled_name = try block_scope.makeMangledName(c, name); | ||
| 1383 | const node = try transCreateNodeVarDecl(c, false, ZigClangQualType_isConstQualified(qual_type), mangled_name); | ||
| 1384 | |||
| 1385 | _ = try appendToken(c, .Colon, ":"); | ||
| 1386 | const loc = ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)); | ||
| 1387 | node.type_node = try transQualType(rp, qual_type, loc); | ||
| 1388 | |||
| 1389 | node.eq_token = try appendToken(c, .Equal, "="); | ||
| 1390 | var init_node = if (ZigClangVarDecl_getInit(var_decl)) |expr| | ||
| 1391 | try transExprCoercing(rp, scope, expr, .used, .r_value) | ||
| 1392 | else | ||
| 1393 | try transCreateNodeUndefinedLiteral(c); | ||
| 1394 | if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { | ||
| 1395 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | ||
| 1396 | try builtin_node.params.push(init_node); | ||
| 1397 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | ||
| 1398 | init_node = &builtin_node.base; | ||
| 1399 | } | ||
| 1400 | node.init_node = init_node; | ||
| 1401 | node.semicolon_token = try appendToken(c, .Semicolon, ";"); | ||
| 1402 | try block_scope.block_node.statements.push(&node.base); | ||
| 1403 | }, | ||
| 1404 | .Typedef => { | ||
| 1405 | const typedef_decl = @ptrCast(*const ZigClangTypedefNameDecl, it[0]); | ||
| 1406 | const name = try c.str(ZigClangNamedDecl_getName_bytes_begin( | ||
| 1407 | @ptrCast(*const ZigClangNamedDecl, typedef_decl), | ||
| 1408 | )); | ||
| 1409 | |||
| 1410 | const underlying_qual = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); | ||
| 1411 | const underlying_type = ZigClangQualType_getTypePtr(underlying_qual); | ||
| 1412 | |||
| 1413 | const mangled_name = try block_scope.makeMangledName(c, name); | ||
| 1414 | if (checkForBuiltinTypedef(name)) |builtin| { | ||
| 1415 | try block_scope.variables.push(.{ | ||
| 1416 | .alias = builtin, | ||
| 1417 | .name = mangled_name, | ||
| 1418 | }); | ||
| 1419 | } else { | ||
| 1420 | const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse return error.UnsupportedTranslation; | ||
| 1421 | try block_scope.block_node.statements.push(&node.base); | ||
| 1422 | } | ||
| 1423 | }, | ||
| 1424 | else => |kind| return revertAndWarn( | ||
| 1425 | rp, | ||
| 1426 | error.UnsupportedTranslation, | ||
| 1427 | ZigClangStmt_getBeginLoc(@ptrCast(*const ZigClangStmt, stmt)), | ||
| 1428 | "TODO implement translation of DeclStmt kind {}", | ||
| 1429 | .{@tagName(kind)}, | ||
| 1430 | ), | ||
| 1431 | } | 1517 | } |
| 1432 | } | 1518 | } |
| 1433 | return &block_scope.block_node.base; | 1519 | unreachable; |
| 1434 | } | 1520 | } |
| 1435 | 1521 | ||
| 1436 | fn transDeclRefExpr( | 1522 | fn transDeclRefExpr( |
| ... | @@ -1458,7 +1544,7 @@ fn transImplicitCastExpr( | ... | @@ -1458,7 +1544,7 @@ fn transImplicitCastExpr( |
| 1458 | switch (ZigClangImplicitCastExpr_getCastKind(expr)) { | 1544 | switch (ZigClangImplicitCastExpr_getCastKind(expr)) { |
| 1459 | .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => { | 1545 | .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => { |
| 1460 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); | 1546 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1461 | return transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); | 1547 | return try transCCast(rp, scope, ZigClangImplicitCastExpr_getBeginLoc(expr), dest_type, src_type, sub_expr_node); |
| 1462 | }, | 1548 | }, |
| 1463 | .LValueToRValue, .NoOp, .FunctionToPointerDecay => { | 1549 | .LValueToRValue, .NoOp, .FunctionToPointerDecay => { |
| 1464 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); | 1550 | const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| ... | @@ -1480,8 +1566,8 @@ fn transImplicitCastExpr( | ... | @@ -1480,8 +1566,8 @@ fn transImplicitCastExpr( |
| 1480 | }, | 1566 | }, |
| 1481 | .PointerToBoolean => { | 1567 | .PointerToBoolean => { |
| 1482 | // @ptrToInt(val) != 0 | 1568 | // @ptrToInt(val) != 0 |
| 1483 | const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); | 1569 | const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1); |
| 1484 | try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); | 1570 | ptr_to_int.params()[0] = try transExpr(rp, scope, sub_expr, .used, .r_value); |
| 1485 | ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1571 | ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1486 | 1572 | ||
| 1487 | const op_token = try appendToken(rp.c, .BangEqual, "!="); | 1573 | const op_token = try appendToken(rp.c, .BangEqual, "!="); |
| ... | @@ -1539,7 +1625,7 @@ fn transBoolExpr( | ... | @@ -1539,7 +1625,7 @@ fn transBoolExpr( |
| 1539 | 1625 | ||
| 1540 | if (grouped) { | 1626 | if (grouped) { |
| 1541 | const rparen = try appendToken(rp.c, .RParen, ")"); | 1627 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 1542 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 1628 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 1543 | grouped_expr.* = .{ | 1629 | grouped_expr.* = .{ |
| 1544 | .lparen = lparen, | 1630 | .lparen = lparen, |
| 1545 | .expr = node, | 1631 | .expr = node, |
| ... | @@ -1705,13 +1791,11 @@ fn transIntegerLiteral( | ... | @@ -1705,13 +1791,11 @@ fn transIntegerLiteral( |
| 1705 | 1791 | ||
| 1706 | // @as(T, x) | 1792 | // @as(T, x) |
| 1707 | const expr_base = @ptrCast(*const ZigClangExpr, expr); | 1793 | const expr_base = @ptrCast(*const ZigClangExpr, expr); |
| 1708 | const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); | 1794 | const as_node = try rp.c.createBuiltinCall("@as", 2); |
| 1709 | const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); | 1795 | const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); |
| 1710 | try as_node.params.push(ty_node); | 1796 | as_node.params()[0] = ty_node; |
| 1711 | _ = try appendToken(rp.c, .Comma, ","); | 1797 | _ = try appendToken(rp.c, .Comma, ","); |
| 1712 | 1798 | as_node.params()[1] = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); | |
| 1713 | const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); | ||
| 1714 | try as_node.params.push(int_lit_node); | ||
| 1715 | 1799 | ||
| 1716 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1800 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1717 | return maybeSuppressResult(rp, scope, result_used, &as_node.base); | 1801 | return maybeSuppressResult(rp, scope, result_used, &as_node.base); |
| ... | @@ -1747,13 +1831,13 @@ fn transStringLiteral( | ... | @@ -1747,13 +1831,13 @@ fn transStringLiteral( |
| 1747 | len = 0; | 1831 | len = 0; |
| 1748 | for (str) |c| len += escapeChar(c, &char_buf).len; | 1832 | for (str) |c| len += escapeChar(c, &char_buf).len; |
| 1749 | 1833 | ||
| 1750 | const buf = try rp.c.a().alloc(u8, len + "\"\"".len); | 1834 | const buf = try rp.c.arena.alloc(u8, len + "\"\"".len); |
| 1751 | buf[0] = '"'; | 1835 | buf[0] = '"'; |
| 1752 | writeEscapedString(buf[1..], str); | 1836 | writeEscapedString(buf[1..], str); |
| 1753 | buf[buf.len - 1] = '"'; | 1837 | buf[buf.len - 1] = '"'; |
| 1754 | 1838 | ||
| 1755 | const token = try appendToken(rp.c, .StringLiteral, buf); | 1839 | const token = try appendToken(rp.c, .StringLiteral, buf); |
| 1756 | const node = try rp.c.a().create(ast.Node.StringLiteral); | 1840 | const node = try rp.c.arena.create(ast.Node.StringLiteral); |
| 1757 | node.* = .{ | 1841 | node.* = .{ |
| 1758 | .token = token, | 1842 | .token = token, |
| 1759 | }; | 1843 | }; |
| ... | @@ -1821,35 +1905,35 @@ fn transCCast( | ... | @@ -1821,35 +1905,35 @@ fn transCCast( |
| 1821 | // 2. Bit-cast to correct signed-ness | 1905 | // 2. Bit-cast to correct signed-ness |
| 1822 | 1906 | ||
| 1823 | // @bitCast(dest_type, intermediate_value) | 1907 | // @bitCast(dest_type, intermediate_value) |
| 1824 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast"); | 1908 | const cast_node = try rp.c.createBuiltinCall("@bitCast", 2); |
| 1825 | try cast_node.params.push(try transQualType(rp, dst_type, loc)); | 1909 | cast_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1826 | _ = try appendToken(rp.c, .Comma, ","); | 1910 | _ = try appendToken(rp.c, .Comma, ","); |
| 1827 | 1911 | ||
| 1828 | switch (cIntTypeCmp(dst_type, src_type)) { | 1912 | switch (cIntTypeCmp(dst_type, src_type)) { |
| 1829 | .lt => { | 1913 | .lt => { |
| 1830 | // @truncate(SameSignSmallerInt, src_type) | 1914 | // @truncate(SameSignSmallerInt, src_type) |
| 1831 | const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate"); | 1915 | const trunc_node = try rp.c.createBuiltinCall("@truncate", 2); |
| 1832 | const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); | 1916 | const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); |
| 1833 | try trunc_node.params.push(ty_node); | 1917 | trunc_node.params()[0] = ty_node; |
| 1834 | _ = try appendToken(rp.c, .Comma, ","); | 1918 | _ = try appendToken(rp.c, .Comma, ","); |
| 1835 | try trunc_node.params.push(expr); | 1919 | trunc_node.params()[1] = expr; |
| 1836 | trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1920 | trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1837 | 1921 | ||
| 1838 | try cast_node.params.push(&trunc_node.base); | 1922 | cast_node.params()[1] = &trunc_node.base; |
| 1839 | }, | 1923 | }, |
| 1840 | .gt => { | 1924 | .gt => { |
| 1841 | // @as(SameSignBiggerInt, src_type) | 1925 | // @as(SameSignBiggerInt, src_type) |
| 1842 | const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); | 1926 | const as_node = try rp.c.createBuiltinCall("@as", 2); |
| 1843 | const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); | 1927 | const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); |
| 1844 | try as_node.params.push(ty_node); | 1928 | as_node.params()[0] = ty_node; |
| 1845 | _ = try appendToken(rp.c, .Comma, ","); | 1929 | _ = try appendToken(rp.c, .Comma, ","); |
| 1846 | try as_node.params.push(expr); | 1930 | as_node.params()[1] = expr; |
| 1847 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1931 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1848 | 1932 | ||
| 1849 | try cast_node.params.push(&as_node.base); | 1933 | cast_node.params()[1] = &as_node.base; |
| 1850 | }, | 1934 | }, |
| 1851 | .eq => { | 1935 | .eq => { |
| 1852 | try cast_node.params.push(expr); | 1936 | cast_node.params()[1] = expr; |
| 1853 | }, | 1937 | }, |
| 1854 | } | 1938 | } |
| 1855 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1939 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| ... | @@ -1857,46 +1941,46 @@ fn transCCast( | ... | @@ -1857,46 +1941,46 @@ fn transCCast( |
| 1857 | } | 1941 | } |
| 1858 | if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { | 1942 | if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { |
| 1859 | // @intCast(dest_type, @ptrToInt(val)) | 1943 | // @intCast(dest_type, @ptrToInt(val)) |
| 1860 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 1944 | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 1861 | try cast_node.params.push(try transQualType(rp, dst_type, loc)); | 1945 | cast_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1862 | _ = try appendToken(rp.c, .Comma, ","); | 1946 | _ = try appendToken(rp.c, .Comma, ","); |
| 1863 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); | 1947 | const builtin_node = try rp.c.createBuiltinCall("@ptrToInt", 1); |
| 1864 | try builtin_node.params.push(expr); | 1948 | builtin_node.params()[0] = expr; |
| 1865 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1949 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1866 | try cast_node.params.push(&builtin_node.base); | 1950 | cast_node.params()[1] = &builtin_node.base; |
| 1867 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1951 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1868 | return &cast_node.base; | 1952 | return &cast_node.base; |
| 1869 | } | 1953 | } |
| 1870 | if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { | 1954 | if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { |
| 1871 | // @intToPtr(dest_type, val) | 1955 | // @intToPtr(dest_type, val) |
| 1872 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); | 1956 | const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2); |
| 1873 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | 1957 | builtin_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1874 | _ = try appendToken(rp.c, .Comma, ","); | 1958 | _ = try appendToken(rp.c, .Comma, ","); |
| 1875 | try builtin_node.params.push(expr); | 1959 | builtin_node.params()[1] = expr; |
| 1876 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1960 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1877 | return &builtin_node.base; | 1961 | return &builtin_node.base; |
| 1878 | } | 1962 | } |
| 1879 | if (cIsFloating(src_type) and cIsFloating(dst_type)) { | 1963 | if (cIsFloating(src_type) and cIsFloating(dst_type)) { |
| 1880 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatCast"); | 1964 | const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2); |
| 1881 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | 1965 | builtin_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1882 | _ = try appendToken(rp.c, .Comma, ","); | 1966 | _ = try appendToken(rp.c, .Comma, ","); |
| 1883 | try builtin_node.params.push(expr); | 1967 | builtin_node.params()[1] = expr; |
| 1884 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1968 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1885 | return &builtin_node.base; | 1969 | return &builtin_node.base; |
| 1886 | } | 1970 | } |
| 1887 | if (cIsFloating(src_type) and !cIsFloating(dst_type)) { | 1971 | if (cIsFloating(src_type) and !cIsFloating(dst_type)) { |
| 1888 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatToInt"); | 1972 | const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2); |
| 1889 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | 1973 | builtin_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1890 | _ = try appendToken(rp.c, .Comma, ","); | 1974 | _ = try appendToken(rp.c, .Comma, ","); |
| 1891 | try builtin_node.params.push(expr); | 1975 | builtin_node.params()[1] = expr; |
| 1892 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1976 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1893 | return &builtin_node.base; | 1977 | return &builtin_node.base; |
| 1894 | } | 1978 | } |
| 1895 | if (!cIsFloating(src_type) and cIsFloating(dst_type)) { | 1979 | if (!cIsFloating(src_type) and cIsFloating(dst_type)) { |
| 1896 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToFloat"); | 1980 | const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2); |
| 1897 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | 1981 | builtin_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1898 | _ = try appendToken(rp.c, .Comma, ","); | 1982 | _ = try appendToken(rp.c, .Comma, ","); |
| 1899 | try builtin_node.params.push(expr); | 1983 | builtin_node.params()[1] = expr; |
| 1900 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1984 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1901 | return &builtin_node.base; | 1985 | return &builtin_node.base; |
| 1902 | } | 1986 | } |
| ... | @@ -1904,54 +1988,54 @@ fn transCCast( | ... | @@ -1904,54 +1988,54 @@ fn transCCast( |
| 1904 | !ZigClangType_isBooleanType(qualTypeCanon(dst_type))) | 1988 | !ZigClangType_isBooleanType(qualTypeCanon(dst_type))) |
| 1905 | { | 1989 | { |
| 1906 | // @boolToInt returns either a comptime_int or a u1 | 1990 | // @boolToInt returns either a comptime_int or a u1 |
| 1907 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | 1991 | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 1908 | try builtin_node.params.push(expr); | 1992 | builtin_node.params()[0] = expr; |
| 1909 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1993 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1910 | 1994 | ||
| 1911 | const inner_cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 1995 | const inner_cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 1912 | try inner_cast_node.params.push(try transCreateNodeIdentifier(rp.c, "u1")); | 1996 | inner_cast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "u1"); |
| 1913 | _ = try appendToken(rp.c, .Comma, ","); | 1997 | _ = try appendToken(rp.c, .Comma, ","); |
| 1914 | try inner_cast_node.params.push(&builtin_node.base); | 1998 | inner_cast_node.params()[1] = &builtin_node.base; |
| 1915 | inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 1999 | inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1916 | 2000 | ||
| 1917 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 2001 | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 1918 | try cast_node.params.push(try transQualType(rp, dst_type, loc)); | 2002 | cast_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1919 | _ = try appendToken(rp.c, .Comma, ","); | 2003 | _ = try appendToken(rp.c, .Comma, ","); |
| 1920 | 2004 | ||
| 1921 | if (cIsSignedInteger(dst_type)) { | 2005 | if (cIsSignedInteger(dst_type)) { |
| 1922 | const bitcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast"); | 2006 | const bitcast_node = try rp.c.createBuiltinCall("@bitCast", 2); |
| 1923 | try bitcast_node.params.push(try transCreateNodeIdentifier(rp.c, "i1")); | 2007 | bitcast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "i1"); |
| 1924 | _ = try appendToken(rp.c, .Comma, ","); | 2008 | _ = try appendToken(rp.c, .Comma, ","); |
| 1925 | try bitcast_node.params.push(&inner_cast_node.base); | 2009 | bitcast_node.params()[1] = &inner_cast_node.base; |
| 1926 | bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2010 | bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1927 | try cast_node.params.push(&bitcast_node.base); | 2011 | cast_node.params()[1] = &bitcast_node.base; |
| 1928 | } else { | 2012 | } else { |
| 1929 | try cast_node.params.push(&inner_cast_node.base); | 2013 | cast_node.params()[1] = &inner_cast_node.base; |
| 1930 | } | 2014 | } |
| 1931 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2015 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1932 | 2016 | ||
| 1933 | return &cast_node.base; | 2017 | return &cast_node.base; |
| 1934 | } | 2018 | } |
| 1935 | if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) { | 2019 | if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) { |
| 1936 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum"); | 2020 | const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2); |
| 1937 | try builtin_node.params.push(try transQualType(rp, dst_type, loc)); | 2021 | builtin_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1938 | _ = try appendToken(rp.c, .Comma, ","); | 2022 | _ = try appendToken(rp.c, .Comma, ","); |
| 1939 | try builtin_node.params.push(expr); | 2023 | builtin_node.params()[1] = expr; |
| 1940 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2024 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1941 | return &builtin_node.base; | 2025 | return &builtin_node.base; |
| 1942 | } | 2026 | } |
| 1943 | if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(src_type)) == .Enum and | 2027 | if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(src_type)) == .Enum and |
| 1944 | ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) != .Enum) | 2028 | ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) != .Enum) |
| 1945 | { | 2029 | { |
| 1946 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt"); | 2030 | const builtin_node = try rp.c.createBuiltinCall("@enumToInt", 1); |
| 1947 | try builtin_node.params.push(expr); | 2031 | builtin_node.params()[0] = expr; |
| 1948 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2032 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1949 | return &builtin_node.base; | 2033 | return &builtin_node.base; |
| 1950 | } | 2034 | } |
| 1951 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); | 2035 | const cast_node = try rp.c.createBuiltinCall("@as", 2); |
| 1952 | try cast_node.params.push(try transQualType(rp, dst_type, loc)); | 2036 | cast_node.params()[0] = try transQualType(rp, dst_type, loc); |
| 1953 | _ = try appendToken(rp.c, .Comma, ","); | 2037 | _ = try appendToken(rp.c, .Comma, ","); |
| 1954 | try cast_node.params.push(expr); | 2038 | cast_node.params()[1] = expr; |
| 1955 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2039 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 1956 | return &cast_node.base; | 2040 | return &cast_node.base; |
| 1957 | } | 2041 | } |
| ... | @@ -2014,7 +2098,10 @@ fn transInitListExprRecord( | ... | @@ -2014,7 +2098,10 @@ fn transInitListExprRecord( |
| 2014 | 2098 | ||
| 2015 | const ty_node = try transType(rp, ty, loc); | 2099 | const ty_node = try transType(rp, ty, loc); |
| 2016 | const init_count = ZigClangInitListExpr_getNumInits(expr); | 2100 | const init_count = ZigClangInitListExpr_getNumInits(expr); |
| 2017 | var init_node = try transCreateNodeStructInitializer(rp.c, ty_node); | 2101 | var field_inits = std.ArrayList(*ast.Node).init(rp.c.gpa); |
| 2102 | defer field_inits.deinit(); | ||
| 2103 | |||
| 2104 | _ = try appendToken(rp.c, .LBrace, "{"); | ||
| 2018 | 2105 | ||
| 2019 | var init_i: c_uint = 0; | 2106 | var init_i: c_uint = 0; |
| 2020 | var it = ZigClangRecordDecl_field_begin(record_def); | 2107 | var it = ZigClangRecordDecl_field_begin(record_def); |
| ... | @@ -2038,26 +2125,31 @@ fn transInitListExprRecord( | ... | @@ -2038,26 +2125,31 @@ fn transInitListExprRecord( |
| 2038 | var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl))); | 2125 | var raw_name = try rp.c.str(ZigClangNamedDecl_getName_bytes_begin(@ptrCast(*const ZigClangNamedDecl, field_decl))); |
| 2039 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { | 2126 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { |
| 2040 | const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?; | 2127 | const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?; |
| 2041 | raw_name = try mem.dupe(rp.c.a(), u8, name.value); | 2128 | raw_name = try mem.dupe(rp.c.arena, u8, name.value); |
| 2042 | } | 2129 | } |
| 2043 | const field_name_tok = try appendIdentifier(rp.c, raw_name); | 2130 | const field_name_tok = try appendIdentifier(rp.c, raw_name); |
| 2044 | 2131 | ||
| 2045 | _ = try appendToken(rp.c, .Equal, "="); | 2132 | _ = try appendToken(rp.c, .Equal, "="); |
| 2046 | 2133 | ||
| 2047 | const field_init_node = try rp.c.a().create(ast.Node.FieldInitializer); | 2134 | const field_init_node = try rp.c.arena.create(ast.Node.FieldInitializer); |
| 2048 | field_init_node.* = .{ | 2135 | field_init_node.* = .{ |
| 2049 | .period_token = period_tok, | 2136 | .period_token = period_tok, |
| 2050 | .name_token = field_name_tok, | 2137 | .name_token = field_name_tok, |
| 2051 | .expr = try transExpr(rp, scope, elem_expr, .used, .r_value), | 2138 | .expr = try transExpr(rp, scope, elem_expr, .used, .r_value), |
| 2052 | }; | 2139 | }; |
| 2053 | 2140 | ||
| 2054 | try init_node.op.StructInitializer.push(&field_init_node.base); | 2141 | try field_inits.append(&field_init_node.base); |
| 2055 | _ = try appendToken(rp.c, .Comma, ","); | 2142 | _ = try appendToken(rp.c, .Comma, ","); |
| 2056 | } | 2143 | } |
| 2057 | 2144 | ||
| 2058 | init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); | 2145 | const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len); |
| 2059 | 2146 | node.* = .{ | |
| 2060 | return &init_node.base; | 2147 | .lhs = ty_node, |
| 2148 | .rtoken = try appendToken(rp.c, .RBrace, "}"), | ||
| 2149 | .list_len = field_inits.items.len, | ||
| 2150 | }; | ||
| 2151 | mem.copy(*ast.Node, node.list(), field_inits.items); | ||
| 2152 | return &node.base; | ||
| 2061 | } | 2153 | } |
| 2062 | 2154 | ||
| 2063 | fn transCreateNodeArrayType( | 2155 | fn transCreateNodeArrayType( |
| ... | @@ -2100,7 +2192,7 @@ fn transInitListExprArray( | ... | @@ -2100,7 +2192,7 @@ fn transInitListExprArray( |
| 2100 | const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize)); | 2192 | const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, math.maxInt(usize)); |
| 2101 | const leftover_count = all_count - init_count; | 2193 | const leftover_count = all_count - init_count; |
| 2102 | 2194 | ||
| 2103 | var init_node: *ast.Node.SuffixOp = undefined; | 2195 | var init_node: *ast.Node.ArrayInitializer = undefined; |
| 2104 | var cat_tok: ast.TokenIndex = undefined; | 2196 | var cat_tok: ast.TokenIndex = undefined; |
| 2105 | if (init_count != 0) { | 2197 | if (init_count != 0) { |
| 2106 | const ty_node = try transCreateNodeArrayType( | 2198 | const ty_node = try transCreateNodeArrayType( |
| ... | @@ -2109,11 +2201,19 @@ fn transInitListExprArray( | ... | @@ -2109,11 +2201,19 @@ fn transInitListExprArray( |
| 2109 | ZigClangQualType_getTypePtr(child_qt), | 2201 | ZigClangQualType_getTypePtr(child_qt), |
| 2110 | init_count, | 2202 | init_count, |
| 2111 | ); | 2203 | ); |
| 2112 | init_node = try transCreateNodeArrayInitializer(rp.c, ty_node); | 2204 | _ = try appendToken(rp.c, .LBrace, "{"); |
| 2205 | init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, init_count); | ||
| 2206 | init_node.* = .{ | ||
| 2207 | .lhs = ty_node, | ||
| 2208 | .rtoken = undefined, | ||
| 2209 | .list_len = init_count, | ||
| 2210 | }; | ||
| 2211 | const init_list = init_node.list(); | ||
| 2212 | |||
| 2113 | var i: c_uint = 0; | 2213 | var i: c_uint = 0; |
| 2114 | while (i < init_count) : (i += 1) { | 2214 | while (i < init_count) : (i += 1) { |
| 2115 | const elem_expr = ZigClangInitListExpr_getInit(expr, i); | 2215 | const elem_expr = ZigClangInitListExpr_getInit(expr, i); |
| 2116 | try init_node.op.ArrayInitializer.push(try transExpr(rp, scope, elem_expr, .used, .r_value)); | 2216 | init_list[i] = try transExpr(rp, scope, elem_expr, .used, .r_value); |
| 2117 | _ = try appendToken(rp.c, .Comma, ","); | 2217 | _ = try appendToken(rp.c, .Comma, ","); |
| 2118 | } | 2218 | } |
| 2119 | init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); | 2219 | init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| ... | @@ -2124,16 +2224,22 @@ fn transInitListExprArray( | ... | @@ -2124,16 +2224,22 @@ fn transInitListExprArray( |
| 2124 | } | 2224 | } |
| 2125 | 2225 | ||
| 2126 | const ty_node = try transCreateNodeArrayType(rp, loc, ZigClangQualType_getTypePtr(child_qt), 1); | 2226 | const ty_node = try transCreateNodeArrayType(rp, loc, ZigClangQualType_getTypePtr(child_qt), 1); |
| 2127 | var filler_init_node = try transCreateNodeArrayInitializer(rp.c, ty_node); | 2227 | _ = try appendToken(rp.c, .LBrace, "{"); |
| 2228 | const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 1); | ||
| 2229 | filler_init_node.* = .{ | ||
| 2230 | .lhs = ty_node, | ||
| 2231 | .rtoken = undefined, | ||
| 2232 | .list_len = 1, | ||
| 2233 | }; | ||
| 2128 | const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); | 2234 | const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); |
| 2129 | try filler_init_node.op.ArrayInitializer.push(try transExpr(rp, scope, filler_val_expr, .used, .r_value)); | 2235 | filler_init_node.list()[0] = try transExpr(rp, scope, filler_val_expr, .used, .r_value); |
| 2130 | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); | 2236 | filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); |
| 2131 | 2237 | ||
| 2132 | const rhs_node = if (leftover_count == 1) | 2238 | const rhs_node = if (leftover_count == 1) |
| 2133 | &filler_init_node.base | 2239 | &filler_init_node.base |
| 2134 | else blk: { | 2240 | else blk: { |
| 2135 | const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**"); | 2241 | const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**"); |
| 2136 | const mul_node = try rp.c.a().create(ast.Node.InfixOp); | 2242 | const mul_node = try rp.c.arena.create(ast.Node.InfixOp); |
| 2137 | mul_node.* = .{ | 2243 | mul_node.* = .{ |
| 2138 | .op_token = mul_tok, | 2244 | .op_token = mul_tok, |
| 2139 | .lhs = &filler_init_node.base, | 2245 | .lhs = &filler_init_node.base, |
| ... | @@ -2147,7 +2253,7 @@ fn transInitListExprArray( | ... | @@ -2147,7 +2253,7 @@ fn transInitListExprArray( |
| 2147 | return rhs_node; | 2253 | return rhs_node; |
| 2148 | } | 2254 | } |
| 2149 | 2255 | ||
| 2150 | const cat_node = try rp.c.a().create(ast.Node.InfixOp); | 2256 | const cat_node = try rp.c.arena.create(ast.Node.InfixOp); |
| 2151 | cat_node.* = .{ | 2257 | cat_node.* = .{ |
| 2152 | .op_token = cat_tok, | 2258 | .op_token = cat_tok, |
| 2153 | .lhs = &init_node.base, | 2259 | .lhs = &init_node.base, |
| ... | @@ -2266,11 +2372,15 @@ fn transIfStmt( | ... | @@ -2266,11 +2372,15 @@ fn transIfStmt( |
| 2266 | // if (c) t else e | 2372 | // if (c) t else e |
| 2267 | const if_node = try transCreateNodeIf(rp.c); | 2373 | const if_node = try transCreateNodeIf(rp.c); |
| 2268 | 2374 | ||
| 2269 | var cond_scope = Scope{ | 2375 | var cond_scope = Scope.Condition{ |
| 2270 | .parent = scope, | 2376 | .base = .{ |
| 2271 | .id = .Condition, | 2377 | .parent = scope, |
| 2378 | .id = .Condition, | ||
| 2379 | }, | ||
| 2272 | }; | 2380 | }; |
| 2273 | if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false); | 2381 | defer cond_scope.deinit(); |
| 2382 | const cond_expr = @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)); | ||
| 2383 | if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); | ||
| 2274 | _ = try appendToken(rp.c, .RParen, ")"); | 2384 | _ = try appendToken(rp.c, .RParen, ")"); |
| 2275 | 2385 | ||
| 2276 | if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value); | 2386 | if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value); |
| ... | @@ -2290,11 +2400,15 @@ fn transWhileLoop( | ... | @@ -2290,11 +2400,15 @@ fn transWhileLoop( |
| 2290 | ) TransError!*ast.Node { | 2400 | ) TransError!*ast.Node { |
| 2291 | const while_node = try transCreateNodeWhile(rp.c); | 2401 | const while_node = try transCreateNodeWhile(rp.c); |
| 2292 | 2402 | ||
| 2293 | var cond_scope = Scope{ | 2403 | var cond_scope = Scope.Condition{ |
| 2294 | .parent = scope, | 2404 | .base = .{ |
| 2295 | .id = .Condition, | 2405 | .parent = scope, |
| 2406 | .id = .Condition, | ||
| 2407 | }, | ||
| 2296 | }; | 2408 | }; |
| 2297 | while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false); | 2409 | defer cond_scope.deinit(); |
| 2410 | const cond_expr = @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)); | ||
| 2411 | while_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); | ||
| 2298 | _ = try appendToken(rp.c, .RParen, ")"); | 2412 | _ = try appendToken(rp.c, .RParen, ")"); |
| 2299 | 2413 | ||
| 2300 | var loop_scope = Scope{ | 2414 | var loop_scope = Scope{ |
| ... | @@ -2323,12 +2437,15 @@ fn transDoWhileLoop( | ... | @@ -2323,12 +2437,15 @@ fn transDoWhileLoop( |
| 2323 | 2437 | ||
| 2324 | // if (!cond) break; | 2438 | // if (!cond) break; |
| 2325 | const if_node = try transCreateNodeIf(rp.c); | 2439 | const if_node = try transCreateNodeIf(rp.c); |
| 2326 | var cond_scope = Scope{ | 2440 | var cond_scope = Scope.Condition{ |
| 2327 | .parent = scope, | 2441 | .base = .{ |
| 2328 | .id = .Condition, | 2442 | .parent = scope, |
| 2443 | .id = .Condition, | ||
| 2444 | }, | ||
| 2329 | }; | 2445 | }; |
| 2446 | defer cond_scope.deinit(); | ||
| 2330 | const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); | 2447 | const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); |
| 2331 | prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); | 2448 | prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); |
| 2332 | _ = try appendToken(rp.c, .RParen, ")"); | 2449 | _ = try appendToken(rp.c, .RParen, ")"); |
| 2333 | if_node.condition = &prefix_op.base; | 2450 | if_node.condition = &prefix_op.base; |
| 2334 | if_node.body = &(try transCreateNodeBreak(rp.c, null)).base; | 2451 | if_node.body = &(try transCreateNodeBreak(rp.c, null)).base; |
| ... | @@ -2345,7 +2462,8 @@ fn transDoWhileLoop( | ... | @@ -2345,7 +2462,8 @@ fn transDoWhileLoop( |
| 2345 | // zig: b; | 2462 | // zig: b; |
| 2346 | // zig: if (!cond) break; | 2463 | // zig: if (!cond) break; |
| 2347 | // zig: } | 2464 | // zig: } |
| 2348 | break :blk (try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?; | 2465 | const node = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value); |
| 2466 | break :blk node.cast(ast.Node.Block).?; | ||
| 2349 | } else blk: { | 2467 | } else blk: { |
| 2350 | // the C statement is without a block, so we need to create a block to contain it. | 2468 | // the C statement is without a block, so we need to create a block to contain it. |
| 2351 | // c: do | 2469 | // c: do |
| ... | @@ -2356,12 +2474,15 @@ fn transDoWhileLoop( | ... | @@ -2356,12 +2474,15 @@ fn transDoWhileLoop( |
| 2356 | // zig: if (!cond) break; | 2474 | // zig: if (!cond) break; |
| 2357 | // zig: } | 2475 | // zig: } |
| 2358 | new = true; | 2476 | new = true; |
| 2359 | const block = try transCreateNodeBlock(rp.c, null); | 2477 | const block = try rp.c.createBlock(null, 2); |
| 2360 | try block.statements.push(try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)); | 2478 | block.statements_len = 1; // over-allocated so we can add another below |
| 2479 | block.statements()[0] = try transStmt(rp, &loop_scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value); | ||
| 2361 | break :blk block; | 2480 | break :blk block; |
| 2362 | }; | 2481 | }; |
| 2363 | 2482 | ||
| 2364 | try body_node.statements.push(&if_node.base); | 2483 | // In both cases above, we reserved 1 extra statement. |
| 2484 | body_node.statements_len += 1; | ||
| 2485 | body_node.statements()[body_node.statements_len - 1] = &if_node.base; | ||
| 2365 | if (new) | 2486 | if (new) |
| 2366 | body_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 2487 | body_node.rbrace = try appendToken(rp.c, .RBrace, "}"); |
| 2367 | while_node.body = &body_node.base; | 2488 | while_node.body = &body_node.base; |
| ... | @@ -2378,24 +2499,26 @@ fn transForLoop( | ... | @@ -2378,24 +2499,26 @@ fn transForLoop( |
| 2378 | .id = .Loop, | 2499 | .id = .Loop, |
| 2379 | }; | 2500 | }; |
| 2380 | 2501 | ||
| 2381 | var block_scope: ?*Scope.Block = null; | 2502 | var block_scope: ?Scope.Block = null; |
| 2503 | defer if (block_scope) |*bs| bs.deinit(); | ||
| 2504 | |||
| 2382 | if (ZigClangForStmt_getInit(stmt)) |init| { | 2505 | if (ZigClangForStmt_getInit(stmt)) |init| { |
| 2383 | block_scope = try Scope.Block.init(rp.c, scope, null); | 2506 | block_scope = try Scope.Block.init(rp.c, scope, null); |
| 2384 | const block = try transCreateNodeBlock(rp.c, null); | ||
| 2385 | block_scope.?.block_node = block; | ||
| 2386 | loop_scope.parent = &block_scope.?.base; | 2507 | loop_scope.parent = &block_scope.?.base; |
| 2387 | const result = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value); | 2508 | const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value); |
| 2388 | if (result != &block.base) | 2509 | try block_scope.?.statements.append(init_node); |
| 2389 | try block.statements.push(result); | ||
| 2390 | } | 2510 | } |
| 2391 | var cond_scope = Scope{ | 2511 | var cond_scope = Scope.Condition{ |
| 2392 | .parent = scope, | 2512 | .base = .{ |
| 2393 | .id = .Condition, | 2513 | .parent = scope, |
| 2514 | .id = .Condition, | ||
| 2515 | }, | ||
| 2394 | }; | 2516 | }; |
| 2517 | defer cond_scope.deinit(); | ||
| 2395 | 2518 | ||
| 2396 | const while_node = try transCreateNodeWhile(rp.c); | 2519 | const while_node = try transCreateNodeWhile(rp.c); |
| 2397 | while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond| | 2520 | while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond| |
| 2398 | try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false) | 2521 | try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false) |
| 2399 | else | 2522 | else |
| 2400 | try transCreateNodeBoolLiteral(rp.c, true); | 2523 | try transCreateNodeBoolLiteral(rp.c, true); |
| 2401 | _ = try appendToken(rp.c, .RParen, ")"); | 2524 | _ = try appendToken(rp.c, .RParen, ")"); |
| ... | @@ -2403,61 +2526,92 @@ fn transForLoop( | ... | @@ -2403,61 +2526,92 @@ fn transForLoop( |
| 2403 | if (ZigClangForStmt_getInc(stmt)) |incr| { | 2526 | if (ZigClangForStmt_getInc(stmt)) |incr| { |
| 2404 | _ = try appendToken(rp.c, .Colon, ":"); | 2527 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2405 | _ = try appendToken(rp.c, .LParen, "("); | 2528 | _ = try appendToken(rp.c, .LParen, "("); |
| 2406 | while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value); | 2529 | while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value); |
| 2407 | _ = try appendToken(rp.c, .RParen, ")"); | 2530 | _ = try appendToken(rp.c, .RParen, ")"); |
| 2408 | } | 2531 | } |
| 2409 | 2532 | ||
| 2410 | while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value); | 2533 | while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value); |
| 2411 | if (block_scope != null) { | 2534 | if (block_scope) |*bs| { |
| 2412 | try block_scope.?.block_node.statements.push(&while_node.base); | 2535 | try bs.statements.append(&while_node.base); |
| 2413 | block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 2536 | const node = try bs.complete(rp.c); |
| 2414 | return &block_scope.?.block_node.base; | 2537 | return &node.base; |
| 2415 | } else { | 2538 | } else { |
| 2416 | _ = try appendToken(rp.c, .Semicolon, ";"); | 2539 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2417 | return &while_node.base; | 2540 | return &while_node.base; |
| 2418 | } | 2541 | } |
| 2419 | } | 2542 | } |
| 2420 | 2543 | ||
| 2544 | fn getSwitchCaseCount(stmt: *const ZigClangSwitchStmt) usize { | ||
| 2545 | const body = ZigClangSwitchStmt_getBody(stmt); | ||
| 2546 | assert(ZigClangStmt_getStmtClass(body) == .CompoundStmtClass); | ||
| 2547 | const comp = @ptrCast(*const ZigClangCompoundStmt, body); | ||
| 2548 | // TODO https://github.com/ziglang/zig/issues/1738 | ||
| 2549 | // return ZigClangCompoundStmt_body_end(comp) - ZigClangCompoundStmt_body_begin(comp); | ||
| 2550 | const start_addr = @ptrToInt(ZigClangCompoundStmt_body_begin(comp)); | ||
| 2551 | const end_addr = @ptrToInt(ZigClangCompoundStmt_body_end(comp)); | ||
| 2552 | return (end_addr - start_addr) / @sizeOf(*ZigClangStmt); | ||
| 2553 | } | ||
| 2554 | |||
| 2421 | fn transSwitch( | 2555 | fn transSwitch( |
| 2422 | rp: RestorePoint, | 2556 | rp: RestorePoint, |
| 2423 | scope: *Scope, | 2557 | scope: *Scope, |
| 2424 | stmt: *const ZigClangSwitchStmt, | 2558 | stmt: *const ZigClangSwitchStmt, |
| 2425 | ) TransError!*ast.Node { | 2559 | ) TransError!*ast.Node { |
| 2426 | const switch_node = try transCreateNodeSwitch(rp.c); | 2560 | const switch_tok = try appendToken(rp.c, .Keyword_switch, "switch"); |
| 2561 | _ = try appendToken(rp.c, .LParen, "("); | ||
| 2562 | |||
| 2563 | const cases_len = getSwitchCaseCount(stmt); | ||
| 2564 | |||
| 2565 | var cond_scope = Scope.Condition{ | ||
| 2566 | .base = .{ | ||
| 2567 | .parent = scope, | ||
| 2568 | .id = .Condition, | ||
| 2569 | }, | ||
| 2570 | }; | ||
| 2571 | defer cond_scope.deinit(); | ||
| 2572 | const switch_expr = try transExpr(rp, &cond_scope.base, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); | ||
| 2573 | _ = try appendToken(rp.c, .RParen, ")"); | ||
| 2574 | _ = try appendToken(rp.c, .LBrace, "{"); | ||
| 2575 | // reserve +1 case in case there is no default case | ||
| 2576 | const switch_node = try ast.Node.Switch.alloc(rp.c.arena, cases_len + 1); | ||
| 2577 | switch_node.* = .{ | ||
| 2578 | .switch_token = switch_tok, | ||
| 2579 | .expr = switch_expr, | ||
| 2580 | .cases_len = cases_len + 1, | ||
| 2581 | .rbrace = try appendToken(rp.c, .RBrace, "}"), | ||
| 2582 | }; | ||
| 2583 | |||
| 2427 | var switch_scope = Scope.Switch{ | 2584 | var switch_scope = Scope.Switch{ |
| 2428 | .base = .{ | 2585 | .base = .{ |
| 2429 | .id = .Switch, | 2586 | .id = .Switch, |
| 2430 | .parent = scope, | 2587 | .parent = scope, |
| 2431 | }, | 2588 | }, |
| 2432 | .cases = &switch_node.cases, | 2589 | .cases = switch_node.cases(), |
| 2590 | .case_index = 0, | ||
| 2433 | .pending_block = undefined, | 2591 | .pending_block = undefined, |
| 2434 | }; | 2592 | }; |
| 2435 | 2593 | ||
| 2436 | var cond_scope = Scope{ | ||
| 2437 | .parent = scope, | ||
| 2438 | .id = .Condition, | ||
| 2439 | }; | ||
| 2440 | switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); | ||
| 2441 | _ = try appendToken(rp.c, .RParen, ")"); | ||
| 2442 | _ = try appendToken(rp.c, .LBrace, "{"); | ||
| 2443 | switch_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 2444 | |||
| 2445 | const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); | ||
| 2446 | // tmp block that all statements will go before being picked up by a case or default | 2594 | // tmp block that all statements will go before being picked up by a case or default |
| 2447 | const block = try transCreateNodeBlock(rp.c, null); | 2595 | var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); |
| 2448 | block_scope.block_node = block; | 2596 | defer block_scope.deinit(); |
| 2449 | 2597 | ||
| 2450 | const switch_block = try transCreateNodeBlock(rp.c, null); | 2598 | // Note that we do not defer a deinit here; the switch_scope.pending_block field |
| 2451 | try switch_block.statements.push(&switch_node.base); | 2599 | // has its own memory management. This resource is freed inside `transCase` and |
| 2452 | switch_scope.pending_block = switch_block; | 2600 | // then the final pending_block is freed at the bottom of this function with |
| 2601 | // pending_block.deinit(). | ||
| 2602 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); | ||
| 2603 | try switch_scope.pending_block.statements.append(&switch_node.base); | ||
| 2453 | 2604 | ||
| 2454 | const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); | 2605 | const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); |
| 2455 | _ = try appendToken(rp.c, .Semicolon, ";"); | 2606 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2456 | 2607 | ||
| 2457 | // take all pending statements | 2608 | // take all pending statements |
| 2458 | var it = last.cast(ast.Node.Block).?.statements.iterator(0); | 2609 | const last_block_stmts = last.cast(ast.Node.Block).?.statements(); |
| 2459 | while (it.next()) |n| { | 2610 | try switch_scope.pending_block.statements.ensureCapacity( |
| 2460 | try switch_scope.pending_block.statements.push(n.*); | 2611 | switch_scope.pending_block.statements.items.len + last_block_stmts.len, |
| 2612 | ); | ||
| 2613 | for (last_block_stmts) |n| { | ||
| 2614 | switch_scope.pending_block.statements.appendAssumeCapacity(n); | ||
| 2461 | } | 2615 | } |
| 2462 | 2616 | ||
| 2463 | switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch"); | 2617 | switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch"); |
| ... | @@ -2466,10 +2620,16 @@ fn transSwitch( | ... | @@ -2466,10 +2620,16 @@ fn transSwitch( |
| 2466 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | 2620 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); |
| 2467 | else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base; | 2621 | else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base; |
| 2468 | _ = try appendToken(rp.c, .Comma, ","); | 2622 | _ = try appendToken(rp.c, .Comma, ","); |
| 2469 | try switch_node.cases.push(&else_prong.base); | 2623 | switch_scope.cases[switch_scope.case_index] = &else_prong.base; |
| 2624 | switch_scope.case_index += 1; | ||
| 2470 | } | 2625 | } |
| 2471 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | 2626 | // We overallocated in case there was no default, so now we correct |
| 2472 | return &switch_scope.pending_block.base; | 2627 | // the number of cases in the AST node. |
| 2628 | switch_node.cases_len = switch_scope.case_index; | ||
| 2629 | |||
| 2630 | const result_node = try switch_scope.pending_block.complete(rp.c); | ||
| 2631 | switch_scope.pending_block.deinit(); | ||
| 2632 | return &result_node.base; | ||
| 2473 | } | 2633 | } |
| 2474 | 2634 | ||
| 2475 | fn transCase( | 2635 | fn transCase( |
| ... | @@ -2479,7 +2639,7 @@ fn transCase( | ... | @@ -2479,7 +2639,7 @@ fn transCase( |
| 2479 | ) TransError!*ast.Node { | 2639 | ) TransError!*ast.Node { |
| 2480 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | 2640 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; |
| 2481 | const switch_scope = scope.getSwitch(); | 2641 | const switch_scope = scope.getSwitch(); |
| 2482 | const label = try std.fmt.allocPrint(rp.c.a(), "__case_{}", .{switch_scope.cases.len - @boolToInt(switch_scope.has_default)}); | 2642 | const label = try std.fmt.allocPrint(rp.c.arena, "__case_{}", .{switch_scope.case_index - @boolToInt(switch_scope.has_default)}); |
| 2483 | _ = try appendToken(rp.c, .Semicolon, ";"); | 2643 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2484 | 2644 | ||
| 2485 | const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: { | 2645 | const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: { |
| ... | @@ -2487,7 +2647,7 @@ fn transCase( | ... | @@ -2487,7 +2647,7 @@ fn transCase( |
| 2487 | const ellips = try appendToken(rp.c, .Ellipsis3, "..."); | 2647 | const ellips = try appendToken(rp.c, .Ellipsis3, "..."); |
| 2488 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | 2648 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); |
| 2489 | 2649 | ||
| 2490 | const node = try rp.c.a().create(ast.Node.InfixOp); | 2650 | const node = try rp.c.arena.create(ast.Node.InfixOp); |
| 2491 | node.* = .{ | 2651 | node.* = .{ |
| 2492 | .op_token = ellips, | 2652 | .op_token = ellips, |
| 2493 | .lhs = lhs_node, | 2653 | .lhs = lhs_node, |
| ... | @@ -2501,22 +2661,21 @@ fn transCase( | ... | @@ -2501,22 +2661,21 @@ fn transCase( |
| 2501 | const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); | 2661 | const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); |
| 2502 | switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; | 2662 | switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; |
| 2503 | _ = try appendToken(rp.c, .Comma, ","); | 2663 | _ = try appendToken(rp.c, .Comma, ","); |
| 2504 | try switch_scope.cases.push(&switch_prong.base); | 2664 | switch_scope.cases[switch_scope.case_index] = &switch_prong.base; |
| 2665 | switch_scope.case_index += 1; | ||
| 2505 | 2666 | ||
| 2506 | const block = try transCreateNodeBlock(rp.c, null); | ||
| 2507 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); | 2667 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); |
| 2508 | _ = try appendToken(rp.c, .Colon, ":"); | 2668 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2509 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 2510 | try block.statements.push(&switch_scope.pending_block.base); | ||
| 2511 | 2669 | ||
| 2512 | // take all pending statements | 2670 | // take all pending statements |
| 2513 | var it = block_scope.block_node.statements.iterator(0); | 2671 | try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); |
| 2514 | while (it.next()) |n| { | 2672 | block_scope.statements.shrink(0); |
| 2515 | try switch_scope.pending_block.statements.push(n.*); | ||
| 2516 | } | ||
| 2517 | block_scope.block_node.statements.shrink(0); | ||
| 2518 | 2673 | ||
| 2519 | switch_scope.pending_block = block; | 2674 | const pending_node = try switch_scope.pending_block.complete(rp.c); |
| 2675 | switch_scope.pending_block.deinit(); | ||
| 2676 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); | ||
| 2677 | |||
| 2678 | try switch_scope.pending_block.statements.append(&pending_node.base); | ||
| 2520 | 2679 | ||
| 2521 | return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value); | 2680 | return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value); |
| 2522 | } | 2681 | } |
| ... | @@ -2535,22 +2694,21 @@ fn transDefault( | ... | @@ -2535,22 +2694,21 @@ fn transDefault( |
| 2535 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | 2694 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); |
| 2536 | else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; | 2695 | else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; |
| 2537 | _ = try appendToken(rp.c, .Comma, ","); | 2696 | _ = try appendToken(rp.c, .Comma, ","); |
| 2538 | try switch_scope.cases.push(&else_prong.base); | 2697 | switch_scope.cases[switch_scope.case_index] = &else_prong.base; |
| 2698 | switch_scope.case_index += 1; | ||
| 2539 | 2699 | ||
| 2540 | const block = try transCreateNodeBlock(rp.c, null); | ||
| 2541 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); | 2700 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); |
| 2542 | _ = try appendToken(rp.c, .Colon, ":"); | 2701 | _ = try appendToken(rp.c, .Colon, ":"); |
| 2543 | switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); | ||
| 2544 | try block.statements.push(&switch_scope.pending_block.base); | ||
| 2545 | 2702 | ||
| 2546 | // take all pending statements | 2703 | // take all pending statements |
| 2547 | var it = block_scope.block_node.statements.iterator(0); | 2704 | try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); |
| 2548 | while (it.next()) |n| { | 2705 | block_scope.statements.shrink(0); |
| 2549 | try switch_scope.pending_block.statements.push(n.*); | 2706 | |
| 2550 | } | 2707 | const pending_node = try switch_scope.pending_block.complete(rp.c); |
| 2551 | block_scope.block_node.statements.shrink(0); | 2708 | switch_scope.pending_block.deinit(); |
| 2709 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); | ||
| 2710 | try switch_scope.pending_block.statements.append(&pending_node.base); | ||
| 2552 | 2711 | ||
| 2553 | switch_scope.pending_block = block; | ||
| 2554 | return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value); | 2712 | return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value); |
| 2555 | } | 2713 | } |
| 2556 | 2714 | ||
| ... | @@ -2565,13 +2723,13 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, | ... | @@ -2565,13 +2723,13 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, |
| 2565 | // See comment in `transIntegerLiteral` for why this code is here. | 2723 | // See comment in `transIntegerLiteral` for why this code is here. |
| 2566 | // @as(T, x) | 2724 | // @as(T, x) |
| 2567 | const expr_base = @ptrCast(*const ZigClangExpr, expr); | 2725 | const expr_base = @ptrCast(*const ZigClangExpr, expr); |
| 2568 | const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); | 2726 | const as_node = try rp.c.createBuiltinCall("@as", 2); |
| 2569 | const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); | 2727 | const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); |
| 2570 | try as_node.params.push(ty_node); | 2728 | as_node.params()[0] = ty_node; |
| 2571 | _ = try appendToken(rp.c, .Comma, ","); | 2729 | _ = try appendToken(rp.c, .Comma, ","); |
| 2572 | 2730 | ||
| 2573 | const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val)); | 2731 | const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val)); |
| 2574 | try as_node.params.push(int_lit_node); | 2732 | as_node.params()[1] = int_lit_node; |
| 2575 | 2733 | ||
| 2576 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2734 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2577 | 2735 | ||
| ... | @@ -2606,7 +2764,7 @@ fn transCharLiteral( | ... | @@ -2606,7 +2764,7 @@ fn transCharLiteral( |
| 2606 | } | 2764 | } |
| 2607 | var char_buf: [4]u8 = undefined; | 2765 | var char_buf: [4]u8 = undefined; |
| 2608 | const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)}); | 2766 | const token = try appendTokenFmt(rp.c, .CharLiteral, "'{}'", .{escapeChar(@intCast(u8, val), &char_buf)}); |
| 2609 | const node = try rp.c.a().create(ast.Node.CharLiteral); | 2767 | const node = try rp.c.arena.create(ast.Node.CharLiteral); |
| 2610 | node.* = .{ | 2768 | node.* = .{ |
| 2611 | .token = token, | 2769 | .token = token, |
| 2612 | }; | 2770 | }; |
| ... | @@ -2627,12 +2785,11 @@ fn transCharLiteral( | ... | @@ -2627,12 +2785,11 @@ fn transCharLiteral( |
| 2627 | // See comment in `transIntegerLiteral` for why this code is here. | 2785 | // See comment in `transIntegerLiteral` for why this code is here. |
| 2628 | // @as(T, x) | 2786 | // @as(T, x) |
| 2629 | const expr_base = @ptrCast(*const ZigClangExpr, stmt); | 2787 | const expr_base = @ptrCast(*const ZigClangExpr, stmt); |
| 2630 | const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); | 2788 | const as_node = try rp.c.createBuiltinCall("@as", 2); |
| 2631 | const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); | 2789 | const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); |
| 2632 | try as_node.params.push(ty_node); | 2790 | as_node.params()[0] = ty_node; |
| 2633 | _ = try appendToken(rp.c, .Comma, ","); | 2791 | _ = try appendToken(rp.c, .Comma, ","); |
| 2634 | 2792 | as_node.params()[1] = int_lit_node; | |
| 2635 | try as_node.params.push(int_lit_node); | ||
| 2636 | 2793 | ||
| 2637 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2794 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2638 | return maybeSuppressResult(rp, scope, result_used, &as_node.base); | 2795 | return maybeSuppressResult(rp, scope, result_used, &as_node.base); |
| ... | @@ -2644,27 +2801,25 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, | ... | @@ -2644,27 +2801,25 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, |
| 2644 | return transCompoundStmt(rp, scope, comp); | 2801 | return transCompoundStmt(rp, scope, comp); |
| 2645 | } | 2802 | } |
| 2646 | const lparen = try appendToken(rp.c, .LParen, "("); | 2803 | const lparen = try appendToken(rp.c, .LParen, "("); |
| 2647 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | 2804 | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 2648 | const block = try transCreateNodeBlock(rp.c, "blk"); | 2805 | defer block_scope.deinit(); |
| 2649 | block_scope.block_node = block; | ||
| 2650 | 2806 | ||
| 2651 | var it = ZigClangCompoundStmt_body_begin(comp); | 2807 | var it = ZigClangCompoundStmt_body_begin(comp); |
| 2652 | const end_it = ZigClangCompoundStmt_body_end(comp); | 2808 | const end_it = ZigClangCompoundStmt_body_end(comp); |
| 2653 | while (it != end_it - 1) : (it += 1) { | 2809 | while (it != end_it - 1) : (it += 1) { |
| 2654 | const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); | 2810 | const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); |
| 2655 | if (result != &block.base) | 2811 | try block_scope.statements.append(result); |
| 2656 | try block.statements.push(result); | ||
| 2657 | } | 2812 | } |
| 2658 | const break_node = try transCreateNodeBreak(rp.c, "blk"); | 2813 | const break_node = try transCreateNodeBreak(rp.c, "blk"); |
| 2659 | break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value); | 2814 | break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value); |
| 2660 | _ = try appendToken(rp.c, .Semicolon, ";"); | 2815 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2661 | try block.statements.push(&break_node.base); | 2816 | try block_scope.statements.append(&break_node.base); |
| 2662 | block.rbrace = try appendToken(rp.c, .RBrace, "}"); | 2817 | const block_node = try block_scope.complete(rp.c); |
| 2663 | const rparen = try appendToken(rp.c, .RParen, ")"); | 2818 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 2664 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 2819 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 2665 | grouped_expr.* = .{ | 2820 | grouped_expr.* = .{ |
| 2666 | .lparen = lparen, | 2821 | .lparen = lparen, |
| 2667 | .expr = &block.base, | 2822 | .expr = &block_node.base, |
| 2668 | .rparen = rparen, | 2823 | .rparen = rparen, |
| 2669 | }; | 2824 | }; |
| 2670 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | 2825 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| ... | @@ -2686,7 +2841,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE | ... | @@ -2686,7 +2841,7 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangMemberE |
| 2686 | const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl); | 2841 | const field_decl = @ptrCast(*const struct_ZigClangFieldDecl, member_decl); |
| 2687 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { | 2842 | if (ZigClangFieldDecl_isAnonymousStructOrUnion(field_decl)) { |
| 2688 | const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?; | 2843 | const name = rp.c.decl_table.get(@ptrToInt(ZigClangFieldDecl_getCanonicalDecl(field_decl))).?; |
| 2689 | break :blk try mem.dupe(rp.c.a(), u8, name.value); | 2844 | break :blk try mem.dupe(rp.c.arena, u8, name.value); |
| 2690 | } | 2845 | } |
| 2691 | } | 2846 | } |
| 2692 | const decl = @ptrCast(*const ZigClangNamedDecl, member_decl); | 2847 | const decl = @ptrCast(*const ZigClangNamedDecl, member_decl); |
| ... | @@ -2720,12 +2875,12 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS | ... | @@ -2720,12 +2875,12 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS |
| 2720 | const is_signed = cIsSignedInteger(qt); | 2875 | const is_signed = cIsSignedInteger(qt); |
| 2721 | 2876 | ||
| 2722 | if (is_longlong or is_signed) { | 2877 | if (is_longlong or is_signed) { |
| 2723 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 2878 | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 2724 | // check if long long first so that signed long long doesn't just become unsigned long long | 2879 | // check if long long first so that signed long long doesn't just become unsigned long long |
| 2725 | var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false); | 2880 | var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false); |
| 2726 | try cast_node.params.push(typeid_node); | 2881 | cast_node.params()[0] = typeid_node; |
| 2727 | _ = try appendToken(rp.c, .Comma, ","); | 2882 | _ = try appendToken(rp.c, .Comma, ","); |
| 2728 | try cast_node.params.push(try transExpr(rp, scope, subscr_expr, .used, .r_value)); | 2883 | cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value); |
| 2729 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2884 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2730 | node.rtoken = try appendToken(rp.c, .RBrace, "]"); | 2885 | node.rtoken = try appendToken(rp.c, .RBrace, "]"); |
| 2731 | node.op.ArrayAccess = &cast_node.base; | 2886 | node.op.ArrayAccess = &cast_node.base; |
| ... | @@ -2761,17 +2916,18 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, | ... | @@ -2761,17 +2916,18 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, |
| 2761 | break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr); | 2916 | break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr); |
| 2762 | } else | 2917 | } else |
| 2763 | raw_fn_expr; | 2918 | raw_fn_expr; |
| 2764 | const node = try transCreateNodeFnCall(rp.c, fn_expr); | ||
| 2765 | 2919 | ||
| 2766 | const num_args = ZigClangCallExpr_getNumArgs(stmt); | 2920 | const num_args = ZigClangCallExpr_getNumArgs(stmt); |
| 2921 | const node = try rp.c.createCall(fn_expr, num_args); | ||
| 2922 | const call_params = node.params(); | ||
| 2923 | |||
| 2767 | const args = ZigClangCallExpr_getArgs(stmt); | 2924 | const args = ZigClangCallExpr_getArgs(stmt); |
| 2768 | var i: usize = 0; | 2925 | var i: usize = 0; |
| 2769 | while (i < num_args) : (i += 1) { | 2926 | while (i < num_args) : (i += 1) { |
| 2770 | if (i != 0) { | 2927 | if (i != 0) { |
| 2771 | _ = try appendToken(rp.c, .Comma, ","); | 2928 | _ = try appendToken(rp.c, .Comma, ","); |
| 2772 | } | 2929 | } |
| 2773 | const arg = try transExpr(rp, scope, args[i], .used, .r_value); | 2930 | call_params[i] = try transExpr(rp, scope, args[i], .used, .r_value); |
| 2774 | try node.op.Call.params.push(arg); | ||
| 2775 | } | 2931 | } |
| 2776 | node.rtoken = try appendToken(rp.c, .RParen, ")"); | 2932 | node.rtoken = try appendToken(rp.c, .RParen, ")"); |
| 2777 | 2933 | ||
| ... | @@ -2830,8 +2986,8 @@ fn transUnaryExprOrTypeTraitExpr( | ... | @@ -2830,8 +2986,8 @@ fn transUnaryExprOrTypeTraitExpr( |
| 2830 | ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt), | 2986 | ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt), |
| 2831 | ); | 2987 | ); |
| 2832 | 2988 | ||
| 2833 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf"); | 2989 | const builtin_node = try rp.c.createBuiltinCall("@sizeOf", 1); |
| 2834 | try builtin_node.params.push(type_node); | 2990 | builtin_node.params()[0] = type_node; |
| 2835 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 2991 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 2836 | return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); | 2992 | return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); |
| 2837 | } | 2993 | } |
| ... | @@ -2940,8 +3096,8 @@ fn transCreatePreCrement( | ... | @@ -2940,8 +3096,8 @@ fn transCreatePreCrement( |
| 2940 | // zig: _ref.* += 1; | 3096 | // zig: _ref.* += 1; |
| 2941 | // zig: break :blk _ref.* | 3097 | // zig: break :blk _ref.* |
| 2942 | // zig: }) | 3098 | // zig: }) |
| 2943 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | 3099 | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 2944 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | 3100 | defer block_scope.deinit(); |
| 2945 | const ref = try block_scope.makeMangledName(rp.c, "ref"); | 3101 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 2946 | 3102 | ||
| 2947 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | 3103 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); |
| ... | @@ -2950,7 +3106,7 @@ fn transCreatePreCrement( | ... | @@ -2950,7 +3106,7 @@ fn transCreatePreCrement( |
| 2950 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); | 3106 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 2951 | node.init_node = &rhs_node.base; | 3107 | node.init_node = &rhs_node.base; |
| 2952 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | 3108 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 2953 | try block_scope.block_node.statements.push(&node.base); | 3109 | try block_scope.statements.append(&node.base); |
| 2954 | 3110 | ||
| 2955 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | 3111 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| 2956 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | 3112 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); |
| ... | @@ -2959,18 +3115,18 @@ fn transCreatePreCrement( | ... | @@ -2959,18 +3115,18 @@ fn transCreatePreCrement( |
| 2959 | const one = try transCreateNodeInt(rp.c, 1); | 3115 | const one = try transCreateNodeInt(rp.c, 1); |
| 2960 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3116 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2961 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); | 3117 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); |
| 2962 | try block_scope.block_node.statements.push(assign); | 3118 | try block_scope.statements.append(assign); |
| 2963 | 3119 | ||
| 2964 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3120 | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label); |
| 2965 | break_node.rhs = ref_node; | 3121 | break_node.rhs = ref_node; |
| 2966 | try block_scope.block_node.statements.push(&break_node.base); | 3122 | try block_scope.statements.append(&break_node.base); |
| 2967 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3123 | const block_node = try block_scope.complete(rp.c); |
| 2968 | // semicolon must immediately follow rbrace because it is the last token in a block | 3124 | // semicolon must immediately follow rbrace because it is the last token in a block |
| 2969 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3125 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 2970 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3126 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 2971 | grouped_expr.* = .{ | 3127 | grouped_expr.* = .{ |
| 2972 | .lparen = try appendToken(rp.c, .LParen, "("), | 3128 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 2973 | .expr = &block_scope.block_node.base, | 3129 | .expr = &block_node.base, |
| 2974 | .rparen = try appendToken(rp.c, .RParen, ")"), | 3130 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 2975 | }; | 3131 | }; |
| 2976 | return &grouped_expr.base; | 3132 | return &grouped_expr.base; |
| ... | @@ -3006,8 +3162,8 @@ fn transCreatePostCrement( | ... | @@ -3006,8 +3162,8 @@ fn transCreatePostCrement( |
| 3006 | // zig: _ref.* += 1; | 3162 | // zig: _ref.* += 1; |
| 3007 | // zig: break :blk _tmp | 3163 | // zig: break :blk _tmp |
| 3008 | // zig: }) | 3164 | // zig: }) |
| 3009 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | 3165 | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3010 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | 3166 | defer block_scope.deinit(); |
| 3011 | const ref = try block_scope.makeMangledName(rp.c, "ref"); | 3167 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3012 | 3168 | ||
| 3013 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | 3169 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); |
| ... | @@ -3016,7 +3172,7 @@ fn transCreatePostCrement( | ... | @@ -3016,7 +3172,7 @@ fn transCreatePostCrement( |
| 3016 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); | 3172 | rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3017 | node.init_node = &rhs_node.base; | 3173 | node.init_node = &rhs_node.base; |
| 3018 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | 3174 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 3019 | try block_scope.block_node.statements.push(&node.base); | 3175 | try block_scope.statements.append(&node.base); |
| 3020 | 3176 | ||
| 3021 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | 3177 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| 3022 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | 3178 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); |
| ... | @@ -3027,23 +3183,23 @@ fn transCreatePostCrement( | ... | @@ -3027,23 +3183,23 @@ fn transCreatePostCrement( |
| 3027 | tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); | 3183 | tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); |
| 3028 | tmp_node.init_node = ref_node; | 3184 | tmp_node.init_node = ref_node; |
| 3029 | tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | 3185 | tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 3030 | try block_scope.block_node.statements.push(&tmp_node.base); | 3186 | try block_scope.statements.append(&tmp_node.base); |
| 3031 | 3187 | ||
| 3032 | const token = try appendToken(rp.c, op_tok_id, bytes); | 3188 | const token = try appendToken(rp.c, op_tok_id, bytes); |
| 3033 | const one = try transCreateNodeInt(rp.c, 1); | 3189 | const one = try transCreateNodeInt(rp.c, 1); |
| 3034 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3190 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3035 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); | 3191 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); |
| 3036 | try block_scope.block_node.statements.push(assign); | 3192 | try block_scope.statements.append(assign); |
| 3037 | 3193 | ||
| 3038 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3194 | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label); |
| 3039 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); | 3195 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); |
| 3040 | try block_scope.block_node.statements.push(&break_node.base); | 3196 | try block_scope.statements.append(&break_node.base); |
| 3041 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3197 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3042 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3198 | const block_node = try block_scope.complete(rp.c); |
| 3043 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3199 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3044 | grouped_expr.* = .{ | 3200 | grouped_expr.* = .{ |
| 3045 | .lparen = try appendToken(rp.c, .LParen, "("), | 3201 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 3046 | .expr = &block_scope.block_node.base, | 3202 | .expr = &block_node.base, |
| 3047 | .rparen = try appendToken(rp.c, .RParen, ")"), | 3203 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 3048 | }; | 3204 | }; |
| 3049 | return &grouped_expr.base; | 3205 | return &grouped_expr.base; |
| ... | @@ -3106,13 +3262,13 @@ fn transCreateCompoundAssign( | ... | @@ -3106,13 +3262,13 @@ fn transCreateCompoundAssign( |
| 3106 | 3262 | ||
| 3107 | if ((is_mod or is_div) and is_signed) { | 3263 | if ((is_mod or is_div) and is_signed) { |
| 3108 | const op_token = try appendToken(rp.c, .Equal, "="); | 3264 | const op_token = try appendToken(rp.c, .Equal, "="); |
| 3109 | const op_node = try rp.c.a().create(ast.Node.InfixOp); | 3265 | const op_node = try rp.c.arena.create(ast.Node.InfixOp); |
| 3110 | const builtin = if (is_mod) "@rem" else "@divTrunc"; | 3266 | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| 3111 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin); | 3267 | const builtin_node = try rp.c.createBuiltinCall(builtin, 2); |
| 3112 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); | 3268 | const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3113 | try builtin_node.params.push(lhs_node); | 3269 | builtin_node.params()[0] = lhs_node; |
| 3114 | _ = try appendToken(rp.c, .Comma, ","); | 3270 | _ = try appendToken(rp.c, .Comma, ","); |
| 3115 | try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); | 3271 | builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); |
| 3116 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3272 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3117 | op_node.* = .{ | 3273 | op_node.* = .{ |
| 3118 | .op_token = op_token, | 3274 | .op_token = op_token, |
| ... | @@ -3132,11 +3288,11 @@ fn transCreateCompoundAssign( | ... | @@ -3132,11 +3288,11 @@ fn transCreateCompoundAssign( |
| 3132 | try transExpr(rp, scope, rhs, .used, .r_value); | 3288 | try transExpr(rp, scope, rhs, .used, .r_value); |
| 3133 | 3289 | ||
| 3134 | if (is_shift) { | 3290 | if (is_shift) { |
| 3135 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 3291 | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 3136 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); | 3292 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); |
| 3137 | try cast_node.params.push(rhs_type); | 3293 | cast_node.params()[0] = rhs_type; |
| 3138 | _ = try appendToken(rp.c, .Comma, ","); | 3294 | _ = try appendToken(rp.c, .Comma, ","); |
| 3139 | try cast_node.params.push(rhs_node); | 3295 | cast_node.params()[1] = rhs_node; |
| 3140 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3296 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3141 | rhs_node = &cast_node.base; | 3297 | rhs_node = &cast_node.base; |
| 3142 | } | 3298 | } |
| ... | @@ -3151,8 +3307,8 @@ fn transCreateCompoundAssign( | ... | @@ -3151,8 +3307,8 @@ fn transCreateCompoundAssign( |
| 3151 | // zig: _ref.* = _ref.* + rhs; | 3307 | // zig: _ref.* = _ref.* + rhs; |
| 3152 | // zig: break :blk _ref.* | 3308 | // zig: break :blk _ref.* |
| 3153 | // zig: }) | 3309 | // zig: }) |
| 3154 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | 3310 | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3155 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | 3311 | defer block_scope.deinit(); |
| 3156 | const ref = try block_scope.makeMangledName(rp.c, "ref"); | 3312 | const ref = try block_scope.makeMangledName(rp.c, "ref"); |
| 3157 | 3313 | ||
| 3158 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); | 3314 | const node = try transCreateNodeVarDecl(rp.c, false, true, ref); |
| ... | @@ -3161,7 +3317,7 @@ fn transCreateCompoundAssign( | ... | @@ -3161,7 +3317,7 @@ fn transCreateCompoundAssign( |
| 3161 | addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value); | 3317 | addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value); |
| 3162 | node.init_node = &addr_node.base; | 3318 | node.init_node = &addr_node.base; |
| 3163 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | 3319 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 3164 | try block_scope.block_node.statements.push(&node.base); | 3320 | try block_scope.statements.append(&node.base); |
| 3165 | 3321 | ||
| 3166 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); | 3322 | const lhs_node = try transCreateNodeIdentifier(rp.c, ref); |
| 3167 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); | 3323 | const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); |
| ... | @@ -3169,12 +3325,12 @@ fn transCreateCompoundAssign( | ... | @@ -3169,12 +3325,12 @@ fn transCreateCompoundAssign( |
| 3169 | 3325 | ||
| 3170 | if ((is_mod or is_div) and is_signed) { | 3326 | if ((is_mod or is_div) and is_signed) { |
| 3171 | const op_token = try appendToken(rp.c, .Equal, "="); | 3327 | const op_token = try appendToken(rp.c, .Equal, "="); |
| 3172 | const op_node = try rp.c.a().create(ast.Node.InfixOp); | 3328 | const op_node = try rp.c.arena.create(ast.Node.InfixOp); |
| 3173 | const builtin = if (is_mod) "@rem" else "@divTrunc"; | 3329 | const builtin = if (is_mod) "@rem" else "@divTrunc"; |
| 3174 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin); | 3330 | const builtin_node = try rp.c.createBuiltinCall(builtin, 2); |
| 3175 | try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node)); | 3331 | builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node); |
| 3176 | _ = try appendToken(rp.c, .Comma, ","); | 3332 | _ = try appendToken(rp.c, .Comma, ","); |
| 3177 | try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); | 3333 | builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); |
| 3178 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3334 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3179 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3335 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3180 | op_node.* = .{ | 3336 | op_node.* = .{ |
| ... | @@ -3184,17 +3340,17 @@ fn transCreateCompoundAssign( | ... | @@ -3184,17 +3340,17 @@ fn transCreateCompoundAssign( |
| 3184 | .rhs = &builtin_node.base, | 3340 | .rhs = &builtin_node.base, |
| 3185 | }; | 3341 | }; |
| 3186 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3342 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3187 | try block_scope.block_node.statements.push(&op_node.base); | 3343 | try block_scope.statements.append(&op_node.base); |
| 3188 | } else { | 3344 | } else { |
| 3189 | const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); | 3345 | const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); |
| 3190 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | 3346 | var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); |
| 3191 | 3347 | ||
| 3192 | if (is_shift) { | 3348 | if (is_shift) { |
| 3193 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 3349 | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 3194 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); | 3350 | const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); |
| 3195 | try cast_node.params.push(rhs_type); | 3351 | cast_node.params()[0] = rhs_type; |
| 3196 | _ = try appendToken(rp.c, .Comma, ","); | 3352 | _ = try appendToken(rp.c, .Comma, ","); |
| 3197 | try cast_node.params.push(rhs_node); | 3353 | cast_node.params()[1] = rhs_node; |
| 3198 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3354 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3199 | rhs_node = &cast_node.base; | 3355 | rhs_node = &cast_node.base; |
| 3200 | } | 3356 | } |
| ... | @@ -3204,17 +3360,17 @@ fn transCreateCompoundAssign( | ... | @@ -3204,17 +3360,17 @@ fn transCreateCompoundAssign( |
| 3204 | 3360 | ||
| 3205 | const eq_token = try appendToken(rp.c, .Equal, "="); | 3361 | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 3206 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); | 3362 | const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); |
| 3207 | try block_scope.block_node.statements.push(assign); | 3363 | try block_scope.statements.append(assign); |
| 3208 | } | 3364 | } |
| 3209 | 3365 | ||
| 3210 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3366 | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label); |
| 3211 | break_node.rhs = ref_node; | 3367 | break_node.rhs = ref_node; |
| 3212 | try block_scope.block_node.statements.push(&break_node.base); | 3368 | try block_scope.statements.append(&break_node.base); |
| 3213 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3369 | const block_node = try block_scope.complete(rp.c); |
| 3214 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3370 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3215 | grouped_expr.* = .{ | 3371 | grouped_expr.* = .{ |
| 3216 | .lparen = try appendToken(rp.c, .LParen, "("), | 3372 | .lparen = try appendToken(rp.c, .LParen, "("), |
| 3217 | .expr = &block_scope.block_node.base, | 3373 | .expr = &block_node.base, |
| 3218 | .rparen = try appendToken(rp.c, .RParen, ")"), | 3374 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 3219 | }; | 3375 | }; |
| 3220 | return &grouped_expr.base; | 3376 | return &grouped_expr.base; |
| ... | @@ -3238,43 +3394,43 @@ fn transCPtrCast( | ... | @@ -3238,43 +3394,43 @@ fn transCPtrCast( |
| 3238 | !ZigClangQualType_isVolatileQualified(child_type))) | 3394 | !ZigClangQualType_isVolatileQualified(child_type))) |
| 3239 | { | 3395 | { |
| 3240 | // Casting away const or volatile requires us to use @intToPtr | 3396 | // Casting away const or volatile requires us to use @intToPtr |
| 3241 | const inttoptr_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); | 3397 | const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2); |
| 3242 | const dst_type_node = try transType(rp, ty, loc); | 3398 | const dst_type_node = try transType(rp, ty, loc); |
| 3243 | try inttoptr_node.params.push(dst_type_node); | 3399 | inttoptr_node.params()[0] = dst_type_node; |
| 3244 | _ = try appendToken(rp.c, .Comma, ","); | 3400 | _ = try appendToken(rp.c, .Comma, ","); |
| 3245 | 3401 | ||
| 3246 | const ptrtoint_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); | 3402 | const ptrtoint_node = try rp.c.createBuiltinCall("@ptrToInt", 1); |
| 3247 | try ptrtoint_node.params.push(expr); | 3403 | ptrtoint_node.params()[0] = expr; |
| 3248 | ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3404 | ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3249 | 3405 | ||
| 3250 | try inttoptr_node.params.push(&ptrtoint_node.base); | 3406 | inttoptr_node.params()[1] = &ptrtoint_node.base; |
| 3251 | inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3407 | inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3252 | return &inttoptr_node.base; | 3408 | return &inttoptr_node.base; |
| 3253 | } else { | 3409 | } else { |
| 3254 | // Implicit downcasting from higher to lower alignment values is forbidden, | 3410 | // Implicit downcasting from higher to lower alignment values is forbidden, |
| 3255 | // use @alignCast to side-step this problem | 3411 | // use @alignCast to side-step this problem |
| 3256 | const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); | 3412 | const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2); |
| 3257 | const dst_type_node = try transType(rp, ty, loc); | 3413 | const dst_type_node = try transType(rp, ty, loc); |
| 3258 | try ptrcast_node.params.push(dst_type_node); | 3414 | ptrcast_node.params()[0] = dst_type_node; |
| 3259 | _ = try appendToken(rp.c, .Comma, ","); | 3415 | _ = try appendToken(rp.c, .Comma, ","); |
| 3260 | 3416 | ||
| 3261 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { | 3417 | if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { |
| 3262 | // void has 1-byte alignment, so @alignCast is not needed | 3418 | // void has 1-byte alignment, so @alignCast is not needed |
| 3263 | try ptrcast_node.params.push(expr); | 3419 | ptrcast_node.params()[1] = expr; |
| 3264 | } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) { | 3420 | } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) { |
| 3265 | // For opaque types a ptrCast is enough | 3421 | // For opaque types a ptrCast is enough |
| 3266 | try ptrcast_node.params.push(expr); | 3422 | ptrcast_node.params()[1] = expr; |
| 3267 | } else { | 3423 | } else { |
| 3268 | const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); | 3424 | const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2); |
| 3269 | const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); | 3425 | const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1); |
| 3270 | const child_type_node = try transQualType(rp, child_type, loc); | 3426 | const child_type_node = try transQualType(rp, child_type, loc); |
| 3271 | try alignof_node.params.push(child_type_node); | 3427 | alignof_node.params()[0] = child_type_node; |
| 3272 | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3428 | alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3273 | try aligncast_node.params.push(&alignof_node.base); | 3429 | aligncast_node.params()[0] = &alignof_node.base; |
| 3274 | _ = try appendToken(rp.c, .Comma, ","); | 3430 | _ = try appendToken(rp.c, .Comma, ","); |
| 3275 | try aligncast_node.params.push(expr); | 3431 | aligncast_node.params()[1] = expr; |
| 3276 | aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3432 | aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3277 | try ptrcast_node.params.push(&aligncast_node.base); | 3433 | ptrcast_node.params()[1] = &aligncast_node.base; |
| 3278 | } | 3434 | } |
| 3279 | ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3435 | ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3280 | 3436 | ||
| ... | @@ -3295,7 +3451,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { | ... | @@ -3295,7 +3451,7 @@ fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node { |
| 3295 | fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node { | 3451 | fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFloatingLiteral, used: ResultUsed) TransError!*ast.Node { |
| 3296 | // TODO use something more accurate | 3452 | // TODO use something more accurate |
| 3297 | const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt); | 3453 | const dbl = ZigClangAPFloat_getValueAsApproximateDouble(stmt); |
| 3298 | const node = try rp.c.a().create(ast.Node.FloatLiteral); | 3454 | const node = try rp.c.arena.create(ast.Node.FloatLiteral); |
| 3299 | node.* = .{ | 3455 | node.* = .{ |
| 3300 | .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}), | 3456 | .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}), |
| 3301 | }; | 3457 | }; |
| ... | @@ -3317,27 +3473,30 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const | ... | @@ -3317,27 +3473,30 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const |
| 3317 | // }) | 3473 | // }) |
| 3318 | const lparen = try appendToken(rp.c, .LParen, "("); | 3474 | const lparen = try appendToken(rp.c, .LParen, "("); |
| 3319 | 3475 | ||
| 3320 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | 3476 | var block_scope = try Scope.Block.init(rp.c, scope, "blk"); |
| 3321 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | 3477 | defer block_scope.deinit(); |
| 3322 | 3478 | ||
| 3323 | const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); | 3479 | const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); |
| 3324 | const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name); | 3480 | const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name); |
| 3325 | tmp_var.eq_token = try appendToken(rp.c, .Equal, "="); | 3481 | tmp_var.eq_token = try appendToken(rp.c, .Equal, "="); |
| 3326 | tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value); | 3482 | tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value); |
| 3327 | tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | 3483 | tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 3328 | try block_scope.block_node.statements.push(&tmp_var.base); | 3484 | try block_scope.statements.append(&tmp_var.base); |
| 3329 | 3485 | ||
| 3330 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3486 | const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label); |
| 3331 | 3487 | ||
| 3332 | const if_node = try transCreateNodeIf(rp.c); | 3488 | const if_node = try transCreateNodeIf(rp.c); |
| 3333 | var cond_scope = Scope{ | 3489 | var cond_scope = Scope.Condition{ |
| 3334 | .parent = &block_scope.base, | 3490 | .base = .{ |
| 3335 | .id = .Condition, | 3491 | .parent = &block_scope.base, |
| 3492 | .id = .Condition, | ||
| 3493 | }, | ||
| 3336 | }; | 3494 | }; |
| 3495 | defer cond_scope.deinit(); | ||
| 3337 | const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name); | 3496 | const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name); |
| 3338 | 3497 | ||
| 3339 | const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, cond_expr)); | 3498 | const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, cond_expr)); |
| 3340 | const cond_node = try finishBoolExpr(rp, &block_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used); | 3499 | const cond_node = try finishBoolExpr(rp, &cond_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used); |
| 3341 | if_node.condition = cond_node; | 3500 | if_node.condition = cond_node; |
| 3342 | _ = try appendToken(rp.c, .RParen, ")"); | 3501 | _ = try appendToken(rp.c, .RParen, ")"); |
| 3343 | 3502 | ||
| ... | @@ -3348,13 +3507,13 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const | ... | @@ -3348,13 +3507,13 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const |
| 3348 | 3507 | ||
| 3349 | break_node.rhs = &if_node.base; | 3508 | break_node.rhs = &if_node.base; |
| 3350 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3509 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3351 | try block_scope.block_node.statements.push(&break_node.base); | 3510 | try block_scope.statements.append(&break_node.base); |
| 3352 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3511 | const block_node = try block_scope.complete(rp.c); |
| 3353 | 3512 | ||
| 3354 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3513 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3355 | grouped_expr.* = .{ | 3514 | grouped_expr.* = .{ |
| 3356 | .lparen = lparen, | 3515 | .lparen = lparen, |
| 3357 | .expr = &block_scope.block_node.base, | 3516 | .expr = &block_node.base, |
| 3358 | .rparen = try appendToken(rp.c, .RParen, ")"), | 3517 | .rparen = try appendToken(rp.c, .RParen, ")"), |
| 3359 | }; | 3518 | }; |
| 3360 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | 3519 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); |
| ... | @@ -3364,17 +3523,20 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla | ... | @@ -3364,17 +3523,20 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla |
| 3364 | const grouped = scope.id == .Condition; | 3523 | const grouped = scope.id == .Condition; |
| 3365 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; | 3524 | const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; |
| 3366 | const if_node = try transCreateNodeIf(rp.c); | 3525 | const if_node = try transCreateNodeIf(rp.c); |
| 3367 | var cond_scope = Scope{ | 3526 | var cond_scope = Scope.Condition{ |
| 3368 | .parent = scope, | 3527 | .base = .{ |
| 3369 | .id = .Condition, | 3528 | .parent = scope, |
| 3529 | .id = .Condition, | ||
| 3530 | }, | ||
| 3370 | }; | 3531 | }; |
| 3532 | defer cond_scope.deinit(); | ||
| 3371 | 3533 | ||
| 3372 | const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt); | 3534 | const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt); |
| 3373 | const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt); | 3535 | const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt); |
| 3374 | const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt); | 3536 | const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt); |
| 3375 | const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt); | 3537 | const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt); |
| 3376 | 3538 | ||
| 3377 | if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false); | 3539 | if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); |
| 3378 | _ = try appendToken(rp.c, .RParen, ")"); | 3540 | _ = try appendToken(rp.c, .RParen, ")"); |
| 3379 | 3541 | ||
| 3380 | if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); | 3542 | if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); |
| ... | @@ -3384,7 +3546,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla | ... | @@ -3384,7 +3546,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla |
| 3384 | 3546 | ||
| 3385 | if (grouped) { | 3547 | if (grouped) { |
| 3386 | const rparen = try appendToken(rp.c, .RParen, ")"); | 3548 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 3387 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3549 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3388 | grouped_expr.* = .{ | 3550 | grouped_expr.* = .{ |
| 3389 | .lparen = lparen, | 3551 | .lparen = lparen, |
| 3390 | .expr = &if_node.base, | 3552 | .expr = &if_node.base, |
| ... | @@ -3415,7 +3577,7 @@ fn maybeSuppressResult( | ... | @@ -3415,7 +3577,7 @@ fn maybeSuppressResult( |
| 3415 | } | 3577 | } |
| 3416 | const lhs = try transCreateNodeIdentifier(rp.c, "_"); | 3578 | const lhs = try transCreateNodeIdentifier(rp.c, "_"); |
| 3417 | const op_token = try appendToken(rp.c, .Equal, "="); | 3579 | const op_token = try appendToken(rp.c, .Equal, "="); |
| 3418 | const op_node = try rp.c.a().create(ast.Node.InfixOp); | 3580 | const op_node = try rp.c.arena.create(ast.Node.InfixOp); |
| 3419 | op_node.* = .{ | 3581 | op_node.* = .{ |
| 3420 | .op_token = op_token, | 3582 | .op_token = op_token, |
| 3421 | .lhs = lhs, | 3583 | .lhs = lhs, |
| ... | @@ -3426,7 +3588,7 @@ fn maybeSuppressResult( | ... | @@ -3426,7 +3588,7 @@ fn maybeSuppressResult( |
| 3426 | } | 3588 | } |
| 3427 | 3589 | ||
| 3428 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { | 3590 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { |
| 3429 | try c.tree.root_node.decls.push(decl_node); | 3591 | try c.root_decls.append(c.gpa, decl_node); |
| 3430 | _ = try c.global_scope.sym_table.put(name, decl_node); | 3592 | _ = try c.global_scope.sym_table.put(name, decl_node); |
| 3431 | } | 3593 | } |
| 3432 | 3594 | ||
| ... | @@ -3524,7 +3686,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC | ... | @@ -3524,7 +3686,7 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC |
| 3524 | if (int_bit_width != 0) { | 3686 | if (int_bit_width != 0) { |
| 3525 | // we can perform the log2 now. | 3687 | // we can perform the log2 now. |
| 3526 | const cast_bit_width = math.log2_int(u64, int_bit_width); | 3688 | const cast_bit_width = math.log2_int(u64, int_bit_width); |
| 3527 | const node = try rp.c.a().create(ast.Node.IntegerLiteral); | 3689 | const node = try rp.c.arena.create(ast.Node.IntegerLiteral); |
| 3528 | node.* = .{ | 3690 | node.* = .{ |
| 3529 | .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}), | 3691 | .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}), |
| 3530 | }; | 3692 | }; |
| ... | @@ -3545,19 +3707,19 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC | ... | @@ -3545,19 +3707,19 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC |
| 3545 | // Symbol "Log2Int" | 3707 | // Symbol "Log2Int" |
| 3546 | // Symbol <zig_type_node> (var from above) | 3708 | // Symbol <zig_type_node> (var from above) |
| 3547 | 3709 | ||
| 3548 | const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import"); | 3710 | const import_fn_call = try rp.c.createBuiltinCall("@import", 1); |
| 3549 | const std_token = try appendToken(rp.c, .StringLiteral, "\"std\""); | 3711 | const std_token = try appendToken(rp.c, .StringLiteral, "\"std\""); |
| 3550 | const std_node = try rp.c.a().create(ast.Node.StringLiteral); | 3712 | const std_node = try rp.c.arena.create(ast.Node.StringLiteral); |
| 3551 | std_node.* = .{ | 3713 | std_node.* = .{ |
| 3552 | .token = std_token, | 3714 | .token = std_token, |
| 3553 | }; | 3715 | }; |
| 3554 | try import_fn_call.params.push(&std_node.base); | 3716 | import_fn_call.params()[0] = &std_node.base; |
| 3555 | import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3717 | import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3556 | 3718 | ||
| 3557 | const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); | 3719 | const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); |
| 3558 | const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int"); | 3720 | const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int"); |
| 3559 | const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access); | 3721 | const log2int_fn_call = try rp.c.createCall(outer_field_access, 1); |
| 3560 | try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node); | 3722 | log2int_fn_call.params()[0] = zig_type_node; |
| 3561 | log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); | 3723 | log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); |
| 3562 | 3724 | ||
| 3563 | return &log2int_fn_call.base; | 3725 | return &log2int_fn_call.base; |
| ... | @@ -3731,8 +3893,8 @@ fn transCreateNodeAssign( | ... | @@ -3731,8 +3893,8 @@ fn transCreateNodeAssign( |
| 3731 | const eq_token = try appendToken(rp.c, .Equal, "="); | 3893 | const eq_token = try appendToken(rp.c, .Equal, "="); |
| 3732 | var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value); | 3894 | var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value); |
| 3733 | if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { | 3895 | if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { |
| 3734 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | 3896 | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 3735 | try builtin_node.params.push(rhs_node); | 3897 | builtin_node.params()[0] = rhs_node; |
| 3736 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3898 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3737 | rhs_node = &builtin_node.base; | 3899 | rhs_node = &builtin_node.base; |
| 3738 | } | 3900 | } |
| ... | @@ -3748,22 +3910,24 @@ fn transCreateNodeAssign( | ... | @@ -3748,22 +3910,24 @@ fn transCreateNodeAssign( |
| 3748 | // zig: lhs = _tmp; | 3910 | // zig: lhs = _tmp; |
| 3749 | // zig: break :blk _tmp | 3911 | // zig: break :blk _tmp |
| 3750 | // zig: }) | 3912 | // zig: }) |
| 3751 | const block_scope = try Scope.Block.init(rp.c, scope, "blk"); | 3913 | const label_name = "blk"; |
| 3752 | block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label); | 3914 | var block_scope = try Scope.Block.init(rp.c, scope, label_name); |
| 3915 | defer block_scope.deinit(); | ||
| 3916 | |||
| 3753 | const tmp = try block_scope.makeMangledName(rp.c, "tmp"); | 3917 | const tmp = try block_scope.makeMangledName(rp.c, "tmp"); |
| 3754 | 3918 | ||
| 3755 | const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); | 3919 | const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); |
| 3756 | node.eq_token = try appendToken(rp.c, .Equal, "="); | 3920 | node.eq_token = try appendToken(rp.c, .Equal, "="); |
| 3757 | var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value); | 3921 | var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value); |
| 3758 | if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { | 3922 | if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { |
| 3759 | const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); | 3923 | const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); |
| 3760 | try builtin_node.params.push(rhs_node); | 3924 | builtin_node.params()[0] = rhs_node; |
| 3761 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 3925 | builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 3762 | rhs_node = &builtin_node.base; | 3926 | rhs_node = &builtin_node.base; |
| 3763 | } | 3927 | } |
| 3764 | node.init_node = rhs_node; | 3928 | node.init_node = rhs_node; |
| 3765 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); | 3929 | node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); |
| 3766 | try block_scope.block_node.statements.push(&node.base); | 3930 | try block_scope.statements.append(&node.base); |
| 3767 | 3931 | ||
| 3768 | const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value); | 3932 | const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value); |
| 3769 | const eq_token = try appendToken(rp.c, .Equal, "="); | 3933 | const eq_token = try appendToken(rp.c, .Equal, "="); |
| ... | @@ -3771,48 +3935,20 @@ fn transCreateNodeAssign( | ... | @@ -3771,48 +3935,20 @@ fn transCreateNodeAssign( |
| 3771 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3935 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3772 | 3936 | ||
| 3773 | const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false); | 3937 | const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false); |
| 3774 | try block_scope.block_node.statements.push(assign); | 3938 | try block_scope.statements.append(assign); |
| 3775 | 3939 | ||
| 3776 | const break_node = try transCreateNodeBreak(rp.c, block_scope.label); | 3940 | const break_node = try transCreateNodeBreak(rp.c, label_name); |
| 3777 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); | 3941 | break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); |
| 3778 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3942 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3779 | try block_scope.block_node.statements.push(&break_node.base); | 3943 | try block_scope.statements.append(&break_node.base); |
| 3780 | block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); | 3944 | const block_node = try block_scope.complete(rp.c); |
| 3781 | // semicolon must immediately follow rbrace because it is the last token in a block | 3945 | // semicolon must immediately follow rbrace because it is the last token in a block |
| 3782 | _ = try appendToken(rp.c, .Semicolon, ";"); | 3946 | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 3783 | return &block_scope.block_node.base; | 3947 | return &block_node.base; |
| 3784 | } | ||
| 3785 | |||
| 3786 | fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { | ||
| 3787 | const builtin_token = try appendToken(c, .Builtin, name); | ||
| 3788 | _ = try appendToken(c, .LParen, "("); | ||
| 3789 | const node = try c.a().create(ast.Node.BuiltinCall); | ||
| 3790 | node.* = .{ | ||
| 3791 | .builtin_token = builtin_token, | ||
| 3792 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), | ||
| 3793 | .rparen_token = undefined, // set after appending args | ||
| 3794 | }; | ||
| 3795 | return node; | ||
| 3796 | } | ||
| 3797 | |||
| 3798 | fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { | ||
| 3799 | _ = try appendToken(c, .LParen, "("); | ||
| 3800 | const node = try c.a().create(ast.Node.SuffixOp); | ||
| 3801 | node.* = .{ | ||
| 3802 | .lhs = .{ .node = fn_expr }, | ||
| 3803 | .op = .{ | ||
| 3804 | .Call = .{ | ||
| 3805 | .params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()), | ||
| 3806 | .async_token = null, | ||
| 3807 | }, | ||
| 3808 | }, | ||
| 3809 | .rtoken = undefined, // set after appending args | ||
| 3810 | }; | ||
| 3811 | return node; | ||
| 3812 | } | 3948 | } |
| 3813 | 3949 | ||
| 3814 | fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node { | 3950 | fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node { |
| 3815 | const field_access_node = try c.a().create(ast.Node.InfixOp); | 3951 | const field_access_node = try c.arena.create(ast.Node.InfixOp); |
| 3816 | field_access_node.* = .{ | 3952 | field_access_node.* = .{ |
| 3817 | .op_token = try appendToken(c, .Period, "."), | 3953 | .op_token = try appendToken(c, .Period, "."), |
| 3818 | .lhs = container, | 3954 | .lhs = container, |
| ... | @@ -3828,7 +3964,7 @@ fn transCreateNodePrefixOp( | ... | @@ -3828,7 +3964,7 @@ fn transCreateNodePrefixOp( |
| 3828 | op_tok_id: std.zig.Token.Id, | 3964 | op_tok_id: std.zig.Token.Id, |
| 3829 | bytes: []const u8, | 3965 | bytes: []const u8, |
| 3830 | ) !*ast.Node.PrefixOp { | 3966 | ) !*ast.Node.PrefixOp { |
| 3831 | const node = try c.a().create(ast.Node.PrefixOp); | 3967 | const node = try c.arena.create(ast.Node.PrefixOp); |
| 3832 | node.* = .{ | 3968 | node.* = .{ |
| 3833 | .op_token = try appendToken(c, op_tok_id, bytes), | 3969 | .op_token = try appendToken(c, op_tok_id, bytes), |
| 3834 | .op = op, | 3970 | .op = op, |
| ... | @@ -3851,7 +3987,7 @@ fn transCreateNodeInfixOp( | ... | @@ -3851,7 +3987,7 @@ fn transCreateNodeInfixOp( |
| 3851 | try appendToken(rp.c, .LParen, "(") | 3987 | try appendToken(rp.c, .LParen, "(") |
| 3852 | else | 3988 | else |
| 3853 | null; | 3989 | null; |
| 3854 | const node = try rp.c.a().create(ast.Node.InfixOp); | 3990 | const node = try rp.c.arena.create(ast.Node.InfixOp); |
| 3855 | node.* = .{ | 3991 | node.* = .{ |
| 3856 | .op_token = op_token, | 3992 | .op_token = op_token, |
| 3857 | .lhs = lhs_node, | 3993 | .lhs = lhs_node, |
| ... | @@ -3860,7 +3996,7 @@ fn transCreateNodeInfixOp( | ... | @@ -3860,7 +3996,7 @@ fn transCreateNodeInfixOp( |
| 3860 | }; | 3996 | }; |
| 3861 | if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base); | 3997 | if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base); |
| 3862 | const rparen = try appendToken(rp.c, .RParen, ")"); | 3998 | const rparen = try appendToken(rp.c, .RParen, ")"); |
| 3863 | const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression); | 3999 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); |
| 3864 | grouped_expr.* = .{ | 4000 | grouped_expr.* = .{ |
| 3865 | .lparen = lparen.?, | 4001 | .lparen = lparen.?, |
| 3866 | .expr = &node.base, | 4002 | .expr = &node.base, |
| ... | @@ -3904,7 +4040,7 @@ fn transCreateNodePtrType( | ... | @@ -3904,7 +4040,7 @@ fn transCreateNodePtrType( |
| 3904 | is_volatile: bool, | 4040 | is_volatile: bool, |
| 3905 | op_tok_id: std.zig.Token.Id, | 4041 | op_tok_id: std.zig.Token.Id, |
| 3906 | ) !*ast.Node.PrefixOp { | 4042 | ) !*ast.Node.PrefixOp { |
| 3907 | const node = try c.a().create(ast.Node.PrefixOp); | 4043 | const node = try c.arena.create(ast.Node.PrefixOp); |
| 3908 | const op_token = switch (op_tok_id) { | 4044 | const op_token = switch (op_tok_id) { |
| 3909 | .LBracket => blk: { | 4045 | .LBracket => blk: { |
| 3910 | const lbracket = try appendToken(c, .LBracket, "["); | 4046 | const lbracket = try appendToken(c, .LBracket, "["); |
| ... | @@ -3946,8 +4082,8 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { | ... | @@ -3946,8 +4082,8 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { |
| 3946 | ZigClangAPSInt_free(aps_int); | 4082 | ZigClangAPSInt_free(aps_int); |
| 3947 | }; | 4083 | }; |
| 3948 | 4084 | ||
| 3949 | const limbs = try c.a().alloc(math.big.Limb, num_limbs); | 4085 | const limbs = try c.arena.alloc(math.big.Limb, num_limbs); |
| 3950 | defer c.a().free(limbs); | 4086 | defer c.arena.free(limbs); |
| 3951 | 4087 | ||
| 3952 | const data = ZigClangAPSInt_getRawData(aps_int); | 4088 | const data = ZigClangAPSInt_getRawData(aps_int); |
| 3953 | switch (@sizeOf(math.big.Limb)) { | 4089 | switch (@sizeOf(math.big.Limb)) { |
| ... | @@ -3972,12 +4108,12 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { | ... | @@ -3972,12 +4108,12 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { |
| 3972 | } | 4108 | } |
| 3973 | 4109 | ||
| 3974 | const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative }; | 4110 | const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative }; |
| 3975 | const str = big.toStringAlloc(c.a(), 10, false) catch |err| switch (err) { | 4111 | const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) { |
| 3976 | error.OutOfMemory => return error.OutOfMemory, | 4112 | error.OutOfMemory => return error.OutOfMemory, |
| 3977 | }; | 4113 | }; |
| 3978 | defer c.a().free(str); | 4114 | defer c.arena.free(str); |
| 3979 | const token = try appendToken(c, .IntegerLiteral, str); | 4115 | const token = try appendToken(c, .IntegerLiteral, str); |
| 3980 | const node = try c.a().create(ast.Node.IntegerLiteral); | 4116 | const node = try c.arena.create(ast.Node.IntegerLiteral); |
| 3981 | node.* = .{ | 4117 | node.* = .{ |
| 3982 | .token = token, | 4118 | .token = token, |
| 3983 | }; | 4119 | }; |
| ... | @@ -3986,7 +4122,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { | ... | @@ -3986,7 +4122,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const ZigClangAPSInt) !*ast.Node { |
| 3986 | 4122 | ||
| 3987 | fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { | 4123 | fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { |
| 3988 | const ltoken = try appendToken(c, .Keyword_return, "return"); | 4124 | const ltoken = try appendToken(c, .Keyword_return, "return"); |
| 3989 | const node = try c.a().create(ast.Node.ControlFlowExpression); | 4125 | const node = try c.arena.create(ast.Node.ControlFlowExpression); |
| 3990 | node.* = .{ | 4126 | node.* = .{ |
| 3991 | .ltoken = ltoken, | 4127 | .ltoken = ltoken, |
| 3992 | .kind = .Return, | 4128 | .kind = .Return, |
| ... | @@ -3997,7 +4133,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { | ... | @@ -3997,7 +4133,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression { |
| 3997 | 4133 | ||
| 3998 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { | 4134 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 3999 | const token = try appendToken(c, .Keyword_undefined, "undefined"); | 4135 | const token = try appendToken(c, .Keyword_undefined, "undefined"); |
| 4000 | const node = try c.a().create(ast.Node.UndefinedLiteral); | 4136 | const node = try c.arena.create(ast.Node.UndefinedLiteral); |
| 4001 | node.* = .{ | 4137 | node.* = .{ |
| 4002 | .token = token, | 4138 | .token = token, |
| 4003 | }; | 4139 | }; |
| ... | @@ -4006,7 +4142,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { | ... | @@ -4006,7 +4142,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |
| 4006 | 4142 | ||
| 4007 | fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { | 4143 | fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { |
| 4008 | const token = try appendToken(c, .Keyword_null, "null"); | 4144 | const token = try appendToken(c, .Keyword_null, "null"); |
| 4009 | const node = try c.a().create(ast.Node.NullLiteral); | 4145 | const node = try c.arena.create(ast.Node.NullLiteral); |
| 4010 | node.* = .{ | 4146 | node.* = .{ |
| 4011 | .token = token, | 4147 | .token = token, |
| 4012 | }; | 4148 | }; |
| ... | @@ -4018,42 +4154,16 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { | ... | @@ -4018,42 +4154,16 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { |
| 4018 | try appendToken(c, .Keyword_true, "true") | 4154 | try appendToken(c, .Keyword_true, "true") |
| 4019 | else | 4155 | else |
| 4020 | try appendToken(c, .Keyword_false, "false"); | 4156 | try appendToken(c, .Keyword_false, "false"); |
| 4021 | const node = try c.a().create(ast.Node.BoolLiteral); | 4157 | const node = try c.arena.create(ast.Node.BoolLiteral); |
| 4022 | node.* = .{ | 4158 | node.* = .{ |
| 4023 | .token = token, | 4159 | .token = token, |
| 4024 | }; | 4160 | }; |
| 4025 | return &node.base; | 4161 | return &node.base; |
| 4026 | } | 4162 | } |
| 4027 | 4163 | ||
| 4028 | fn transCreateNodeArrayInitializer(c: *Context, ty: *ast.Node) !*ast.Node.SuffixOp { | ||
| 4029 | _ = try appendToken(c, .LBrace, "{"); | ||
| 4030 | const node = try c.a().create(ast.Node.SuffixOp); | ||
| 4031 | node.* = .{ | ||
| 4032 | .lhs = .{ .node = ty }, | ||
| 4033 | .op = .{ | ||
| 4034 | .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()), | ||
| 4035 | }, | ||
| 4036 | .rtoken = undefined, // set after appending values | ||
| 4037 | }; | ||
| 4038 | return node; | ||
| 4039 | } | ||
| 4040 | |||
| 4041 | fn transCreateNodeStructInitializer(c: *Context, ty: *ast.Node) !*ast.Node.SuffixOp { | ||
| 4042 | _ = try appendToken(c, .LBrace, "{"); | ||
| 4043 | const node = try c.a().create(ast.Node.SuffixOp); | ||
| 4044 | node.* = .{ | ||
| 4045 | .lhs = .{ .node = ty }, | ||
| 4046 | .op = .{ | ||
| 4047 | .StructInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()), | ||
| 4048 | }, | ||
| 4049 | .rtoken = undefined, // set after appending values | ||
| 4050 | }; | ||
| 4051 | return node; | ||
| 4052 | } | ||
| 4053 | |||
| 4054 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { | 4164 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 4055 | const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); | 4165 | const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); |
| 4056 | const node = try c.a().create(ast.Node.IntegerLiteral); | 4166 | const node = try c.arena.create(ast.Node.IntegerLiteral); |
| 4057 | node.* = .{ | 4167 | node.* = .{ |
| 4058 | .token = token, | 4168 | .token = token, |
| 4059 | }; | 4169 | }; |
| ... | @@ -4062,7 +4172,7 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { | ... | @@ -4062,7 +4172,7 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 4062 | 4172 | ||
| 4063 | fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node { | 4173 | fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node { |
| 4064 | const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int}); | 4174 | const token = try appendTokenFmt(c, .FloatLiteral, "{}", .{int}); |
| 4065 | const node = try c.a().create(ast.Node.FloatLiteral); | 4175 | const node = try c.arena.create(ast.Node.FloatLiteral); |
| 4066 | node.* = .{ | 4176 | node.* = .{ |
| 4067 | .token = token, | 4177 | .token = token, |
| 4068 | }; | 4178 | }; |
| ... | @@ -4070,8 +4180,8 @@ fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node { | ... | @@ -4070,8 +4180,8 @@ fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node { |
| 4070 | } | 4180 | } |
| 4071 | 4181 | ||
| 4072 | fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { | 4182 | fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { |
| 4073 | const call_node = try transCreateNodeBuiltinFnCall(c, "@Type"); | 4183 | const call_node = try c.createBuiltinCall("@Type", 1); |
| 4074 | try call_node.params.push(try transCreateNodeEnumLiteral(c, "Opaque")); | 4184 | call_node.params()[0] = try transCreateNodeEnumLiteral(c, "Opaque"); |
| 4075 | call_node.rparen_token = try appendToken(c, .RParen, ")"); | 4185 | call_node.rparen_token = try appendToken(c, .RParen, ")"); |
| 4076 | return &call_node.base; | 4186 | return &call_node.base; |
| 4077 | } | 4187 | } |
| ... | @@ -4085,39 +4195,36 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a | ... | @@ -4085,39 +4195,36 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a |
| 4085 | const name_tok = try appendIdentifier(c, name); | 4195 | const name_tok = try appendIdentifier(c, name); |
| 4086 | _ = try appendToken(c, .LParen, "("); | 4196 | _ = try appendToken(c, .LParen, "("); |
| 4087 | 4197 | ||
| 4088 | var fn_params = ast.Node.FnProto.ParamList.init(c.a()); | 4198 | var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa); |
| 4089 | var it = proto_alias.params.iterator(0); | 4199 | defer fn_params.deinit(); |
| 4090 | while (it.next()) |pn| { | 4200 | |
| 4091 | if (it.index != 0) { | 4201 | for (proto_alias.params()) |param, i| { |
| 4202 | if (i != 0) { | ||
| 4092 | _ = try appendToken(c, .Comma, ","); | 4203 | _ = try appendToken(c, .Comma, ","); |
| 4093 | } | 4204 | } |
| 4094 | const param = pn.*.cast(ast.Node.ParamDecl).?; | ||
| 4095 | |||
| 4096 | const param_name_tok = param.name_token orelse | 4205 | const param_name_tok = param.name_token orelse |
| 4097 | try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()}); | 4206 | try appendTokenFmt(c, .Identifier, "arg_{}", .{c.getMangle()}); |
| 4098 | 4207 | ||
| 4099 | _ = try appendToken(c, .Colon, ":"); | 4208 | _ = try appendToken(c, .Colon, ":"); |
| 4100 | 4209 | ||
| 4101 | const param_node = try c.a().create(ast.Node.ParamDecl); | 4210 | (try fn_params.addOne()).* = .{ |
| 4102 | param_node.* = .{ | ||
| 4103 | .doc_comments = null, | 4211 | .doc_comments = null, |
| 4104 | .comptime_token = null, | 4212 | .comptime_token = null, |
| 4105 | .noalias_token = param.noalias_token, | 4213 | .noalias_token = param.noalias_token, |
| 4106 | .name_token = param_name_tok, | 4214 | .name_token = param_name_tok, |
| 4107 | .param_type = param.param_type, | 4215 | .param_type = param.param_type, |
| 4108 | }; | 4216 | }; |
| 4109 | try fn_params.push(&param_node.base); | ||
| 4110 | } | 4217 | } |
| 4111 | 4218 | ||
| 4112 | _ = try appendToken(c, .RParen, ")"); | 4219 | _ = try appendToken(c, .RParen, ")"); |
| 4113 | 4220 | ||
| 4114 | const fn_proto = try c.a().create(ast.Node.FnProto); | 4221 | const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len); |
| 4115 | fn_proto.* = .{ | 4222 | fn_proto.* = .{ |
| 4116 | .doc_comments = null, | 4223 | .doc_comments = null, |
| 4117 | .visib_token = pub_tok, | 4224 | .visib_token = pub_tok, |
| 4118 | .fn_token = fn_tok, | 4225 | .fn_token = fn_tok, |
| 4119 | .name_token = name_tok, | 4226 | .name_token = name_tok, |
| 4120 | .params = fn_params, | 4227 | .params_len = fn_params.items.len, |
| 4121 | .return_type = proto_alias.return_type, | 4228 | .return_type = proto_alias.return_type, |
| 4122 | .var_args_token = null, | 4229 | .var_args_token = null, |
| 4123 | .extern_export_inline_token = inline_tok, | 4230 | .extern_export_inline_token = inline_tok, |
| ... | @@ -4127,26 +4234,35 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a | ... | @@ -4127,26 +4234,35 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a |
| 4127 | .section_expr = null, | 4234 | .section_expr = null, |
| 4128 | .callconv_expr = null, | 4235 | .callconv_expr = null, |
| 4129 | }; | 4236 | }; |
| 4237 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | ||
| 4130 | 4238 | ||
| 4131 | const block = try transCreateNodeBlock(c, null); | 4239 | const block_lbrace = try appendToken(c, .LBrace, "{"); |
| 4132 | 4240 | ||
| 4133 | const return_expr = try transCreateNodeReturnExpr(c); | 4241 | const return_expr = try transCreateNodeReturnExpr(c); |
| 4134 | const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); | 4242 | const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); |
| 4135 | const call_expr = try transCreateNodeFnCall(c, unwrap_expr); | 4243 | |
| 4136 | it = fn_params.iterator(0); | 4244 | const call_expr = try c.createCall(unwrap_expr, fn_params.items.len); |
| 4137 | while (it.next()) |pn| { | 4245 | const call_params = call_expr.params(); |
| 4138 | if (it.index != 0) { | 4246 | |
| 4247 | for (fn_params.items) |param, i| { | ||
| 4248 | if (i != 0) { | ||
| 4139 | _ = try appendToken(c, .Comma, ","); | 4249 | _ = try appendToken(c, .Comma, ","); |
| 4140 | } | 4250 | } |
| 4141 | const param = pn.*.cast(ast.Node.ParamDecl).?; | 4251 | call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)); |
| 4142 | try call_expr.op.Call.params.push(try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?))); | ||
| 4143 | } | 4252 | } |
| 4144 | call_expr.rtoken = try appendToken(c, .RParen, ")"); | 4253 | call_expr.rtoken = try appendToken(c, .RParen, ")"); |
| 4254 | |||
| 4145 | return_expr.rhs = &call_expr.base; | 4255 | return_expr.rhs = &call_expr.base; |
| 4146 | _ = try appendToken(c, .Semicolon, ";"); | 4256 | _ = try appendToken(c, .Semicolon, ";"); |
| 4147 | 4257 | ||
| 4148 | block.rbrace = try appendToken(c, .RBrace, "}"); | 4258 | const block = try ast.Node.Block.alloc(c.arena, 1); |
| 4149 | try block.statements.push(&return_expr.base); | 4259 | block.* = .{ |
| 4260 | .label = null, | ||
| 4261 | .lbrace = block_lbrace, | ||
| 4262 | .statements_len = 1, | ||
| 4263 | .rbrace = try appendToken(c, .RBrace, "}"), | ||
| 4264 | }; | ||
| 4265 | block.statements()[0] = &return_expr.base; | ||
| 4150 | fn_proto.body_node = &block.base; | 4266 | fn_proto.body_node = &block.base; |
| 4151 | return &fn_proto.base; | 4267 | return &fn_proto.base; |
| 4152 | } | 4268 | } |
| ... | @@ -4154,17 +4270,17 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a | ... | @@ -4154,17 +4270,17 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a |
| 4154 | fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node { | 4270 | fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node { |
| 4155 | _ = try appendToken(c, .Period, "."); | 4271 | _ = try appendToken(c, .Period, "."); |
| 4156 | const qm = try appendToken(c, .QuestionMark, "?"); | 4272 | const qm = try appendToken(c, .QuestionMark, "?"); |
| 4157 | const node = try c.a().create(ast.Node.SuffixOp); | 4273 | const node = try c.arena.create(ast.Node.SuffixOp); |
| 4158 | node.* = .{ | 4274 | node.* = .{ |
| 4159 | .op = .UnwrapOptional, | 4275 | .op = .UnwrapOptional, |
| 4160 | .lhs = .{ .node = wrapped }, | 4276 | .lhs = wrapped, |
| 4161 | .rtoken = qm, | 4277 | .rtoken = qm, |
| 4162 | }; | 4278 | }; |
| 4163 | return &node.base; | 4279 | return &node.base; |
| 4164 | } | 4280 | } |
| 4165 | 4281 | ||
| 4166 | fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { | 4282 | fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { |
| 4167 | const node = try c.a().create(ast.Node.EnumLiteral); | 4283 | const node = try c.arena.create(ast.Node.EnumLiteral); |
| 4168 | node.* = .{ | 4284 | node.* = .{ |
| 4169 | .dot = try appendToken(c, .Period, "."), | 4285 | .dot = try appendToken(c, .Period, "."), |
| 4170 | .name = try appendIdentifier(c, name), | 4286 | .name = try appendIdentifier(c, name), |
| ... | @@ -4173,7 +4289,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { | ... | @@ -4173,7 +4289,7 @@ fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node { |
| 4173 | } | 4289 | } |
| 4174 | 4290 | ||
| 4175 | fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node { | 4291 | fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node { |
| 4176 | const node = try c.a().create(ast.Node.StringLiteral); | 4292 | const node = try c.arena.create(ast.Node.StringLiteral); |
| 4177 | node.* = .{ | 4293 | node.* = .{ |
| 4178 | .token = try appendToken(c, .StringLiteral, str), | 4294 | .token = try appendToken(c, .StringLiteral, str), |
| 4179 | }; | 4295 | }; |
| ... | @@ -4183,7 +4299,7 @@ fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node { | ... | @@ -4183,7 +4299,7 @@ fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node { |
| 4183 | fn transCreateNodeIf(c: *Context) !*ast.Node.If { | 4299 | fn transCreateNodeIf(c: *Context) !*ast.Node.If { |
| 4184 | const if_tok = try appendToken(c, .Keyword_if, "if"); | 4300 | const if_tok = try appendToken(c, .Keyword_if, "if"); |
| 4185 | _ = try appendToken(c, .LParen, "("); | 4301 | _ = try appendToken(c, .LParen, "("); |
| 4186 | const node = try c.a().create(ast.Node.If); | 4302 | const node = try c.arena.create(ast.Node.If); |
| 4187 | node.* = .{ | 4303 | node.* = .{ |
| 4188 | .if_token = if_tok, | 4304 | .if_token = if_tok, |
| 4189 | .condition = undefined, | 4305 | .condition = undefined, |
| ... | @@ -4195,7 +4311,7 @@ fn transCreateNodeIf(c: *Context) !*ast.Node.If { | ... | @@ -4195,7 +4311,7 @@ fn transCreateNodeIf(c: *Context) !*ast.Node.If { |
| 4195 | } | 4311 | } |
| 4196 | 4312 | ||
| 4197 | fn transCreateNodeElse(c: *Context) !*ast.Node.Else { | 4313 | fn transCreateNodeElse(c: *Context) !*ast.Node.Else { |
| 4198 | const node = try c.a().create(ast.Node.Else); | 4314 | const node = try c.arena.create(ast.Node.Else); |
| 4199 | node.* = .{ | 4315 | node.* = .{ |
| 4200 | .else_token = try appendToken(c, .Keyword_else, "else"), | 4316 | .else_token = try appendToken(c, .Keyword_else, "else"), |
| 4201 | .payload = null, | 4317 | .payload = null, |
| ... | @@ -4204,20 +4320,11 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else { | ... | @@ -4204,20 +4320,11 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else { |
| 4204 | return node; | 4320 | return node; |
| 4205 | } | 4321 | } |
| 4206 | 4322 | ||
| 4207 | fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { | 4323 | fn transCreateNodeBreakToken(c: *Context, label: ?ast.TokenIndex) !*ast.Node.ControlFlowExpression { |
| 4208 | const label_node = if (label) |l| blk: { | 4324 | const other_token = label orelse return transCreateNodeBreak(c, null); |
| 4209 | const ll = try appendIdentifier(c, l); | 4325 | const loc = c.token_locs.items[other_token]; |
| 4210 | _ = try appendToken(c, .Colon, ":"); | 4326 | const label_name = c.source_buffer.items[loc.start..loc.end]; |
| 4211 | break :blk ll; | 4327 | return transCreateNodeBreak(c, label_name); |
| 4212 | } else null; | ||
| 4213 | const block_node = try c.a().create(ast.Node.Block); | ||
| 4214 | block_node.* = .{ | ||
| 4215 | .label = label_node, | ||
| 4216 | .lbrace = try appendToken(c, .LBrace, "{"), | ||
| 4217 | .statements = ast.Node.Block.StatementList.init(c.a()), | ||
| 4218 | .rbrace = undefined, | ||
| 4219 | }; | ||
| 4220 | return block_node; | ||
| 4221 | } | 4328 | } |
| 4222 | 4329 | ||
| 4223 | fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression { | 4330 | fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression { |
| ... | @@ -4226,7 +4333,7 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE | ... | @@ -4226,7 +4333,7 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE |
| 4226 | _ = try appendToken(c, .Colon, ":"); | 4333 | _ = try appendToken(c, .Colon, ":"); |
| 4227 | break :blk try transCreateNodeIdentifier(c, l); | 4334 | break :blk try transCreateNodeIdentifier(c, l); |
| 4228 | } else null; | 4335 | } else null; |
| 4229 | const node = try c.a().create(ast.Node.ControlFlowExpression); | 4336 | const node = try c.arena.create(ast.Node.ControlFlowExpression); |
| 4230 | node.* = .{ | 4337 | node.* = .{ |
| 4231 | .ltoken = ltoken, | 4338 | .ltoken = ltoken, |
| 4232 | .kind = .{ .Break = label_node }, | 4339 | .kind = .{ .Break = label_node }, |
| ... | @@ -4240,7 +4347,7 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con | ... | @@ -4240,7 +4347,7 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con |
| 4240 | const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var"); | 4347 | const mut_tok = if (is_const) try appendToken(c, .Keyword_const, "const") else try appendToken(c, .Keyword_var, "var"); |
| 4241 | const name_tok = try appendIdentifier(c, name); | 4348 | const name_tok = try appendIdentifier(c, name); |
| 4242 | 4349 | ||
| 4243 | const node = try c.a().create(ast.Node.VarDecl); | 4350 | const node = try c.arena.create(ast.Node.VarDecl); |
| 4244 | node.* = .{ | 4351 | node.* = .{ |
| 4245 | .doc_comments = null, | 4352 | .doc_comments = null, |
| 4246 | .visib_token = visib_tok, | 4353 | .visib_token = visib_tok, |
| ... | @@ -4264,7 +4371,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While { | ... | @@ -4264,7 +4371,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While { |
| 4264 | const while_tok = try appendToken(c, .Keyword_while, "while"); | 4371 | const while_tok = try appendToken(c, .Keyword_while, "while"); |
| 4265 | _ = try appendToken(c, .LParen, "("); | 4372 | _ = try appendToken(c, .LParen, "("); |
| 4266 | 4373 | ||
| 4267 | const node = try c.a().create(ast.Node.While); | 4374 | const node = try c.arena.create(ast.Node.While); |
| 4268 | node.* = .{ | 4375 | node.* = .{ |
| 4269 | .label = null, | 4376 | .label = null, |
| 4270 | .inline_token = null, | 4377 | .inline_token = null, |
| ... | @@ -4280,7 +4387,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While { | ... | @@ -4280,7 +4387,7 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While { |
| 4280 | 4387 | ||
| 4281 | fn transCreateNodeContinue(c: *Context) !*ast.Node { | 4388 | fn transCreateNodeContinue(c: *Context) !*ast.Node { |
| 4282 | const ltoken = try appendToken(c, .Keyword_continue, "continue"); | 4389 | const ltoken = try appendToken(c, .Keyword_continue, "continue"); |
| 4283 | const node = try c.a().create(ast.Node.ControlFlowExpression); | 4390 | const node = try c.arena.create(ast.Node.ControlFlowExpression); |
| 4284 | node.* = .{ | 4391 | node.* = .{ |
| 4285 | .ltoken = ltoken, | 4392 | .ltoken = ltoken, |
| 4286 | .kind = .{ .Continue = null }, | 4393 | .kind = .{ .Continue = null }, |
| ... | @@ -4290,36 +4397,22 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node { | ... | @@ -4290,36 +4397,22 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node { |
| 4290 | return &node.base; | 4397 | return &node.base; |
| 4291 | } | 4398 | } |
| 4292 | 4399 | ||
| 4293 | fn transCreateNodeSwitch(c: *Context) !*ast.Node.Switch { | ||
| 4294 | const switch_tok = try appendToken(c, .Keyword_switch, "switch"); | ||
| 4295 | _ = try appendToken(c, .LParen, "("); | ||
| 4296 | |||
| 4297 | const node = try c.a().create(ast.Node.Switch); | ||
| 4298 | node.* = .{ | ||
| 4299 | .switch_token = switch_tok, | ||
| 4300 | .expr = undefined, | ||
| 4301 | .cases = ast.Node.Switch.CaseList.init(c.a()), | ||
| 4302 | .rbrace = undefined, | ||
| 4303 | }; | ||
| 4304 | return node; | ||
| 4305 | } | ||
| 4306 | |||
| 4307 | fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase { | 4400 | fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase { |
| 4308 | const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>"); | 4401 | const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>"); |
| 4309 | 4402 | ||
| 4310 | const node = try c.a().create(ast.Node.SwitchCase); | 4403 | const node = try ast.Node.SwitchCase.alloc(c.arena, 1); |
| 4311 | node.* = .{ | 4404 | node.* = .{ |
| 4312 | .items = ast.Node.SwitchCase.ItemList.init(c.a()), | 4405 | .items_len = 1, |
| 4313 | .arrow_token = arrow_tok, | 4406 | .arrow_token = arrow_tok, |
| 4314 | .payload = null, | 4407 | .payload = null, |
| 4315 | .expr = undefined, | 4408 | .expr = undefined, |
| 4316 | }; | 4409 | }; |
| 4317 | try node.items.push(lhs); | 4410 | node.items()[0] = lhs; |
| 4318 | return node; | 4411 | return node; |
| 4319 | } | 4412 | } |
| 4320 | 4413 | ||
| 4321 | fn transCreateNodeSwitchElse(c: *Context) !*ast.Node { | 4414 | fn transCreateNodeSwitchElse(c: *Context) !*ast.Node { |
| 4322 | const node = try c.a().create(ast.Node.SwitchElse); | 4415 | const node = try c.arena.create(ast.Node.SwitchElse); |
| 4323 | node.* = .{ | 4416 | node.* = .{ |
| 4324 | .token = try appendToken(c, .Keyword_else, "else"), | 4417 | .token = try appendToken(c, .Keyword_else, "else"), |
| 4325 | }; | 4418 | }; |
| ... | @@ -4344,15 +4437,15 @@ fn transCreateNodeShiftOp( | ... | @@ -4344,15 +4437,15 @@ fn transCreateNodeShiftOp( |
| 4344 | const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value); | 4437 | const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value); |
| 4345 | const op_token = try appendToken(rp.c, op_tok_id, bytes); | 4438 | const op_token = try appendToken(rp.c, op_tok_id, bytes); |
| 4346 | 4439 | ||
| 4347 | const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); | 4440 | const cast_node = try rp.c.createBuiltinCall("@intCast", 2); |
| 4348 | const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location); | 4441 | const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location); |
| 4349 | try cast_node.params.push(rhs_type); | 4442 | cast_node.params()[0] = rhs_type; |
| 4350 | _ = try appendToken(rp.c, .Comma, ","); | 4443 | _ = try appendToken(rp.c, .Comma, ","); |
| 4351 | const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value); | 4444 | const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value); |
| 4352 | try cast_node.params.push(rhs); | 4445 | cast_node.params()[1] = rhs; |
| 4353 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | 4446 | cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); |
| 4354 | 4447 | ||
| 4355 | const node = try rp.c.a().create(ast.Node.InfixOp); | 4448 | const node = try rp.c.arena.create(ast.Node.InfixOp); |
| 4356 | node.* = .{ | 4449 | node.* = .{ |
| 4357 | .op_token = op_token, | 4450 | .op_token = op_token, |
| 4358 | .lhs = lhs, | 4451 | .lhs = lhs, |
| ... | @@ -4364,9 +4457,9 @@ fn transCreateNodeShiftOp( | ... | @@ -4364,9 +4457,9 @@ fn transCreateNodeShiftOp( |
| 4364 | } | 4457 | } |
| 4365 | 4458 | ||
| 4366 | fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { | 4459 | fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { |
| 4367 | const node = try c.a().create(ast.Node.SuffixOp); | 4460 | const node = try c.arena.create(ast.Node.SuffixOp); |
| 4368 | node.* = .{ | 4461 | node.* = .{ |
| 4369 | .lhs = .{ .node = lhs }, | 4462 | .lhs = lhs, |
| 4370 | .op = .Deref, | 4463 | .op = .Deref, |
| 4371 | .rtoken = try appendToken(c, .PeriodAsterisk, ".*"), | 4464 | .rtoken = try appendToken(c, .PeriodAsterisk, ".*"), |
| 4372 | }; | 4465 | }; |
| ... | @@ -4375,9 +4468,9 @@ fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { | ... | @@ -4375,9 +4468,9 @@ fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { |
| 4375 | 4468 | ||
| 4376 | fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp { | 4469 | fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp { |
| 4377 | _ = try appendToken(c, .LBrace, "["); | 4470 | _ = try appendToken(c, .LBrace, "["); |
| 4378 | const node = try c.a().create(ast.Node.SuffixOp); | 4471 | const node = try c.arena.create(ast.Node.SuffixOp); |
| 4379 | node.* = .{ | 4472 | node.* = .{ |
| 4380 | .lhs = .{ .node = lhs }, | 4473 | .lhs = lhs, |
| 4381 | .op = .{ | 4474 | .op = .{ |
| 4382 | .ArrayAccess = undefined, | 4475 | .ArrayAccess = undefined, |
| 4383 | }, | 4476 | }, |
| ... | @@ -4392,7 +4485,8 @@ const RestorePoint = struct { | ... | @@ -4392,7 +4485,8 @@ const RestorePoint = struct { |
| 4392 | src_buf_index: usize, | 4485 | src_buf_index: usize, |
| 4393 | 4486 | ||
| 4394 | fn activate(self: RestorePoint) void { | 4487 | fn activate(self: RestorePoint) void { |
| 4395 | self.c.tree.tokens.shrink(self.token_index); | 4488 | self.c.token_ids.shrink(self.c.gpa, self.token_index); |
| 4489 | self.c.token_locs.shrink(self.c.gpa, self.token_index); | ||
| 4396 | self.c.source_buffer.shrink(self.src_buf_index); | 4490 | self.c.source_buffer.shrink(self.src_buf_index); |
| 4397 | } | 4491 | } |
| 4398 | }; | 4492 | }; |
| ... | @@ -4400,7 +4494,7 @@ const RestorePoint = struct { | ... | @@ -4400,7 +4494,7 @@ const RestorePoint = struct { |
| 4400 | fn makeRestorePoint(c: *Context) RestorePoint { | 4494 | fn makeRestorePoint(c: *Context) RestorePoint { |
| 4401 | return RestorePoint{ | 4495 | return RestorePoint{ |
| 4402 | .c = c, | 4496 | .c = c, |
| 4403 | .token_index = c.tree.tokens.len, | 4497 | .token_index = c.token_ids.items.len, |
| 4404 | .src_buf_index = c.source_buffer.items.len, | 4498 | .src_buf_index = c.source_buffer.items.len, |
| 4405 | }; | 4499 | }; |
| 4406 | } | 4500 | } |
| ... | @@ -4647,8 +4741,10 @@ fn finishTransFnProto( | ... | @@ -4647,8 +4741,10 @@ fn finishTransFnProto( |
| 4647 | const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null; | 4741 | const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null; |
| 4648 | const lparen_tok = try appendToken(rp.c, .LParen, "("); | 4742 | const lparen_tok = try appendToken(rp.c, .LParen, "("); |
| 4649 | 4743 | ||
| 4650 | var fn_params = ast.Node.FnProto.ParamList.init(rp.c.a()); | 4744 | var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(rp.c.gpa); |
| 4745 | defer fn_params.deinit(); | ||
| 4651 | const param_count: usize = if (fn_proto_ty != null) ZigClangFunctionProtoType_getNumParams(fn_proto_ty.?) else 0; | 4746 | const param_count: usize = if (fn_proto_ty != null) ZigClangFunctionProtoType_getNumParams(fn_proto_ty.?) else 0; |
| 4747 | try fn_params.ensureCapacity(param_count + 1); // +1 for possible var args node | ||
| 4652 | 4748 | ||
| 4653 | var i: usize = 0; | 4749 | var i: usize = 0; |
| 4654 | while (i < param_count) : (i += 1) { | 4750 | while (i < param_count) : (i += 1) { |
| ... | @@ -4672,15 +4768,13 @@ fn finishTransFnProto( | ... | @@ -4672,15 +4768,13 @@ fn finishTransFnProto( |
| 4672 | 4768 | ||
| 4673 | const type_node = try transQualType(rp, param_qt, source_loc); | 4769 | const type_node = try transQualType(rp, param_qt, source_loc); |
| 4674 | 4770 | ||
| 4675 | const param_node = try rp.c.a().create(ast.Node.ParamDecl); | 4771 | fn_params.addOneAssumeCapacity().* = .{ |
| 4676 | param_node.* = .{ | ||
| 4677 | .doc_comments = null, | 4772 | .doc_comments = null, |
| 4678 | .comptime_token = null, | 4773 | .comptime_token = null, |
| 4679 | .noalias_token = noalias_tok, | 4774 | .noalias_token = noalias_tok, |
| 4680 | .name_token = param_name_tok, | 4775 | .name_token = param_name_tok, |
| 4681 | .param_type = .{ .type_expr = type_node }, | 4776 | .param_type = .{ .type_expr = type_node }, |
| 4682 | }; | 4777 | }; |
| 4683 | try fn_params.push(&param_node.base); | ||
| 4684 | 4778 | ||
| 4685 | if (i + 1 < param_count) { | 4779 | if (i + 1 < param_count) { |
| 4686 | _ = try appendToken(rp.c, .Comma, ","); | 4780 | _ = try appendToken(rp.c, .Comma, ","); |
| ... | @@ -4692,15 +4786,13 @@ fn finishTransFnProto( | ... | @@ -4692,15 +4786,13 @@ fn finishTransFnProto( |
| 4692 | _ = try appendToken(rp.c, .Comma, ","); | 4786 | _ = try appendToken(rp.c, .Comma, ","); |
| 4693 | } | 4787 | } |
| 4694 | 4788 | ||
| 4695 | const var_arg_node = try rp.c.a().create(ast.Node.ParamDecl); | 4789 | fn_params.addOneAssumeCapacity().* = .{ |
| 4696 | var_arg_node.* = .{ | ||
| 4697 | .doc_comments = null, | 4790 | .doc_comments = null, |
| 4698 | .comptime_token = null, | 4791 | .comptime_token = null, |
| 4699 | .noalias_token = null, | 4792 | .noalias_token = null, |
| 4700 | .name_token = null, | 4793 | .name_token = null, |
| 4701 | .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") } | 4794 | .param_type = .{ .var_args = try appendToken(rp.c, .Ellipsis3, "...") } |
| 4702 | }; | 4795 | }; |
| 4703 | try fn_params.push(&var_arg_node.base); | ||
| 4704 | } | 4796 | } |
| 4705 | 4797 | ||
| 4706 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); | 4798 | const rparen_tok = try appendToken(rp.c, .RParen, ")"); |
| ... | @@ -4713,7 +4805,7 @@ fn finishTransFnProto( | ... | @@ -4713,7 +4805,7 @@ fn finishTransFnProto( |
| 4713 | _ = try appendToken(rp.c, .LParen, "("); | 4805 | _ = try appendToken(rp.c, .LParen, "("); |
| 4714 | const expr = try transCreateNodeStringLiteral( | 4806 | const expr = try transCreateNodeStringLiteral( |
| 4715 | rp.c, | 4807 | rp.c, |
| 4716 | try std.fmt.allocPrint(rp.c.a(), "\"{}\"", .{str_ptr[0..str_len]}), | 4808 | try std.fmt.allocPrint(rp.c.arena, "\"{}\"", .{str_ptr[0..str_len]}), |
| 4717 | ); | 4809 | ); |
| 4718 | _ = try appendToken(rp.c, .RParen, ")"); | 4810 | _ = try appendToken(rp.c, .RParen, ")"); |
| 4719 | 4811 | ||
| ... | @@ -4767,13 +4859,13 @@ fn finishTransFnProto( | ... | @@ -4767,13 +4859,13 @@ fn finishTransFnProto( |
| 4767 | } | 4859 | } |
| 4768 | }; | 4860 | }; |
| 4769 | 4861 | ||
| 4770 | const fn_proto = try rp.c.a().create(ast.Node.FnProto); | 4862 | const fn_proto = try ast.Node.FnProto.alloc(rp.c.arena, fn_params.items.len); |
| 4771 | fn_proto.* = .{ | 4863 | fn_proto.* = .{ |
| 4772 | .doc_comments = null, | 4864 | .doc_comments = null, |
| 4773 | .visib_token = pub_tok, | 4865 | .visib_token = pub_tok, |
| 4774 | .fn_token = fn_tok, | 4866 | .fn_token = fn_tok, |
| 4775 | .name_token = name_tok, | 4867 | .name_token = name_tok, |
| 4776 | .params = fn_params, | 4868 | .params_len = fn_params.items.len, |
| 4777 | .return_type = .{ .Explicit = return_type_node }, | 4869 | .return_type = .{ .Explicit = return_type_node }, |
| 4778 | .var_args_token = null, // TODO this field is broken in the AST data model | 4870 | .var_args_token = null, // TODO this field is broken in the AST data model |
| 4779 | .extern_export_inline_token = extern_export_inline_tok, | 4871 | .extern_export_inline_token = extern_export_inline_tok, |
| ... | @@ -4783,6 +4875,7 @@ fn finishTransFnProto( | ... | @@ -4783,6 +4875,7 @@ fn finishTransFnProto( |
| 4783 | .section_expr = linksection_expr, | 4875 | .section_expr = linksection_expr, |
| 4784 | .callconv_expr = callconv_expr, | 4876 | .callconv_expr = callconv_expr, |
| 4785 | }; | 4877 | }; |
| 4878 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | ||
| 4786 | return fn_proto; | 4879 | return fn_proto; |
| 4787 | } | 4880 | } |
| 4788 | 4881 | ||
| ... | @@ -4816,20 +4909,20 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp | ... | @@ -4816,20 +4909,20 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp |
| 4816 | const semi_tok = try appendToken(c, .Semicolon, ";"); | 4909 | const semi_tok = try appendToken(c, .Semicolon, ";"); |
| 4817 | _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)}); | 4910 | _ = try appendTokenFmt(c, .LineComment, "// {}", .{c.locStr(loc)}); |
| 4818 | 4911 | ||
| 4819 | const msg_node = try c.a().create(ast.Node.StringLiteral); | 4912 | const msg_node = try c.arena.create(ast.Node.StringLiteral); |
| 4820 | msg_node.* = .{ | 4913 | msg_node.* = .{ |
| 4821 | .token = msg_tok, | 4914 | .token = msg_tok, |
| 4822 | }; | 4915 | }; |
| 4823 | 4916 | ||
| 4824 | const call_node = try c.a().create(ast.Node.BuiltinCall); | 4917 | const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1); |
| 4825 | call_node.* = .{ | 4918 | call_node.* = .{ |
| 4826 | .builtin_token = builtin_tok, | 4919 | .builtin_token = builtin_tok, |
| 4827 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), | 4920 | .params_len = 1, |
| 4828 | .rparen_token = rparen_tok, | 4921 | .rparen_token = rparen_tok, |
| 4829 | }; | 4922 | }; |
| 4830 | try call_node.params.push(&msg_node.base); | 4923 | call_node.params()[0] = &msg_node.base; |
| 4831 | 4924 | ||
| 4832 | const var_decl_node = try c.a().create(ast.Node.VarDecl); | 4925 | const var_decl_node = try c.arena.create(ast.Node.VarDecl); |
| 4833 | var_decl_node.* = .{ | 4926 | var_decl_node.* = .{ |
| 4834 | .doc_comments = null, | 4927 | .doc_comments = null, |
| 4835 | .visib_token = pub_tok, | 4928 | .visib_token = pub_tok, |
| ... | @@ -4856,23 +4949,20 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd | ... | @@ -4856,23 +4949,20 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd |
| 4856 | 4949 | ||
| 4857 | fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex { | 4950 | fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex { |
| 4858 | assert(token_id != .Invalid); | 4951 | assert(token_id != .Invalid); |
| 4859 | const start_index = c.source_buffer.items.len; | ||
| 4860 | errdefer c.source_buffer.shrink(start_index); | ||
| 4861 | 4952 | ||
| 4862 | try c.source_buffer.outStream().print(format, args); | 4953 | try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1); |
| 4863 | const end_index = c.source_buffer.items.len; | 4954 | try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1); |
| 4864 | const token_index = c.tree.tokens.len; | ||
| 4865 | const new_token = try c.tree.tokens.addOne(); | ||
| 4866 | errdefer c.tree.tokens.shrink(token_index); | ||
| 4867 | 4955 | ||
| 4868 | new_token.* = .{ | 4956 | const start_index = c.source_buffer.items.len; |
| 4869 | .id = token_id, | 4957 | try c.source_buffer.outStream().print(format ++ " ", args); |
| 4958 | |||
| 4959 | c.token_ids.appendAssumeCapacity(token_id); | ||
| 4960 | c.token_locs.appendAssumeCapacity(.{ | ||
| 4870 | .start = start_index, | 4961 | .start = start_index, |
| 4871 | .end = end_index, | 4962 | .end = c.source_buffer.items.len - 1, // back up before the space |
| 4872 | }; | 4963 | }); |
| 4873 | try c.source_buffer.append(' '); | ||
| 4874 | 4964 | ||
| 4875 | return token_index; | 4965 | return c.token_ids.items.len - 1; |
| 4876 | } | 4966 | } |
| 4877 | 4967 | ||
| 4878 | // TODO hook up with codegen | 4968 | // TODO hook up with codegen |
| ... | @@ -4931,7 +5021,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { | ... | @@ -4931,7 +5021,7 @@ fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex { |
| 4931 | 5021 | ||
| 4932 | fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { | 5022 | fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { |
| 4933 | const token_index = try appendIdentifier(c, name); | 5023 | const token_index = try appendIdentifier(c, name); |
| 4934 | const identifier = try c.a().create(ast.Node.Identifier); | 5024 | const identifier = try c.arena.create(ast.Node.Identifier); |
| 4935 | identifier.* = .{ | 5025 | identifier.* = .{ |
| 4936 | .token = token_index, | 5026 | .token = token_index, |
| 4937 | }; | 5027 | }; |
| ... | @@ -4940,7 +5030,7 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { | ... | @@ -4940,7 +5030,7 @@ fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node { |
| 4940 | 5030 | ||
| 4941 | fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node { | 5031 | fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node { |
| 4942 | const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name}); | 5032 | const token_index = try appendTokenFmt(c, .Identifier, "{}", .{name}); |
| 4943 | const identifier = try c.a().create(ast.Node.Identifier); | 5033 | const identifier = try c.arena.create(ast.Node.Identifier); |
| 4944 | identifier.* = .{ | 5034 | identifier.* = .{ |
| 4945 | .token = token_index, | 5035 | .token = token_index, |
| 4946 | }; | 5036 | }; |
| ... | @@ -4955,7 +5045,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -4955,7 +5045,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4955 | // TODO if we see #undef, delete it from the table | 5045 | // TODO if we see #undef, delete it from the table |
| 4956 | var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit); | 5046 | var it = ZigClangASTUnit_getLocalPreprocessingEntities_begin(unit); |
| 4957 | const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); | 5047 | const it_end = ZigClangASTUnit_getLocalPreprocessingEntities_end(unit); |
| 4958 | var tok_list = CTokenList.init(c.a()); | 5048 | var tok_list = CTokenList.init(c.arena); |
| 4959 | const scope = c.global_scope; | 5049 | const scope = c.global_scope; |
| 4960 | 5050 | ||
| 4961 | while (it.I != it_end.I) : (it.I += 1) { | 5051 | while (it.I != it_end.I) : (it.I += 1) { |
| ... | @@ -4970,7 +5060,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { | ... | @@ -4970,7 +5060,7 @@ fn transPreprocessorEntities(c: *Context, unit: *ZigClangASTUnit) Error!void { |
| 4970 | const name = try c.str(raw_name); | 5060 | const name = try c.str(raw_name); |
| 4971 | // TODO https://github.com/ziglang/zig/issues/3756 | 5061 | // TODO https://github.com/ziglang/zig/issues/3756 |
| 4972 | // TODO https://github.com/ziglang/zig/issues/1802 | 5062 | // TODO https://github.com/ziglang/zig/issues/1802 |
| 4973 | const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.a(), "{}_{}", .{ name, c.getMangle() }) else name; | 5063 | const mangled_name = if (isZigPrimitiveType(name)) try std.fmt.allocPrint(c.arena, "{}_{}", .{ name, c.getMangle() }) else name; |
| 4974 | if (scope.containsNow(mangled_name)) { | 5064 | if (scope.containsNow(mangled_name)) { |
| 4975 | continue; | 5065 | continue; |
| 4976 | } | 5066 | } |
| ... | @@ -5060,7 +5150,8 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n | ... | @@ -5060,7 +5150,8 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n |
| 5060 | } | 5150 | } |
| 5061 | 5151 | ||
| 5062 | fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { | 5152 | fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { |
| 5063 | const block_scope = try Scope.Block.init(c, &c.global_scope.base, null); | 5153 | var block_scope = try Scope.Block.init(c, &c.global_scope.base, null); |
| 5154 | defer block_scope.deinit(); | ||
| 5064 | const scope = &block_scope.base; | 5155 | const scope = &block_scope.base; |
| 5065 | 5156 | ||
| 5066 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); | 5157 | const pub_tok = try appendToken(c, .Keyword_pub, "pub"); |
| ... | @@ -5078,7 +5169,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5078,7 +5169,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5078 | .{}, | 5169 | .{}, |
| 5079 | ); | 5170 | ); |
| 5080 | } | 5171 | } |
| 5081 | var fn_params = ast.Node.FnProto.ParamList.init(c.a()); | 5172 | |
| 5173 | var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa); | ||
| 5174 | defer fn_params.deinit(); | ||
| 5175 | |||
| 5082 | while (true) { | 5176 | while (true) { |
| 5083 | const param_tok = it.next().?; | 5177 | const param_tok = it.next().?; |
| 5084 | if (param_tok.id != .Identifier) { | 5178 | if (param_tok.id != .Identifier) { |
| ... | @@ -5096,20 +5190,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5096,20 +5190,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5096 | _ = try appendToken(c, .Colon, ":"); | 5190 | _ = try appendToken(c, .Colon, ":"); |
| 5097 | 5191 | ||
| 5098 | const token_index = try appendToken(c, .Keyword_var, "var"); | 5192 | const token_index = try appendToken(c, .Keyword_var, "var"); |
| 5099 | const identifier = try c.a().create(ast.Node.Identifier); | 5193 | const identifier = try c.arena.create(ast.Node.Identifier); |
| 5100 | identifier.* = .{ | 5194 | identifier.* = .{ |
| 5101 | .token = token_index, | 5195 | .token = token_index, |
| 5102 | }; | 5196 | }; |
| 5103 | 5197 | ||
| 5104 | const param_node = try c.a().create(ast.Node.ParamDecl); | 5198 | (try fn_params.addOne()).* = .{ |
| 5105 | param_node.* = .{ | ||
| 5106 | .doc_comments = null, | 5199 | .doc_comments = null, |
| 5107 | .comptime_token = null, | 5200 | .comptime_token = null, |
| 5108 | .noalias_token = null, | 5201 | .noalias_token = null, |
| 5109 | .name_token = param_name_tok, | 5202 | .name_token = param_name_tok, |
| 5110 | .param_type = .{ .type_expr = &identifier.base }, | 5203 | .param_type = .{ .type_expr = &identifier.base }, |
| 5111 | }; | 5204 | }; |
| 5112 | try fn_params.push(&param_node.base); | ||
| 5113 | 5205 | ||
| 5114 | if (it.peek().?.id != .Comma) | 5206 | if (it.peek().?.id != .Comma) |
| 5115 | break; | 5207 | break; |
| ... | @@ -5129,16 +5221,15 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5129,16 +5221,15 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5129 | 5221 | ||
| 5130 | _ = try appendToken(c, .RParen, ")"); | 5222 | _ = try appendToken(c, .RParen, ")"); |
| 5131 | 5223 | ||
| 5132 | const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); | 5224 | const type_of = try c.createBuiltinCall("@TypeOf", 1); |
| 5133 | type_of.rparen_token = try appendToken(c, .RParen, ")"); | ||
| 5134 | 5225 | ||
| 5135 | const fn_proto = try c.a().create(ast.Node.FnProto); | 5226 | const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len); |
| 5136 | fn_proto.* = .{ | 5227 | fn_proto.* = .{ |
| 5137 | .visib_token = pub_tok, | 5228 | .visib_token = pub_tok, |
| 5138 | .extern_export_inline_token = inline_tok, | 5229 | .extern_export_inline_token = inline_tok, |
| 5139 | .fn_token = fn_tok, | 5230 | .fn_token = fn_tok, |
| 5140 | .name_token = name_tok, | 5231 | .name_token = name_tok, |
| 5141 | .params = fn_params, | 5232 | .params_len = fn_params.items.len, |
| 5142 | .return_type = .{ .Explicit = &type_of.base }, | 5233 | .return_type = .{ .Explicit = &type_of.base }, |
| 5143 | .doc_comments = null, | 5234 | .doc_comments = null, |
| 5144 | .var_args_token = null, | 5235 | .var_args_token = null, |
| ... | @@ -5148,8 +5239,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5148,8 +5239,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5148 | .section_expr = null, | 5239 | .section_expr = null, |
| 5149 | .callconv_expr = null, | 5240 | .callconv_expr = null, |
| 5150 | }; | 5241 | }; |
| 5151 | 5242 | mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); | |
| 5152 | const block = try transCreateNodeBlock(c, null); | ||
| 5153 | 5243 | ||
| 5154 | const return_expr = try transCreateNodeReturnExpr(c); | 5244 | const return_expr = try transCreateNodeReturnExpr(c); |
| 5155 | const expr = try parseCExpr(c, it, source, source_loc, scope); | 5245 | const expr = try parseCExpr(c, it, source, source_loc, scope); |
| ... | @@ -5165,17 +5255,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5165,17 +5255,18 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5165 | _ = try appendToken(c, .Semicolon, ";"); | 5255 | _ = try appendToken(c, .Semicolon, ";"); |
| 5166 | const type_of_arg = if (expr.id != .Block) expr else blk: { | 5256 | const type_of_arg = if (expr.id != .Block) expr else blk: { |
| 5167 | const blk = @fieldParentPtr(ast.Node.Block, "base", expr); | 5257 | const blk = @fieldParentPtr(ast.Node.Block, "base", expr); |
| 5168 | const blk_last = blk.statements.at(blk.statements.len - 1).*; | 5258 | const blk_last = blk.statements()[blk.statements_len - 1]; |
| 5169 | std.debug.assert(blk_last.id == .ControlFlowExpression); | 5259 | std.debug.assert(blk_last.id == .ControlFlowExpression); |
| 5170 | const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last); | 5260 | const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last); |
| 5171 | break :blk br.rhs.?; | 5261 | break :blk br.rhs.?; |
| 5172 | }; | 5262 | }; |
| 5173 | try type_of.params.push(type_of_arg); | 5263 | type_of.params()[0] = type_of_arg; |
| 5264 | type_of.rparen_token = try appendToken(c, .RParen, ")"); | ||
| 5174 | return_expr.rhs = expr; | 5265 | return_expr.rhs = expr; |
| 5175 | 5266 | ||
| 5176 | block.rbrace = try appendToken(c, .RBrace, "}"); | 5267 | try block_scope.statements.append(&return_expr.base); |
| 5177 | try block.statements.push(&return_expr.base); | 5268 | const block_node = try block_scope.complete(c); |
| 5178 | fn_proto.body_node = &block.base; | 5269 | fn_proto.body_node = &block_node.base; |
| 5179 | _ = try c.global_scope.macro_table.put(name, &fn_proto.base); | 5270 | _ = try c.global_scope.macro_table.put(name, &fn_proto.base); |
| 5180 | } | 5271 | } |
| 5181 | 5272 | ||
| ... | @@ -5207,22 +5298,23 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ | ... | @@ -5207,22 +5298,23 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ |
| 5207 | }, | 5298 | }, |
| 5208 | .Comma => { | 5299 | .Comma => { |
| 5209 | _ = try appendToken(c, .Semicolon, ";"); | 5300 | _ = try appendToken(c, .Semicolon, ";"); |
| 5210 | const block_scope = try Scope.Block.init(c, scope, "blk"); | 5301 | const label_name = "blk"; |
| 5211 | block_scope.block_node = try transCreateNodeBlock(c, block_scope.label); | 5302 | var block_scope = try Scope.Block.init(c, scope, label_name); |
| 5303 | defer block_scope.deinit(); | ||
| 5212 | 5304 | ||
| 5213 | var last = node; | 5305 | var last = node; |
| 5214 | while (true) { | 5306 | while (true) { |
| 5215 | // suppress result | 5307 | // suppress result |
| 5216 | const lhs = try transCreateNodeIdentifier(c, "_"); | 5308 | const lhs = try transCreateNodeIdentifier(c, "_"); |
| 5217 | const op_token = try appendToken(c, .Equal, "="); | 5309 | const op_token = try appendToken(c, .Equal, "="); |
| 5218 | const op_node = try c.a().create(ast.Node.InfixOp); | 5310 | const op_node = try c.arena.create(ast.Node.InfixOp); |
| 5219 | op_node.* = .{ | 5311 | op_node.* = .{ |
| 5220 | .op_token = op_token, | 5312 | .op_token = op_token, |
| 5221 | .lhs = lhs, | 5313 | .lhs = lhs, |
| 5222 | .op = .Assign, | 5314 | .op = .Assign, |
| 5223 | .rhs = last, | 5315 | .rhs = last, |
| 5224 | }; | 5316 | }; |
| 5225 | try block_scope.block_node.statements.push(&op_node.base); | 5317 | try block_scope.statements.append(&op_node.base); |
| 5226 | 5318 | ||
| 5227 | last = try parseCPrefixOpExpr(c, it, source, source_loc, scope); | 5319 | last = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 5228 | _ = try appendToken(c, .Semicolon, ";"); | 5320 | _ = try appendToken(c, .Semicolon, ";"); |
| ... | @@ -5232,11 +5324,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ | ... | @@ -5232,11 +5324,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ |
| 5232 | } | 5324 | } |
| 5233 | } | 5325 | } |
| 5234 | 5326 | ||
| 5235 | const break_node = try transCreateNodeBreak(c, block_scope.label); | 5327 | const break_node = try transCreateNodeBreak(c, label_name); |
| 5236 | break_node.rhs = last; | 5328 | break_node.rhs = last; |
| 5237 | try block_scope.block_node.statements.push(&break_node.base); | 5329 | try block_scope.statements.append(&break_node.base); |
| 5238 | block_scope.block_node.rbrace = try appendToken(c, .RBrace, "}"); | 5330 | const block_node = try block_scope.complete(c); |
| 5239 | return &block_scope.block_node.base; | 5331 | return &block_node.base; |
| 5240 | }, | 5332 | }, |
| 5241 | else => { | 5333 | else => { |
| 5242 | _ = it.prev(); | 5334 | _ = it.prev(); |
| ... | @@ -5253,11 +5345,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl | ... | @@ -5253,11 +5345,11 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl |
| 5253 | switch (lit_bytes[1]) { | 5345 | switch (lit_bytes[1]) { |
| 5254 | '0'...'7' => { | 5346 | '0'...'7' => { |
| 5255 | // Octal | 5347 | // Octal |
| 5256 | lit_bytes = try std.fmt.allocPrint(c.a(), "0o{}", .{lit_bytes}); | 5348 | lit_bytes = try std.fmt.allocPrint(c.arena, "0o{}", .{lit_bytes}); |
| 5257 | }, | 5349 | }, |
| 5258 | 'X' => { | 5350 | 'X' => { |
| 5259 | // Hexadecimal with capital X, valid in C but not in Zig | 5351 | // Hexadecimal with capital X, valid in C but not in Zig |
| 5260 | lit_bytes = try std.fmt.allocPrint(c.a(), "0x{}", .{lit_bytes[2..]}); | 5352 | lit_bytes = try std.fmt.allocPrint(c.arena, "0x{}", .{lit_bytes[2..]}); |
| 5261 | }, | 5353 | }, |
| 5262 | else => {}, | 5354 | else => {}, |
| 5263 | } | 5355 | } |
| ... | @@ -5267,15 +5359,15 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl | ... | @@ -5267,15 +5359,15 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl |
| 5267 | return transCreateNodeInt(c, lit_bytes); | 5359 | return transCreateNodeInt(c, lit_bytes); |
| 5268 | } | 5360 | } |
| 5269 | 5361 | ||
| 5270 | const cast_node = try transCreateNodeBuiltinFnCall(c, "@as"); | 5362 | const cast_node = try c.createBuiltinCall("@as", 2); |
| 5271 | try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) { | 5363 | cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) { |
| 5272 | .U => "c_uint", | 5364 | .U => "c_uint", |
| 5273 | .L => "c_long", | 5365 | .L => "c_long", |
| 5274 | .LU => "c_ulong", | 5366 | .LU => "c_ulong", |
| 5275 | .LL => "c_longlong", | 5367 | .LL => "c_longlong", |
| 5276 | .LLU => "c_ulonglong", | 5368 | .LLU => "c_ulonglong", |
| 5277 | else => unreachable, | 5369 | else => unreachable, |
| 5278 | })); | 5370 | }); |
| 5279 | lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (tok.id.IntegerLiteral) { | 5371 | lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (tok.id.IntegerLiteral) { |
| 5280 | .U, .L => @as(u8, 1), | 5372 | .U, .L => @as(u8, 1), |
| 5281 | .LU, .LL => 2, | 5373 | .LU, .LL => 2, |
| ... | @@ -5283,23 +5375,23 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl | ... | @@ -5283,23 +5375,23 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl |
| 5283 | else => unreachable, | 5375 | else => unreachable, |
| 5284 | }]; | 5376 | }]; |
| 5285 | _ = try appendToken(c, .Comma, ","); | 5377 | _ = try appendToken(c, .Comma, ","); |
| 5286 | try cast_node.params.push(try transCreateNodeInt(c, lit_bytes)); | 5378 | cast_node.params()[1] = try transCreateNodeInt(c, lit_bytes); |
| 5287 | cast_node.rparen_token = try appendToken(c, .RParen, ")"); | 5379 | cast_node.rparen_token = try appendToken(c, .RParen, ")"); |
| 5288 | return &cast_node.base; | 5380 | return &cast_node.base; |
| 5289 | } else if (tok.id == .FloatLiteral) { | 5381 | } else if (tok.id == .FloatLiteral) { |
| 5290 | if (lit_bytes[0] == '.') | 5382 | if (lit_bytes[0] == '.') |
| 5291 | lit_bytes = try std.fmt.allocPrint(c.a(), "0{}", .{lit_bytes}); | 5383 | lit_bytes = try std.fmt.allocPrint(c.arena, "0{}", .{lit_bytes}); |
| 5292 | if (tok.id.FloatLiteral == .None) { | 5384 | if (tok.id.FloatLiteral == .None) { |
| 5293 | return transCreateNodeFloat(c, lit_bytes); | 5385 | return transCreateNodeFloat(c, lit_bytes); |
| 5294 | } | 5386 | } |
| 5295 | const cast_node = try transCreateNodeBuiltinFnCall(c, "@as"); | 5387 | const cast_node = try c.createBuiltinCall("@as", 2); |
| 5296 | try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) { | 5388 | cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) { |
| 5297 | .F => "f32", | 5389 | .F => "f32", |
| 5298 | .L => "c_longdouble", | 5390 | .L => "c_longdouble", |
| 5299 | else => unreachable, | 5391 | else => unreachable, |
| 5300 | })); | 5392 | }); |
| 5301 | _ = try appendToken(c, .Comma, ","); | 5393 | _ = try appendToken(c, .Comma, ","); |
| 5302 | try cast_node.params.push(try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1])); | 5394 | cast_node.params()[1] = try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]); |
| 5303 | cast_node.rparen_token = try appendToken(c, .RParen, ")"); | 5395 | cast_node.rparen_token = try appendToken(c, .RParen, ")"); |
| 5304 | return &cast_node.base; | 5396 | return &cast_node.base; |
| 5305 | } else unreachable; | 5397 | } else unreachable; |
| ... | @@ -5318,7 +5410,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const | ... | @@ -5318,7 +5410,7 @@ fn zigifyEscapeSequences(ctx: *Context, source_bytes: []const u8, name: []const |
| 5318 | break; | 5410 | break; |
| 5319 | } | 5411 | } |
| 5320 | } else return source; | 5412 | } else return source; |
| 5321 | var bytes = try ctx.a().alloc(u8, source.len * 2); | 5413 | var bytes = try ctx.arena.alloc(u8, source.len * 2); |
| 5322 | var state: enum { | 5414 | var state: enum { |
| 5323 | Start, | 5415 | Start, |
| 5324 | Escape, | 5416 | Escape, |
| ... | @@ -5472,14 +5564,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5472,14 +5564,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5472 | const first_tok = it.list.at(0); | 5564 | const first_tok = it.list.at(0); |
| 5473 | if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) { | 5565 | if (source[tok.start] != '\'' or source[tok.start + 1] == '\\' or tok.end - tok.start == 3) { |
| 5474 | const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc)); | 5566 | const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc)); |
| 5475 | const node = try c.a().create(ast.Node.CharLiteral); | 5567 | const node = try c.arena.create(ast.Node.CharLiteral); |
| 5476 | node.* = .{ | 5568 | node.* = .{ |
| 5477 | .token = token, | 5569 | .token = token, |
| 5478 | }; | 5570 | }; |
| 5479 | return &node.base; | 5571 | return &node.base; |
| 5480 | } else { | 5572 | } else { |
| 5481 | const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start+1..tok.end-1]}); | 5573 | const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{source[tok.start+1..tok.end-1]}); |
| 5482 | const node = try c.a().create(ast.Node.IntegerLiteral); | 5574 | const node = try c.arena.create(ast.Node.IntegerLiteral); |
| 5483 | node.* = .{ | 5575 | node.* = .{ |
| 5484 | .token = token, | 5576 | .token = token, |
| 5485 | }; | 5577 | }; |
| ... | @@ -5489,7 +5581,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5489,7 +5581,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5489 | .StringLiteral => { | 5581 | .StringLiteral => { |
| 5490 | const first_tok = it.list.at(0); | 5582 | const first_tok = it.list.at(0); |
| 5491 | const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc)); | 5583 | const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, source[tok.start..tok.end], source[first_tok.start..first_tok.end], source_loc)); |
| 5492 | const node = try c.a().create(ast.Node.StringLiteral); | 5584 | const node = try c.arena.create(ast.Node.StringLiteral); |
| 5493 | node.* = .{ | 5585 | node.* = .{ |
| 5494 | .token = token, | 5586 | .token = token, |
| 5495 | }; | 5587 | }; |
| ... | @@ -5569,10 +5661,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5569,10 +5661,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5569 | //else | 5661 | //else |
| 5570 | // @as(dest, x) ) | 5662 | // @as(dest, x) ) |
| 5571 | const if_node = try transCreateNodeIf(c); | 5663 | const if_node = try transCreateNodeIf(c); |
| 5572 | const type_info_node = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); | 5664 | const type_info_node = try c.createBuiltinCall("@typeInfo", 1); |
| 5573 | try type_info_node.params.push(inner_node); | 5665 | type_info_node.params()[0] = inner_node; |
| 5574 | type_info_node.rparen_token = try appendToken(c, .LParen, ")"); | 5666 | type_info_node.rparen_token = try appendToken(c, .LParen, ")"); |
| 5575 | const cmp_node = try c.a().create(ast.Node.InfixOp); | 5667 | const cmp_node = try c.arena.create(ast.Node.InfixOp); |
| 5576 | cmp_node.* = .{ | 5668 | cmp_node.* = .{ |
| 5577 | .op_token = try appendToken(c, .EqualEqual, "=="), | 5669 | .op_token = try appendToken(c, .EqualEqual, "=="), |
| 5578 | .lhs = &type_info_node.base, | 5670 | .lhs = &type_info_node.base, |
| ... | @@ -5582,22 +5674,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5582,22 +5674,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5582 | if_node.condition = &cmp_node.base; | 5674 | if_node.condition = &cmp_node.base; |
| 5583 | _ = try appendToken(c, .RParen, ")"); | 5675 | _ = try appendToken(c, .RParen, ")"); |
| 5584 | 5676 | ||
| 5585 | const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr"); | 5677 | const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2); |
| 5586 | try int_to_ptr.params.push(inner_node); | 5678 | int_to_ptr.params()[0] = inner_node; |
| 5587 | try int_to_ptr.params.push(node_to_cast); | 5679 | int_to_ptr.params()[1] = node_to_cast; |
| 5588 | int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); | 5680 | int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); |
| 5589 | if_node.body = &int_to_ptr.base; | 5681 | if_node.body = &int_to_ptr.base; |
| 5590 | 5682 | ||
| 5591 | const else_node = try transCreateNodeElse(c); | 5683 | const else_node = try transCreateNodeElse(c); |
| 5592 | if_node.@"else" = else_node; | 5684 | if_node.@"else" = else_node; |
| 5593 | 5685 | ||
| 5594 | const as_node = try transCreateNodeBuiltinFnCall(c, "@as"); | 5686 | const as_node = try c.createBuiltinCall("@as", 2); |
| 5595 | try as_node.params.push(inner_node); | 5687 | as_node.params()[0] = inner_node; |
| 5596 | try as_node.params.push(node_to_cast); | 5688 | as_node.params()[1] = node_to_cast; |
| 5597 | as_node.rparen_token = try appendToken(c, .RParen, ")"); | 5689 | as_node.rparen_token = try appendToken(c, .RParen, ")"); |
| 5598 | else_node.body = &as_node.base; | 5690 | else_node.body = &as_node.base; |
| 5599 | 5691 | ||
| 5600 | const group_node = try c.a().create(ast.Node.GroupedExpression); | 5692 | const group_node = try c.arena.create(ast.Node.GroupedExpression); |
| 5601 | group_node.* = .{ | 5693 | group_node.* = .{ |
| 5602 | .lparen = lparen, | 5694 | .lparen = lparen, |
| 5603 | .expr = &if_node.base, | 5695 | .expr = &if_node.base, |
| ... | @@ -5614,14 +5706,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5614,14 +5706,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5614 | // @as(dest, x) ) | 5706 | // @as(dest, x) ) |
| 5615 | 5707 | ||
| 5616 | const if_1 = try transCreateNodeIf(c); | 5708 | const if_1 = try transCreateNodeIf(c); |
| 5617 | const type_info_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); | 5709 | const type_info_1 = try c.createBuiltinCall("@typeInfo", 1); |
| 5618 | const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); | 5710 | const type_of_1 = try c.createBuiltinCall("@TypeOf", 1); |
| 5619 | try type_info_1.params.push(&type_of_1.base); | 5711 | type_info_1.params()[0] = &type_of_1.base; |
| 5620 | try type_of_1.params.push(node_to_cast); | 5712 | type_of_1.params()[0] = node_to_cast; |
| 5621 | type_of_1.rparen_token = try appendToken(c, .RParen, ")"); | 5713 | type_of_1.rparen_token = try appendToken(c, .RParen, ")"); |
| 5622 | type_info_1.rparen_token = try appendToken(c, .RParen, ")"); | 5714 | type_info_1.rparen_token = try appendToken(c, .RParen, ")"); |
| 5623 | 5715 | ||
| 5624 | const cmp_1 = try c.a().create(ast.Node.InfixOp); | 5716 | const cmp_1 = try c.arena.create(ast.Node.InfixOp); |
| 5625 | cmp_1.* = .{ | 5717 | cmp_1.* = .{ |
| 5626 | .op_token = try appendToken(c, .EqualEqual, "=="), | 5718 | .op_token = try appendToken(c, .EqualEqual, "=="), |
| 5627 | .lhs = &type_info_1.base, | 5719 | .lhs = &type_info_1.base, |
| ... | @@ -5633,7 +5725,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5633,7 +5725,7 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5633 | 5725 | ||
| 5634 | const period_tok = try appendToken(c, .Period, "."); | 5726 | const period_tok = try appendToken(c, .Period, "."); |
| 5635 | const child_ident = try transCreateNodeIdentifier(c, "Child"); | 5727 | const child_ident = try transCreateNodeIdentifier(c, "Child"); |
| 5636 | const inner_node_child = try c.a().create(ast.Node.InfixOp); | 5728 | const inner_node_child = try c.arena.create(ast.Node.InfixOp); |
| 5637 | inner_node_child.* = .{ | 5729 | inner_node_child.* = .{ |
| 5638 | .op_token = period_tok, | 5730 | .op_token = period_tok, |
| 5639 | .lhs = inner_node, | 5731 | .lhs = inner_node, |
| ... | @@ -5641,20 +5733,20 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5641,20 +5733,20 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5641 | .rhs = child_ident, | 5733 | .rhs = child_ident, |
| 5642 | }; | 5734 | }; |
| 5643 | 5735 | ||
| 5644 | const align_of = try transCreateNodeBuiltinFnCall(c, "@alignOf"); | 5736 | const align_of = try c.createBuiltinCall("@alignOf", 1); |
| 5645 | try align_of.params.push(&inner_node_child.base); | 5737 | align_of.params()[0] = &inner_node_child.base; |
| 5646 | align_of.rparen_token = try appendToken(c, .RParen, ")"); | 5738 | align_of.rparen_token = try appendToken(c, .RParen, ")"); |
| 5647 | // hack to get zig fmt to render a comma in builtin calls | 5739 | // hack to get zig fmt to render a comma in builtin calls |
| 5648 | _ = try appendToken(c, .Comma, ","); | 5740 | _ = try appendToken(c, .Comma, ","); |
| 5649 | 5741 | ||
| 5650 | const align_cast = try transCreateNodeBuiltinFnCall(c, "@alignCast"); | 5742 | const align_cast = try c.createBuiltinCall("@alignCast", 2); |
| 5651 | try align_cast.params.push(&align_of.base); | 5743 | align_cast.params()[0] = &align_of.base; |
| 5652 | try align_cast.params.push(node_to_cast); | 5744 | align_cast.params()[1] = node_to_cast; |
| 5653 | align_cast.rparen_token = try appendToken(c, .RParen, ")"); | 5745 | align_cast.rparen_token = try appendToken(c, .RParen, ")"); |
| 5654 | 5746 | ||
| 5655 | const ptr_cast = try transCreateNodeBuiltinFnCall(c, "@ptrCast"); | 5747 | const ptr_cast = try c.createBuiltinCall("@ptrCast", 2); |
| 5656 | try ptr_cast.params.push(inner_node); | 5748 | ptr_cast.params()[0] = inner_node; |
| 5657 | try ptr_cast.params.push(&align_cast.base); | 5749 | ptr_cast.params()[1] = &align_cast.base; |
| 5658 | ptr_cast.rparen_token = try appendToken(c, .RParen, ")"); | 5750 | ptr_cast.rparen_token = try appendToken(c, .RParen, ")"); |
| 5659 | if_1.body = &ptr_cast.base; | 5751 | if_1.body = &ptr_cast.base; |
| 5660 | 5752 | ||
| ... | @@ -5662,14 +5754,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5662,14 +5754,14 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5662 | if_1.@"else" = else_1; | 5754 | if_1.@"else" = else_1; |
| 5663 | 5755 | ||
| 5664 | const if_2 = try transCreateNodeIf(c); | 5756 | const if_2 = try transCreateNodeIf(c); |
| 5665 | const type_info_2 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); | 5757 | const type_info_2 = try c.createBuiltinCall("@typeInfo", 1); |
| 5666 | const type_of_2 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); | 5758 | const type_of_2 = try c.createBuiltinCall("@TypeOf", 1); |
| 5667 | try type_info_2.params.push(&type_of_2.base); | 5759 | type_info_2.params()[0] = &type_of_2.base; |
| 5668 | try type_of_2.params.push(node_to_cast); | 5760 | type_of_2.params()[0] = node_to_cast; |
| 5669 | type_of_2.rparen_token = try appendToken(c, .RParen, ")"); | 5761 | type_of_2.rparen_token = try appendToken(c, .RParen, ")"); |
| 5670 | type_info_2.rparen_token = try appendToken(c, .RParen, ")"); | 5762 | type_info_2.rparen_token = try appendToken(c, .RParen, ")"); |
| 5671 | 5763 | ||
| 5672 | const cmp_2 = try c.a().create(ast.Node.InfixOp); | 5764 | const cmp_2 = try c.arena.create(ast.Node.InfixOp); |
| 5673 | cmp_2.* = .{ | 5765 | cmp_2.* = .{ |
| 5674 | .op_token = try appendToken(c, .EqualEqual, "=="), | 5766 | .op_token = try appendToken(c, .EqualEqual, "=="), |
| 5675 | .lhs = &type_info_2.base, | 5767 | .lhs = &type_info_2.base, |
| ... | @@ -5677,17 +5769,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5677,17 +5769,17 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5677 | .rhs = try transCreateNodeEnumLiteral(c, "Int"), | 5769 | .rhs = try transCreateNodeEnumLiteral(c, "Int"), |
| 5678 | }; | 5770 | }; |
| 5679 | if_2.condition = &cmp_2.base; | 5771 | if_2.condition = &cmp_2.base; |
| 5680 | const cmp_4 = try c.a().create(ast.Node.InfixOp); | 5772 | const cmp_4 = try c.arena.create(ast.Node.InfixOp); |
| 5681 | cmp_4.* = .{ | 5773 | cmp_4.* = .{ |
| 5682 | .op_token = try appendToken(c, .Keyword_and, "and"), | 5774 | .op_token = try appendToken(c, .Keyword_and, "and"), |
| 5683 | .lhs = &cmp_2.base, | 5775 | .lhs = &cmp_2.base, |
| 5684 | .op = .BoolAnd, | 5776 | .op = .BoolAnd, |
| 5685 | .rhs = undefined, | 5777 | .rhs = undefined, |
| 5686 | }; | 5778 | }; |
| 5687 | const type_info_3 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); | 5779 | const type_info_3 = try c.createBuiltinCall("@typeInfo", 1); |
| 5688 | try type_info_3.params.push(inner_node); | 5780 | type_info_3.params()[0] = inner_node; |
| 5689 | type_info_3.rparen_token = try appendToken(c, .LParen, ")"); | 5781 | type_info_3.rparen_token = try appendToken(c, .LParen, ")"); |
| 5690 | const cmp_3 = try c.a().create(ast.Node.InfixOp); | 5782 | const cmp_3 = try c.arena.create(ast.Node.InfixOp); |
| 5691 | cmp_3.* = .{ | 5783 | cmp_3.* = .{ |
| 5692 | .op_token = try appendToken(c, .EqualEqual, "=="), | 5784 | .op_token = try appendToken(c, .EqualEqual, "=="), |
| 5693 | .lhs = &type_info_3.base, | 5785 | .lhs = &type_info_3.base, |
| ... | @@ -5699,22 +5791,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5699,22 +5791,22 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5699 | else_1.body = &if_2.base; | 5791 | else_1.body = &if_2.base; |
| 5700 | _ = try appendToken(c, .RParen, ")"); | 5792 | _ = try appendToken(c, .RParen, ")"); |
| 5701 | 5793 | ||
| 5702 | const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr"); | 5794 | const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2); |
| 5703 | try int_to_ptr.params.push(inner_node); | 5795 | int_to_ptr.params()[0] = inner_node; |
| 5704 | try int_to_ptr.params.push(node_to_cast); | 5796 | int_to_ptr.params()[1] = node_to_cast; |
| 5705 | int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); | 5797 | int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); |
| 5706 | if_2.body = &int_to_ptr.base; | 5798 | if_2.body = &int_to_ptr.base; |
| 5707 | 5799 | ||
| 5708 | const else_2 = try transCreateNodeElse(c); | 5800 | const else_2 = try transCreateNodeElse(c); |
| 5709 | if_2.@"else" = else_2; | 5801 | if_2.@"else" = else_2; |
| 5710 | 5802 | ||
| 5711 | const as = try transCreateNodeBuiltinFnCall(c, "@as"); | 5803 | const as = try c.createBuiltinCall("@as", 2); |
| 5712 | try as.params.push(inner_node); | 5804 | as.params()[0] = inner_node; |
| 5713 | try as.params.push(node_to_cast); | 5805 | as.params()[1] = node_to_cast; |
| 5714 | as.rparen_token = try appendToken(c, .RParen, ")"); | 5806 | as.rparen_token = try appendToken(c, .RParen, ")"); |
| 5715 | else_2.body = &as.base; | 5807 | else_2.body = &as.base; |
| 5716 | 5808 | ||
| 5717 | const group_node = try c.a().create(ast.Node.GroupedExpression); | 5809 | const group_node = try c.arena.create(ast.Node.GroupedExpression); |
| 5718 | group_node.* = .{ | 5810 | group_node.* = .{ |
| 5719 | .lparen = lparen, | 5811 | .lparen = lparen, |
| 5720 | .expr = &if_1.base, | 5812 | .expr = &if_1.base, |
| ... | @@ -5740,7 +5832,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { | ... | @@ -5740,7 +5832,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { |
| 5740 | if (!isBoolRes(node)) { | 5832 | if (!isBoolRes(node)) { |
| 5741 | if (node.id != .InfixOp) return node; | 5833 | if (node.id != .InfixOp) return node; |
| 5742 | 5834 | ||
| 5743 | const group_node = try c.a().create(ast.Node.GroupedExpression); | 5835 | const group_node = try c.arena.create(ast.Node.GroupedExpression); |
| 5744 | group_node.* = .{ | 5836 | group_node.* = .{ |
| 5745 | .lparen = try appendToken(c, .LParen, "("), | 5837 | .lparen = try appendToken(c, .LParen, "("), |
| 5746 | .expr = node, | 5838 | .expr = node, |
| ... | @@ -5749,8 +5841,8 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { | ... | @@ -5749,8 +5841,8 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { |
| 5749 | return &group_node.base; | 5841 | return &group_node.base; |
| 5750 | } | 5842 | } |
| 5751 | 5843 | ||
| 5752 | const builtin_node = try transCreateNodeBuiltinFnCall(c, "@boolToInt"); | 5844 | const builtin_node = try c.createBuiltinCall("@boolToInt", 1); |
| 5753 | try builtin_node.params.push(node); | 5845 | builtin_node.params()[0] = node; |
| 5754 | builtin_node.rparen_token = try appendToken(c, .RParen, ")"); | 5846 | builtin_node.rparen_token = try appendToken(c, .RParen, ")"); |
| 5755 | return &builtin_node.base; | 5847 | return &builtin_node.base; |
| 5756 | } | 5848 | } |
| ... | @@ -5759,7 +5851,7 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node { | ... | @@ -5759,7 +5851,7 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node { |
| 5759 | if (isBoolRes(node)) { | 5851 | if (isBoolRes(node)) { |
| 5760 | if (node.id != .InfixOp) return node; | 5852 | if (node.id != .InfixOp) return node; |
| 5761 | 5853 | ||
| 5762 | const group_node = try c.a().create(ast.Node.GroupedExpression); | 5854 | const group_node = try c.arena.create(ast.Node.GroupedExpression); |
| 5763 | group_node.* = .{ | 5855 | group_node.* = .{ |
| 5764 | .lparen = try appendToken(c, .LParen, "("), | 5856 | .lparen = try appendToken(c, .LParen, "("), |
| 5765 | .expr = node, | 5857 | .expr = node, |
| ... | @@ -5770,14 +5862,14 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node { | ... | @@ -5770,14 +5862,14 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node { |
| 5770 | 5862 | ||
| 5771 | const op_token = try appendToken(c, .BangEqual, "!="); | 5863 | const op_token = try appendToken(c, .BangEqual, "!="); |
| 5772 | const zero = try transCreateNodeInt(c, 0); | 5864 | const zero = try transCreateNodeInt(c, 0); |
| 5773 | const res = try c.a().create(ast.Node.InfixOp); | 5865 | const res = try c.arena.create(ast.Node.InfixOp); |
| 5774 | res.* = .{ | 5866 | res.* = .{ |
| 5775 | .op_token = op_token, | 5867 | .op_token = op_token, |
| 5776 | .lhs = node, | 5868 | .lhs = node, |
| 5777 | .op = .BangEqual, | 5869 | .op = .BangEqual, |
| 5778 | .rhs = zero, | 5870 | .rhs = zero, |
| 5779 | }; | 5871 | }; |
| 5780 | const group_node = try c.a().create(ast.Node.GroupedExpression); | 5872 | const group_node = try c.arena.create(ast.Node.GroupedExpression); |
| 5781 | group_node.* = .{ | 5873 | group_node.* = .{ |
| 5782 | .lparen = try appendToken(c, .LParen, "("), | 5874 | .lparen = try appendToken(c, .LParen, "("), |
| 5783 | .expr = &res.base, | 5875 | .expr = &res.base, |
| ... | @@ -5928,10 +6020,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5928,10 +6020,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5928 | continue; | 6020 | continue; |
| 5929 | }, | 6021 | }, |
| 5930 | .LParen => { | 6022 | .LParen => { |
| 5931 | const call_node = try transCreateNodeFnCall(c, node); | 6023 | _ = try appendToken(c, .LParen, "("); |
| 6024 | var call_params = std.ArrayList(*ast.Node).init(c.gpa); | ||
| 6025 | defer call_params.deinit(); | ||
| 5932 | while (true) { | 6026 | while (true) { |
| 5933 | const arg = try parseCPrefixOpExpr(c, it, source, source_loc, scope); | 6027 | const arg = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 5934 | try call_node.op.Call.params.push(arg); | 6028 | try call_params.append(arg); |
| 5935 | const next = it.next().?; | 6029 | const next = it.next().?; |
| 5936 | if (next.id == .Comma) | 6030 | if (next.id == .Comma) |
| 5937 | _ = try appendToken(c, .Comma, ",") | 6031 | _ = try appendToken(c, .Comma, ",") |
| ... | @@ -5949,7 +6043,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5949,7 +6043,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5949 | return error.ParseError; | 6043 | return error.ParseError; |
| 5950 | } | 6044 | } |
| 5951 | } | 6045 | } |
| 5952 | call_node.rtoken = try appendToken(c, .RParen, ")"); | 6046 | const call_node = try ast.Node.Call.alloc(c.arena, call_params.items.len); |
| 6047 | call_node.* = .{ | ||
| 6048 | .lhs = node, | ||
| 6049 | .params_len = call_params.items.len, | ||
| 6050 | .async_token = null, | ||
| 6051 | .rtoken = try appendToken(c, .RParen, ")"), | ||
| 6052 | }; | ||
| 6053 | mem.copy(*ast.Node, call_node.params(), call_params.items); | ||
| 5953 | node = &call_node.base; | 6054 | node = &call_node.base; |
| 5954 | continue; | 6055 | continue; |
| 5955 | }, | 6056 | }, |
| ... | @@ -5989,7 +6090,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -5989,7 +6090,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 5989 | const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt; | 6090 | const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt; |
| 5990 | const lhs_node = try cast_fn(c, node); | 6091 | const lhs_node = try cast_fn(c, node); |
| 5991 | const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope); | 6092 | const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope); |
| 5992 | const op_node = try c.a().create(ast.Node.InfixOp); | 6093 | const op_node = try c.arena.create(ast.Node.InfixOp); |
| 5993 | op_node.* = .{ | 6094 | op_node.* = .{ |
| 5994 | .op_token = op_token, | 6095 | .op_token = op_token, |
| 5995 | .lhs = lhs_node, | 6096 | .lhs = lhs_node, |
| ... | @@ -6037,7 +6138,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, | ... | @@ -6037,7 +6138,7 @@ fn parseCPrefixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, |
| 6037 | } | 6138 | } |
| 6038 | 6139 | ||
| 6039 | fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 { | 6140 | fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 { |
| 6040 | const tok = c.tree.tokens.at(token); | 6141 | const tok = c.token_locs.items[token]; |
| 6041 | const slice = c.source_buffer.span()[tok.start..tok.end]; | 6142 | const slice = c.source_buffer.span()[tok.start..tok.end]; |
| 6042 | return if (mem.startsWith(u8, slice, "@\"")) | 6143 | return if (mem.startsWith(u8, slice, "@\"")) |
| 6043 | slice[2 .. slice.len - 1] | 6144 | slice[2 .. slice.len - 1] |
| ... | @@ -6060,9 +6161,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { | ... | @@ -6060,9 +6161,8 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { |
| 6060 | return null; | 6161 | return null; |
| 6061 | if (getContainerTypeOf(c, infix.lhs)) |ty_node| { | 6162 | if (getContainerTypeOf(c, infix.lhs)) |ty_node| { |
| 6062 | if (ty_node.cast(ast.Node.ContainerDecl)) |container| { | 6163 | if (ty_node.cast(ast.Node.ContainerDecl)) |container| { |
| 6063 | var it = container.fields_and_decls.iterator(0); | 6164 | for (container.fieldsAndDecls()) |field_ref| { |
| 6064 | while (it.next()) |field_ref| { | 6165 | const field = field_ref.cast(ast.Node.ContainerField).?; |
| 6065 | const field = field_ref.*.cast(ast.Node.ContainerField).?; | ||
| 6066 | const ident = infix.rhs.cast(ast.Node.Identifier).?; | 6166 | const ident = infix.rhs.cast(ast.Node.Identifier).?; |
| 6067 | if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) { | 6167 | if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) { |
| 6068 | return getContainer(c, field.type_expr.?); | 6168 | return getContainer(c, field.type_expr.?); |
| ... | @@ -6087,9 +6187,8 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node { | ... | @@ -6087,9 +6187,8 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node { |
| 6087 | return null; | 6187 | return null; |
| 6088 | if (getContainerTypeOf(c, infix.lhs)) |ty_node| { | 6188 | if (getContainerTypeOf(c, infix.lhs)) |ty_node| { |
| 6089 | if (ty_node.cast(ast.Node.ContainerDecl)) |container| { | 6189 | if (ty_node.cast(ast.Node.ContainerDecl)) |container| { |
| 6090 | var it = container.fields_and_decls.iterator(0); | 6190 | for (container.fieldsAndDecls()) |field_ref| { |
| 6091 | while (it.next()) |field_ref| { | 6191 | const field = field_ref.cast(ast.Node.ContainerField).?; |
| 6092 | const field = field_ref.*.cast(ast.Node.ContainerField).?; | ||
| 6093 | const ident = infix.rhs.cast(ast.Node.Identifier).?; | 6192 | const ident = infix.rhs.cast(ast.Node.Identifier).?; |
| 6094 | if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) { | 6193 | if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) { |
| 6095 | return getContainer(c, field.type_expr.?); | 6194 | return getContainer(c, field.type_expr.?); |
src/analyze.cpp+18-3| ... | @@ -3612,6 +3612,12 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { | ... | @@ -3612,6 +3612,12 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { |
| 3612 | auto entry = decls_scope->decl_table.put_unique(tld->name, tld); | 3612 | auto entry = decls_scope->decl_table.put_unique(tld->name, tld); |
| 3613 | if (entry) { | 3613 | if (entry) { |
| 3614 | Tld *other_tld = entry->value; | 3614 | Tld *other_tld = entry->value; |
| 3615 | if (other_tld->id == TldIdVar) { | ||
| 3616 | ZigVar *var = reinterpret_cast<TldVar *>(other_tld)->var; | ||
| 3617 | if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { | ||
| 3618 | return; // already reported compile error | ||
| 3619 | } | ||
| 3620 | } | ||
| 3615 | ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name))); | 3621 | ErrorMsg *msg = add_node_error(g, tld->source_node, buf_sprintf("redefinition of '%s'", buf_ptr(tld->name))); |
| 3616 | add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here")); | 3622 | add_error_note(g, msg, other_tld->source_node, buf_sprintf("previous definition is here")); |
| 3617 | return; | 3623 | return; |
| ... | @@ -3887,9 +3893,18 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -3887,9 +3893,18 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3887 | if (search_scope != nullptr) { | 3893 | if (search_scope != nullptr) { |
| 3888 | Tld *tld = find_decl(g, search_scope, name); | 3894 | Tld *tld = find_decl(g, search_scope, name); |
| 3889 | if (tld != nullptr && tld != src_tld) { | 3895 | if (tld != nullptr && tld != src_tld) { |
| 3890 | ErrorMsg *msg = add_node_error(g, source_node, | 3896 | bool want_err_msg = true; |
| 3891 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | 3897 | if (tld->id == TldIdVar) { |
| 3892 | add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); | 3898 | ZigVar *var = reinterpret_cast<TldVar *>(tld)->var; |
| 3899 | if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { | ||
| 3900 | want_err_msg = false; | ||
| 3901 | } | ||
| 3902 | } | ||
| 3903 | if (want_err_msg) { | ||
| 3904 | ErrorMsg *msg = add_node_error(g, source_node, | ||
| 3905 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | ||
| 3906 | add_error_note(g, msg, tld->source_node, buf_sprintf("previous definition is here")); | ||
| 3907 | } | ||
| 3893 | variable_entry->var_type = g->builtin_types.entry_invalid; | 3908 | variable_entry->var_type = g->builtin_types.entry_invalid; |
| 3894 | } | 3909 | } |
| 3895 | } | 3910 | } |
src/ir.cpp+12-3| ... | @@ -5300,9 +5300,18 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s | ... | @@ -5300,9 +5300,18 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s |
| 5300 | } else { | 5300 | } else { |
| 5301 | Tld *tld = find_decl(codegen, parent_scope, name); | 5301 | Tld *tld = find_decl(codegen, parent_scope, name); |
| 5302 | if (tld != nullptr) { | 5302 | if (tld != nullptr) { |
| 5303 | ErrorMsg *msg = add_node_error(codegen, node, | 5303 | bool want_err_msg = true; |
| 5304 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | 5304 | if (tld->id == TldIdVar) { |
| 5305 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); | 5305 | ZigVar *var = reinterpret_cast<TldVar *>(tld)->var; |
| 5306 | if (var != nullptr && var->var_type != nullptr && type_is_invalid(var->var_type)) { | ||
| 5307 | want_err_msg = false; | ||
| 5308 | } | ||
| 5309 | } | ||
| 5310 | if (want_err_msg) { | ||
| 5311 | ErrorMsg *msg = add_node_error(codegen, node, | ||
| 5312 | buf_sprintf("redefinition of '%s'", buf_ptr(name))); | ||
| 5313 | add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); | ||
| 5314 | } | ||
| 5306 | variable_entry->var_type = codegen->builtin_types.entry_invalid; | 5315 | variable_entry->var_type = codegen->builtin_types.entry_invalid; |
| 5307 | } | 5316 | } |
| 5308 | } | 5317 | } |