| ... | @@ -131,11 +131,23 @@ const Parser = struct { | ... | @@ -131,11 +131,23 @@ const Parser = struct { |
| 131 | return @intCast(Node.Index, i); | 131 | return @intCast(Node.Index, i); |
| 132 | } | 132 | } |
| 133 | | 133 | |
| 134 | fn reserveNode(p: *Parser) !usize { | 134 | fn reserveNode(p: *Parser, tag: Ast.Node.Tag) !usize { |
| 135 | try p.nodes.resize(p.gpa, p.nodes.len + 1); | 135 | try p.nodes.resize(p.gpa, p.nodes.len + 1); |
| | 136 | p.nodes.items(.tag)[p.nodes.len - 1] = tag; |
| 136 | return p.nodes.len - 1; | 137 | return p.nodes.len - 1; |
| 137 | } | 138 | } |
| 138 | | 139 | |
| | 140 | fn unreserveNode(p: *Parser, node_index: usize) void { |
| | 141 | if (p.nodes.len == node_index) { |
| | 142 | p.nodes.resize(p.gpa, p.nodes.len - 1) catch unreachable; |
| | 143 | } else { |
| | 144 | // There is zombie node left in the tree, let's make it as inoffensive as possible |
| | 145 | // (sadly there's no no-op node) |
| | 146 | p.nodes.items(.tag)[node_index] = .unreachable_literal; |
| | 147 | p.nodes.items(.main_token)[node_index] = p.tok_i; |
| | 148 | } |
| | 149 | } |
| | 150 | |
| 139 | fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index { | 151 | fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index { |
| 140 | const fields = std.meta.fields(@TypeOf(extra)); | 152 | const fields = std.meta.fields(@TypeOf(extra)); |
| 141 | try p.extra_data.ensureUnusedCapacity(p.gpa, fields.len); | 153 | try p.extra_data.ensureUnusedCapacity(p.gpa, fields.len); |
| ... | @@ -637,13 +649,15 @@ const Parser = struct { | ... | @@ -637,13 +649,15 @@ const Parser = struct { |
| 637 | return fn_proto; | 649 | return fn_proto; |
| 638 | }, | 650 | }, |
| 639 | .l_brace => { | 651 | .l_brace => { |
| 640 | const fn_decl_index = try p.reserveNode(); | | |
| 641 | const body_block = try p.parseBlock(); | | |
| 642 | assert(body_block != 0); | | |
| 643 | if (is_extern) { | 652 | if (is_extern) { |
| 644 | try p.warnMsg(.{ .tag = .extern_fn_body, .token = extern_export_inline_token }); | 653 | try p.warnMsg(.{ .tag = .extern_fn_body, .token = extern_export_inline_token }); |
| 645 | return null_node; | 654 | return null_node; |
| 646 | } | 655 | } |
| | 656 | const fn_decl_index = try p.reserveNode(.fn_decl); |
| | 657 | errdefer p.unreserveNode(fn_decl_index); |
| | 658 | |
| | 659 | const body_block = try p.parseBlock(); |
| | 660 | assert(body_block != 0); |
| 647 | return p.setNode(fn_decl_index, .{ | 661 | return p.setNode(fn_decl_index, .{ |
| 648 | .tag = .fn_decl, | 662 | .tag = .fn_decl, |
| 649 | .main_token = p.nodes.items(.main_token)[fn_proto], | 663 | .main_token = p.nodes.items(.main_token)[fn_proto], |
| ... | @@ -724,7 +738,8 @@ const Parser = struct { | ... | @@ -724,7 +738,8 @@ const Parser = struct { |
| 724 | const fn_token = p.eatToken(.keyword_fn) orelse return null_node; | 738 | const fn_token = p.eatToken(.keyword_fn) orelse return null_node; |
| 725 | | 739 | |
| 726 | // We want the fn proto node to be before its children in the array. | 740 | // We want the fn proto node to be before its children in the array. |
| 727 | const fn_proto_index = try p.reserveNode(); | 741 | const fn_proto_index = try p.reserveNode(.fn_proto); |
| | 742 | errdefer p.unreserveNode(fn_proto_index); |
| 728 | | 743 | |
| 729 | _ = p.eatToken(.identifier); | 744 | _ = p.eatToken(.identifier); |
| 730 | const params = try p.parseParamDeclList(); | 745 | const params = try p.parseParamDeclList(); |