aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-03-19 23:06:19 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-03-19 23:15:18 -0700
commit56677f2f2da41af5999b84b7f740d7bc463d1032 (patch)
treeacc501152db65974b9e381d72de6c6dc385ad667 /lib/std
parent937c43ddf1297f355cc535adf3ec08f9f741b6c8 (diff)
downloadzig-56677f2f2da41af5999b84b7f740d7bc463d1032.tar.gz
zig-56677f2f2da41af5999b84b7f740d7bc463d1032.zip
astgen: support blocks
We are now passing this test: ```zig export fn _start() noreturn {} ``` ``` test.zig:1:30: error: expected noreturn, found void ``` I ran into an issue where we get an integer overflow trying to compute node index offsets from the containing Decl. The problem is that the parser adds the Decl node after adding the child nodes. For some things, it is easy to reserve the node index and then set it later, however, for this case, it is not a trivial code change, because depending on tokens after parsing the decl determines whether we want to add a new node or not. Possible strategies here: 1. Rework the parser code to make sure that Decl nodes are before children nodes in the AST node array. 2. Use signed integers for Decl node offsets. 3. Just flip the order of subtraction and addition. Expect Decl Node index to be greater than children Node indexes. I opted for (3) because it seems like the simplest thing to do. We'll want to unify the logic for computing the offsets though because if the logic gets repeated, it will probably get repeated wrong.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/zig/parse.zig25
1 files changed, 20 insertions, 5 deletions
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 805ee95571..874a210375 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -139,6 +139,16 @@ const Parser = struct {
return result;
}
+ fn setNode(p: *Parser, i: usize, elem: ast.NodeList.Elem) Node.Index {
+ p.nodes.set(i, elem);
+ return @intCast(Node.Index, i);
+ }
+
+ fn reserveNode(p: *Parser) !usize {
+ try p.nodes.resize(p.gpa, p.nodes.len + 1);
+ return p.nodes.len - 1;
+ }
+
fn addExtra(p: *Parser, extra: anytype) Allocator.Error!Node.Index {
const fields = std.meta.fields(@TypeOf(extra));
try p.extra_data.ensureCapacity(p.gpa, p.extra_data.items.len + fields.len);
@@ -554,9 +564,10 @@ const Parser = struct {
return fn_proto;
},
.l_brace => {
+ const fn_decl_index = try p.reserveNode();
const body_block = try p.parseBlock();
assert(body_block != 0);
- return p.addNode(.{
+ return p.setNode(fn_decl_index, .{
.tag = .fn_decl,
.main_token = p.nodes.items(.main_token)[fn_proto],
.data = .{
@@ -634,6 +645,10 @@ const Parser = struct {
/// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)
fn parseFnProto(p: *Parser) !Node.Index {
const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
+
+ // We want the fn proto node to be before its children in the array.
+ const fn_proto_index = try p.reserveNode();
+
_ = p.eatToken(.identifier);
const params = try p.parseParamDeclList();
defer params.deinit(p.gpa);
@@ -651,7 +666,7 @@ const Parser = struct {
if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
switch (params) {
- .zero_or_one => |param| return p.addNode(.{
+ .zero_or_one => |param| return p.setNode(fn_proto_index, .{
.tag = .fn_proto_simple,
.main_token = fn_token,
.data = .{
@@ -661,7 +676,7 @@ const Parser = struct {
}),
.multi => |list| {
const span = try p.listToSpan(list);
- return p.addNode(.{
+ return p.setNode(fn_proto_index, .{
.tag = .fn_proto_multi,
.main_token = fn_token,
.data = .{
@@ -676,7 +691,7 @@ const Parser = struct {
}
}
switch (params) {
- .zero_or_one => |param| return p.addNode(.{
+ .zero_or_one => |param| return p.setNode(fn_proto_index, .{
.tag = .fn_proto_one,
.main_token = fn_token,
.data = .{
@@ -691,7 +706,7 @@ const Parser = struct {
}),
.multi => |list| {
const span = try p.listToSpan(list);
- return p.addNode(.{
+ return p.setNode(fn_proto_index, .{
.tag = .fn_proto,
.main_token = fn_token,
.data = .{