authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-11 23:52:08+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-10-30 15:58:11+02:00
logad32e46bceb03c0b0d67fe73e0de0e308f0675e6
tree296539931ed2c3dcd39fa4453074ed0661b2241c
parenta1d7f0053d6fa56bcc879e83987babd42bb21a20
signaturelock-open Commit is signed but in an unrecognized format.

stage2: switch astgen


3 files changed, 228 insertions(+), 2 deletions(-)

src/astgen.zig+152-2
......@@ -183,6 +183,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
183183 .VarDecl => unreachable, // Handled in `blockExpr`.
184184 .SwitchCase => unreachable, // Handled in `switchExpr`.
185185 .SwitchElse => unreachable, // Handled in `switchExpr`.
186 .Range => unreachable, // Handled in `switchExpr`.
186187 .Else => unreachable, // Handled explicitly the control flow expression functions.
187188 .Payload => unreachable, // Handled explicitly.
188189 .PointerPayload => unreachable, // Handled explicitly.
......@@ -279,9 +280,9 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
279280 .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?),
280281 .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?),
281282 .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?),
283 .Switch => return switchExpr(mod, scope, rl, node.castTag(.Switch).?),
282284
283285 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
284 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
285286 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
286287 .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}),
287288 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
......@@ -289,7 +290,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
289290 .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}),
290291 .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}),
291292 .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}),
292 .Switch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Switch", .{}),
293293 .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}),
294294 .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}),
295295 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
......@@ -1561,6 +1561,156 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
15611561 return &for_block.base;
15621562}
15631563
1564fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst {
1565 var block_scope: Scope.GenZIR = .{
1566 .parent = scope,
1567 .decl = scope.decl().?,
1568 .arena = scope.arena(),
1569 .instructions = .{},
1570 };
1571 defer block_scope.instructions.deinit(mod.gpa);
1572
1573 const tree = scope.tree();
1574 const switch_src = tree.token_locs[switch_node.switch_token].start;
1575 const target_ptr = try expr(mod, &block_scope.base, .ref, switch_node.expr);
1576 const cases = try scope.arena().alloc(zir.Inst.Switch.Case, switch_node.cases_len);
1577 var kw_args: std.meta.fieldInfo(zir.Inst.Switch, "kw_args").field_type = .{};
1578
1579 // first we gather all the switch items and check else/'_' prongs
1580 var case_index: usize = 0;
1581 var else_src: ?usize = null;
1582 var underscore_src: ?usize = null;
1583 for (switch_node.cases()) |uncasted_case| {
1584 const case = uncasted_case.castTag(.SwitchCase).?;
1585 const case_src = tree.token_locs[case.firstToken()].start;
1586
1587 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
1588 if (else_src) |src| {
1589 return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{});
1590 // TODO notes "previous else prong is here"
1591 }
1592 kw_args.special_case = .@"else";
1593 else_src = case_src;
1594 cases[cases.len - 1] = .{
1595 .values = &[_]*zir.Inst{},
1596 .body = undefined, // filled below
1597 };
1598 continue;
1599 } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and
1600 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
1601 {
1602 if (underscore_src) |src| {
1603 return mod.fail(scope, case_src, "multiple '_' prongs in switch expression", .{});
1604 // TODO notes "previous '_' prong is here"
1605 }
1606 kw_args.special_case = .underscore;
1607 underscore_src = case_src;
1608 cases[cases.len - 1] = .{
1609 .values = &[_]*zir.Inst{},
1610 .body = undefined, // filled below
1611 };
1612 continue;
1613 }
1614
1615 if (else_src) |some_else| {
1616 if (underscore_src) |some_underscore| {
1617 return mod.fail(scope, case_src, "else and '_' prong in switch expression", .{});
1618 // TODO notes "else prong is here"
1619 // TODO notes "'_' prong is here"
1620 }
1621 }
1622
1623 // Regular case, we need to fill `values`.
1624 const values = try block_scope.arena.alloc(*zir.Inst, case.items_len);
1625 for (case.items()) |item, i| {
1626 if (item.castTag(.Range)) |range| {
1627 values[i] = try switchRange(mod, &block_scope.base, range);
1628 if (kw_args.support_range == null)
1629 kw_args.support_range = values[i];
1630 } else {
1631 values[i] = try expr(mod, &block_scope.base, .none, item);
1632 }
1633 }
1634 cases[case_index] = .{
1635 .values = values,
1636 .body = undefined, // filled below
1637 };
1638 case_index += 1;
1639 }
1640
1641 // Then we add the switch instruction to finish the block.
1642 _ = try addZIRInst(mod, scope, switch_src, zir.Inst.Switch, .{
1643 .target_ptr = target_ptr,
1644 .cases = cases,
1645 }, kw_args);
1646 const block = try addZIRInstBlock(mod, scope, switch_src, .block, .{
1647 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1648 });
1649
1650 // Most result location types can be forwarded directly; however
1651 // if we need to write to a pointer which has an inferred type,
1652 // proper type inference requires peer type resolution on the switch case.
1653 const case_rl: ResultLoc = switch (rl) {
1654 .discard, .none, .ty, .ptr, .ref => rl,
1655 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
1656 };
1657
1658 var case_scope: Scope.GenZIR = .{
1659 .parent = scope,
1660 .decl = block_scope.decl,
1661 .arena = block_scope.arena,
1662 .instructions = .{},
1663 };
1664 defer case_scope.instructions.deinit(mod.gpa);
1665
1666 // And finally we fill generate the bodies of each case.
1667 case_index = 0;
1668 for (switch_node.cases()) |uncasted_case| {
1669 const case = uncasted_case.castTag(.SwitchCase).?;
1670 const case_src = tree.token_locs[case.firstToken()].start;
1671 // reset without freeing to reduce allocations.
1672 defer case_scope.instructions.items.len = 0;
1673
1674 // What index in positionals.cases should this one be placed at.
1675 // For special cases it will be at the end.
1676 var cur_index = case_index;
1677 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
1678 // validated above
1679 cur_index = cases.len - 1;
1680 } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and
1681 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
1682 {
1683 // validated above
1684 cur_index = cases.len - 1;
1685 }
1686
1687 // Generate the body of this case.
1688 const case_body = try expr(mod, &case_scope.base, case_rl, case.expr);
1689 if (!case_body.tag.isNoReturn()) {
1690 _ = try addZIRInst(mod, &case_scope.base, case_src, zir.Inst.Break, .{
1691 .block = block,
1692 .operand = case_body,
1693 }, .{});
1694 }
1695 cases[cur_index].body = .{
1696 .instructions = try scope.arena().dupe(*zir.Inst, case_scope.instructions.items),
1697 };
1698 }
1699
1700 return &block.base;
1701}
1702
1703/// Only used for `a...b` in switches.
1704fn switchRange(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
1705 const tree = scope.tree();
1706 const src = tree.token_locs[node.op_token].start;
1707
1708 const start = try expr(mod, scope, .none, node.lhs);
1709 const end = try expr(mod, scope, .none, node.rhs);
1710
1711 return try addZIRBinOp(mod, scope, src, .switch_range, start, end);
1712}
1713
15641714fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst {
15651715 const tree = scope.tree();
15661716 const src = tree.token_locs[cfe.ltoken].start;
src/zir.zig+75
......@@ -272,6 +272,10 @@ pub const Inst = struct {
272272 ensure_err_payload_void,
273273 /// Enum literal
274274 enum_literal,
275 /// A switch expression.
276 @"switch",
277 /// A range in a switch case, `lhs...rhs`.
278 switch_range,
275279
276280 pub fn Type(tag: Tag) type {
277281 return switch (tag) {
......@@ -351,6 +355,7 @@ pub const Inst = struct {
351355 .error_union_type,
352356 .merge_error_sets,
353357 .slice_start,
358 .switch_range,
354359 => BinOp,
355360
356361 .block,
......@@ -389,6 +394,7 @@ pub const Inst = struct {
389394 .enum_literal => EnumLiteral,
390395 .error_set => ErrorSet,
391396 .slice => Slice,
397 .@"switch" => Switch,
392398 };
393399 }
394400
......@@ -493,6 +499,7 @@ pub const Inst = struct {
493499 .slice,
494500 .slice_start,
495501 .import,
502 .switch_range,
496503 => false,
497504
498505 .@"break",
......@@ -504,6 +511,7 @@ pub const Inst = struct {
504511 .unreach_nocheck,
505512 .@"unreachable",
506513 .loop,
514 .@"switch",
507515 => true,
508516 };
509517 }
......@@ -987,6 +995,33 @@ pub const Inst = struct {
987995 sentinel: ?*Inst = null,
988996 },
989997 };
998
999 pub const Switch = struct {
1000 pub const base_tag = Tag.@"switch";
1001 base: Inst,
1002
1003 positionals: struct {
1004 target_ptr: *Inst,
1005 cases: []Case,
1006 },
1007 kw_args: struct {
1008 /// if not null target must support ranges, (be int)
1009 support_range: ?*Inst = null,
1010 special_case: enum {
1011 /// all of positionals.cases are regular cases
1012 none,
1013 /// last case in positionals.cases is an else case
1014 @"else",
1015 /// last case in positionals.cases is an underscore case
1016 underscore,
1017 } = .none,
1018 },
1019
1020 pub const Case = struct {
1021 values: []*Inst,
1022 body: Module.Body,
1023 };
1024 };
9901025};
9911026
9921027pub const ErrorMsg = struct {
......@@ -1238,6 +1273,26 @@ const Writer = struct {
12381273 }
12391274 try stream.writeByte(']');
12401275 },
1276 []Inst.Switch.Case => {
1277 if (param.len == 0) {
1278 return stream.writeAll("{}");
1279 }
1280 try stream.writeAll("{\n");
1281 self.indent += 2;
1282 for (param) |*case, i| {
1283 if (i != 0) {
1284 try stream.writeAll(",\n");
1285 }
1286 try stream.writeByteNTimes(' ', self.indent);
1287 try self.writeParamToStream(stream, &case.values);
1288 try stream.writeAll(" => ");
1289 try self.writeParamToStream(stream, &case.body);
1290 }
1291 try stream.writeByte('\n');
1292 self.indent -= 2;
1293 try stream.writeByteNTimes(' ', self.indent);
1294 try stream.writeByte('}');
1295 },
12411296 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
12421297 }
12431298 }
......@@ -1650,6 +1705,26 @@ const Parser = struct {
16501705 try requireEatBytes(self, "]");
16511706 return strings.toOwnedSlice();
16521707 },
1708 []Inst.Switch.Case => {
1709 try requireEatBytes(self, "{");
1710 skipSpace(self);
1711 if (eatByte(self, '}')) return &[0]Inst.Switch.Case{};
1712
1713 var cases = std.ArrayList(Inst.Switch.Case).init(&self.arena.allocator);
1714 while (true) {
1715 const cur = try cases.addOne();
1716 skipSpace(self);
1717 cur.values = try self.parseParameterGeneric([]*Inst, body_ctx);
1718 skipSpace(self);
1719 try requireEatBytes(self, "=>");
1720 cur.body = try self.parseBody(body_ctx);
1721 skipSpace(self);
1722 if (!eatByte(self, ',')) break;
1723 }
1724 skipSpace(self);
1725 try requireEatBytes(self, "}");
1726 return cases.toOwnedSlice();
1727 },
16531728 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
16541729 }
16551730 return self.fail("TODO parse parameter {}", .{@typeName(T)});
src/zir_sema.zig+1
......@@ -135,6 +135,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
135135 .slice => return analyzeInstSlice(mod, scope, old_inst.castTag(.slice).?),
136136 .slice_start => return analyzeInstSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
137137 .import => return analyzeInstImport(mod, scope, old_inst.castTag(.import).?),
138 .@"switch", .switch_range => @panic("TODO switch sema"),
138139 }
139140}
140141