From 22cec31ec149d17a253e58a752e6f75cfa91f017 Mon Sep 17 00:00:00 2001 From: Anthony Bullard Date: Tue, 11 Mar 2025 06:26:52 -0500 Subject: [PATCH 1/4] Add Region to node --- src/check/parse/IR.zig | 191 +++++++++++++++++++++++++------------ src/check/parse/Parser.zig | 98 +++++++++---------- 2 files changed, 179 insertions(+), 110 deletions(-) diff --git a/src/check/parse/IR.zig b/src/check/parse/IR.zig index fa647847b1..acc6a10303 100644 --- a/src/check/parse/IR.zig +++ b/src/check/parse/IR.zig @@ -93,6 +93,7 @@ pub const Node = struct { tag: Tag, data: Data, main_token: TokenIdx, + region: Region, pub const List = collections.SafeMultiList(Node); @@ -477,6 +478,7 @@ pub const NodeStore = struct { .tag = .root, .main_token = 0, .data = .{ .lhs = 0, .rhs = 0 }, + .region = .{ .start = 0, .end = 0 }, }); store.extra_data.ensureTotalCapacity(gpa, capacity / 2) catch |err| exitOnOom(err); store.scratch_statements.ensureTotalCapacity(gpa, scratch_90th_percentile_capacity) catch |err| exitOnOom(err); @@ -568,11 +570,12 @@ pub const NodeStore = struct { // ------------------------------------------------------------------------ /// Any node type can be malformed, but must come with a diagnostic reason - pub fn addMalformed(store: *NodeStore, comptime t: type, reason: Diagnostic.Tag, token: TokenIdx) t { + pub fn addMalformed(store: *NodeStore, comptime t: type, reason: Diagnostic.Tag, region: Region) t { const nid = store.nodes.append(store.gpa, .{ .tag = .malformed, - .main_token = token, + .main_token = 0, .data = .{ .lhs = @intFromEnum(reason), .rhs = 0 }, + .region = region, }); return .{ .id = @intFromEnum(nid) }; } @@ -586,6 +589,7 @@ pub const NodeStore = struct { .lhs = file.statements.span.start, .rhs = file.statements.span.len, }, + .region = file.region, }); } @@ -597,6 +601,7 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = emptyRegion(), }; switch (header) { .app => |app| { @@ -614,6 +619,7 @@ pub const NodeStore = struct { .num_packages = @as(u10, @intCast(app.packages.span.len)), .num_provides = @as(u22, @intCast(app.provides.span.len)), })); + node.region = app.region; store.extra_data.append(store.gpa, app.platform.id) catch |err| exitOnOom(err); }, @@ -621,6 +627,7 @@ pub const NodeStore = struct { node.tag = .module_header; node.data.lhs = mod.exposes.span.start; node.data.rhs = mod.exposes.span.len; + node.region = mod.region; }, else => {}, } @@ -636,6 +643,7 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = emptyRegion(), }; switch (item) { @@ -647,6 +655,7 @@ pub const NodeStore = struct { node.data.lhs = a; node.data.rhs = 1; } + node.region = i.region; }, .upper_ident => |i| { node.tag = .exposed_item_upper; @@ -656,10 +665,12 @@ pub const NodeStore = struct { node.data.lhs = a; node.data.rhs = 1; } + node.region = i.region; }, .upper_ident_star => |i| { node.tag = .exposed_item_upper_star; node.main_token = i.ident; + node.region = i.region; }, } @@ -675,31 +686,38 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = emptyRegion(), }; switch (statement) { .decl => |d| { node.tag = .decl; node.data.lhs = d.pattern.id; node.data.rhs = d.body.id; + node.region = d.region; }, .expr => |expr| { node.tag = .expr; node.data.lhs = expr.expr.id; + node.region = expr.region; }, .crash => |c| { node.tag = .crash; node.data.lhs = c.expr.id; + node.region = c.region; }, .expect => |e| { node.tag = .expect; node.data.lhs = e.body.id; + node.region = e.region; }, .@"return" => |r| { node.tag = .@"return"; node.data.lhs = r.expr.id; + node.region = r.region; }, .import => |i| { node.tag = .import; + node.region = i.region; node.main_token = i.module_name_tok; var rhs = ImportRhs{ .aliased = 0, @@ -729,11 +747,13 @@ pub const NodeStore = struct { }, .type_decl => |d| { node.tag = .type_decl; + node.region = d.region; node.data.lhs = d.header.id; node.data.rhs = d.anno.id; }, .type_anno => |a| { node.tag = .type_anno; + node.region = a.region; node.data.lhs = a.name; node.data.rhs = a.anno.id; }, @@ -750,53 +770,64 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = emptyRegion(), }; switch (pattern) { .ident => |i| { node.tag = .ident_patt; + node.region = i.region; node.main_token = i.ident_tok; }, .tag => |t| { node.tag = .tag_patt; + node.region = t.region; node.main_token = t.tag_tok; node.data.lhs = t.args.span.start; node.data.rhs = t.args.span.len; }, .number => |n| { node.tag = .number_patt; + node.region = n.region; node.main_token = n.number_tok; }, .string => |s| { node.tag = .string_patt; + node.region = s.region; node.main_token = s.string_tok; node.data.lhs = s.expr.id; }, .record => |r| { node.tag = .record_patt; + node.region = r.region; node.data.lhs = r.fields.span.start; node.data.rhs = r.fields.span.len; }, .list => |l| { node.tag = .list_patt; + node.region = l.region; node.data.lhs = l.patterns.span.start; node.data.rhs = l.patterns.span.len; }, .list_rest => |r| { node.tag = .list_rest_patt; + node.region = r.region; if (r.name) |n| { node.data.lhs = n; } }, .tuple => |t| { node.tag = .tuple_patt; + node.region = t.region; node.data.lhs = t.patterns.span.start; node.data.rhs = t.patterns.span.len; }, - .underscore => |_| { + .underscore => |u| { node.tag = .underscore_patt; + node.region = u.region; }, .alternatives => |a| { std.debug.assert(a.patterns.span.len > 1); + node.region = a.region; node.tag = .alternatives_patt; node.data.lhs = a.patterns.span.start; node.data.rhs = a.patterns.span.len; @@ -814,48 +845,58 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = emptyRegion(), }; switch (expr) { .int => |e| { node.tag = .int; + node.region = e.region; node.main_token = e.token; }, .float => |e| { node.tag = .float; + node.region = e.region; node.main_token = e.token; }, .string_part => |e| { node.tag = .string_part; + node.region = e.region; node.main_token = e.token; }, .string => |e| { node.tag = .string; + node.region = e.region; node.main_token = e.token; node.data.lhs = e.parts.span.start; node.data.rhs = e.parts.span.len; }, .list => |l| { node.tag = .list; + node.region = l.region; node.main_token = l.region.start; node.data.lhs = l.items.span.start; node.data.rhs = l.items.span.len; }, .tuple => |t| { node.tag = .tuple; + node.region = t.region; node.data.lhs = t.items.span.start; node.data.rhs = t.items.span.len; }, .record => |r| { node.tag = .record; + node.region = r.region; node.data.lhs = r.fields.span.start; node.data.rhs = r.fields.span.len; }, .tag => |e| { node.tag = .tag; + node.region = e.region; node.main_token = e.token; }, .lambda => |l| { node.tag = .lambda; + node.region = l.region; node.data.lhs = l.args.span.start; node.data.rhs = l.args.span.len; const body_idx = store.extra_data.items.len; @@ -864,6 +905,7 @@ pub const NodeStore = struct { }, .apply => |app| { node.tag = .apply; + node.region = app.region; node.data.lhs = app.args.span.start; node.data.rhs = app.args.span.len; const fn_ed_idx = store.extra_data.items.len; @@ -873,26 +915,31 @@ pub const NodeStore = struct { .record_updater => |_| {}, .field_access => |fa| { node.tag = .field_access; + node.region = fa.region; node.data.lhs = fa.left.id; node.data.rhs = fa.right.id; }, .bin_op => |op| { node.tag = .bin_op; + node.region = op.region; node.main_token = op.operator; node.data.lhs = op.left.id; node.data.rhs = op.right.id; }, .suffix_single_question => |op| { node.tag = .suffix_single_question; + node.region = op.region; node.data.lhs = op.expr.id; }, .unary_op => |u| { node.tag = .unary_op; + node.region = u.region; node.main_token = u.operator; node.data.lhs = u.expr.id; }, .if_then_else => |i| { node.tag = .if_then_else; + node.region = i.region; node.data.lhs = i.condition.id; node.data.rhs = @as(u32, @intCast(store.extra_data.items.len)); store.extra_data.append(store.gpa, i.then.id) catch |err| exitOnOom(err); @@ -900,12 +947,14 @@ pub const NodeStore = struct { }, .match => |m| { node.tag = .match; + node.region = m.region; node.data.lhs = m.branches.span.start; node.data.rhs = m.branches.span.len; store.extra_data.append(store.gpa, m.expr.id) catch |err| exitOnOom(err); }, .ident => |id| { node.tag = .ident; + node.region = id.region; node.main_token = id.token; if (id.qualifier) |qualifier| { node.data.lhs = qualifier; @@ -914,17 +963,20 @@ pub const NodeStore = struct { }, .dbg => |d| { node.tag = .dbg; + node.region = d.region; node.data.lhs = d.expr.id; }, .record_builder => |_| {}, .block => |body| { node.tag = .block; + node.region = body.region; node.main_token = 0; node.data.lhs = body.statements.span.start; node.data.rhs = body.statements.span.len; }, - .ellipsis => |_| { + .ellipsis => |e| { node.tag = .ellipsis; + node.region = e.region; }, } const nid = store.nodes.append(store.gpa, node); @@ -939,6 +991,7 @@ pub const NodeStore = struct { .lhs = if (field.rest) 1 else 0, .rhs = 0, }, + .region = field.region, }; if (field.value) |value| { node.data.rhs = value.id; @@ -953,7 +1006,7 @@ pub const NodeStore = struct { .name = node.main_token, .value = if (node.data.rhs == 0) null else .{ .id = node.data.rhs }, .rest = node.data.lhs == 1, - .region = emptyRegion(), + .region = node.region, }; } @@ -965,6 +1018,7 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = field.region, }; node.tag = .record_field; node.main_token = field.name; @@ -987,6 +1041,7 @@ pub const NodeStore = struct { .lhs = branch.pattern.id, .rhs = branch.body.id, }, + .region = branch.region, }; const nid = store.nodes.append(store.gpa, node); @@ -1001,6 +1056,7 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = header.region, }; node.data.lhs = header.args.span.start; @@ -1018,6 +1074,7 @@ pub const NodeStore = struct { .lhs = @as(u32, @intCast(field.name)), .rhs = @as(u32, @intCast(field.ty.id)), }, + .region = field.region, }; const nid = store.nodes.append(store.gpa, node); @@ -1032,24 +1089,29 @@ pub const NodeStore = struct { .lhs = 0, .rhs = 0, }, + .region = emptyRegion(), }; switch (anno) { .ty_var => |v| { node.tag = .ty_var; + node.region = v.region; node.main_token = v.tok; }, - .underscore => |_| { + .underscore => |u| { node.tag = .ty_underscore; + node.region = u.region; }, .tag => |t| { node.tag = .ty_tag; + node.region = t.region; node.main_token = t.tok; node.data.lhs = t.args.span.start; node.data.rhs = t.args.span.len; }, .tag_union => |tu| { node.tag = .ty_union; + node.region = tu.region; node.data.lhs = tu.tags.span.start; var rhs = TypeAnno.TagUnionRhs{ .open = 0, @@ -1063,16 +1125,19 @@ pub const NodeStore = struct { }, .tuple => |t| { node.tag = .ty_tuple; + node.region = t.region; node.data.lhs = t.annos.span.start; node.data.rhs = t.annos.span.len; }, .record => |r| { node.tag = .ty_record; + node.region = r.region; node.data.lhs = r.fields.span.start; node.data.rhs = r.fields.span.len; }, .@"fn" => |f| { node.tag = .ty_fn; + node.region = f.region; node.data.lhs = f.args.span.start; node.data.rhs = f.args.span.len; const ret_idx = store.extra_data.items.len; @@ -1081,6 +1146,7 @@ pub const NodeStore = struct { }, .parens => |p| { node.tag = .ty_parens; + node.region = p.region; node.data.lhs = p.anno.id; }, } @@ -1100,7 +1166,7 @@ pub const NodeStore = struct { return .{ .header = .{ .id = header }, .statements = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs } }, - .region = .{ .start = 0, .end = 0 }, + .region = node.region, }; } pub fn getHeader(store: *NodeStore, header: HeaderIdx) Header { @@ -1126,7 +1192,7 @@ pub const NodeStore = struct { .start = extra_data_start, .len = rhs.num_provides, } }, - .region = emptyRegion(), + .region = node.region, }, }; }, @@ -1136,7 +1202,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, else => { @@ -1151,13 +1217,13 @@ pub const NodeStore = struct { .exposed_item_lower => { if (node.data.rhs == 1) { return .{ .lower_ident = .{ - .region = emptyRegion(), + .region = node.region, .ident = node.main_token, .as = node.data.lhs, } }; } return .{ .lower_ident = .{ - .region = emptyRegion(), + .region = node.region, .ident = node.main_token, .as = null, } }; @@ -1165,20 +1231,20 @@ pub const NodeStore = struct { .exposed_item_upper => { if (node.data.rhs == 1) { return .{ .upper_ident = .{ - .region = emptyRegion(), + .region = node.region, .ident = node.main_token, .as = node.data.lhs, } }; } return .{ .upper_ident = .{ - .region = emptyRegion(), + .region = node.region, .ident = node.main_token, .as = null, } }; }, .exposed_item_upper_star => { return .{ .upper_ident_star = .{ - .region = emptyRegion(), + .region = node.region, .ident = node.main_token, } }; }, @@ -1199,13 +1265,13 @@ pub const NodeStore = struct { return .{ .decl = .{ .pattern = .{ .id = node.data.lhs }, .body = .{ .id = node.data.rhs }, - .region = emptyRegion(), + .region = node.region, } }; }, .expr => { return .{ .expr = .{ .expr = .{ .id = node.data.lhs }, - .region = emptyRegion(), + .region = node.region, } }; }, .import => { @@ -1228,7 +1294,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = rhs.num_exposes, } }, - .region = emptyRegion(), + .region = node.region, }; const imp = Statement{ .import = i }; return imp; @@ -1236,31 +1302,31 @@ pub const NodeStore = struct { .expect => { return .{ .expect = .{ .body = .{ .id = node.data.lhs }, - .region = emptyRegion(), + .region = node.region, } }; }, .crash => { return .{ .crash = .{ .expr = .{ .id = node.data.lhs }, - .region = emptyRegion(), + .region = node.region, } }; }, .@"return" => { return .{ .@"return" = .{ .expr = .{ .id = node.data.lhs }, - .region = emptyRegion(), + .region = node.region, } }; }, .type_decl => { return .{ .type_decl = .{ - .region = emptyRegion(), + .region = node.region, .header = .{ .id = node.data.lhs }, .anno = .{ .id = node.data.rhs }, } }; }, .type_anno => { return .{ .type_anno = .{ - .region = emptyRegion(), + .region = node.region, .name = node.data.lhs, .anno = .{ .id = node.data.rhs }, } }; @@ -1277,7 +1343,7 @@ pub const NodeStore = struct { .ident_patt => { return .{ .ident = .{ .ident_tok = node.main_token, - .region = emptyRegion(), + .region = node.region, } }; }, .tag_patt => { @@ -1287,25 +1353,25 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .string_patt => { return .{ .string = .{ .string_tok = node.main_token, - .region = emptyRegion(), + .region = node.region, .expr = .{ .id = node.data.lhs }, } }; }, .number_patt => { return .{ .number = .{ .number_tok = node.main_token, - .region = emptyRegion(), + .region = node.region, } }; }, .record_patt => { return .{ .record = .{ - .region = emptyRegion(), + .region = node.region, .fields = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs, @@ -1314,7 +1380,7 @@ pub const NodeStore = struct { }, .list_patt => { return .{ .list = .{ - .region = emptyRegion(), + .region = node.region, .patterns = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs, @@ -1323,13 +1389,13 @@ pub const NodeStore = struct { }, .list_rest_patt => { return .{ .list_rest = .{ - .region = emptyRegion(), + .region = node.region, .name = if (node.data.lhs == 0) null else node.data.lhs, } }; }, .tuple_patt => { return .{ .tuple = .{ - .region = emptyRegion(), + .region = node.region, .patterns = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs, @@ -1338,7 +1404,7 @@ pub const NodeStore = struct { }, .alternatives_patt => { return .{ .alternatives = .{ - .region = emptyRegion(), + .region = node.region, .patterns = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs, @@ -1347,7 +1413,7 @@ pub const NodeStore = struct { }, .underscore_patt => { return .{ .underscore = .{ - .region = emptyRegion(), + .region = node.region, } }; }, else => { @@ -1362,7 +1428,7 @@ pub const NodeStore = struct { .int => { return .{ .int = .{ .token = node.main_token, - .region = emptyRegion(), + .region = node.region, } }; }, .ident => { @@ -1373,18 +1439,18 @@ pub const NodeStore = struct { return .{ .ident = .{ .token = node.main_token, .qualifier = qualifier, - .region = emptyRegion(), + .region = node.region, } }; }, .tag => { return .{ .tag = .{ - .region = emptyRegion(), + .region = node.region, .token = node.main_token, } }; }, .string_part => { return .{ .string_part = .{ - .region = emptyRegion(), + .region = node.region, .token = node.main_token, } }; }, @@ -1395,7 +1461,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .list => { @@ -1404,7 +1470,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .tuple => { @@ -1413,7 +1479,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .record => { @@ -1422,7 +1488,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .field_access => { @@ -1430,7 +1496,7 @@ pub const NodeStore = struct { .left = .{ .id = node.data.lhs }, .right = .{ .id = node.data.rhs }, .operator = node.main_token, - .region = emptyRegion(), + .region = node.region, } }; }, .lambda => { @@ -1439,7 +1505,7 @@ pub const NodeStore = struct { .id = @as(u32, @intCast(store.extra_data.items[@as(usize, @intCast(node.main_token))])), }, .args = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs } }, - .region = emptyRegion(), + .region = node.region, } }; }, .apply => { @@ -1450,12 +1516,12 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .suffix_single_question => { return .{ .suffix_single_question = .{ - .region = emptyRegion(), + .region = node.region, .operator = node.main_token, .expr = .{ .id = node.data.lhs }, } }; @@ -1466,7 +1532,7 @@ pub const NodeStore = struct { const then_ed = store.extra_data.items[then_idx]; const else_ed = store.extra_data.items[else_idx]; return .{ .if_then_else = .{ - .region = emptyRegion(), + .region = node.region, .condition = .{ .id = node.data.lhs }, .then = .{ .id = then_ed }, .@"else" = .{ .id = else_ed }, @@ -1475,7 +1541,7 @@ pub const NodeStore = struct { .match => { const expr_idx = @as(usize, @intCast(node.data.lhs + node.data.rhs)); return .{ .match = .{ - .region = emptyRegion(), + .region = node.region, .expr = .{ .id = store.extra_data.items[expr_idx] }, .branches = .{ .span = .{ .start = node.data.lhs, @@ -1485,7 +1551,7 @@ pub const NodeStore = struct { }, .dbg => { return .{ .dbg = .{ - .region = emptyRegion(), + .region = node.region, .expr = .{ .id = node.data.lhs }, } }; }, @@ -1494,7 +1560,7 @@ pub const NodeStore = struct { .left = .{ .id = node.data.lhs }, .right = .{ .id = node.data.rhs }, .operator = node.main_token, - .region = emptyRegion(), + .region = node.region, } }; }, .block => { @@ -1504,12 +1570,12 @@ pub const NodeStore = struct { } }; return .{ .block = .{ .statements = statements, - .region = emptyRegion(), + .region = node.region, } }; }, .ellipsis => { return .{ .ellipsis = .{ - .region = emptyRegion(), + .region = node.region, } }; }, else => { @@ -1527,14 +1593,14 @@ pub const NodeStore = struct { .name = name, .value = value, .optional = optional, - .region = emptyRegion(), + .region = node.region, }; } pub fn getBranch(store: *NodeStore, branch: WhenBranchIdx) WhenBranch { const node = store.nodes.get(@enumFromInt(branch.id)); return .{ - .region = emptyRegion(), + .region = node.region, .pattern = .{ .id = node.data.lhs }, .body = .{ .id = node.data.rhs }, }; @@ -1544,7 +1610,7 @@ pub const NodeStore = struct { const node = store.nodes.get(@enumFromInt(header.id)); std.debug.assert(node.tag == .ty_header); return .{ - .region = emptyRegion(), + .region = node.region, .name = node.main_token, .args = .{ .span = .{ .start = node.data.lhs, @@ -1556,7 +1622,7 @@ pub const NodeStore = struct { pub fn getAnnoRecordField(store: *NodeStore, idx: AnnoRecordFieldIdx) AnnoRecordField { const node = store.nodes.get(@enumFromInt(idx.id)); return .{ - .region = emptyRegion(), + .region = node.region, .name = node.data.lhs, .ty = .{ .id = node.data.rhs }, }; @@ -1569,12 +1635,12 @@ pub const NodeStore = struct { .ty_var => { return .{ .ty_var = .{ .tok = node.main_token, - .region = emptyRegion(), + .region = node.region, } }; }, .ty_underscore => { return .{ .underscore = .{ - .region = emptyRegion(), + .region = node.region, } }; }, .ty_tag => { @@ -1584,7 +1650,7 @@ pub const NodeStore = struct { .start = node.data.lhs, .len = node.data.rhs, } }, - .region = emptyRegion(), + .region = node.region, } }; }, .ty_union => { @@ -1592,7 +1658,7 @@ pub const NodeStore = struct { const tags_ed_end = node.data.lhs + rhs.tags_len; return .{ .tag_union = .{ - .region = emptyRegion(), + .region = node.region, .open_anno = if (rhs.open == 1) .{ .id = store.extra_data.items[tags_ed_end] } else null, .tags = .{ .span = .{ .start = node.data.lhs, @@ -1602,7 +1668,7 @@ pub const NodeStore = struct { }, .ty_tuple => { return .{ .tuple = .{ - .region = emptyRegion(), + .region = node.region, .annos = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs, @@ -1611,7 +1677,7 @@ pub const NodeStore = struct { }, .ty_record => { return .{ .record = .{ - .region = emptyRegion(), + .region = node.region, .fields = .{ .span = .{ .start = node.data.lhs, .len = node.data.rhs, @@ -1620,7 +1686,7 @@ pub const NodeStore = struct { }, .ty_fn => { return .{ .@"fn" = .{ - .region = emptyRegion(), + .region = node.region, .ret = .{ .id = store.extra_data.items[@as(usize, @intCast(node.main_token))] }, .args = .{ .span = .{ .start = node.data.lhs, @@ -1630,7 +1696,7 @@ pub const NodeStore = struct { }, .ty_parens => { return .{ .parens = .{ - .region = emptyRegion(), + .region = node.region, .anno = .{ .id = node.data.lhs }, } }; }, @@ -2199,6 +2265,7 @@ pub const NodeStore = struct { record_builder: struct { mapper: ExprIdx, fields: RecordFieldIdx, + region: Region, }, ellipsis: struct { region: Region, diff --git a/src/check/parse/Parser.zig b/src/check/parse/Parser.zig index f00f4dacab..943a6af31e 100644 --- a/src/check/parse/Parser.zig +++ b/src/check/parse/Parser.zig @@ -114,14 +114,15 @@ pub fn pushDiagnostic(self: *Parser, tag: IR.Diagnostic.Tag, region: IR.Region) }) catch |err| exitOnOom(err); } /// add a malformed token -pub fn pushMalformed(self: *Parser, comptime t: type, tag: IR.Diagnostic.Tag) t { +pub fn pushMalformed(self: *Parser, comptime t: type, tag: IR.Diagnostic.Tag, start: TokenIdx) t { const pos = self.pos; self.advanceOne(); // TODO: find a better point to advance to + const region = IR.Region{ .start = start, .end = pos }; self.diagnostics.append(self.gpa, .{ .tag = tag, - .region = .{ .start = pos, .end = pos }, + .region = region, }) catch |err| exitOnOom(err); - return self.store.addMalformed(t, tag, pos); + return self.store.addMalformed(t, tag, region); } /// parse a `.roc` module /// @@ -206,7 +207,7 @@ pub fn parseHeader(self: *Parser) IR.NodeStore.HeaderIdx { // .KwPackage => {}, // .KwHosted => {}, else => { - return self.pushMalformed(IR.NodeStore.HeaderIdx, .missing_header); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .missing_header, self.pos); }, } } @@ -229,7 +230,7 @@ fn parseModuleHeader(self: *Parser) IR.NodeStore.HeaderIdx { } self.expect(.CloseSquare) catch {}; self.store.clearScratchExposedItemsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .import_exposing_no_close); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .import_exposing_no_close, start); }; const exposes = self.store.exposedItemSpanFrom(scratch_top); @@ -245,13 +246,14 @@ fn parseModuleHeader(self: *Parser) IR.NodeStore.HeaderIdx { pub fn parseAppHeader(self: *Parser) IR.NodeStore.HeaderIdx { var platform: ?IR.NodeStore.ExprIdx = null; var platform_name: ?TokenIdx = null; + const start = self.pos; std.debug.assert(self.peek() == .KwApp); self.advance(); // Advance past KwApp // Get provides self.expect(.OpenSquare) catch { - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_provides_open_square); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_provides_open_square, start); }; const scratch_top = self.store.scratchExposedItemTop(); self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { @@ -260,44 +262,44 @@ pub fn parseAppHeader(self: *Parser) IR.NodeStore.HeaderIdx { } self.expect(.CloseSquare) catch {}; self.store.clearScratchExposedItemsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .import_exposing_no_close); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .import_exposing_no_close, start); }; const provides = self.store.exposedItemSpanFrom(scratch_top); // Get platform and packages const fields_scratch_top = self.store.scratchRecordFieldTop(); self.expect(.OpenCurly) catch { - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_platform_open_curly); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_platform_open_curly, start); }; while (self.peek() != .CloseCurly) { const entry_start = self.pos; if (self.peek() != .LowerIdent) { self.store.clearScratchRecordFieldsFrom(fields_scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_or_platform_name); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_or_platform_name, start); } const name_tok = self.pos; self.advance(); if (self.peek() != .OpColon) { self.store.clearScratchRecordFieldsFrom(fields_scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_or_platform_colon); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_or_platform_colon, start); } self.advance(); if (self.peek() == .KwPlatform) { if (platform != null) { self.store.clearScratchRecordFieldsFrom(fields_scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .multiple_platforms); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .multiple_platforms, start); } self.advance(); if (self.peek() != .StringStart) { self.store.clearScratchRecordFieldsFrom(fields_scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_platform_string); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_platform_string, start); } platform = self.parseStringExpr(); platform_name = name_tok; } else { if (self.peek() != .StringStart) { self.store.clearScratchRecordFieldsFrom(fields_scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_or_platform_string); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_or_platform_string, start); } const value = self.parseStringExpr(); self.store.addScratchRecordField(self.store.addRecordField(.{ @@ -315,7 +317,7 @@ pub fn parseAppHeader(self: *Parser) IR.NodeStore.HeaderIdx { } if (self.peek() != .CloseCurly) { self.store.clearScratchRecordFieldsFrom(fields_scratch_top); - return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_platform_close_curly); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_package_platform_close_curly, start); } const packages = self.store.recordFieldSpanFrom(fields_scratch_top); self.advance(); @@ -335,7 +337,7 @@ pub fn parseAppHeader(self: *Parser) IR.NodeStore.HeaderIdx { return idx; } } - return self.pushMalformed(IR.NodeStore.HeaderIdx, .no_platform); + return self.pushMalformed(IR.NodeStore.HeaderIdx, .no_platform, start); } /// Parses an ExposedItem, adding it to the NodeStore and returning the Idx @@ -350,7 +352,7 @@ pub fn parseExposedItem(self: *Parser) IR.NodeStore.ExposedItemIdx { self.advance(); // Advance past KwAs as = self.pos; self.expect(.LowerIdent) catch { - return self.pushMalformed(IR.NodeStore.ExposedItemIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExposedItemIdx, .unexpected_token, start); }; end = self.pos; } else { @@ -371,7 +373,7 @@ pub fn parseExposedItem(self: *Parser) IR.NodeStore.ExposedItemIdx { self.advance(); // Advance past KwAs as = self.pos; self.expect(.UpperIdent) catch { - return self.pushMalformed(IR.NodeStore.ExposedItemIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExposedItemIdx, .unexpected_token, start); }; end = self.pos; } else if (self.peekNext() == .DotStar) { @@ -393,7 +395,7 @@ pub fn parseExposedItem(self: *Parser) IR.NodeStore.ExposedItemIdx { return ei; }, else => { - return self.pushMalformed(IR.NodeStore.ExposedItemIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExposedItemIdx, .unexpected_token, start); }, } } @@ -420,7 +422,7 @@ pub fn parseStmt(self: *Parser) ?IR.NodeStore.StatementIdx { self.advance(); // Advance past KwAs alias_tok = self.pos; self.expect(.UpperIdent) catch { - const malformed = self.pushMalformed(IR.NodeStore.StatementIdx, .unexpected_token); + const malformed = self.pushMalformed(IR.NodeStore.StatementIdx, .unexpected_token, start); self.advance(); return malformed; }; @@ -428,7 +430,7 @@ pub fn parseStmt(self: *Parser) ?IR.NodeStore.StatementIdx { self.advance(); // Advance past ident self.advance(); // Advance past KwExposing self.expect(.OpenSquare) catch { - return self.pushMalformed(IR.NodeStore.StatementIdx, .import_exposing_no_open); + return self.pushMalformed(IR.NodeStore.StatementIdx, .import_exposing_no_open, start); }; const scratch_top = self.store.scratchExposedItemTop(); self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { @@ -437,7 +439,7 @@ pub fn parseStmt(self: *Parser) ?IR.NodeStore.StatementIdx { } self.expect(.CloseSquare) catch {}; self.store.clearScratchExposedItemsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.StatementIdx, .import_exposing_no_close); + return self.pushMalformed(IR.NodeStore.StatementIdx, .import_exposing_no_close, start); }; exposes = self.store.exposedItemSpanFrom(scratch_top); } else { @@ -546,7 +548,7 @@ pub fn parseStmt(self: *Parser) ?IR.NodeStore.StatementIdx { if (self.peekNext() == .OpColon or self.peekNext() == .LowerIdent) { const header = self.parseTypeHeader(); if (self.peek() != .OpColon) { - return self.pushMalformed(IR.NodeStore.StatementIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.StatementIdx, .unexpected_token, start); } self.advance(); const anno = self.parseTypeAnno(.not_looking_for_args); @@ -622,7 +624,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt self.advance(); } self.store.clearScratchPatternsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token, start); }; const args = self.store.patternSpanFrom(scratch_top); pattern = self.store.addPattern(.{ .tag = .{ @@ -660,7 +662,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt self.advance(); } self.store.clearScratchPatternsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token, start); }; const patterns = self.store.patternSpanFrom(scratch_top); @@ -681,7 +683,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt } const fields = self.store.patternRecordFieldSpanFrom(scratch_top); if (self.peek() != .CloseCurly) { - return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token, start); } self.advance(); pattern = self.store.addPattern(.{ .record = .{ @@ -696,7 +698,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt if (self.peek() == .KwAs) { self.advance(); if (self.peek() != .LowerIdent) { - return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token, start); } name = self.pos; end = self.pos; @@ -721,7 +723,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt self.advance(); } self.store.clearScratchPatternsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternIdx, .unexpected_token, start); }; const patterns = self.store.patternSpanFrom(scratch_top); @@ -786,7 +788,7 @@ pub fn parsePatternRecordField(self: *Parser, alternatives: Alternatives) IR.Nod while (self.peek() != .CloseCurly) { self.advance(); } - return self.pushMalformed(IR.NodeStore.PatternRecordFieldIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternRecordFieldIdx, .unexpected_token, field_start); } const name = self.pos; self.advance(); @@ -795,7 +797,7 @@ pub fn parsePatternRecordField(self: *Parser, alternatives: Alternatives) IR.Nod while (self.peek() != .CloseCurly) { self.advance(); } - return self.pushMalformed(IR.NodeStore.PatternRecordFieldIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.PatternRecordFieldIdx, .unexpected_token, field_start); } self.advance(); if (self.peekNext() != .Comma or self.peekNext() != .CloseCurly) { @@ -873,7 +875,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { self.advance(); } self.store.clearScratchExprsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; const items = self.store.exprSpanFrom(scratch_top); expr = self.store.addExpr(.{ .list = .{ @@ -890,7 +892,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { self.advance(); } self.store.clearScratchExprsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; const items = self.store.exprSpanFrom(scratch_top); expr = self.store.addExpr(.{ .tuple = .{ @@ -907,7 +909,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { const scratch_top = self.store.scratchRecordFieldTop(); self.parseCollectionSpan(IR.NodeStore.RecordFieldIdx, .CloseCurly, IR.NodeStore.addScratchRecordField, parseRecordField) catch { self.store.clearScratchRecordFieldsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; const fields = self.store.recordFieldSpanFrom(scratch_top); expr = self.store.addExpr(.{ .record = .{ @@ -939,7 +941,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { const scratch_top = self.store.scratchPatternTop(); self.parseCollectionSpan(IR.NodeStore.PatternIdx, .OpBar, IR.NodeStore.addScratchPattern, parsePatternNoAlts) catch { self.store.clearScratchPatternsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; const args = self.store.patternSpanFrom(scratch_top); const body = self.parseExpr(); @@ -954,7 +956,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { const condition = self.parseExpr(); const then = self.parseExpr(); if (self.peek() != .KwElse) { - return self.pushMalformed(IR.NodeStore.ExprIdx, .no_else); + return self.pushMalformed(IR.NodeStore.ExprIdx, .no_else, start); } self.advance(); const else_idx = self.parseExpr(); @@ -970,7 +972,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { const e = self.parseExpr(); self.expect(.OpenCurly) catch { - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; const scratch_top = self.store.scratchWhenBranchTop(); while (self.peek() != .CloseCurly) { @@ -981,7 +983,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { } const branches = self.store.whenBranchSpanFrom(scratch_top); if (self.peek() != .CloseCurly) { - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); } self.advance(); expr = self.store.addExpr(.{ .match = .{ @@ -1005,7 +1007,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { self.advance(); }, else => { - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }, } if (expr) |e| { @@ -1050,7 +1052,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { } return expression; } - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); } /// todo @@ -1062,7 +1064,7 @@ fn parseExprSuffix(self: *Parser, start: u32, e: IR.NodeStore.ExprIdx) IR.NodeSt const scratch_top = self.store.scratchExprTop(); self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseRound, IR.NodeStore.addScratchExpr, parseExpr) catch { self.store.clearScratchExprsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; const args = self.store.exprSpanFrom(scratch_top); @@ -1087,7 +1089,7 @@ fn parseExprSuffix(self: *Parser, start: u32, e: IR.NodeStore.ExprIdx) IR.NodeSt pub fn parseRecordField(self: *Parser) IR.NodeStore.RecordFieldIdx { const start = self.pos; self.expect(.LowerIdent) catch { - return self.pushMalformed(IR.NodeStore.RecordFieldIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.RecordFieldIdx, .unexpected_token, start); }; const name = start; var value: ?IR.NodeStore.ExprIdx = null; @@ -1235,7 +1237,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ const scratch_top = self.store.scratchTypeAnnoTop(); self.parseCollectionSpan(IR.NodeStore.TypeAnnoIdx, .CloseRound, IR.NodeStore.addScratchTypeAnno, parseTypeAnnoInCollection) catch { self.store.clearScratchTypeAnnosFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); }; const args = self.store.typeAnnoSpanFrom(scratch_top); anno = self.store.addTypeAnno(.{ .tag = .{ @@ -1273,7 +1275,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ const ret = self.parseTypeAnno(.not_looking_for_args); if (self.peek() != .CloseRound) { self.store.clearScratchTypeAnnosFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); } const function = self.store.addTypeAnno(.{ .@"fn" = .{ .args = args, @@ -1288,7 +1290,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ } if (self.peek() != .CloseRound) { self.store.clearScratchTypeAnnosFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); } self.advance(); // Advance past CloseRound const annos = self.store.typeAnnoSpanFrom(scratch_top); @@ -1302,7 +1304,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ const scratch_top = self.store.scratchAnnoRecordFieldTop(); self.parseCollectionSpan(IR.NodeStore.AnnoRecordFieldIdx, .CloseCurly, IR.NodeStore.addScratchAnnoRecordField, parseAnnoRecordField) catch { self.store.clearScratchAnnoRecordFieldsFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); }; const fields = self.store.annoRecordFieldSpanFrom(scratch_top); anno = self.store.addTypeAnno(.{ .record = .{ @@ -1315,7 +1317,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ const scratch_top = self.store.scratchTypeAnnoTop(); self.parseCollectionSpan(IR.NodeStore.TypeAnnoIdx, .CloseSquare, IR.NodeStore.addScratchTypeAnno, parseTypeAnnoInCollection) catch { self.store.clearScratchTypeAnnosFrom(scratch_top); - return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); }; const tags = self.store.typeAnnoSpanFrom(scratch_top); anno = self.store.addTypeAnno(.{ .tag_union = .{ @@ -1345,7 +1347,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ } const args = self.store.typeAnnoSpanFrom(scratch_top); if (self.peek() != .OpArrow and self.peek() != .OpFatArrow) { - return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); } self.advance(); // Advance past arrow // TODO: Handle thin vs fat arrow @@ -1374,7 +1376,7 @@ pub fn parseAnnoRecordField(self: *Parser) IR.NodeStore.AnnoRecordFieldIdx { while (self.peek() != .CloseCurly and self.peek() != .Comma) { self.advance(); // Advance until we end this field or the record } - return self.pushMalformed(IR.NodeStore.AnnoRecordFieldIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.AnnoRecordFieldIdx, .unexpected_token, field_start); } const name = self.pos; self.advance(); // Advance past LowerIdent @@ -1382,7 +1384,7 @@ pub fn parseAnnoRecordField(self: *Parser) IR.NodeStore.AnnoRecordFieldIdx { while (self.peek() != .CloseCurly and self.peek() != .Comma) { self.advance(); // Advance until we end this field or the record } - return self.pushMalformed(IR.NodeStore.AnnoRecordFieldIdx, .unexpected_token); + return self.pushMalformed(IR.NodeStore.AnnoRecordFieldIdx, .unexpected_token, field_start); } self.advance(); // Advance past OpColon const ty = self.parseTypeAnno(.looking_for_args); From 36c45280fef1e9ad227c8f188709def4ed791057 Mon Sep 17 00:00:00 2001 From: Anthony Bullard Date: Tue, 11 Mar 2025 08:47:22 -0500 Subject: [PATCH 2/4] Multiline list formatting - no comments --- src/check/parse/IR.zig | 23 +++++++++++++++++++++++ src/check/parse/Parser.zig | 35 +++++++++++++++++++---------------- src/fmt.zig | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/check/parse/IR.zig b/src/check/parse/IR.zig index acc6a10303..54da2f32af 100644 --- a/src/check/parse/IR.zig +++ b/src/check/parse/IR.zig @@ -31,6 +31,28 @@ tokens: TokenizedBuffer, store: NodeStore, errors: []const Diagnostic, +pub fn regionIsMultiline(self: *IR, region: Region) bool { + std.debug.print("\n\n=========\n\nLooking for mulitiline region at {any}\n", .{region}); + var i = region.start; + const tags = self.tokens.tokens.items(.tag); + std.debug.print("Tokens\n------\n{any}\n\n", .{tags[i .. region.end + 1]}); + while (i <= region.end) { + if (tags[i] == .Newline) { + std.debug.print("Found newline at {d}\n", .{i}); + return true; + } + if (tags[i] == .Comma and (tags[i + 1] == .CloseSquare or + tags[i + 1] == .CloseRound or + tags[i + 1] == .CloseCurly)) + { + std.debug.print("Found comma at end of collection at {d}\n", .{i}); + return true; + } + i += 1; + } + return false; +} + pub fn deinit(self: *IR) void { defer self.tokens.deinit(); defer self.store.deinit(); @@ -871,6 +893,7 @@ pub const NodeStore = struct { node.data.rhs = e.parts.span.len; }, .list => |l| { + std.debug.print("Adding list with region {any}\n", .{l.region}); node.tag = .list; node.region = l.region; node.main_token = l.region.start; diff --git a/src/check/parse/Parser.zig b/src/check/parse/Parser.zig index 943a6af31e..0bddb07093 100644 --- a/src/check/parse/Parser.zig +++ b/src/check/parse/Parser.zig @@ -179,16 +179,19 @@ fn parseCollection(self: *Parser, comptime T: type, end_token: Token.Tag, scratc } /// Parses the items of type T until we encounter end_token, with each item separated by a Comma token -fn parseCollectionSpan(self: *Parser, comptime T: type, end_token: Token.Tag, scratch_fn: fn (*IR.NodeStore, T) void, parser: fn (*Parser) T) ExpectError!void { +/// Returns the ending position of the collection +fn parseCollectionSpan(self: *Parser, comptime T: type, end_token: Token.Tag, scratch_fn: fn (*IR.NodeStore, T) void, parser: fn (*Parser) T) ExpectError!u32 { while (self.peek() != end_token) { scratch_fn(&self.store, parser(self)); self.expect(.Comma) catch { break; }; } + const collection_end = self.pos; self.expect(end_token) catch { return ExpectError.expected_not_found; }; + return collection_end; } /// Parses a module header using the following grammar: @@ -224,7 +227,7 @@ fn parseModuleHeader(self: *Parser) IR.NodeStore.HeaderIdx { std.debug.panic("TODO: Handle header with no exposes open bracket: {s}", .{@tagName(self.peek())}); }; const scratch_top = self.store.scratchExposedItemTop(); - self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { + _ = self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { while (self.peek() != .CloseSquare and self.peek() != .EndOfFile) { self.advance(); } @@ -256,7 +259,7 @@ pub fn parseAppHeader(self: *Parser) IR.NodeStore.HeaderIdx { return self.pushMalformed(IR.NodeStore.HeaderIdx, .expected_provides_open_square, start); }; const scratch_top = self.store.scratchExposedItemTop(); - self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { + _ = self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { while (self.peek() != .CloseSquare and self.peek() != .EndOfFile) { self.advance(); } @@ -433,7 +436,7 @@ pub fn parseStmt(self: *Parser) ?IR.NodeStore.StatementIdx { return self.pushMalformed(IR.NodeStore.StatementIdx, .import_exposing_no_open, start); }; const scratch_top = self.store.scratchExposedItemTop(); - self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { + _ = self.parseCollectionSpan(IR.NodeStore.ExposedItemIdx, .CloseSquare, IR.NodeStore.addScratchExposedItem, Parser.parseExposedItem) catch { while (self.peek() != .CloseSquare and self.peek() != .EndOfFile) { self.advance(); } @@ -619,7 +622,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt self.advance(); // Advance past NoSpaceOpenRound // Parse args const scratch_top = self.store.scratchPatternTop(); - self.parseCollectionSpan(IR.NodeStore.PatternIdx, .CloseRound, IR.NodeStore.addScratchPattern, parsePatternWithAlts) catch { + _ = self.parseCollectionSpan(IR.NodeStore.PatternIdx, .CloseRound, IR.NodeStore.addScratchPattern, parsePatternWithAlts) catch { while (self.peek() != .CloseRound and self.peek() != .EndOfFile) { self.advance(); } @@ -657,7 +660,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt // List self.advance(); const scratch_top = self.store.scratchPatternTop(); - self.parseCollectionSpan(IR.NodeStore.PatternIdx, .CloseSquare, IR.NodeStore.addScratchPattern, parsePatternWithAlts) catch { + _ = self.parseCollectionSpan(IR.NodeStore.PatternIdx, .CloseSquare, IR.NodeStore.addScratchPattern, parsePatternWithAlts) catch { while (self.peek() != .CloseSquare and self.peek() != .EndOfFile) { self.advance(); } @@ -718,7 +721,7 @@ pub fn parsePattern(self: *Parser, alternatives: Alternatives) IR.NodeStore.Patt .OpenRound, .NoSpaceOpenRound => { self.advance(); const scratch_top = self.store.scratchPatternTop(); - self.parseCollectionSpan(IR.NodeStore.PatternIdx, .CloseRound, IR.NodeStore.addScratchPattern, parsePatternWithAlts) catch { + _ = self.parseCollectionSpan(IR.NodeStore.PatternIdx, .CloseRound, IR.NodeStore.addScratchPattern, parsePatternWithAlts) catch { while (self.peek() != .CloseRound and self.peek() != .EndOfFile) { self.advance(); } @@ -870,7 +873,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { .OpenSquare => { self.advance(); const scratch_top = self.store.scratchExprTop(); - self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseSquare, IR.NodeStore.addScratchExpr, parseExpr) catch { + const list_end = self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseSquare, IR.NodeStore.addScratchExpr, parseExpr) catch { while (self.peek() != .CloseSquare) { self.advance(); } @@ -880,14 +883,14 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { const items = self.store.exprSpanFrom(scratch_top); expr = self.store.addExpr(.{ .list = .{ .items = items, - .region = .{ .start = start, .end = self.pos }, + .region = .{ .start = start, .end = list_end }, } }); }, .OpenRound => { self.advance(); // TODO: Parenthesized expressions const scratch_top = self.store.scratchExprTop(); - self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseRound, IR.NodeStore.addScratchExpr, parseExpr) catch { + _ = self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseRound, IR.NodeStore.addScratchExpr, parseExpr) catch { while (self.peek() != .CloseRound) { self.advance(); } @@ -907,7 +910,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { // This is the best guesstimation of this being a Record for now. I believe we have to have a NoSpaceOpColon // for this to be full-proof without backtracking. const scratch_top = self.store.scratchRecordFieldTop(); - self.parseCollectionSpan(IR.NodeStore.RecordFieldIdx, .CloseCurly, IR.NodeStore.addScratchRecordField, parseRecordField) catch { + _ = self.parseCollectionSpan(IR.NodeStore.RecordFieldIdx, .CloseCurly, IR.NodeStore.addScratchRecordField, parseRecordField) catch { self.store.clearScratchRecordFieldsFrom(scratch_top); return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; @@ -939,7 +942,7 @@ pub fn parseExprWithBp(self: *Parser, min_bp: u8) IR.NodeStore.ExprIdx { .OpBar => { self.advance(); const scratch_top = self.store.scratchPatternTop(); - self.parseCollectionSpan(IR.NodeStore.PatternIdx, .OpBar, IR.NodeStore.addScratchPattern, parsePatternNoAlts) catch { + _ = self.parseCollectionSpan(IR.NodeStore.PatternIdx, .OpBar, IR.NodeStore.addScratchPattern, parsePatternNoAlts) catch { self.store.clearScratchPatternsFrom(scratch_top); return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; @@ -1062,7 +1065,7 @@ fn parseExprSuffix(self: *Parser, start: u32, e: IR.NodeStore.ExprIdx) IR.NodeSt if (self.peek() == .NoSpaceOpenRound) { self.advance(); const scratch_top = self.store.scratchExprTop(); - self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseRound, IR.NodeStore.addScratchExpr, parseExpr) catch { + _ = self.parseCollectionSpan(IR.NodeStore.ExprIdx, .CloseRound, IR.NodeStore.addScratchExpr, parseExpr) catch { self.store.clearScratchExprsFrom(scratch_top); return self.pushMalformed(IR.NodeStore.ExprIdx, .unexpected_token, start); }; @@ -1235,7 +1238,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ self.advance(); // Advance past UpperIdent self.advance(); // Advance past NoSpaceOpenRound const scratch_top = self.store.scratchTypeAnnoTop(); - self.parseCollectionSpan(IR.NodeStore.TypeAnnoIdx, .CloseRound, IR.NodeStore.addScratchTypeAnno, parseTypeAnnoInCollection) catch { + _ = self.parseCollectionSpan(IR.NodeStore.TypeAnnoIdx, .CloseRound, IR.NodeStore.addScratchTypeAnno, parseTypeAnnoInCollection) catch { self.store.clearScratchTypeAnnosFrom(scratch_top); return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); }; @@ -1302,7 +1305,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ .OpenCurly => { self.advance(); // Advance past OpenCurly const scratch_top = self.store.scratchAnnoRecordFieldTop(); - self.parseCollectionSpan(IR.NodeStore.AnnoRecordFieldIdx, .CloseCurly, IR.NodeStore.addScratchAnnoRecordField, parseAnnoRecordField) catch { + _ = self.parseCollectionSpan(IR.NodeStore.AnnoRecordFieldIdx, .CloseCurly, IR.NodeStore.addScratchAnnoRecordField, parseAnnoRecordField) catch { self.store.clearScratchAnnoRecordFieldsFrom(scratch_top); return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); }; @@ -1315,7 +1318,7 @@ pub fn parseTypeAnno(self: *Parser, looking_for_args: TyFnArgs) IR.NodeStore.Typ .OpenSquare => { self.advance(); // Advance past OpenSquare const scratch_top = self.store.scratchTypeAnnoTop(); - self.parseCollectionSpan(IR.NodeStore.TypeAnnoIdx, .CloseSquare, IR.NodeStore.addScratchTypeAnno, parseTypeAnnoInCollection) catch { + _ = self.parseCollectionSpan(IR.NodeStore.TypeAnnoIdx, .CloseSquare, IR.NodeStore.addScratchTypeAnno, parseTypeAnnoInCollection) catch { self.store.clearScratchTypeAnnosFrom(scratch_top); return self.pushMalformed(IR.NodeStore.TypeAnnoIdx, .unexpected_token, start); }; diff --git a/src/fmt.zig b/src/fmt.zig index 6e45a2d9f6..1cdbf61f0b 100644 --- a/src/fmt.zig +++ b/src/fmt.zig @@ -184,15 +184,31 @@ fn formatExpr(fmt: *Formatter, ei: ExprIdx) void { fmt.pushTokenText(i.token); }, .list => |l| { + const multiline = fmt.ast.regionIsMultiline(l.region); fmt.push('['); + if (multiline) { + fmt.curr_indent += 1; + } var i: usize = 0; for (fmt.ast.store.exprSlice(l.items)) |item| { + if (multiline) { + fmt.newline(); + fmt.pushIndent(); + } fmt.formatExpr(item); - if (i < (l.items.span.len - 1)) { + if (!multiline and i < (l.items.span.len - 1)) { fmt.pushAll(", "); } + if (multiline) { + fmt.push(','); + } i += 1; } + if (multiline) { + fmt.curr_indent -= 1; + fmt.newline(); + fmt.pushIndent(); + } fmt.push(']'); }, .tuple => |t| { @@ -969,6 +985,23 @@ test "BinOp with higher BP right" { // try exprBinOpIs(expr, .OpStar); } +test "Multiline list formatting" { + const expr = "[1,2,3,]"; + const expr2 = + \\[1, 2, + \\ 3] + ; + const expected = + \\[ + \\ 1, + \\ 2, + \\ 3, + \\] + ; + try exprFmtsTo(expr, expected, .no_debug); + try exprFmtsTo(expr2, expected, .no_debug); +} + test "BinOp omnibus" { const expr = "Err(foo) ?? 12 > 5 * 5 or 13 + 2 < 5 and 10 - 1 >= 16 or 12 <= 3 / 5"; const expr_sloppy = "Err(foo)??12>5*5 or 13+2<5 and 10-1>=16 or 12<=3/5"; From ae1a690ffc7c047835b70a80fb0fe21d074b0876 Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 12 Mar 2025 08:35:34 +1100 Subject: [PATCH 3/4] fix zig lint --- src/check/parse/IR.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/check/parse/IR.zig b/src/check/parse/IR.zig index 54da2f32af..7f2693ca96 100644 --- a/src/check/parse/IR.zig +++ b/src/check/parse/IR.zig @@ -31,6 +31,7 @@ tokens: TokenizedBuffer, store: NodeStore, errors: []const Diagnostic, +/// Returns true if the given region spans multiple lines. pub fn regionIsMultiline(self: *IR, region: Region) bool { std.debug.print("\n\n=========\n\nLooking for mulitiline region at {any}\n", .{region}); var i = region.start; From b7a2a750db269d98b04b126472f77762ef78eefd Mon Sep 17 00:00:00 2001 From: Luke Boswell Date: Wed, 12 Mar 2025 08:41:04 +1100 Subject: [PATCH 4/4] remove stray debug comments --- src/check/parse/IR.zig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/check/parse/IR.zig b/src/check/parse/IR.zig index 7f2693ca96..f7b4b6a71f 100644 --- a/src/check/parse/IR.zig +++ b/src/check/parse/IR.zig @@ -33,20 +33,16 @@ errors: []const Diagnostic, /// Returns true if the given region spans multiple lines. pub fn regionIsMultiline(self: *IR, region: Region) bool { - std.debug.print("\n\n=========\n\nLooking for mulitiline region at {any}\n", .{region}); var i = region.start; const tags = self.tokens.tokens.items(.tag); - std.debug.print("Tokens\n------\n{any}\n\n", .{tags[i .. region.end + 1]}); while (i <= region.end) { if (tags[i] == .Newline) { - std.debug.print("Found newline at {d}\n", .{i}); return true; } if (tags[i] == .Comma and (tags[i + 1] == .CloseSquare or tags[i + 1] == .CloseRound or tags[i + 1] == .CloseCurly)) { - std.debug.print("Found comma at end of collection at {d}\n", .{i}); return true; } i += 1; @@ -894,7 +890,6 @@ pub const NodeStore = struct { node.data.rhs = e.parts.span.len; }, .list => |l| { - std.debug.print("Adding list with region {any}\n", .{l.region}); node.tag = .list; node.region = l.region; node.main_token = l.region.start;