authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-16 05:57:32+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-07-16 05:57:32+00:00
loge079fdeee78d37a50c4e2a9fafe77903d62dbc34
treec7b06e08f3696ae2b4f70a6783a7573aef8347b6
parent82562b205f9d99c27c4d5224311734e141bf2fda
parentd29dd5834b9d7386bb88e44bd2852428863cae81
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #5885 from ziglang/stage2-locals

self-hosted compiler local consts

9 files changed, 1504 insertions(+), 1002 deletions(-)

lib/std/zig/ast.zig+321-225
......@@ -323,8 +323,8 @@ pub const Error = union(enum) {
323323 node: *Node,
324324
325325 pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: anytype) !void {
326 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{
327 @tagName(self.node.id),
326 return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ ", found {}", .{
327 @tagName(self.node.tag),
328328 });
329329 }
330330 };
......@@ -333,8 +333,8 @@ pub const Error = union(enum) {
333333 node: *Node,
334334
335335 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: anytype) !void {
336 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++
337 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});
336 return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ " or " ++
337 @tagName(Node.Tag.FnProto) ++ ", found {}", .{@tagName(self.node.tag)});
338338 }
339339 };
340340
......@@ -396,9 +396,9 @@ pub const Error = union(enum) {
396396};
397397
398398pub const Node = struct {
399 id: Id,
399 tag: Tag,
400400
401 pub const Id = enum {
401 pub const Tag = enum {
402402 // Top level
403403 Root,
404404 Use,
......@@ -408,8 +408,54 @@ pub const Node = struct {
408408 VarDecl,
409409 Defer,
410410
411 // Operators
412 InfixOp,
411 // Infix operators
412 Catch,
413
414 // SimpleInfixOp
415 Add,
416 AddWrap,
417 ArrayCat,
418 ArrayMult,
419 Assign,
420 AssignBitAnd,
421 AssignBitOr,
422 AssignBitShiftLeft,
423 AssignBitShiftRight,
424 AssignBitXor,
425 AssignDiv,
426 AssignSub,
427 AssignSubWrap,
428 AssignMod,
429 AssignAdd,
430 AssignAddWrap,
431 AssignMul,
432 AssignMulWrap,
433 BangEqual,
434 BitAnd,
435 BitOr,
436 BitShiftLeft,
437 BitShiftRight,
438 BitXor,
439 BoolAnd,
440 BoolOr,
441 Div,
442 EqualEqual,
443 ErrorUnion,
444 GreaterOrEqual,
445 GreaterThan,
446 LessOrEqual,
447 LessThan,
448 MergeErrorSets,
449 Mod,
450 Mul,
451 MulWrap,
452 Period,
453 Range,
454 Sub,
455 SubWrap,
456 UnwrapOptional,
457
458 // SimplePrefixOp
413459 AddressOf,
414460 Await,
415461 BitNot,
......@@ -419,6 +465,7 @@ pub const Node = struct {
419465 NegationWrap,
420466 Resume,
421467 Try,
468
422469 ArrayType,
423470 /// ArrayType but has a sentinel node.
424471 ArrayTypeSentinel,
......@@ -484,49 +531,177 @@ pub const Node = struct {
484531 ContainerField,
485532 ErrorTag,
486533 FieldInitializer,
534
535 pub fn Type(tag: Tag) type {
536 return switch (tag) {
537 .Root => Root,
538 .Use => Use,
539 .TestDecl => TestDecl,
540 .VarDecl => VarDecl,
541 .Defer => Defer,
542 .Catch => Catch,
543
544 .Add,
545 .AddWrap,
546 .ArrayCat,
547 .ArrayMult,
548 .Assign,
549 .AssignBitAnd,
550 .AssignBitOr,
551 .AssignBitShiftLeft,
552 .AssignBitShiftRight,
553 .AssignBitXor,
554 .AssignDiv,
555 .AssignSub,
556 .AssignSubWrap,
557 .AssignMod,
558 .AssignAdd,
559 .AssignAddWrap,
560 .AssignMul,
561 .AssignMulWrap,
562 .BangEqual,
563 .BitAnd,
564 .BitOr,
565 .BitShiftLeft,
566 .BitShiftRight,
567 .BitXor,
568 .BoolAnd,
569 .BoolOr,
570 .Div,
571 .EqualEqual,
572 .ErrorUnion,
573 .GreaterOrEqual,
574 .GreaterThan,
575 .LessOrEqual,
576 .LessThan,
577 .MergeErrorSets,
578 .Mod,
579 .Mul,
580 .MulWrap,
581 .Period,
582 .Range,
583 .Sub,
584 .SubWrap,
585 .UnwrapOptional,
586 => SimpleInfixOp,
587
588 .AddressOf,
589 .Await,
590 .BitNot,
591 .BoolNot,
592 .OptionalType,
593 .Negation,
594 .NegationWrap,
595 .Resume,
596 .Try,
597 => SimplePrefixOp,
598
599 .ArrayType => ArrayType,
600 .ArrayTypeSentinel => ArrayTypeSentinel,
601
602 .PtrType => PtrType,
603 .SliceType => SliceType,
604 .SuffixOp => SuffixOp,
605
606 .ArrayInitializer => ArrayInitializer,
607 .ArrayInitializerDot => ArrayInitializerDot,
608
609 .StructInitializer => StructInitializer,
610 .StructInitializerDot => StructInitializerDot,
611
612 .Call => Call,
613 .Switch => Switch,
614 .While => While,
615 .For => For,
616 .If => If,
617 .ControlFlowExpression => ControlFlowExpression,
618 .Suspend => Suspend,
619 .AnyType => AnyType,
620 .ErrorType => ErrorType,
621 .FnProto => FnProto,
622 .AnyFrameType => AnyFrameType,
623 .IntegerLiteral => IntegerLiteral,
624 .FloatLiteral => FloatLiteral,
625 .EnumLiteral => EnumLiteral,
626 .StringLiteral => StringLiteral,
627 .MultilineStringLiteral => MultilineStringLiteral,
628 .CharLiteral => CharLiteral,
629 .BoolLiteral => BoolLiteral,
630 .NullLiteral => NullLiteral,
631 .UndefinedLiteral => UndefinedLiteral,
632 .Unreachable => Unreachable,
633 .Identifier => Identifier,
634 .GroupedExpression => GroupedExpression,
635 .BuiltinCall => BuiltinCall,
636 .ErrorSetDecl => ErrorSetDecl,
637 .ContainerDecl => ContainerDecl,
638 .Asm => Asm,
639 .Comptime => Comptime,
640 .Nosuspend => Nosuspend,
641 .Block => Block,
642 .DocComment => DocComment,
643 .SwitchCase => SwitchCase,
644 .SwitchElse => SwitchElse,
645 .Else => Else,
646 .Payload => Payload,
647 .PointerPayload => PointerPayload,
648 .PointerIndexPayload => PointerIndexPayload,
649 .ContainerField => ContainerField,
650 .ErrorTag => ErrorTag,
651 .FieldInitializer => FieldInitializer,
652 };
653 }
487654 };
488655
656 /// Prefer `castTag` to this.
489657 pub fn cast(base: *Node, comptime T: type) ?*T {
490 if (base.id == comptime typeToId(T)) {
491 return @fieldParentPtr(T, "base", base);
658 if (std.meta.fieldInfo(T, "base").default_value) |default_base| {
659 return base.castTag(default_base.tag);
660 }
661 inline for (@typeInfo(Tag).Enum.fields) |field| {
662 const tag = @intToEnum(Tag, field.value);
663 if (base.tag == tag) {
664 if (T == tag.Type()) {
665 return @fieldParentPtr(T, "base", base);
666 }
667 return null;
668 }
669 }
670 unreachable;
671 }
672
673 pub fn castTag(base: *Node, comptime tag: Tag) ?*tag.Type() {
674 if (base.tag == tag) {
675 return @fieldParentPtr(tag.Type(), "base", base);
492676 }
493677 return null;
494678 }
495679
496680 pub fn iterate(base: *Node, index: usize) ?*Node {
497 inline for (@typeInfo(Id).Enum.fields) |f| {
498 if (base.id == @field(Id, f.name)) {
499 const T = @field(Node, f.name);
500 return @fieldParentPtr(T, "base", base).iterate(index);
681 inline for (@typeInfo(Tag).Enum.fields) |field| {
682 const tag = @intToEnum(Tag, field.value);
683 if (base.tag == tag) {
684 return @fieldParentPtr(tag.Type(), "base", base).iterate(index);
501685 }
502686 }
503687 unreachable;
504688 }
505689
506690 pub fn firstToken(base: *const Node) TokenIndex {
507 inline for (@typeInfo(Id).Enum.fields) |f| {
508 if (base.id == @field(Id, f.name)) {
509 const T = @field(Node, f.name);
510 return @fieldParentPtr(T, "base", base).firstToken();
691 inline for (@typeInfo(Tag).Enum.fields) |field| {
692 const tag = @intToEnum(Tag, field.value);
693 if (base.tag == tag) {
694 return @fieldParentPtr(tag.Type(), "base", base).firstToken();
511695 }
512696 }
513697 unreachable;
514698 }
515699
516700 pub fn lastToken(base: *const Node) TokenIndex {
517 inline for (@typeInfo(Id).Enum.fields) |f| {
518 if (base.id == @field(Id, f.name)) {
519 const T = @field(Node, f.name);
520 return @fieldParentPtr(T, "base", base).lastToken();
521 }
522 }
523 unreachable;
524 }
525
526 pub fn typeToId(comptime T: type) Id {
527 inline for (@typeInfo(Id).Enum.fields) |f| {
528 if (T == @field(Node, f.name)) {
529 return @field(Id, f.name);
701 inline for (@typeInfo(Tag).Enum.fields) |field| {
702 const tag = @intToEnum(Tag, field.value);
703 if (base.tag == tag) {
704 return @fieldParentPtr(tag.Type(), "base", base).lastToken();
530705 }
531706 }
532707 unreachable;
......@@ -535,7 +710,7 @@ pub const Node = struct {
535710 pub fn requireSemiColon(base: *const Node) bool {
536711 var n = base;
537712 while (true) {
538 switch (n.id) {
713 switch (n.tag) {
539714 .Root,
540715 .ContainerField,
541716 .Block,
......@@ -556,7 +731,7 @@ pub const Node = struct {
556731 continue;
557732 }
558733
559 return while_node.body.id != .Block;
734 return while_node.body.tag != .Block;
560735 },
561736 .For => {
562737 const for_node = @fieldParentPtr(For, "base", n);
......@@ -565,7 +740,7 @@ pub const Node = struct {
565740 continue;
566741 }
567742
568 return for_node.body.id != .Block;
743 return for_node.body.tag != .Block;
569744 },
570745 .If => {
571746 const if_node = @fieldParentPtr(If, "base", n);
......@@ -574,7 +749,7 @@ pub const Node = struct {
574749 continue;
575750 }
576751
577 return if_node.body.id != .Block;
752 return if_node.body.tag != .Block;
578753 },
579754 .Else => {
580755 const else_node = @fieldParentPtr(Else, "base", n);
......@@ -583,23 +758,23 @@ pub const Node = struct {
583758 },
584759 .Defer => {
585760 const defer_node = @fieldParentPtr(Defer, "base", n);
586 return defer_node.expr.id != .Block;
761 return defer_node.expr.tag != .Block;
587762 },
588763 .Comptime => {
589764 const comptime_node = @fieldParentPtr(Comptime, "base", n);
590 return comptime_node.expr.id != .Block;
765 return comptime_node.expr.tag != .Block;
591766 },
592767 .Suspend => {
593768 const suspend_node = @fieldParentPtr(Suspend, "base", n);
594769 if (suspend_node.body) |body| {
595 return body.id != .Block;
770 return body.tag != .Block;
596771 }
597772
598773 return true;
599774 },
600775 .Nosuspend => {
601776 const nosuspend_node = @fieldParentPtr(Nosuspend, "base", n);
602 return nosuspend_node.expr.id != .Block;
777 return nosuspend_node.expr.tag != .Block;
603778 },
604779 else => return true,
605780 }
......@@ -613,7 +788,7 @@ pub const Node = struct {
613788 std.debug.warn(" ", .{});
614789 }
615790 }
616 std.debug.warn("{}\n", .{@tagName(self.id)});
791 std.debug.warn("{}\n", .{@tagName(self.tag)});
617792
618793 var child_i: usize = 0;
619794 while (self.iterate(child_i)) |child| : (child_i += 1) {
......@@ -623,7 +798,7 @@ pub const Node = struct {
623798
624799 /// The decls data follows this struct in memory as an array of Node pointers.
625800 pub const Root = struct {
626 base: Node = Node{ .id = .Root },
801 base: Node = Node{ .tag = .Root },
627802 eof_token: TokenIndex,
628803 decls_len: NodeIndex,
629804
......@@ -678,7 +853,7 @@ pub const Node = struct {
678853 /// Trailed in memory by possibly many things, with each optional thing
679854 /// determined by a bit in `trailer_flags`.
680855 pub const VarDecl = struct {
681 base: Node = Node{ .id = .VarDecl },
856 base: Node = Node{ .tag = .VarDecl },
682857 trailer_flags: TrailerFlags,
683858 mut_token: TokenIndex,
684859 name_token: TokenIndex,
......@@ -779,7 +954,7 @@ pub const Node = struct {
779954 };
780955
781956 pub const Use = struct {
782 base: Node = Node{ .id = .Use },
957 base: Node = Node{ .tag = .Use },
783958 doc_comments: ?*DocComment,
784959 visib_token: ?TokenIndex,
785960 use_token: TokenIndex,
......@@ -806,7 +981,7 @@ pub const Node = struct {
806981 };
807982
808983 pub const ErrorSetDecl = struct {
809 base: Node = Node{ .id = .ErrorSetDecl },
984 base: Node = Node{ .tag = .ErrorSetDecl },
810985 error_token: TokenIndex,
811986 rbrace_token: TokenIndex,
812987 decls_len: NodeIndex,
......@@ -856,7 +1031,7 @@ pub const Node = struct {
8561031
8571032 /// The fields and decls Node pointers directly follow this struct in memory.
8581033 pub const ContainerDecl = struct {
859 base: Node = Node{ .id = .ContainerDecl },
1034 base: Node = Node{ .tag = .ContainerDecl },
8601035 kind_token: TokenIndex,
8611036 layout_token: ?TokenIndex,
8621037 lbrace_token: TokenIndex,
......@@ -925,7 +1100,7 @@ pub const Node = struct {
9251100 };
9261101
9271102 pub const ContainerField = struct {
928 base: Node = Node{ .id = .ContainerField },
1103 base: Node = Node{ .tag = .ContainerField },
9291104 doc_comments: ?*DocComment,
9301105 comptime_token: ?TokenIndex,
9311106 name_token: TokenIndex,
......@@ -976,7 +1151,7 @@ pub const Node = struct {
9761151 };
9771152
9781153 pub const ErrorTag = struct {
979 base: Node = Node{ .id = .ErrorTag },
1154 base: Node = Node{ .tag = .ErrorTag },
9801155 doc_comments: ?*DocComment,
9811156 name_token: TokenIndex,
9821157
......@@ -1001,7 +1176,7 @@ pub const Node = struct {
10011176 };
10021177
10031178 pub const Identifier = struct {
1004 base: Node = Node{ .id = .Identifier },
1179 base: Node = Node{ .tag = .Identifier },
10051180 token: TokenIndex,
10061181
10071182 pub fn iterate(self: *const Identifier, index: usize) ?*Node {
......@@ -1020,7 +1195,7 @@ pub const Node = struct {
10201195 /// The params are directly after the FnProto in memory.
10211196 /// Next, each optional thing determined by a bit in `trailer_flags`.
10221197 pub const FnProto = struct {
1023 base: Node = Node{ .id = .FnProto },
1198 base: Node = Node{ .tag = .FnProto },
10241199 trailer_flags: TrailerFlags,
10251200 fn_token: TokenIndex,
10261201 params_len: NodeIndex,
......@@ -1230,7 +1405,7 @@ pub const Node = struct {
12301405 };
12311406
12321407 pub const AnyFrameType = struct {
1233 base: Node = Node{ .id = .AnyFrameType },
1408 base: Node = Node{ .tag = .AnyFrameType },
12341409 anyframe_token: TokenIndex,
12351410 result: ?Result,
12361411
......@@ -1262,7 +1437,7 @@ pub const Node = struct {
12621437
12631438 /// The statements of the block follow Block directly in memory.
12641439 pub const Block = struct {
1265 base: Node = Node{ .id = .Block },
1440 base: Node = Node{ .tag = .Block },
12661441 statements_len: NodeIndex,
12671442 lbrace: TokenIndex,
12681443 rbrace: TokenIndex,
......@@ -1316,7 +1491,7 @@ pub const Node = struct {
13161491 };
13171492
13181493 pub const Defer = struct {
1319 base: Node = Node{ .id = .Defer },
1494 base: Node = Node{ .tag = .Defer },
13201495 defer_token: TokenIndex,
13211496 payload: ?*Node,
13221497 expr: *Node,
......@@ -1340,7 +1515,7 @@ pub const Node = struct {
13401515 };
13411516
13421517 pub const Comptime = struct {
1343 base: Node = Node{ .id = .Comptime },
1518 base: Node = Node{ .tag = .Comptime },
13441519 doc_comments: ?*DocComment,
13451520 comptime_token: TokenIndex,
13461521 expr: *Node,
......@@ -1364,7 +1539,7 @@ pub const Node = struct {
13641539 };
13651540
13661541 pub const Nosuspend = struct {
1367 base: Node = Node{ .id = .Nosuspend },
1542 base: Node = Node{ .tag = .Nosuspend },
13681543 nosuspend_token: TokenIndex,
13691544 expr: *Node,
13701545
......@@ -1387,7 +1562,7 @@ pub const Node = struct {
13871562 };
13881563
13891564 pub const Payload = struct {
1390 base: Node = Node{ .id = .Payload },
1565 base: Node = Node{ .tag = .Payload },
13911566 lpipe: TokenIndex,
13921567 error_symbol: *Node,
13931568 rpipe: TokenIndex,
......@@ -1411,7 +1586,7 @@ pub const Node = struct {
14111586 };
14121587
14131588 pub const PointerPayload = struct {
1414 base: Node = Node{ .id = .PointerPayload },
1589 base: Node = Node{ .tag = .PointerPayload },
14151590 lpipe: TokenIndex,
14161591 ptr_token: ?TokenIndex,
14171592 value_symbol: *Node,
......@@ -1436,7 +1611,7 @@ pub const Node = struct {
14361611 };
14371612
14381613 pub const PointerIndexPayload = struct {
1439 base: Node = Node{ .id = .PointerIndexPayload },
1614 base: Node = Node{ .tag = .PointerIndexPayload },
14401615 lpipe: TokenIndex,
14411616 ptr_token: ?TokenIndex,
14421617 value_symbol: *Node,
......@@ -1467,7 +1642,7 @@ pub const Node = struct {
14671642 };
14681643
14691644 pub const Else = struct {
1470 base: Node = Node{ .id = .Else },
1645 base: Node = Node{ .tag = .Else },
14711646 else_token: TokenIndex,
14721647 payload: ?*Node,
14731648 body: *Node,
......@@ -1498,7 +1673,7 @@ pub const Node = struct {
14981673 /// The cases node pointers are found in memory after Switch.
14991674 /// They must be SwitchCase or SwitchElse nodes.
15001675 pub const Switch = struct {
1501 base: Node = Node{ .id = .Switch },
1676 base: Node = Node{ .tag = .Switch },
15021677 switch_token: TokenIndex,
15031678 rbrace: TokenIndex,
15041679 cases_len: NodeIndex,
......@@ -1552,7 +1727,7 @@ pub const Node = struct {
15521727
15531728 /// Items sub-nodes appear in memory directly following SwitchCase.
15541729 pub const SwitchCase = struct {
1555 base: Node = Node{ .id = .SwitchCase },
1730 base: Node = Node{ .tag = .SwitchCase },
15561731 arrow_token: TokenIndex,
15571732 payload: ?*Node,
15581733 expr: *Node,
......@@ -1610,7 +1785,7 @@ pub const Node = struct {
16101785 };
16111786
16121787 pub const SwitchElse = struct {
1613 base: Node = Node{ .id = .SwitchElse },
1788 base: Node = Node{ .tag = .SwitchElse },
16141789 token: TokenIndex,
16151790
16161791 pub fn iterate(self: *const SwitchElse, index: usize) ?*Node {
......@@ -1627,7 +1802,7 @@ pub const Node = struct {
16271802 };
16281803
16291804 pub const While = struct {
1630 base: Node = Node{ .id = .While },
1805 base: Node = Node{ .tag = .While },
16311806 label: ?TokenIndex,
16321807 inline_token: ?TokenIndex,
16331808 while_token: TokenIndex,
......@@ -1686,7 +1861,7 @@ pub const Node = struct {
16861861 };
16871862
16881863 pub const For = struct {
1689 base: Node = Node{ .id = .For },
1864 base: Node = Node{ .tag = .For },
16901865 label: ?TokenIndex,
16911866 inline_token: ?TokenIndex,
16921867 for_token: TokenIndex,
......@@ -1737,7 +1912,7 @@ pub const Node = struct {
17371912 };
17381913
17391914 pub const If = struct {
1740 base: Node = Node{ .id = .If },
1915 base: Node = Node{ .tag = .If },
17411916 if_token: TokenIndex,
17421917 condition: *Node,
17431918 payload: ?*Node,
......@@ -1779,116 +1954,22 @@ pub const Node = struct {
17791954 }
17801955 };
17811956
1782 pub const InfixOp = struct {
1783 base: Node = Node{ .id = .InfixOp },
1957 pub const Catch = struct {
1958 base: Node = Node{ .tag = .Catch },
17841959 op_token: TokenIndex,
17851960 lhs: *Node,
1786 op: Op,
17871961 rhs: *Node,
1962 payload: ?*Node,
17881963
1789 pub const Op = union(enum) {
1790 Add,
1791 AddWrap,
1792 ArrayCat,
1793 ArrayMult,
1794 Assign,
1795 AssignBitAnd,
1796 AssignBitOr,
1797 AssignBitShiftLeft,
1798 AssignBitShiftRight,
1799 AssignBitXor,
1800 AssignDiv,
1801 AssignSub,
1802 AssignSubWrap,
1803 AssignMod,
1804 AssignAdd,
1805 AssignAddWrap,
1806 AssignMul,
1807 AssignMulWrap,
1808 BangEqual,
1809 BitAnd,
1810 BitOr,
1811 BitShiftLeft,
1812 BitShiftRight,
1813 BitXor,
1814 BoolAnd,
1815 BoolOr,
1816 Catch: ?*Node,
1817 Div,
1818 EqualEqual,
1819 ErrorUnion,
1820 GreaterOrEqual,
1821 GreaterThan,
1822 LessOrEqual,
1823 LessThan,
1824 MergeErrorSets,
1825 Mod,
1826 Mul,
1827 MulWrap,
1828 Period,
1829 Range,
1830 Sub,
1831 SubWrap,
1832 UnwrapOptional,
1833 };
1834
1835 pub fn iterate(self: *const InfixOp, index: usize) ?*Node {
1964 pub fn iterate(self: *const Catch, index: usize) ?*Node {
18361965 var i = index;
18371966
18381967 if (i < 1) return self.lhs;
18391968 i -= 1;
18401969
1841 switch (self.op) {
1842 .Catch => |maybe_payload| {
1843 if (maybe_payload) |payload| {
1844 if (i < 1) return payload;
1845 i -= 1;
1846 }
1847 },
1848
1849 .Add,
1850 .AddWrap,
1851 .ArrayCat,
1852 .ArrayMult,
1853 .Assign,
1854 .AssignBitAnd,
1855 .AssignBitOr,
1856 .AssignBitShiftLeft,
1857 .AssignBitShiftRight,
1858 .AssignBitXor,
1859 .AssignDiv,
1860 .AssignSub,
1861 .AssignSubWrap,
1862 .AssignMod,
1863 .AssignAdd,
1864 .AssignAddWrap,
1865 .AssignMul,
1866 .AssignMulWrap,
1867 .BangEqual,
1868 .BitAnd,
1869 .BitOr,
1870 .BitShiftLeft,
1871 .BitShiftRight,
1872 .BitXor,
1873 .BoolAnd,
1874 .BoolOr,
1875 .Div,
1876 .EqualEqual,
1877 .ErrorUnion,
1878 .GreaterOrEqual,
1879 .GreaterThan,
1880 .LessOrEqual,
1881 .LessThan,
1882 .MergeErrorSets,
1883 .Mod,
1884 .Mul,
1885 .MulWrap,
1886 .Period,
1887 .Range,
1888 .Sub,
1889 .SubWrap,
1890 .UnwrapOptional,
1891 => {},
1970 if (self.payload) |payload| {
1971 if (i < 1) return payload;
1972 i -= 1;
18921973 }
18931974
18941975 if (i < 1) return self.rhs;
......@@ -1897,50 +1978,65 @@ pub const Node = struct {
18971978 return null;
18981979 }
18991980
1900 pub fn firstToken(self: *const InfixOp) TokenIndex {
1981 pub fn firstToken(self: *const Catch) TokenIndex {
19011982 return self.lhs.firstToken();
19021983 }
19031984
1904 pub fn lastToken(self: *const InfixOp) TokenIndex {
1985 pub fn lastToken(self: *const Catch) TokenIndex {
19051986 return self.rhs.lastToken();
19061987 }
19071988 };
19081989
1909 pub const AddressOf = SimplePrefixOp(.AddressOf);
1910 pub const Await = SimplePrefixOp(.Await);
1911 pub const BitNot = SimplePrefixOp(.BitNot);
1912 pub const BoolNot = SimplePrefixOp(.BoolNot);
1913 pub const OptionalType = SimplePrefixOp(.OptionalType);
1914 pub const Negation = SimplePrefixOp(.Negation);
1915 pub const NegationWrap = SimplePrefixOp(.NegationWrap);
1916 pub const Resume = SimplePrefixOp(.Resume);
1917 pub const Try = SimplePrefixOp(.Try);
1990 pub const SimpleInfixOp = struct {
1991 base: Node,
1992 op_token: TokenIndex,
1993 lhs: *Node,
1994 rhs: *Node,
19181995
1919 pub fn SimplePrefixOp(comptime tag: Id) type {
1920 return struct {
1921 base: Node = Node{ .id = tag },
1922 op_token: TokenIndex,
1923 rhs: *Node,
1996 pub fn iterate(self: *const SimpleInfixOp, index: usize) ?*Node {
1997 var i = index;
19241998
1925 const Self = @This();
1999 if (i < 1) return self.lhs;
2000 i -= 1;
19262001
1927 pub fn iterate(self: *const Self, index: usize) ?*Node {
1928 if (index == 0) return self.rhs;
1929 return null;
1930 }
2002 if (i < 1) return self.rhs;
2003 i -= 1;
19312004
1932 pub fn firstToken(self: *const Self) TokenIndex {
1933 return self.op_token;
1934 }
2005 return null;
2006 }
19352007
1936 pub fn lastToken(self: *const Self) TokenIndex {
1937 return self.rhs.lastToken();
1938 }
1939 };
1940 }
2008 pub fn firstToken(self: *const SimpleInfixOp) TokenIndex {
2009 return self.lhs.firstToken();
2010 }
2011
2012 pub fn lastToken(self: *const SimpleInfixOp) TokenIndex {
2013 return self.rhs.lastToken();
2014 }
2015 };
2016
2017 pub const SimplePrefixOp = struct {
2018 base: Node,
2019 op_token: TokenIndex,
2020 rhs: *Node,
2021
2022 const Self = @This();
2023
2024 pub fn iterate(self: *const Self, index: usize) ?*Node {
2025 if (index == 0) return self.rhs;
2026 return null;
2027 }
2028
2029 pub fn firstToken(self: *const Self) TokenIndex {
2030 return self.op_token;
2031 }
2032
2033 pub fn lastToken(self: *const Self) TokenIndex {
2034 return self.rhs.lastToken();
2035 }
2036 };
19412037
19422038 pub const ArrayType = struct {
1943 base: Node = Node{ .id = .ArrayType },
2039 base: Node = Node{ .tag = .ArrayType },
19442040 op_token: TokenIndex,
19452041 rhs: *Node,
19462042 len_expr: *Node,
......@@ -1967,7 +2063,7 @@ pub const Node = struct {
19672063 };
19682064
19692065 pub const ArrayTypeSentinel = struct {
1970 base: Node = Node{ .id = .ArrayTypeSentinel },
2066 base: Node = Node{ .tag = .ArrayTypeSentinel },
19712067 op_token: TokenIndex,
19722068 rhs: *Node,
19732069 len_expr: *Node,
......@@ -1998,7 +2094,7 @@ pub const Node = struct {
19982094 };
19992095
20002096 pub const PtrType = struct {
2001 base: Node = Node{ .id = .PtrType },
2097 base: Node = Node{ .tag = .PtrType },
20022098 op_token: TokenIndex,
20032099 rhs: *Node,
20042100 /// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents
......@@ -2034,7 +2130,7 @@ pub const Node = struct {
20342130 };
20352131
20362132 pub const SliceType = struct {
2037 base: Node = Node{ .id = .SliceType },
2133 base: Node = Node{ .tag = .SliceType },
20382134 op_token: TokenIndex,
20392135 rhs: *Node,
20402136 /// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents
......@@ -2070,7 +2166,7 @@ pub const Node = struct {
20702166 };
20712167
20722168 pub const FieldInitializer = struct {
2073 base: Node = Node{ .id = .FieldInitializer },
2169 base: Node = Node{ .tag = .FieldInitializer },
20742170 period_token: TokenIndex,
20752171 name_token: TokenIndex,
20762172 expr: *Node,
......@@ -2095,7 +2191,7 @@ pub const Node = struct {
20952191
20962192 /// Elements occur directly in memory after ArrayInitializer.
20972193 pub const ArrayInitializer = struct {
2098 base: Node = Node{ .id = .ArrayInitializer },
2194 base: Node = Node{ .tag = .ArrayInitializer },
20992195 rtoken: TokenIndex,
21002196 list_len: NodeIndex,
21012197 lhs: *Node,
......@@ -2148,7 +2244,7 @@ pub const Node = struct {
21482244
21492245 /// Elements occur directly in memory after ArrayInitializerDot.
21502246 pub const ArrayInitializerDot = struct {
2151 base: Node = Node{ .id = .ArrayInitializerDot },
2247 base: Node = Node{ .tag = .ArrayInitializerDot },
21522248 dot: TokenIndex,
21532249 rtoken: TokenIndex,
21542250 list_len: NodeIndex,
......@@ -2198,7 +2294,7 @@ pub const Node = struct {
21982294
21992295 /// Elements occur directly in memory after StructInitializer.
22002296 pub const StructInitializer = struct {
2201 base: Node = Node{ .id = .StructInitializer },
2297 base: Node = Node{ .tag = .StructInitializer },
22022298 rtoken: TokenIndex,
22032299 list_len: NodeIndex,
22042300 lhs: *Node,
......@@ -2251,7 +2347,7 @@ pub const Node = struct {
22512347
22522348 /// Elements occur directly in memory after StructInitializerDot.
22532349 pub const StructInitializerDot = struct {
2254 base: Node = Node{ .id = .StructInitializerDot },
2350 base: Node = Node{ .tag = .StructInitializerDot },
22552351 dot: TokenIndex,
22562352 rtoken: TokenIndex,
22572353 list_len: NodeIndex,
......@@ -2301,7 +2397,7 @@ pub const Node = struct {
23012397
23022398 /// Parameter nodes directly follow Call in memory.
23032399 pub const Call = struct {
2304 base: Node = Node{ .id = .Call },
2400 base: Node = Node{ .tag = .Call },
23052401 lhs: *Node,
23062402 rtoken: TokenIndex,
23072403 params_len: NodeIndex,
......@@ -2355,7 +2451,7 @@ pub const Node = struct {
23552451 };
23562452
23572453 pub const SuffixOp = struct {
2358 base: Node = Node{ .id = .SuffixOp },
2454 base: Node = Node{ .tag = .SuffixOp },
23592455 op: Op,
23602456 lhs: *Node,
23612457 rtoken: TokenIndex,
......@@ -2415,7 +2511,7 @@ pub const Node = struct {
24152511 };
24162512
24172513 pub const GroupedExpression = struct {
2418 base: Node = Node{ .id = .GroupedExpression },
2514 base: Node = Node{ .tag = .GroupedExpression },
24192515 lparen: TokenIndex,
24202516 expr: *Node,
24212517 rparen: TokenIndex,
......@@ -2441,7 +2537,7 @@ pub const Node = struct {
24412537 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
24422538 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
24432539 pub const ControlFlowExpression = struct {
2444 base: Node = Node{ .id = .ControlFlowExpression },
2540 base: Node = Node{ .tag = .ControlFlowExpression },
24452541 ltoken: TokenIndex,
24462542 kind: Kind,
24472543 rhs: ?*Node,
......@@ -2496,7 +2592,7 @@ pub const Node = struct {
24962592 };
24972593
24982594 pub const Suspend = struct {
2499 base: Node = Node{ .id = .Suspend },
2595 base: Node = Node{ .tag = .Suspend },
25002596 suspend_token: TokenIndex,
25012597 body: ?*Node,
25022598
......@@ -2525,7 +2621,7 @@ pub const Node = struct {
25252621 };
25262622
25272623 pub const IntegerLiteral = struct {
2528 base: Node = Node{ .id = .IntegerLiteral },
2624 base: Node = Node{ .tag = .IntegerLiteral },
25292625 token: TokenIndex,
25302626
25312627 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {
......@@ -2542,7 +2638,7 @@ pub const Node = struct {
25422638 };
25432639
25442640 pub const EnumLiteral = struct {
2545 base: Node = Node{ .id = .EnumLiteral },
2641 base: Node = Node{ .tag = .EnumLiteral },
25462642 dot: TokenIndex,
25472643 name: TokenIndex,
25482644
......@@ -2560,7 +2656,7 @@ pub const Node = struct {
25602656 };
25612657
25622658 pub const FloatLiteral = struct {
2563 base: Node = Node{ .id = .FloatLiteral },
2659 base: Node = Node{ .tag = .FloatLiteral },
25642660 token: TokenIndex,
25652661
25662662 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {
......@@ -2578,7 +2674,7 @@ pub const Node = struct {
25782674
25792675 /// Parameters are in memory following BuiltinCall.
25802676 pub const BuiltinCall = struct {
2581 base: Node = Node{ .id = .BuiltinCall },
2677 base: Node = Node{ .tag = .BuiltinCall },
25822678 params_len: NodeIndex,
25832679 builtin_token: TokenIndex,
25842680 rparen_token: TokenIndex,
......@@ -2627,7 +2723,7 @@ pub const Node = struct {
26272723 };
26282724
26292725 pub const StringLiteral = struct {
2630 base: Node = Node{ .id = .StringLiteral },
2726 base: Node = Node{ .tag = .StringLiteral },
26312727 token: TokenIndex,
26322728
26332729 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {
......@@ -2645,7 +2741,7 @@ pub const Node = struct {
26452741
26462742 /// The string literal tokens appear directly in memory after MultilineStringLiteral.
26472743 pub const MultilineStringLiteral = struct {
2648 base: Node = Node{ .id = .MultilineStringLiteral },
2744 base: Node = Node{ .tag = .MultilineStringLiteral },
26492745 lines_len: TokenIndex,
26502746
26512747 /// After this the caller must initialize the lines list.
......@@ -2687,7 +2783,7 @@ pub const Node = struct {
26872783 };
26882784
26892785 pub const CharLiteral = struct {
2690 base: Node = Node{ .id = .CharLiteral },
2786 base: Node = Node{ .tag = .CharLiteral },
26912787 token: TokenIndex,
26922788
26932789 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {
......@@ -2704,7 +2800,7 @@ pub const Node = struct {
27042800 };
27052801
27062802 pub const BoolLiteral = struct {
2707 base: Node = Node{ .id = .BoolLiteral },
2803 base: Node = Node{ .tag = .BoolLiteral },
27082804 token: TokenIndex,
27092805
27102806 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {
......@@ -2721,7 +2817,7 @@ pub const Node = struct {
27212817 };
27222818
27232819 pub const NullLiteral = struct {
2724 base: Node = Node{ .id = .NullLiteral },
2820 base: Node = Node{ .tag = .NullLiteral },
27252821 token: TokenIndex,
27262822
27272823 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {
......@@ -2738,7 +2834,7 @@ pub const Node = struct {
27382834 };
27392835
27402836 pub const UndefinedLiteral = struct {
2741 base: Node = Node{ .id = .UndefinedLiteral },
2837 base: Node = Node{ .tag = .UndefinedLiteral },
27422838 token: TokenIndex,
27432839
27442840 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {
......@@ -2755,7 +2851,7 @@ pub const Node = struct {
27552851 };
27562852
27572853 pub const Asm = struct {
2758 base: Node = Node{ .id = .Asm },
2854 base: Node = Node{ .tag = .Asm },
27592855 asm_token: TokenIndex,
27602856 rparen: TokenIndex,
27612857 volatile_token: ?TokenIndex,
......@@ -2875,7 +2971,7 @@ pub const Node = struct {
28752971 };
28762972
28772973 pub const Unreachable = struct {
2878 base: Node = Node{ .id = .Unreachable },
2974 base: Node = Node{ .tag = .Unreachable },
28792975 token: TokenIndex,
28802976
28812977 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {
......@@ -2892,7 +2988,7 @@ pub const Node = struct {
28922988 };
28932989
28942990 pub const ErrorType = struct {
2895 base: Node = Node{ .id = .ErrorType },
2991 base: Node = Node{ .tag = .ErrorType },
28962992 token: TokenIndex,
28972993
28982994 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {
......@@ -2909,7 +3005,7 @@ pub const Node = struct {
29093005 };
29103006
29113007 pub const AnyType = struct {
2912 base: Node = Node{ .id = .AnyType },
3008 base: Node = Node{ .tag = .AnyType },
29133009 token: TokenIndex,
29143010
29153011 pub fn iterate(self: *const AnyType, index: usize) ?*Node {
......@@ -2929,7 +3025,7 @@ pub const Node = struct {
29293025 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
29303026 /// and forwards to find same-line doc comments.
29313027 pub const DocComment = struct {
2932 base: Node = Node{ .id = .DocComment },
3028 base: Node = Node{ .tag = .DocComment },
29333029 /// Points to the first doc comment token. API users are expected to iterate over the
29343030 /// tokens array, looking for more doc comments, ignoring line comments, and stopping
29353031 /// at the first other token.
......@@ -2951,7 +3047,7 @@ pub const Node = struct {
29513047 };
29523048
29533049 pub const TestDecl = struct {
2954 base: Node = Node{ .id = .TestDecl },
3050 base: Node = Node{ .tag = .TestDecl },
29553051 doc_comments: ?*DocComment,
29563052 test_token: TokenIndex,
29573053 name: *Node,
......@@ -2996,7 +3092,7 @@ pub const PtrInfo = struct {
29963092
29973093test "iterate" {
29983094 var root = Node.Root{
2999 .base = Node{ .id = Node.Id.Root },
3095 .base = Node{ .tag = Node.Tag.Root },
30003096 .decls_len = 0,
30013097 .eof_token = 0,
30023098 };
lib/std/zig/parse.zig+172-142
......@@ -1015,7 +1015,7 @@ const Parser = struct {
10151015 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
10161016 fn parseBoolOrExpr(p: *Parser) !?*Node {
10171017 return p.parseBinOpExpr(
1018 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),
1018 SimpleBinOpParseFn(.Keyword_or, .BoolOr),
10191019 parseBoolAndExpr,
10201020 .Infinitely,
10211021 );
......@@ -1128,8 +1128,9 @@ const Parser = struct {
11281128 const expr_node = try p.expectNode(parseExpr, .{
11291129 .ExpectedExpr = .{ .token = p.tok_i },
11301130 });
1131 const node = try p.arena.allocator.create(Node.Resume);
1131 const node = try p.arena.allocator.create(Node.SimplePrefixOp);
11321132 node.* = .{
1133 .base = .{ .tag = .Resume },
11331134 .op_token = token,
11341135 .rhs = expr_node,
11351136 };
......@@ -1404,8 +1405,8 @@ const Parser = struct {
14041405 fn parseErrorUnionExpr(p: *Parser) !?*Node {
14051406 const suffix_expr = (try p.parseSuffixExpr()) orelse return null;
14061407
1407 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(p)) |node| {
1408 const error_union = node.cast(Node.InfixOp).?;
1408 if (try SimpleBinOpParseFn(.Bang, .ErrorUnion)(p)) |node| {
1409 const error_union = node.castTag(.ErrorUnion).?;
14091410 const type_expr = try p.expectNode(parseTypeExpr, .{
14101411 .ExpectedTypeExpr = .{ .token = p.tok_i },
14111412 });
......@@ -1438,10 +1439,56 @@ const Parser = struct {
14381439 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
14391440 });
14401441
1442 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
14411443 while (try p.parseSuffixOp()) |node| {
1442 switch (node.id) {
1444 switch (node.tag) {
14431445 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
1444 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1446 .Catch => node.castTag(.Catch).?.lhs = res,
1447
1448 .Add,
1449 .AddWrap,
1450 .ArrayCat,
1451 .ArrayMult,
1452 .Assign,
1453 .AssignBitAnd,
1454 .AssignBitOr,
1455 .AssignBitShiftLeft,
1456 .AssignBitShiftRight,
1457 .AssignBitXor,
1458 .AssignDiv,
1459 .AssignSub,
1460 .AssignSubWrap,
1461 .AssignMod,
1462 .AssignAdd,
1463 .AssignAddWrap,
1464 .AssignMul,
1465 .AssignMulWrap,
1466 .BangEqual,
1467 .BitAnd,
1468 .BitOr,
1469 .BitShiftLeft,
1470 .BitShiftRight,
1471 .BitXor,
1472 .BoolAnd,
1473 .BoolOr,
1474 .Div,
1475 .EqualEqual,
1476 .ErrorUnion,
1477 .GreaterOrEqual,
1478 .GreaterThan,
1479 .LessOrEqual,
1480 .LessThan,
1481 .MergeErrorSets,
1482 .Mod,
1483 .Mul,
1484 .MulWrap,
1485 .Period,
1486 .Range,
1487 .Sub,
1488 .SubWrap,
1489 .UnwrapOptional,
1490 => node.cast(Node.SimpleInfixOp).?.lhs = res,
1491
14451492 else => unreachable,
14461493 }
14471494 res = node;
......@@ -1469,10 +1516,55 @@ const Parser = struct {
14691516 var res = expr;
14701517
14711518 while (true) {
1519 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
14721520 if (try p.parseSuffixOp()) |node| {
1473 switch (node.id) {
1521 switch (node.tag) {
14741522 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,
1475 .InfixOp => node.cast(Node.InfixOp).?.lhs = res,
1523 .Catch => node.castTag(.Catch).?.lhs = res,
1524
1525 .Add,
1526 .AddWrap,
1527 .ArrayCat,
1528 .ArrayMult,
1529 .Assign,
1530 .AssignBitAnd,
1531 .AssignBitOr,
1532 .AssignBitShiftLeft,
1533 .AssignBitShiftRight,
1534 .AssignBitXor,
1535 .AssignDiv,
1536 .AssignSub,
1537 .AssignSubWrap,
1538 .AssignMod,
1539 .AssignAdd,
1540 .AssignAddWrap,
1541 .AssignMul,
1542 .AssignMulWrap,
1543 .BangEqual,
1544 .BitAnd,
1545 .BitOr,
1546 .BitShiftLeft,
1547 .BitShiftRight,
1548 .BitXor,
1549 .BoolAnd,
1550 .BoolOr,
1551 .Div,
1552 .EqualEqual,
1553 .ErrorUnion,
1554 .GreaterOrEqual,
1555 .GreaterThan,
1556 .LessOrEqual,
1557 .LessThan,
1558 .MergeErrorSets,
1559 .Mod,
1560 .Mul,
1561 .MulWrap,
1562 .Period,
1563 .Range,
1564 .Sub,
1565 .SubWrap,
1566 .UnwrapOptional,
1567 => node.cast(Node.SimpleInfixOp).?.lhs = res,
14761568 else => unreachable,
14771569 }
14781570 res = node;
......@@ -1559,11 +1651,11 @@ const Parser = struct {
15591651 const global_error_set = try p.createLiteral(Node.ErrorType, token);
15601652 if (period == null or identifier == null) return global_error_set;
15611653
1562 const node = try p.arena.allocator.create(Node.InfixOp);
1654 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
15631655 node.* = .{
1656 .base = Node{ .tag = .Period },
15641657 .op_token = period.?,
15651658 .lhs = global_error_set,
1566 .op = .Period,
15671659 .rhs = identifier.?,
15681660 };
15691661 return &node.base;
......@@ -1660,7 +1752,7 @@ const Parser = struct {
16601752 }
16611753
16621754 if (try p.parseLoopTypeExpr()) |node| {
1663 switch (node.id) {
1755 switch (node.tag) {
16641756 .For => node.cast(Node.For).?.label = label,
16651757 .While => node.cast(Node.While).?.label = label,
16661758 else => unreachable,
......@@ -2236,11 +2328,11 @@ const Parser = struct {
22362328 .ExpectedExpr = .{ .token = p.tok_i },
22372329 });
22382330
2239 const node = try p.arena.allocator.create(Node.InfixOp);
2331 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
22402332 node.* = .{
2333 .base = Node{ .tag = .Range },
22412334 .op_token = token,
22422335 .lhs = expr,
2243 .op = .Range,
22442336 .rhs = range_end,
22452337 };
22462338 return &node.base;
......@@ -2265,7 +2357,7 @@ const Parser = struct {
22652357 /// / EQUAL
22662358 fn parseAssignOp(p: *Parser) !?*Node {
22672359 const token = p.nextToken();
2268 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2360 const op: Node.Tag = switch (p.token_ids[token]) {
22692361 .AsteriskEqual => .AssignMul,
22702362 .SlashEqual => .AssignDiv,
22712363 .PercentEqual => .AssignMod,
......@@ -2286,11 +2378,11 @@ const Parser = struct {
22862378 },
22872379 };
22882380
2289 const node = try p.arena.allocator.create(Node.InfixOp);
2381 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
22902382 node.* = .{
2383 .base = .{ .tag = op },
22912384 .op_token = token,
22922385 .lhs = undefined, // set by caller
2293 .op = op,
22942386 .rhs = undefined, // set by caller
22952387 };
22962388 return &node.base;
......@@ -2305,7 +2397,7 @@ const Parser = struct {
23052397 /// / RARROWEQUAL
23062398 fn parseCompareOp(p: *Parser) !?*Node {
23072399 const token = p.nextToken();
2308 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2400 const op: Node.Tag = switch (p.token_ids[token]) {
23092401 .EqualEqual => .EqualEqual,
23102402 .BangEqual => .BangEqual,
23112403 .AngleBracketLeft => .LessThan,
......@@ -2329,12 +2421,22 @@ const Parser = struct {
23292421 /// / KEYWORD_catch Payload?
23302422 fn parseBitwiseOp(p: *Parser) !?*Node {
23312423 const token = p.nextToken();
2332 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2424 const op: Node.Tag = switch (p.token_ids[token]) {
23332425 .Ampersand => .BitAnd,
23342426 .Caret => .BitXor,
23352427 .Pipe => .BitOr,
23362428 .Keyword_orelse => .UnwrapOptional,
2337 .Keyword_catch => .{ .Catch = try p.parsePayload() },
2429 .Keyword_catch => {
2430 const payload = try p.parsePayload();
2431 const node = try p.arena.allocator.create(Node.Catch);
2432 node.* = .{
2433 .op_token = token,
2434 .lhs = undefined, // set by caller
2435 .rhs = undefined, // set by caller
2436 .payload = payload,
2437 };
2438 return &node.base;
2439 },
23382440 else => {
23392441 p.putBackToken(token);
23402442 return null;
......@@ -2349,7 +2451,7 @@ const Parser = struct {
23492451 /// / RARROW2
23502452 fn parseBitShiftOp(p: *Parser) !?*Node {
23512453 const token = p.nextToken();
2352 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2454 const op: Node.Tag = switch (p.token_ids[token]) {
23532455 .AngleBracketAngleBracketLeft => .BitShiftLeft,
23542456 .AngleBracketAngleBracketRight => .BitShiftRight,
23552457 else => {
......@@ -2369,7 +2471,7 @@ const Parser = struct {
23692471 /// / MINUSPERCENT
23702472 fn parseAdditionOp(p: *Parser) !?*Node {
23712473 const token = p.nextToken();
2372 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2474 const op: Node.Tag = switch (p.token_ids[token]) {
23732475 .Plus => .Add,
23742476 .Minus => .Sub,
23752477 .PlusPlus => .ArrayCat,
......@@ -2393,7 +2495,7 @@ const Parser = struct {
23932495 /// / ASTERISKPERCENT
23942496 fn parseMultiplyOp(p: *Parser) !?*Node {
23952497 const token = p.nextToken();
2396 const op: Node.InfixOp.Op = switch (p.token_ids[token]) {
2498 const op: Node.Tag = switch (p.token_ids[token]) {
23972499 .PipePipe => .MergeErrorSets,
23982500 .Asterisk => .Mul,
23992501 .Slash => .Div,
......@@ -2434,9 +2536,10 @@ const Parser = struct {
24342536 }
24352537 }
24362538
2437 fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Id, token: TokenIndex) !?*Node {
2438 const node = try p.arena.allocator.create(Node.SimplePrefixOp(tag));
2539 fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Tag, token: TokenIndex) !?*Node {
2540 const node = try p.arena.allocator.create(Node.SimplePrefixOp);
24392541 node.* = .{
2542 .base = .{ .tag = tag },
24402543 .op_token = token,
24412544 .rhs = undefined, // set by caller
24422545 };
......@@ -2457,8 +2560,9 @@ const Parser = struct {
24572560 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
24582561 fn parsePrefixTypeOp(p: *Parser) !?*Node {
24592562 if (p.eatToken(.QuestionMark)) |token| {
2460 const node = try p.arena.allocator.create(Node.OptionalType);
2563 const node = try p.arena.allocator.create(Node.SimplePrefixOp);
24612564 node.* = .{
2565 .base = .{ .tag = .OptionalType },
24622566 .op_token = token,
24632567 .rhs = undefined, // set by caller
24642568 };
......@@ -2670,14 +2774,14 @@ const Parser = struct {
26702774
26712775 if (p.eatToken(.Period)) |period| {
26722776 if (try p.parseIdentifier()) |identifier| {
2673 // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser.
2777 // TODO: It's a bit weird to return a SimpleInfixOp from the SuffixOp parser.
26742778 // Should there be an Node.SuffixOp.FieldAccess variant? Or should
26752779 // this grammar rule be altered?
2676 const node = try p.arena.allocator.create(Node.InfixOp);
2780 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
26772781 node.* = .{
2782 .base = Node{ .tag = .Period },
26782783 .op_token = period,
26792784 .lhs = undefined, // set by caller
2680 .op = .Period,
26812785 .rhs = identifier,
26822786 };
26832787 return &node.base;
......@@ -2984,7 +3088,7 @@ const Parser = struct {
29843088 }.parse;
29853089 }
29863090
2987 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn {
3091 fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.Tag) NodeParseFn {
29883092 return struct {
29893093 pub fn parse(p: *Parser) Error!?*Node {
29903094 const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {
......@@ -2998,11 +3102,11 @@ const Parser = struct {
29983102 else => return null,
29993103 } else p.eatToken(token) orelse return null;
30003104
3001 const node = try p.arena.allocator.create(Node.InfixOp);
3105 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
30023106 node.* = .{
3107 .base = .{ .tag = op },
30033108 .op_token = op_token,
30043109 .lhs = undefined, // set by caller
3005 .op = op,
30063110 .rhs = undefined, // set by caller
30073111 };
30083112 return &node.base;
......@@ -3072,7 +3176,6 @@ const Parser = struct {
30723176 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {
30733177 const result = try p.arena.allocator.create(T);
30743178 result.* = T{
3075 .base = Node{ .id = Node.typeToId(T) },
30763179 .token = token,
30773180 };
30783181 return &result.base;
......@@ -3148,8 +3251,9 @@ const Parser = struct {
31483251
31493252 fn parseTry(p: *Parser) !?*Node {
31503253 const token = p.eatToken(.Keyword_try) orelse return null;
3151 const node = try p.arena.allocator.create(Node.Try);
3254 const node = try p.arena.allocator.create(Node.SimplePrefixOp);
31523255 node.* = .{
3256 .base = .{ .tag = .Try },
31533257 .op_token = token,
31543258 .rhs = undefined, // set by caller
31553259 };
......@@ -3213,58 +3317,19 @@ const Parser = struct {
32133317 if (try opParseFn(p)) |first_op| {
32143318 var rightmost_op = first_op;
32153319 while (true) {
3216 switch (rightmost_op.id) {
3217 .AddressOf => {
3218 if (try opParseFn(p)) |rhs| {
3219 rightmost_op.cast(Node.AddressOf).?.rhs = rhs;
3220 rightmost_op = rhs;
3221 } else break;
3222 },
3223 .Await => {
3224 if (try opParseFn(p)) |rhs| {
3225 rightmost_op.cast(Node.Await).?.rhs = rhs;
3226 rightmost_op = rhs;
3227 } else break;
3228 },
3229 .BitNot => {
3230 if (try opParseFn(p)) |rhs| {
3231 rightmost_op.cast(Node.BitNot).?.rhs = rhs;
3232 rightmost_op = rhs;
3233 } else break;
3234 },
3235 .BoolNot => {
3236 if (try opParseFn(p)) |rhs| {
3237 rightmost_op.cast(Node.BoolNot).?.rhs = rhs;
3238 rightmost_op = rhs;
3239 } else break;
3240 },
3241 .OptionalType => {
3242 if (try opParseFn(p)) |rhs| {
3243 rightmost_op.cast(Node.OptionalType).?.rhs = rhs;
3244 rightmost_op = rhs;
3245 } else break;
3246 },
3247 .Negation => {
3320 switch (rightmost_op.tag) {
3321 .AddressOf,
3322 .Await,
3323 .BitNot,
3324 .BoolNot,
3325 .OptionalType,
3326 .Negation,
3327 .NegationWrap,
3328 .Resume,
3329 .Try,
3330 => {
32483331 if (try opParseFn(p)) |rhs| {
3249 rightmost_op.cast(Node.Negation).?.rhs = rhs;
3250 rightmost_op = rhs;
3251 } else break;
3252 },
3253 .NegationWrap => {
3254 if (try opParseFn(p)) |rhs| {
3255 rightmost_op.cast(Node.NegationWrap).?.rhs = rhs;
3256 rightmost_op = rhs;
3257 } else break;
3258 },
3259 .Resume => {
3260 if (try opParseFn(p)) |rhs| {
3261 rightmost_op.cast(Node.Resume).?.rhs = rhs;
3262 rightmost_op = rhs;
3263 } else break;
3264 },
3265 .Try => {
3266 if (try opParseFn(p)) |rhs| {
3267 rightmost_op.cast(Node.Try).?.rhs = rhs;
3332 rightmost_op.cast(Node.SimplePrefixOp).?.rhs = rhs;
32683333 rightmost_op = rhs;
32693334 } else break;
32703335 },
......@@ -3310,57 +3375,18 @@ const Parser = struct {
33103375 }
33113376
33123377 // If any prefix op existed, a child node on the RHS is required
3313 switch (rightmost_op.id) {
3314 .AddressOf => {
3315 const prefix_op = rightmost_op.cast(Node.AddressOf).?;
3316 prefix_op.rhs = try p.expectNode(childParseFn, .{
3317 .InvalidToken = .{ .token = p.tok_i },
3318 });
3319 },
3320 .Await => {
3321 const prefix_op = rightmost_op.cast(Node.Await).?;
3322 prefix_op.rhs = try p.expectNode(childParseFn, .{
3323 .InvalidToken = .{ .token = p.tok_i },
3324 });
3325 },
3326 .BitNot => {
3327 const prefix_op = rightmost_op.cast(Node.BitNot).?;
3328 prefix_op.rhs = try p.expectNode(childParseFn, .{
3329 .InvalidToken = .{ .token = p.tok_i },
3330 });
3331 },
3332 .BoolNot => {
3333 const prefix_op = rightmost_op.cast(Node.BoolNot).?;
3334 prefix_op.rhs = try p.expectNode(childParseFn, .{
3335 .InvalidToken = .{ .token = p.tok_i },
3336 });
3337 },
3338 .OptionalType => {
3339 const prefix_op = rightmost_op.cast(Node.OptionalType).?;
3340 prefix_op.rhs = try p.expectNode(childParseFn, .{
3341 .InvalidToken = .{ .token = p.tok_i },
3342 });
3343 },
3344 .Negation => {
3345 const prefix_op = rightmost_op.cast(Node.Negation).?;
3346 prefix_op.rhs = try p.expectNode(childParseFn, .{
3347 .InvalidToken = .{ .token = p.tok_i },
3348 });
3349 },
3350 .NegationWrap => {
3351 const prefix_op = rightmost_op.cast(Node.NegationWrap).?;
3352 prefix_op.rhs = try p.expectNode(childParseFn, .{
3353 .InvalidToken = .{ .token = p.tok_i },
3354 });
3355 },
3356 .Resume => {
3357 const prefix_op = rightmost_op.cast(Node.Resume).?;
3358 prefix_op.rhs = try p.expectNode(childParseFn, .{
3359 .InvalidToken = .{ .token = p.tok_i },
3360 });
3361 },
3362 .Try => {
3363 const prefix_op = rightmost_op.cast(Node.Try).?;
3378 switch (rightmost_op.tag) {
3379 .AddressOf,
3380 .Await,
3381 .BitNot,
3382 .BoolNot,
3383 .OptionalType,
3384 .Negation,
3385 .NegationWrap,
3386 .Resume,
3387 .Try,
3388 => {
3389 const prefix_op = rightmost_op.cast(Node.SimplePrefixOp).?;
33643390 prefix_op.rhs = try p.expectNode(childParseFn, .{
33653391 .InvalidToken = .{ .token = p.tok_i },
33663392 });
......@@ -3425,9 +3451,13 @@ const Parser = struct {
34253451 const left = res;
34263452 res = node;
34273453
3428 const op = node.cast(Node.InfixOp).?;
3429 op.*.lhs = left;
3430 op.*.rhs = right;
3454 if (node.castTag(.Catch)) |op| {
3455 op.lhs = left;
3456 op.rhs = right;
3457 } else if (node.cast(Node.SimpleInfixOp)) |op| {
3458 op.lhs = left;
3459 op.rhs = right;
3460 }
34313461
34323462 switch (chain) {
34333463 .Once => break,
......@@ -3438,12 +3468,12 @@ const Parser = struct {
34383468 return res;
34393469 }
34403470
3441 fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
3442 const node = try p.arena.allocator.create(Node.InfixOp);
3471 fn createInfixOp(p: *Parser, op_token: TokenIndex, tag: Node.Tag) !*Node {
3472 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
34433473 node.* = .{
3444 .op_token = index,
3474 .base = Node{ .tag = tag },
3475 .op_token = op_token,
34453476 .lhs = undefined, // set by caller
3446 .op = op,
34473477 .rhs = undefined, // set by caller
34483478 };
34493479 return &node.base;
lib/std/zig/render.zig+150-72
......@@ -223,7 +223,7 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tre
223223}
224224
225225fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Error || Error)!void {
226 switch (decl.id) {
226 switch (decl.tag) {
227227 .FnProto => {
228228 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
229229
......@@ -365,7 +365,7 @@ fn renderExpression(
365365 base: *ast.Node,
366366 space: Space,
367367) (@TypeOf(stream).Error || Error)!void {
368 switch (base.id) {
368 switch (base.tag) {
369369 .Identifier => {
370370 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
371371 return renderToken(tree, stream, identifier.token, indent, start_col, space);
......@@ -436,13 +436,10 @@ fn renderExpression(
436436 }
437437 },
438438
439 .InfixOp => {
440 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
439 .Catch => {
440 const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);
441441
442 const op_space = switch (infix_op_node.op) {
443 ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion, ast.Node.InfixOp.Op.Range => Space.None,
444 else => Space.Space,
445 };
442 const op_space = Space.Space;
446443 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
447444
448445 const after_op_space = blk: {
......@@ -458,60 +455,99 @@ fn renderExpression(
458455 start_col.* = indent + indent_delta;
459456 }
460457
461 switch (infix_op_node.op) {
462 ast.Node.InfixOp.Op.Catch => |maybe_payload| if (maybe_payload) |payload| {
463 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
464 },
465 else => {},
458 if (infix_op_node.payload) |payload| {
459 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
466460 }
467461
468462 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
469463 },
470464
471 .BitNot => {
472 const bit_not = @fieldParentPtr(ast.Node.BitNot, "base", base);
473 try renderToken(tree, stream, bit_not.op_token, indent, start_col, Space.None);
474 return renderExpression(allocator, stream, tree, indent, start_col, bit_not.rhs, space);
475 },
476 .BoolNot => {
477 const bool_not = @fieldParentPtr(ast.Node.BoolNot, "base", base);
478 try renderToken(tree, stream, bool_not.op_token, indent, start_col, Space.None);
479 return renderExpression(allocator, stream, tree, indent, start_col, bool_not.rhs, space);
480 },
481 .Negation => {
482 const negation = @fieldParentPtr(ast.Node.Negation, "base", base);
483 try renderToken(tree, stream, negation.op_token, indent, start_col, Space.None);
484 return renderExpression(allocator, stream, tree, indent, start_col, negation.rhs, space);
485 },
486 .NegationWrap => {
487 const negation_wrap = @fieldParentPtr(ast.Node.NegationWrap, "base", base);
488 try renderToken(tree, stream, negation_wrap.op_token, indent, start_col, Space.None);
489 return renderExpression(allocator, stream, tree, indent, start_col, negation_wrap.rhs, space);
490 },
491 .OptionalType => {
492 const opt_type = @fieldParentPtr(ast.Node.OptionalType, "base", base);
493 try renderToken(tree, stream, opt_type.op_token, indent, start_col, Space.None);
494 return renderExpression(allocator, stream, tree, indent, start_col, opt_type.rhs, space);
495 },
496 .AddressOf => {
497 const addr_of = @fieldParentPtr(ast.Node.AddressOf, "base", base);
498 try renderToken(tree, stream, addr_of.op_token, indent, start_col, Space.None);
499 return renderExpression(allocator, stream, tree, indent, start_col, addr_of.rhs, space);
500 },
501 .Try => {
502 const try_node = @fieldParentPtr(ast.Node.Try, "base", base);
503 try renderToken(tree, stream, try_node.op_token, indent, start_col, Space.Space);
504 return renderExpression(allocator, stream, tree, indent, start_col, try_node.rhs, space);
465 .Add,
466 .AddWrap,
467 .ArrayCat,
468 .ArrayMult,
469 .Assign,
470 .AssignBitAnd,
471 .AssignBitOr,
472 .AssignBitShiftLeft,
473 .AssignBitShiftRight,
474 .AssignBitXor,
475 .AssignDiv,
476 .AssignSub,
477 .AssignSubWrap,
478 .AssignMod,
479 .AssignAdd,
480 .AssignAddWrap,
481 .AssignMul,
482 .AssignMulWrap,
483 .BangEqual,
484 .BitAnd,
485 .BitOr,
486 .BitShiftLeft,
487 .BitShiftRight,
488 .BitXor,
489 .BoolAnd,
490 .BoolOr,
491 .Div,
492 .EqualEqual,
493 .ErrorUnion,
494 .GreaterOrEqual,
495 .GreaterThan,
496 .LessOrEqual,
497 .LessThan,
498 .MergeErrorSets,
499 .Mod,
500 .Mul,
501 .MulWrap,
502 .Period,
503 .Range,
504 .Sub,
505 .SubWrap,
506 .UnwrapOptional,
507 => {
508 const infix_op_node = @fieldParentPtr(ast.Node.SimpleInfixOp, "base", base);
509
510 const op_space = switch (base.tag) {
511 .Period, .ErrorUnion, .Range => Space.None,
512 else => Space.Space,
513 };
514 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
515
516 const after_op_space = blk: {
517 const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token));
518 break :blk if (loc.line == 0) op_space else Space.Newline;
519 };
520
521 try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space);
522 if (after_op_space == Space.Newline and
523 tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine)
524 {
525 try stream.writeByteNTimes(' ', indent + indent_delta);
526 start_col.* = indent + indent_delta;
527 }
528
529 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
505530 },
506 .Resume => {
507 const resume_node = @fieldParentPtr(ast.Node.Resume, "base", base);
508 try renderToken(tree, stream, resume_node.op_token, indent, start_col, Space.Space);
509 return renderExpression(allocator, stream, tree, indent, start_col, resume_node.rhs, space);
531
532 .BitNot,
533 .BoolNot,
534 .Negation,
535 .NegationWrap,
536 .OptionalType,
537 .AddressOf,
538 => {
539 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
540 try renderToken(tree, stream, casted_node.op_token, indent, start_col, Space.None);
541 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);
510542 },
511 .Await => {
512 const await_node = @fieldParentPtr(ast.Node.Await, "base", base);
513 try renderToken(tree, stream, await_node.op_token, indent, start_col, Space.Space);
514 return renderExpression(allocator, stream, tree, indent, start_col, await_node.rhs, space);
543
544 .Try,
545 .Resume,
546 .Await,
547 => {
548 const casted_node = @fieldParentPtr(ast.Node.SimplePrefixOp, "base", base);
549 try renderToken(tree, stream, casted_node.op_token, indent, start_col, Space.Space);
550 return renderExpression(allocator, stream, tree, indent, start_col, casted_node.rhs, space);
515551 },
516552
517553 .ArrayType => {
......@@ -659,7 +695,7 @@ fn renderExpression(
659695 .ArrayInitializer, .ArrayInitializerDot => {
660696 var rtoken: ast.TokenIndex = undefined;
661697 var exprs: []*ast.Node = undefined;
662 const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.id) {
698 const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.tag) {
663699 .ArrayInitializerDot => blk: {
664700 const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
665701 rtoken = casted.rtoken;
......@@ -793,14 +829,14 @@ fn renderExpression(
793829 }
794830
795831 try renderExtraNewline(tree, stream, start_col, next_expr);
796 if (next_expr.id != .MultilineStringLiteral) {
832 if (next_expr.tag != .MultilineStringLiteral) {
797833 try stream.writeByteNTimes(' ', new_indent);
798834 }
799835 } else {
800836 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // ,
801837 }
802838 }
803 if (exprs[exprs.len - 1].id != .MultilineStringLiteral) {
839 if (exprs[exprs.len - 1].tag != .MultilineStringLiteral) {
804840 try stream.writeByteNTimes(' ', indent);
805841 }
806842 return renderToken(tree, stream, rtoken, indent, start_col, space);
......@@ -823,7 +859,7 @@ fn renderExpression(
823859 .StructInitializer, .StructInitializerDot => {
824860 var rtoken: ast.TokenIndex = undefined;
825861 var field_inits: []*ast.Node = undefined;
826 const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.id) {
862 const lhs: union(enum) { dot: ast.TokenIndex, node: *ast.Node } = switch (base.tag) {
827863 .StructInitializerDot => blk: {
828864 const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
829865 rtoken = casted.rtoken;
......@@ -877,7 +913,7 @@ fn renderExpression(
877913 if (field_inits.len == 1) blk: {
878914 const field_init = field_inits[0].cast(ast.Node.FieldInitializer).?;
879915
880 switch (field_init.expr.id) {
916 switch (field_init.expr.tag) {
881917 .StructInitializer,
882918 .StructInitializerDot,
883919 => break :blk,
......@@ -974,7 +1010,7 @@ fn renderExpression(
9741010
9751011 const params = call.params();
9761012 for (params) |param_node, i| {
977 const param_node_new_indent = if (param_node.id == .MultilineStringLiteral) blk: {
1013 const param_node_new_indent = if (param_node.tag == .MultilineStringLiteral) blk: {
9781014 break :blk indent;
9791015 } else blk: {
9801016 try stream.writeByteNTimes(' ', new_indent);
......@@ -1284,7 +1320,7 @@ fn renderExpression(
12841320 // declarations inside are fields
12851321 const src_has_only_fields = blk: {
12861322 for (fields_and_decls) |decl| {
1287 if (decl.id != .ContainerField) break :blk false;
1323 if (decl.tag != .ContainerField) break :blk false;
12881324 }
12891325 break :blk true;
12901326 };
......@@ -1831,7 +1867,7 @@ fn renderExpression(
18311867
18321868 const rparen = tree.nextToken(for_node.array_expr.lastToken());
18331869
1834 const body_is_block = for_node.body.id == .Block;
1870 const body_is_block = for_node.body.tag == .Block;
18351871 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
18361872 const body_on_same_line = body_is_block or src_one_line_to_body;
18371873
......@@ -1874,7 +1910,7 @@ fn renderExpression(
18741910
18751911 try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition
18761912
1877 const body_is_if_block = if_node.body.id == .If;
1913 const body_is_if_block = if_node.body.tag == .If;
18781914 const body_is_block = nodeIsBlock(if_node.body);
18791915
18801916 if (body_is_if_block) {
......@@ -1978,7 +2014,7 @@ fn renderExpression(
19782014
19792015 const indent_once = indent + indent_delta;
19802016
1981 if (asm_node.template.id == .MultilineStringLiteral) {
2017 if (asm_node.template.tag == .MultilineStringLiteral) {
19822018 // After rendering a multiline string literal the cursor is
19832019 // already offset by indent
19842020 try stream.writeByteNTimes(' ', indent_delta);
......@@ -2245,7 +2281,7 @@ fn renderVarDecl(
22452281 }
22462282
22472283 if (var_decl.getTrailer("init_node")) |init_node| {
2248 const s = if (init_node.id == .MultilineStringLiteral) Space.None else Space.Space;
2284 const s = if (init_node.tag == .MultilineStringLiteral) Space.None else Space.Space;
22492285 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =
22502286 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
22512287 }
......@@ -2287,7 +2323,7 @@ fn renderStatement(
22872323 start_col: *usize,
22882324 base: *ast.Node,
22892325) (@TypeOf(stream).Error || Error)!void {
2290 switch (base.id) {
2326 switch (base.tag) {
22912327 .VarDecl => {
22922328 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
22932329 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
......@@ -2566,7 +2602,7 @@ fn renderDocCommentsToken(
25662602}
25672603
25682604fn nodeIsBlock(base: *const ast.Node) bool {
2569 return switch (base.id) {
2605 return switch (base.tag) {
25702606 .Block,
25712607 .If,
25722608 .For,
......@@ -2578,10 +2614,52 @@ fn nodeIsBlock(base: *const ast.Node) bool {
25782614}
25792615
25802616fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2581 const infix_op = base.cast(ast.Node.InfixOp) orelse return false;
2582 return switch (infix_op.op) {
2583 ast.Node.InfixOp.Op.Period => false,
2584 else => true,
2617 return switch (base.tag) {
2618 .Catch,
2619 .Add,
2620 .AddWrap,
2621 .ArrayCat,
2622 .ArrayMult,
2623 .Assign,
2624 .AssignBitAnd,
2625 .AssignBitOr,
2626 .AssignBitShiftLeft,
2627 .AssignBitShiftRight,
2628 .AssignBitXor,
2629 .AssignDiv,
2630 .AssignSub,
2631 .AssignSubWrap,
2632 .AssignMod,
2633 .AssignAdd,
2634 .AssignAddWrap,
2635 .AssignMul,
2636 .AssignMulWrap,
2637 .BangEqual,
2638 .BitAnd,
2639 .BitOr,
2640 .BitShiftLeft,
2641 .BitShiftRight,
2642 .BitXor,
2643 .BoolAnd,
2644 .BoolOr,
2645 .Div,
2646 .EqualEqual,
2647 .ErrorUnion,
2648 .GreaterOrEqual,
2649 .GreaterThan,
2650 .LessOrEqual,
2651 .LessThan,
2652 .MergeErrorSets,
2653 .Mod,
2654 .Mul,
2655 .MulWrap,
2656 .Range,
2657 .Sub,
2658 .SubWrap,
2659 .UnwrapOptional,
2660 => true,
2661
2662 else => false,
25852663 };
25862664}
25872665
src-self-hosted/Module.zig+87-480
......@@ -19,6 +19,7 @@ const Body = ir.Body;
1919const ast = std.zig.ast;
2020const trace = @import("tracy.zig").trace;
2121const liveness = @import("liveness.zig");
22const astgen = @import("astgen.zig");
2223
2324/// General-purpose allocator. Used for both temporary and long-term storage.
2425gpa: *Allocator,
......@@ -76,6 +77,8 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
7677
7778keep_source_files_loaded: bool,
7879
80pub const InnerError = error{ OutOfMemory, AnalysisFail };
81
7982const WorkItem = union(enum) {
8083 /// Write the machine code for a Decl to the output file.
8184 codegen_decl: *Decl,
......@@ -209,6 +212,7 @@ pub const Decl = struct {
209212 },
210213 .block => unreachable,
211214 .gen_zir => unreachable,
215 .local_var => unreachable,
212216 .decl => unreachable,
213217 }
214218 }
......@@ -304,6 +308,7 @@ pub const Scope = struct {
304308 .block => return self.cast(Block).?.arena,
305309 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
306310 .gen_zir => return self.cast(GenZIR).?.arena,
311 .local_var => return self.cast(LocalVar).?.gen_zir.arena,
307312 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
308313 .file => unreachable,
309314 }
......@@ -315,6 +320,7 @@ pub const Scope = struct {
315320 return switch (self.tag) {
316321 .block => self.cast(Block).?.decl,
317322 .gen_zir => self.cast(GenZIR).?.decl,
323 .local_var => return self.cast(LocalVar).?.gen_zir.decl,
318324 .decl => self.cast(DeclAnalysis).?.decl,
319325 .zir_module => null,
320326 .file => null,
......@@ -327,6 +333,7 @@ pub const Scope = struct {
327333 switch (self.tag) {
328334 .block => return self.cast(Block).?.decl.scope,
329335 .gen_zir => return self.cast(GenZIR).?.decl.scope,
336 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope,
330337 .decl => return self.cast(DeclAnalysis).?.decl.scope,
331338 .zir_module, .file => return self,
332339 }
......@@ -339,6 +346,7 @@ pub const Scope = struct {
339346 switch (self.tag) {
340347 .block => unreachable,
341348 .gen_zir => unreachable,
349 .local_var => unreachable,
342350 .decl => unreachable,
343351 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
344352 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
......@@ -353,9 +361,22 @@ pub const Scope = struct {
353361 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
354362 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
355363 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,
364 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope.cast(File).?.contents.tree,
356365 }
357366 }
358367
368 /// Asserts the scope is a child of a `GenZIR` and returns it.
369 pub fn getGenZIR(self: *Scope) *GenZIR {
370 return switch (self.tag) {
371 .block => unreachable,
372 .gen_zir => self.cast(GenZIR).?,
373 .local_var => return self.cast(LocalVar).?.gen_zir,
374 .decl => unreachable,
375 .zir_module => unreachable,
376 .file => unreachable,
377 };
378 }
379
359380 pub fn dumpInst(self: *Scope, inst: *Inst) void {
360381 const zir_module = self.namespace();
361382 const loc = std.zig.findLineColumn(zir_module.source.bytes, inst.src);
......@@ -376,6 +397,7 @@ pub const Scope = struct {
376397 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
377398 .block => unreachable,
378399 .gen_zir => unreachable,
400 .local_var => unreachable,
379401 .decl => unreachable,
380402 }
381403 }
......@@ -386,6 +408,7 @@ pub const Scope = struct {
386408 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
387409 .block => unreachable,
388410 .gen_zir => unreachable,
411 .local_var => unreachable,
389412 .decl => unreachable,
390413 }
391414 }
......@@ -395,6 +418,7 @@ pub const Scope = struct {
395418 .file => return @fieldParentPtr(File, "base", base).getSource(module),
396419 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
397420 .gen_zir => unreachable,
421 .local_var => unreachable,
398422 .block => unreachable,
399423 .decl => unreachable,
400424 }
......@@ -407,6 +431,7 @@ pub const Scope = struct {
407431 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
408432 .block => unreachable,
409433 .gen_zir => unreachable,
434 .local_var => unreachable,
410435 .decl => unreachable,
411436 }
412437 }
......@@ -426,6 +451,7 @@ pub const Scope = struct {
426451 },
427452 .block => unreachable,
428453 .gen_zir => unreachable,
454 .local_var => unreachable,
429455 .decl => unreachable,
430456 }
431457 }
......@@ -446,6 +472,7 @@ pub const Scope = struct {
446472 block,
447473 decl,
448474 gen_zir,
475 local_var,
449476 };
450477
451478 pub const File = struct {
......@@ -673,10 +700,25 @@ pub const Scope = struct {
673700 pub const GenZIR = struct {
674701 pub const base_tag: Tag = .gen_zir;
675702 base: Scope = Scope{ .tag = base_tag },
703 /// Parents can be: `GenZIR`, `ZIRModule`, `File`
704 parent: *Scope,
676705 decl: *Decl,
677706 arena: *Allocator,
707 /// The first N instructions in a function body ZIR are arg instructions.
678708 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
679709 };
710
711 /// This structure lives as long as the AST generation of the Block
712 /// node that contains the variable.
713 pub const LocalVar = struct {
714 pub const base_tag: Tag = .local_var;
715 base: Scope = Scope{ .tag = base_tag },
716 /// Parents can be: `LocalVar`, `GenZIR`.
717 parent: *Scope,
718 gen_zir: *GenZIR,
719 name: []const u8,
720 inst: *zir.Inst,
721 };
680722};
681723
682724pub const AllErrors = struct {
......@@ -944,8 +986,6 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
944986 };
945987}
946988
947const InnerError = error{ OutOfMemory, AnalysisFail };
948
949989pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
950990 while (self.work_queue.readItem()) |work_item| switch (work_item) {
951991 .codegen_decl => |decl| switch (decl.analysis) {
......@@ -1113,7 +1153,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11131153 const file_scope = decl.scope.cast(Scope.File).?;
11141154 const tree = try self.getAstTree(file_scope);
11151155 const ast_node = tree.root_node.decls()[decl.src_index];
1116 switch (ast_node.id) {
1156 switch (ast_node.tag) {
11171157 .FnProto => {
11181158 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
11191159
......@@ -1127,6 +1167,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11271167 var fn_type_scope: Scope.GenZIR = .{
11281168 .decl = decl,
11291169 .arena = &fn_type_scope_arena.allocator,
1170 .parent = decl.scope,
11301171 };
11311172 defer fn_type_scope.instructions.deinit(self.gpa);
11321173
......@@ -1140,7 +1181,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11401181 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
11411182 .type_expr => |node| node,
11421183 };
1143 param_types[i] = try self.astGenExpr(&fn_type_scope.base, param_type_node);
1184 param_types[i] = try astgen.expr(self, &fn_type_scope.base, param_type_node);
11441185 }
11451186 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
11461187 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
......@@ -1168,7 +1209,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
11681209 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
11691210 };
11701211
1171 const return_type_inst = try self.astGenExpr(&fn_type_scope.base, return_type_expr);
1212 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, return_type_expr);
11721213 const fn_src = tree.token_locs[fn_proto.fn_token].start;
11731214 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
11741215 .return_type = return_type_inst,
......@@ -1204,12 +1245,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
12041245 var gen_scope: Scope.GenZIR = .{
12051246 .decl = decl,
12061247 .arena = &gen_scope_arena.allocator,
1248 .parent = decl.scope,
12071249 };
12081250 defer gen_scope.instructions.deinit(self.gpa);
12091251
1252 // We need an instruction for each parameter, and they must be first in the body.
1253 try gen_scope.instructions.resize(self.gpa, fn_proto.params_len);
1254 var params_scope = &gen_scope.base;
1255 for (fn_proto.params()) |param, i| {
1256 const name_token = param.name_token.?;
1257 const src = tree.token_locs[name_token].start;
1258 const param_name = tree.tokenSlice(name_token);
1259 const arg = try newZIRInst(&gen_scope_arena.allocator, src, zir.Inst.Arg, .{}, .{});
1260 gen_scope.instructions.items[i] = &arg.base;
1261 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVar);
1262 sub_scope.* = .{
1263 .parent = params_scope,
1264 .gen_zir = &gen_scope,
1265 .name = param_name,
1266 .inst = &arg.base,
1267 };
1268 params_scope = &sub_scope.base;
1269 }
1270
12101271 const body_block = body_node.cast(ast.Node.Block).?;
12111272
1212 try self.astGenBlock(&gen_scope.base, body_block);
1273 try astgen.blockExpr(self, params_scope, body_block);
12131274
12141275 if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or
12151276 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()))
......@@ -1298,465 +1359,6 @@ fn analyzeBodyValueAsType(self: *Module, block_scope: *Scope.Block, body: zir.Mo
12981359 unreachable;
12991360}
13001361
1301fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst {
1302 switch (ast_node.id) {
1303 .Identifier => return self.astGenIdent(scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)),
1304 .Asm => return self.astGenAsm(scope, @fieldParentPtr(ast.Node.Asm, "base", ast_node)),
1305 .StringLiteral => return self.astGenStringLiteral(scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)),
1306 .IntegerLiteral => return self.astGenIntegerLiteral(scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)),
1307 .BuiltinCall => return self.astGenBuiltinCall(scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)),
1308 .Call => return self.astGenCall(scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)),
1309 .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)),
1310 .ControlFlowExpression => return self.astGenControlFlowExpression(scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)),
1311 .If => return self.astGenIf(scope, @fieldParentPtr(ast.Node.If, "base", ast_node)),
1312 .InfixOp => return self.astGenInfixOp(scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)),
1313 .BoolNot => return self.astGenBoolNot(scope, @fieldParentPtr(ast.Node.BoolNot, "base", ast_node)),
1314 else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}),
1315 }
1316}
1317
1318fn astGenBoolNot(self: *Module, scope: *Scope, node: *ast.Node.BoolNot) InnerError!*zir.Inst {
1319 const operand = try self.astGenExpr(scope, node.rhs);
1320 const tree = scope.tree();
1321 const src = tree.token_locs[node.op_token].start;
1322 return self.addZIRInst(scope, src, zir.Inst.BoolNot, .{ .operand = operand }, .{});
1323}
1324
1325fn astGenInfixOp(self: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst {
1326 switch (infix_node.op) {
1327 .Assign => {
1328 if (infix_node.lhs.id == .Identifier) {
1329 const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs);
1330 const tree = scope.tree();
1331 const ident_name = tree.tokenSlice(ident.token);
1332 if (std.mem.eql(u8, ident_name, "_")) {
1333 return self.astGenExpr(scope, infix_node.rhs);
1334 } else {
1335 return self.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
1336 }
1337 } else {
1338 return self.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
1339 }
1340 },
1341 .Add => {
1342 const lhs = try self.astGenExpr(scope, infix_node.lhs);
1343 const rhs = try self.astGenExpr(scope, infix_node.rhs);
1344
1345 const tree = scope.tree();
1346 const src = tree.token_locs[infix_node.op_token].start;
1347
1348 return self.addZIRInst(scope, src, zir.Inst.Add, .{ .lhs = lhs, .rhs = rhs }, .{});
1349 },
1350 .BangEqual,
1351 .EqualEqual,
1352 .GreaterThan,
1353 .GreaterOrEqual,
1354 .LessThan,
1355 .LessOrEqual,
1356 => {
1357 const lhs = try self.astGenExpr(scope, infix_node.lhs);
1358 const rhs = try self.astGenExpr(scope, infix_node.rhs);
1359
1360 const tree = scope.tree();
1361 const src = tree.token_locs[infix_node.op_token].start;
1362
1363 const op: std.math.CompareOperator = switch (infix_node.op) {
1364 .BangEqual => .neq,
1365 .EqualEqual => .eq,
1366 .GreaterThan => .gt,
1367 .GreaterOrEqual => .gte,
1368 .LessThan => .lt,
1369 .LessOrEqual => .lte,
1370 else => unreachable,
1371 };
1372
1373 return self.addZIRInst(scope, src, zir.Inst.Cmp, .{
1374 .lhs = lhs,
1375 .op = op,
1376 .rhs = rhs,
1377 }, .{});
1378 },
1379 else => |op| {
1380 return self.failNode(scope, &infix_node.base, "TODO implement infix operator {}", .{op});
1381 },
1382 }
1383}
1384
1385fn astGenIf(self: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst {
1386 if (if_node.payload) |payload| {
1387 return self.failNode(scope, payload, "TODO implement astGenIf for optionals", .{});
1388 }
1389 if (if_node.@"else") |else_node| {
1390 if (else_node.payload) |payload| {
1391 return self.failNode(scope, payload, "TODO implement astGenIf for error unions", .{});
1392 }
1393 }
1394 var block_scope: Scope.GenZIR = .{
1395 .decl = scope.decl().?,
1396 .arena = scope.arena(),
1397 .instructions = .{},
1398 };
1399 defer block_scope.instructions.deinit(self.gpa);
1400
1401 const cond = try self.astGenExpr(&block_scope.base, if_node.condition);
1402
1403 const tree = scope.tree();
1404 const if_src = tree.token_locs[if_node.if_token].start;
1405 const condbr = try self.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{
1406 .condition = cond,
1407 .true_body = undefined, // populated below
1408 .false_body = undefined, // populated below
1409 }, .{});
1410
1411 const block = try self.addZIRInstBlock(scope, if_src, .{
1412 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1413 });
1414 var then_scope: Scope.GenZIR = .{
1415 .decl = block_scope.decl,
1416 .arena = block_scope.arena,
1417 .instructions = .{},
1418 };
1419 defer then_scope.instructions.deinit(self.gpa);
1420
1421 const then_result = try self.astGenExpr(&then_scope.base, if_node.body);
1422 if (!then_result.tag.isNoReturn()) {
1423 const then_src = tree.token_locs[if_node.body.lastToken()].start;
1424 _ = try self.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{
1425 .block = block,
1426 .operand = then_result,
1427 }, .{});
1428 }
1429 condbr.positionals.true_body = .{
1430 .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items),
1431 };
1432
1433 var else_scope: Scope.GenZIR = .{
1434 .decl = block_scope.decl,
1435 .arena = block_scope.arena,
1436 .instructions = .{},
1437 };
1438 defer else_scope.instructions.deinit(self.gpa);
1439
1440 if (if_node.@"else") |else_node| {
1441 const else_result = try self.astGenExpr(&else_scope.base, else_node.body);
1442 if (!else_result.tag.isNoReturn()) {
1443 const else_src = tree.token_locs[else_node.body.lastToken()].start;
1444 _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{
1445 .block = block,
1446 .operand = else_result,
1447 }, .{});
1448 }
1449 } else {
1450 // TODO Optimization opportunity: we can avoid an allocation and a memcpy here
1451 // by directly allocating the body for this one instruction.
1452 const else_src = tree.token_locs[if_node.lastToken()].start;
1453 _ = try self.addZIRInst(&else_scope.base, else_src, zir.Inst.BreakVoid, .{
1454 .block = block,
1455 }, .{});
1456 }
1457 condbr.positionals.false_body = .{
1458 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
1459 };
1460
1461 return &block.base;
1462}
1463
1464fn astGenControlFlowExpression(
1465 self: *Module,
1466 scope: *Scope,
1467 cfe: *ast.Node.ControlFlowExpression,
1468) InnerError!*zir.Inst {
1469 switch (cfe.kind) {
1470 .Break => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Break", .{}),
1471 .Continue => return self.failNode(scope, &cfe.base, "TODO implement astGenExpr for Continue", .{}),
1472 .Return => {},
1473 }
1474 const tree = scope.tree();
1475 const src = tree.token_locs[cfe.ltoken].start;
1476 if (cfe.rhs) |rhs_node| {
1477 const operand = try self.astGenExpr(scope, rhs_node);
1478 return self.addZIRInst(scope, src, zir.Inst.Return, .{ .operand = operand }, .{});
1479 } else {
1480 return self.addZIRInst(scope, src, zir.Inst.ReturnVoid, .{}, .{});
1481 }
1482}
1483
1484fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
1485 const tree = scope.tree();
1486 const ident_name = tree.tokenSlice(ident.token);
1487 const src = tree.token_locs[ident.token].start;
1488 if (mem.eql(u8, ident_name, "_")) {
1489 return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});
1490 }
1491
1492 if (getSimplePrimitiveValue(ident_name)) |typed_value| {
1493 return self.addZIRInstConst(scope, src, typed_value);
1494 }
1495
1496 if (ident_name.len >= 2) integer: {
1497 const first_c = ident_name[0];
1498 if (first_c == 'i' or first_c == 'u') {
1499 const is_signed = first_c == 'i';
1500 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
1501 error.Overflow => return self.failNode(
1502 scope,
1503 &ident.base,
1504 "primitive integer type '{}' exceeds maximum bit width of 65535",
1505 .{ident_name},
1506 ),
1507 error.InvalidCharacter => break :integer,
1508 };
1509 const val = switch (bit_count) {
1510 8 => if (is_signed) Value.initTag(.i8_type) else Value.initTag(.u8_type),
1511 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type),
1512 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
1513 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
1514 else => return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),
1515 };
1516 return self.addZIRInstConst(scope, src, .{
1517 .ty = Type.initTag(.type),
1518 .val = val,
1519 });
1520 }
1521 }
1522
1523 if (self.lookupDeclName(scope, ident_name)) |decl| {
1524 return try self.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
1525 }
1526
1527 // Function parameter
1528 if (scope.decl()) |decl| {
1529 if (tree.root_node.decls()[decl.src_index].cast(ast.Node.FnProto)) |fn_proto| {
1530 for (fn_proto.params()) |param, i| {
1531 const param_name = tree.tokenSlice(param.name_token.?);
1532 if (mem.eql(u8, param_name, ident_name)) {
1533 return try self.addZIRInst(scope, src, zir.Inst.Arg, .{ .index = i }, .{});
1534 }
1535 }
1536 }
1537 }
1538
1539 return self.failNode(scope, &ident.base, "TODO implement local variable identifier lookup", .{});
1540}
1541
1542fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
1543 const tree = scope.tree();
1544 const unparsed_bytes = tree.tokenSlice(str_lit.token);
1545 const arena = scope.arena();
1546
1547 var bad_index: usize = undefined;
1548 const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) {
1549 error.InvalidCharacter => {
1550 const bad_byte = unparsed_bytes[bad_index];
1551 const src = tree.token_locs[str_lit.token].start;
1552 return self.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte});
1553 },
1554 else => |e| return e,
1555 };
1556
1557 const src = tree.token_locs[str_lit.token].start;
1558 return self.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
1559}
1560
1561fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
1562 const arena = scope.arena();
1563 const tree = scope.tree();
1564 const prefixed_bytes = tree.tokenSlice(int_lit.token);
1565 const base = if (mem.startsWith(u8, prefixed_bytes, "0x"))
1566 16
1567 else if (mem.startsWith(u8, prefixed_bytes, "0o"))
1568 8
1569 else if (mem.startsWith(u8, prefixed_bytes, "0b"))
1570 2
1571 else
1572 @as(u8, 10);
1573
1574 const bytes = if (base == 10)
1575 prefixed_bytes
1576 else
1577 prefixed_bytes[2..];
1578
1579 if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
1580 const int_payload = try arena.create(Value.Payload.Int_u64);
1581 int_payload.* = .{ .int = small_int };
1582 const src = tree.token_locs[int_lit.token].start;
1583 return self.addZIRInstConst(scope, src, .{
1584 .ty = Type.initTag(.comptime_int),
1585 .val = Value.initPayload(&int_payload.base),
1586 });
1587 } else |err| {
1588 return self.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
1589 }
1590}
1591
1592fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !void {
1593 const tracy = trace(@src());
1594 defer tracy.end();
1595
1596 if (block_node.label) |label| {
1597 return self.failTok(scope, label, "TODO implement labeled blocks", .{});
1598 }
1599 for (block_node.statements()) |statement| {
1600 _ = try self.astGenExpr(scope, statement);
1601 }
1602}
1603
1604fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
1605 if (asm_node.outputs.len != 0) {
1606 return self.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{});
1607 }
1608 const arena = scope.arena();
1609 const tree = scope.tree();
1610
1611 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);
1612 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);
1613
1614 for (asm_node.inputs) |input, i| {
1615 // TODO semantically analyze constraints
1616 inputs[i] = try self.astGenExpr(scope, input.constraint);
1617 args[i] = try self.astGenExpr(scope, input.expr);
1618 }
1619
1620 const src = tree.token_locs[asm_node.asm_token].start;
1621 const return_type = try self.addZIRInstConst(scope, src, .{
1622 .ty = Type.initTag(.type),
1623 .val = Value.initTag(.void_type),
1624 });
1625 const asm_inst = try self.addZIRInst(scope, src, zir.Inst.Asm, .{
1626 .asm_source = try self.astGenExpr(scope, asm_node.template),
1627 .return_type = return_type,
1628 }, .{
1629 .@"volatile" = asm_node.volatile_token != null,
1630 //.clobbers = TODO handle clobbers
1631 .inputs = inputs,
1632 .args = args,
1633 });
1634 return asm_inst;
1635}
1636
1637fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
1638 const tree = scope.tree();
1639 const builtin_name = tree.tokenSlice(call.builtin_token);
1640 const src = tree.token_locs[call.builtin_token].start;
1641
1642 inline for (std.meta.declarations(zir.Inst)) |inst| {
1643 if (inst.data != .Type) continue;
1644 const T = inst.data.Type;
1645 if (!@hasDecl(T, "builtin_name")) continue;
1646 if (std.mem.eql(u8, builtin_name, T.builtin_name)) {
1647 var value: T = undefined;
1648 const positionals = @typeInfo(std.meta.fieldInfo(T, "positionals").field_type).Struct;
1649 if (positionals.fields.len == 0) {
1650 return self.addZIRInst(scope, src, T, value.positionals, value.kw_args);
1651 }
1652 const arg_count: ?usize = if (positionals.fields[0].field_type == []*zir.Inst) null else positionals.fields.len;
1653 if (arg_count) |some| {
1654 if (call.params_len != some) {
1655 return self.failTok(
1656 scope,
1657 call.builtin_token,
1658 "expected {} parameter{}, found {}",
1659 .{ some, if (some == 1) "" else "s", call.params_len },
1660 );
1661 }
1662 const params = call.params();
1663 inline for (positionals.fields) |p, i| {
1664 @field(value.positionals, p.name) = try self.astGenExpr(scope, params[i]);
1665 }
1666 } else {
1667 return self.failTok(scope, call.builtin_token, "TODO var args builtin '{}'", .{builtin_name});
1668 }
1669
1670 return self.addZIRInst(scope, src, T, value.positionals, .{});
1671 }
1672 }
1673 return self.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
1674}
1675
1676fn astGenCall(self: *Module, scope: *Scope, call: *ast.Node.Call) InnerError!*zir.Inst {
1677 const tree = scope.tree();
1678 const lhs = try self.astGenExpr(scope, call.lhs);
1679
1680 const param_nodes = call.params();
1681 const args = try scope.cast(Scope.GenZIR).?.arena.alloc(*zir.Inst, param_nodes.len);
1682 for (param_nodes) |param_node, i| {
1683 args[i] = try self.astGenExpr(scope, param_node);
1684 }
1685
1686 const src = tree.token_locs[call.lhs.firstToken()].start;
1687 return self.addZIRInst(scope, src, zir.Inst.Call, .{
1688 .func = lhs,
1689 .args = args,
1690 }, .{});
1691}
1692
1693fn astGenUnreachable(self: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {
1694 const tree = scope.tree();
1695 const src = tree.token_locs[unreach_node.token].start;
1696 return self.addZIRInst(scope, src, zir.Inst.Unreachable, .{}, .{});
1697}
1698
1699fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
1700 const simple_types = std.ComptimeStringMap(Value.Tag, .{
1701 .{ "u8", .u8_type },
1702 .{ "i8", .i8_type },
1703 .{ "isize", .isize_type },
1704 .{ "usize", .usize_type },
1705 .{ "c_short", .c_short_type },
1706 .{ "c_ushort", .c_ushort_type },
1707 .{ "c_int", .c_int_type },
1708 .{ "c_uint", .c_uint_type },
1709 .{ "c_long", .c_long_type },
1710 .{ "c_ulong", .c_ulong_type },
1711 .{ "c_longlong", .c_longlong_type },
1712 .{ "c_ulonglong", .c_ulonglong_type },
1713 .{ "c_longdouble", .c_longdouble_type },
1714 .{ "f16", .f16_type },
1715 .{ "f32", .f32_type },
1716 .{ "f64", .f64_type },
1717 .{ "f128", .f128_type },
1718 .{ "c_void", .c_void_type },
1719 .{ "bool", .bool_type },
1720 .{ "void", .void_type },
1721 .{ "type", .type_type },
1722 .{ "anyerror", .anyerror_type },
1723 .{ "comptime_int", .comptime_int_type },
1724 .{ "comptime_float", .comptime_float_type },
1725 .{ "noreturn", .noreturn_type },
1726 });
1727 if (simple_types.get(name)) |tag| {
1728 return TypedValue{
1729 .ty = Type.initTag(.type),
1730 .val = Value.initTag(tag),
1731 };
1732 }
1733 if (mem.eql(u8, name, "null")) {
1734 return TypedValue{
1735 .ty = Type.initTag(.@"null"),
1736 .val = Value.initTag(.null_value),
1737 };
1738 }
1739 if (mem.eql(u8, name, "undefined")) {
1740 return TypedValue{
1741 .ty = Type.initTag(.@"undefined"),
1742 .val = Value.initTag(.undef),
1743 };
1744 }
1745 if (mem.eql(u8, name, "true")) {
1746 return TypedValue{
1747 .ty = Type.initTag(.bool),
1748 .val = Value.initTag(.bool_true),
1749 };
1750 }
1751 if (mem.eql(u8, name, "false")) {
1752 return TypedValue{
1753 .ty = Type.initTag(.bool),
1754 .val = Value.initTag(.bool_false),
1755 };
1756 }
1757 return null;
1758}
1759
17601362fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
17611363 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);
17621364 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);
......@@ -2368,7 +1970,7 @@ fn newZIRInst(
23681970 return inst;
23691971}
23701972
2371fn addZIRInstSpecial(
1973pub fn addZIRInstSpecial(
23721974 self: *Module,
23731975 scope: *Scope,
23741976 src: usize,
......@@ -2376,14 +1978,14 @@ fn addZIRInstSpecial(
23761978 positionals: std.meta.fieldInfo(T, "positionals").field_type,
23771979 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
23781980) !*T {
2379 const gen_zir = scope.cast(Scope.GenZIR).?;
1981 const gen_zir = scope.getGenZIR();
23801982 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);
23811983 const inst = try newZIRInst(gen_zir.arena, src, T, positionals, kw_args);
23821984 gen_zir.instructions.appendAssumeCapacity(&inst.base);
23831985 return inst;
23841986}
23851987
2386fn addZIRInst(
1988pub fn addZIRInst(
23871989 self: *Module,
23881990 scope: *Scope,
23891991 src: usize,
......@@ -2396,13 +1998,13 @@ fn addZIRInst(
23961998}
23971999
23982000/// TODO The existence of this function is a workaround for a bug in stage1.
2399fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {
2001pub fn addZIRInstConst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*zir.Inst {
24002002 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;
24012003 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
24022004}
24032005
24042006/// TODO The existence of this function is a workaround for a bug in stage1.
2405fn addZIRInstBlock(self: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block {
2007pub fn addZIRInstBlock(self: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Block {
24062008 const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type;
24072009 return self.addZIRInstSpecial(scope, src, zir.Inst.Block, P{ .body = body }, .{});
24082010}
......@@ -2637,7 +2239,7 @@ fn getNextAnonNameIndex(self: *Module) usize {
26372239 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
26382240}
26392241
2640fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
2242pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
26412243 const namespace = scope.namespace();
26422244 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
26432245 return self.decl_table.get(name_hash);
......@@ -2658,17 +2260,16 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile
26582260fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
26592261 const b = try self.requireRuntimeBlock(scope, inst.base.src);
26602262 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
2263 const param_index = b.instructions.items.len;
26612264 const param_count = fn_ty.fnParamLen();
2662 if (inst.positionals.index >= param_count) {
2265 if (param_index >= param_count) {
26632266 return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{
2664 inst.positionals.index,
2267 param_index,
26652268 param_count,
26662269 });
26672270 }
2668 const param_type = fn_ty.fnParamType(inst.positionals.index);
2669 return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, .{
2670 .index = inst.positionals.index,
2671 });
2271 const param_type = fn_ty.fnParamType(param_index);
2272 return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, {});
26722273}
26732274
26742275fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
......@@ -3646,13 +3247,13 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I
36463247 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
36473248}
36483249
3649fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
3250pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
36503251 @setCold(true);
36513252 const err_msg = try ErrorMsg.create(self.gpa, src, format, args);
36523253 return self.failWithOwnedErrorMsg(scope, src, err_msg);
36533254}
36543255
3655fn failTok(
3256pub fn failTok(
36563257 self: *Module,
36573258 scope: *Scope,
36583259 token_index: ast.TokenIndex,
......@@ -3664,7 +3265,7 @@ fn failTok(
36643265 return self.fail(scope, src, format, args);
36653266}
36663267
3667fn failNode(
3268pub fn failNode(
36683269 self: *Module,
36693270 scope: *Scope,
36703271 ast_node: *ast.Node,
......@@ -3705,6 +3306,12 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
37053306 gen_zir.decl.generation = self.generation;
37063307 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
37073308 },
3309 .local_var => {
3310 const gen_zir = scope.cast(Scope.LocalVar).?.gen_zir;
3311 gen_zir.decl.analysis = .sema_failure;
3312 gen_zir.decl.generation = self.generation;
3313 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3314 },
37083315 .zir_module => {
37093316 const zir_module = scope.cast(Scope.ZIRModule).?;
37103317 zir_module.status = .loaded_sema_failure;
src-self-hosted/astgen.zig created+643
......@@ -0,0 +1,643 @@
1const std = @import("std");
2const mem = std.mem;
3const Value = @import("value.zig").Value;
4const Type = @import("type.zig").Type;
5const TypedValue = @import("TypedValue.zig");
6const assert = std.debug.assert;
7const zir = @import("zir.zig");
8const Module = @import("Module.zig");
9const ast = std.zig.ast;
10const trace = @import("tracy.zig").trace;
11const Scope = Module.Scope;
12const InnerError = Module.InnerError;
13
14/// Turn Zig AST into untyped ZIR istructions.
15pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
16 switch (node.tag) {
17 .VarDecl => unreachable, // Handled in `blockExpr`.
18
19 .Identifier => return identifier(mod, scope, node.castTag(.Identifier).?),
20 .Asm => return assembly(mod, scope, node.castTag(.Asm).?),
21 .StringLiteral => return stringLiteral(mod, scope, node.castTag(.StringLiteral).?),
22 .IntegerLiteral => return integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?),
23 .BuiltinCall => return builtinCall(mod, scope, node.castTag(.BuiltinCall).?),
24 .Call => return callExpr(mod, scope, node.castTag(.Call).?),
25 .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?),
26 .ControlFlowExpression => return controlFlowExpr(mod, scope, node.castTag(.ControlFlowExpression).?),
27 .If => return ifExpr(mod, scope, node.castTag(.If).?),
28 .Assign => return assign(mod, scope, node.castTag(.Assign).?),
29 .Add => return add(mod, scope, node.castTag(.Add).?),
30 .BangEqual => return cmp(mod, scope, node.castTag(.BangEqual).?, .neq),
31 .EqualEqual => return cmp(mod, scope, node.castTag(.EqualEqual).?, .eq),
32 .GreaterThan => return cmp(mod, scope, node.castTag(.GreaterThan).?, .gt),
33 .GreaterOrEqual => return cmp(mod, scope, node.castTag(.GreaterOrEqual).?, .gte),
34 .LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt),
35 .LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte),
36 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),
37 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
38 }
39}
40
41pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block) !void {
42 const tracy = trace(@src());
43 defer tracy.end();
44
45 if (block_node.label) |label| {
46 return mod.failTok(parent_scope, label, "TODO implement labeled blocks", .{});
47 }
48
49 var block_arena = std.heap.ArenaAllocator.init(mod.gpa);
50 defer block_arena.deinit();
51
52 var scope = parent_scope;
53 for (block_node.statements()) |statement| {
54 switch (statement.tag) {
55 .VarDecl => {
56 const sub_scope = try block_arena.allocator.create(Scope.LocalVar);
57 const var_decl_node = @fieldParentPtr(ast.Node.VarDecl, "base", statement);
58 sub_scope.* = try varDecl(mod, scope, var_decl_node);
59 scope = &sub_scope.base;
60 },
61 else => _ = try expr(mod, scope, statement),
62 }
63 }
64}
65
66fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scope.LocalVar {
67 // TODO implement detection of shadowing
68 if (node.getTrailer("comptime_token")) |comptime_token| {
69 return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{});
70 }
71 if (node.getTrailer("align_node")) |align_node| {
72 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
73 }
74 if (node.getTrailer("type_node")) |type_node| {
75 return mod.failNode(scope, type_node, "TODO implement typed locals", .{});
76 }
77 const tree = scope.tree();
78 switch (tree.token_ids[node.mut_token]) {
79 .Keyword_const => {},
80 .Keyword_var => {
81 return mod.failTok(scope, node.mut_token, "TODO implement mutable locals", .{});
82 },
83 else => unreachable,
84 }
85 // Depending on the type of AST the initialization expression is, we may need an lvalue
86 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
87 // the variable, no memory location needed.
88 const init_node = node.getTrailer("init_node").?;
89 if (nodeNeedsMemoryLocation(init_node)) {
90 return mod.failNode(scope, init_node, "TODO implement result locations", .{});
91 }
92 const init_inst = try expr(mod, scope, init_node);
93 const ident_name = tree.tokenSlice(node.name_token); // TODO support @"aoeu" identifiers
94 return Scope.LocalVar{
95 .parent = scope,
96 .gen_zir = scope.getGenZIR(),
97 .name = ident_name,
98 .inst = init_inst,
99 };
100}
101
102fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
103 const operand = try expr(mod, scope, node.rhs);
104 const tree = scope.tree();
105 const src = tree.token_locs[node.op_token].start;
106 return mod.addZIRInst(scope, src, zir.Inst.BoolNot, .{ .operand = operand }, .{});
107}
108
109fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
110 if (infix_node.lhs.tag == .Identifier) {
111 const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs);
112 const tree = scope.tree();
113 const ident_name = tree.tokenSlice(ident.token);
114 if (std.mem.eql(u8, ident_name, "_")) {
115 return expr(mod, scope, infix_node.rhs);
116 } else {
117 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
118 }
119 } else {
120 return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{});
121 }
122}
123
124fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
125 const lhs = try expr(mod, scope, infix_node.lhs);
126 const rhs = try expr(mod, scope, infix_node.rhs);
127
128 const tree = scope.tree();
129 const src = tree.token_locs[infix_node.op_token].start;
130
131 return mod.addZIRInst(scope, src, zir.Inst.Add, .{ .lhs = lhs, .rhs = rhs }, .{});
132}
133
134fn cmp(
135 mod: *Module,
136 scope: *Scope,
137 infix_node: *ast.Node.SimpleInfixOp,
138 op: std.math.CompareOperator,
139) InnerError!*zir.Inst {
140 const lhs = try expr(mod, scope, infix_node.lhs);
141 const rhs = try expr(mod, scope, infix_node.rhs);
142
143 const tree = scope.tree();
144 const src = tree.token_locs[infix_node.op_token].start;
145
146 return mod.addZIRInst(scope, src, zir.Inst.Cmp, .{
147 .lhs = lhs,
148 .op = op,
149 .rhs = rhs,
150 }, .{});
151}
152
153fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst {
154 if (if_node.payload) |payload| {
155 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});
156 }
157 if (if_node.@"else") |else_node| {
158 if (else_node.payload) |payload| {
159 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{});
160 }
161 }
162 var block_scope: Scope.GenZIR = .{
163 .parent = scope,
164 .decl = scope.decl().?,
165 .arena = scope.arena(),
166 .instructions = .{},
167 };
168 defer block_scope.instructions.deinit(mod.gpa);
169
170 const cond = try expr(mod, &block_scope.base, if_node.condition);
171
172 const tree = scope.tree();
173 const if_src = tree.token_locs[if_node.if_token].start;
174 const condbr = try mod.addZIRInstSpecial(&block_scope.base, if_src, zir.Inst.CondBr, .{
175 .condition = cond,
176 .true_body = undefined, // populated below
177 .false_body = undefined, // populated below
178 }, .{});
179
180 const block = try mod.addZIRInstBlock(scope, if_src, .{
181 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
182 });
183 var then_scope: Scope.GenZIR = .{
184 .parent = scope,
185 .decl = block_scope.decl,
186 .arena = block_scope.arena,
187 .instructions = .{},
188 };
189 defer then_scope.instructions.deinit(mod.gpa);
190
191 const then_result = try expr(mod, &then_scope.base, if_node.body);
192 if (!then_result.tag.isNoReturn()) {
193 const then_src = tree.token_locs[if_node.body.lastToken()].start;
194 _ = try mod.addZIRInst(&then_scope.base, then_src, zir.Inst.Break, .{
195 .block = block,
196 .operand = then_result,
197 }, .{});
198 }
199 condbr.positionals.true_body = .{
200 .instructions = try then_scope.arena.dupe(*zir.Inst, then_scope.instructions.items),
201 };
202
203 var else_scope: Scope.GenZIR = .{
204 .parent = scope,
205 .decl = block_scope.decl,
206 .arena = block_scope.arena,
207 .instructions = .{},
208 };
209 defer else_scope.instructions.deinit(mod.gpa);
210
211 if (if_node.@"else") |else_node| {
212 const else_result = try expr(mod, &else_scope.base, else_node.body);
213 if (!else_result.tag.isNoReturn()) {
214 const else_src = tree.token_locs[else_node.body.lastToken()].start;
215 _ = try mod.addZIRInst(&else_scope.base, else_src, zir.Inst.Break, .{
216 .block = block,
217 .operand = else_result,
218 }, .{});
219 }
220 } else {
221 // TODO Optimization opportunity: we can avoid an allocation and a memcpy here
222 // by directly allocating the body for this one instruction.
223 const else_src = tree.token_locs[if_node.lastToken()].start;
224 _ = try mod.addZIRInst(&else_scope.base, else_src, zir.Inst.BreakVoid, .{
225 .block = block,
226 }, .{});
227 }
228 condbr.positionals.false_body = .{
229 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
230 };
231
232 return &block.base;
233}
234
235fn controlFlowExpr(
236 mod: *Module,
237 scope: *Scope,
238 cfe: *ast.Node.ControlFlowExpression,
239) InnerError!*zir.Inst {
240 switch (cfe.kind) {
241 .Break => return mod.failNode(scope, &cfe.base, "TODO implement astgen.Expr for Break", .{}),
242 .Continue => return mod.failNode(scope, &cfe.base, "TODO implement astgen.Expr for Continue", .{}),
243 .Return => {},
244 }
245 const tree = scope.tree();
246 const src = tree.token_locs[cfe.ltoken].start;
247 if (cfe.rhs) |rhs_node| {
248 const operand = try expr(mod, scope, rhs_node);
249 return mod.addZIRInst(scope, src, zir.Inst.Return, .{ .operand = operand }, .{});
250 } else {
251 return mod.addZIRInst(scope, src, zir.Inst.ReturnVoid, .{}, .{});
252 }
253}
254
255fn identifier(mod: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst {
256 const tracy = trace(@src());
257 defer tracy.end();
258
259 const tree = scope.tree();
260 // TODO implement @"aoeu" identifiers
261 const ident_name = tree.tokenSlice(ident.token);
262 const src = tree.token_locs[ident.token].start;
263 if (mem.eql(u8, ident_name, "_")) {
264 return mod.failNode(scope, &ident.base, "TODO implement '_' identifier", .{});
265 }
266
267 if (getSimplePrimitiveValue(ident_name)) |typed_value| {
268 return mod.addZIRInstConst(scope, src, typed_value);
269 }
270
271 if (ident_name.len >= 2) integer: {
272 const first_c = ident_name[0];
273 if (first_c == 'i' or first_c == 'u') {
274 const is_signed = first_c == 'i';
275 const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) {
276 error.Overflow => return mod.failNode(
277 scope,
278 &ident.base,
279 "primitive integer type '{}' exceeds maximum bit width of 65535",
280 .{ident_name},
281 ),
282 error.InvalidCharacter => break :integer,
283 };
284 const val = switch (bit_count) {
285 8 => if (is_signed) Value.initTag(.i8_type) else Value.initTag(.u8_type),
286 16 => if (is_signed) Value.initTag(.i16_type) else Value.initTag(.u16_type),
287 32 => if (is_signed) Value.initTag(.i32_type) else Value.initTag(.u32_type),
288 64 => if (is_signed) Value.initTag(.i64_type) else Value.initTag(.u64_type),
289 else => return mod.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}),
290 };
291 return mod.addZIRInstConst(scope, src, .{
292 .ty = Type.initTag(.type),
293 .val = val,
294 });
295 }
296 }
297
298 // Local variables, including function parameters.
299 {
300 var s = scope;
301 while (true) switch (s.tag) {
302 .local_var => {
303 const local_var = s.cast(Scope.LocalVar).?;
304 if (mem.eql(u8, local_var.name, ident_name)) {
305 return local_var.inst;
306 }
307 s = local_var.parent;
308 },
309 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,
310 else => break,
311 };
312 }
313
314 if (mod.lookupDeclName(scope, ident_name)) |decl| {
315 return try mod.addZIRInst(scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
316 }
317
318 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});
319}
320
321fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst {
322 const tree = scope.tree();
323 const unparsed_bytes = tree.tokenSlice(str_lit.token);
324 const arena = scope.arena();
325
326 var bad_index: usize = undefined;
327 const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) {
328 error.InvalidCharacter => {
329 const bad_byte = unparsed_bytes[bad_index];
330 const src = tree.token_locs[str_lit.token].start;
331 return mod.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte});
332 },
333 else => |e| return e,
334 };
335
336 const src = tree.token_locs[str_lit.token].start;
337 return mod.addZIRInst(scope, src, zir.Inst.Str, .{ .bytes = bytes }, .{});
338}
339
340fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst {
341 const arena = scope.arena();
342 const tree = scope.tree();
343 const prefixed_bytes = tree.tokenSlice(int_lit.token);
344 const base = if (mem.startsWith(u8, prefixed_bytes, "0x"))
345 16
346 else if (mem.startsWith(u8, prefixed_bytes, "0o"))
347 8
348 else if (mem.startsWith(u8, prefixed_bytes, "0b"))
349 2
350 else
351 @as(u8, 10);
352
353 const bytes = if (base == 10)
354 prefixed_bytes
355 else
356 prefixed_bytes[2..];
357
358 if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
359 const int_payload = try arena.create(Value.Payload.Int_u64);
360 int_payload.* = .{ .int = small_int };
361 const src = tree.token_locs[int_lit.token].start;
362 return mod.addZIRInstConst(scope, src, .{
363 .ty = Type.initTag(.comptime_int),
364 .val = Value.initPayload(&int_payload.base),
365 });
366 } else |err| {
367 return mod.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{});
368 }
369}
370
371fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst {
372 if (asm_node.outputs.len != 0) {
373 return mod.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{});
374 }
375 const arena = scope.arena();
376 const tree = scope.tree();
377
378 const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len);
379 const args = try arena.alloc(*zir.Inst, asm_node.inputs.len);
380
381 for (asm_node.inputs) |input, i| {
382 // TODO semantically analyze constraints
383 inputs[i] = try expr(mod, scope, input.constraint);
384 args[i] = try expr(mod, scope, input.expr);
385 }
386
387 const src = tree.token_locs[asm_node.asm_token].start;
388 const return_type = try mod.addZIRInstConst(scope, src, .{
389 .ty = Type.initTag(.type),
390 .val = Value.initTag(.void_type),
391 });
392 const asm_inst = try mod.addZIRInst(scope, src, zir.Inst.Asm, .{
393 .asm_source = try expr(mod, scope, asm_node.template),
394 .return_type = return_type,
395 }, .{
396 .@"volatile" = asm_node.volatile_token != null,
397 //.clobbers = TODO handle clobbers
398 .inputs = inputs,
399 .args = args,
400 });
401 return asm_inst;
402}
403
404fn builtinCall(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst {
405 const tree = scope.tree();
406 const builtin_name = tree.tokenSlice(call.builtin_token);
407 const src = tree.token_locs[call.builtin_token].start;
408
409 inline for (std.meta.declarations(zir.Inst)) |inst| {
410 if (inst.data != .Type) continue;
411 const T = inst.data.Type;
412 if (!@hasDecl(T, "builtin_name")) continue;
413 if (std.mem.eql(u8, builtin_name, T.builtin_name)) {
414 var value: T = undefined;
415 const positionals = @typeInfo(std.meta.fieldInfo(T, "positionals").field_type).Struct;
416 if (positionals.fields.len == 0) {
417 return mod.addZIRInst(scope, src, T, value.positionals, value.kw_args);
418 }
419 const arg_count: ?usize = if (positionals.fields[0].field_type == []*zir.Inst) null else positionals.fields.len;
420 if (arg_count) |some| {
421 if (call.params_len != some) {
422 return mod.failTok(
423 scope,
424 call.builtin_token,
425 "expected {} parameter{}, found {}",
426 .{ some, if (some == 1) "" else "s", call.params_len },
427 );
428 }
429 const params = call.params();
430 inline for (positionals.fields) |p, i| {
431 @field(value.positionals, p.name) = try expr(mod, scope, params[i]);
432 }
433 } else {
434 return mod.failTok(scope, call.builtin_token, "TODO var args builtin '{}'", .{builtin_name});
435 }
436
437 return mod.addZIRInst(scope, src, T, value.positionals, .{});
438 }
439 }
440 return mod.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name});
441}
442
443fn callExpr(mod: *Module, scope: *Scope, node: *ast.Node.Call) InnerError!*zir.Inst {
444 const tree = scope.tree();
445 const lhs = try expr(mod, scope, node.lhs);
446
447 const param_nodes = node.params();
448 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, param_nodes.len);
449 for (param_nodes) |param_node, i| {
450 args[i] = try expr(mod, scope, param_node);
451 }
452
453 const src = tree.token_locs[node.lhs.firstToken()].start;
454 return mod.addZIRInst(scope, src, zir.Inst.Call, .{
455 .func = lhs,
456 .args = args,
457 }, .{});
458}
459
460fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst {
461 const tree = scope.tree();
462 const src = tree.token_locs[unreach_node.token].start;
463 return mod.addZIRInst(scope, src, zir.Inst.Unreachable, .{}, .{});
464}
465
466fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
467 const simple_types = std.ComptimeStringMap(Value.Tag, .{
468 .{ "u8", .u8_type },
469 .{ "i8", .i8_type },
470 .{ "isize", .isize_type },
471 .{ "usize", .usize_type },
472 .{ "c_short", .c_short_type },
473 .{ "c_ushort", .c_ushort_type },
474 .{ "c_int", .c_int_type },
475 .{ "c_uint", .c_uint_type },
476 .{ "c_long", .c_long_type },
477 .{ "c_ulong", .c_ulong_type },
478 .{ "c_longlong", .c_longlong_type },
479 .{ "c_ulonglong", .c_ulonglong_type },
480 .{ "c_longdouble", .c_longdouble_type },
481 .{ "f16", .f16_type },
482 .{ "f32", .f32_type },
483 .{ "f64", .f64_type },
484 .{ "f128", .f128_type },
485 .{ "c_void", .c_void_type },
486 .{ "bool", .bool_type },
487 .{ "void", .void_type },
488 .{ "type", .type_type },
489 .{ "anyerror", .anyerror_type },
490 .{ "comptime_int", .comptime_int_type },
491 .{ "comptime_float", .comptime_float_type },
492 .{ "noreturn", .noreturn_type },
493 });
494 if (simple_types.get(name)) |tag| {
495 return TypedValue{
496 .ty = Type.initTag(.type),
497 .val = Value.initTag(tag),
498 };
499 }
500 if (mem.eql(u8, name, "null")) {
501 return TypedValue{
502 .ty = Type.initTag(.@"null"),
503 .val = Value.initTag(.null_value),
504 };
505 }
506 if (mem.eql(u8, name, "undefined")) {
507 return TypedValue{
508 .ty = Type.initTag(.@"undefined"),
509 .val = Value.initTag(.undef),
510 };
511 }
512 if (mem.eql(u8, name, "true")) {
513 return TypedValue{
514 .ty = Type.initTag(.bool),
515 .val = Value.initTag(.bool_true),
516 };
517 }
518 if (mem.eql(u8, name, "false")) {
519 return TypedValue{
520 .ty = Type.initTag(.bool),
521 .val = Value.initTag(.bool_false),
522 };
523 }
524 return null;
525}
526
527fn nodeNeedsMemoryLocation(node: *ast.Node) bool {
528 return switch (node.tag) {
529 .Root,
530 .Use,
531 .TestDecl,
532 .DocComment,
533 .SwitchCase,
534 .SwitchElse,
535 .Else,
536 .Payload,
537 .PointerPayload,
538 .PointerIndexPayload,
539 .ContainerField,
540 .ErrorTag,
541 .FieldInitializer,
542 => unreachable,
543
544 .ControlFlowExpression,
545 .BitNot,
546 .BoolNot,
547 .VarDecl,
548 .Defer,
549 .AddressOf,
550 .OptionalType,
551 .Negation,
552 .NegationWrap,
553 .Resume,
554 .ArrayType,
555 .ArrayTypeSentinel,
556 .PtrType,
557 .SliceType,
558 .Suspend,
559 .AnyType,
560 .ErrorType,
561 .FnProto,
562 .AnyFrameType,
563 .IntegerLiteral,
564 .FloatLiteral,
565 .EnumLiteral,
566 .StringLiteral,
567 .MultilineStringLiteral,
568 .CharLiteral,
569 .BoolLiteral,
570 .NullLiteral,
571 .UndefinedLiteral,
572 .Unreachable,
573 .Identifier,
574 .ErrorSetDecl,
575 .ContainerDecl,
576 .Asm,
577 .Add,
578 .AddWrap,
579 .ArrayCat,
580 .ArrayMult,
581 .Assign,
582 .AssignBitAnd,
583 .AssignBitOr,
584 .AssignBitShiftLeft,
585 .AssignBitShiftRight,
586 .AssignBitXor,
587 .AssignDiv,
588 .AssignSub,
589 .AssignSubWrap,
590 .AssignMod,
591 .AssignAdd,
592 .AssignAddWrap,
593 .AssignMul,
594 .AssignMulWrap,
595 .BangEqual,
596 .BitAnd,
597 .BitOr,
598 .BitShiftLeft,
599 .BitShiftRight,
600 .BitXor,
601 .BoolAnd,
602 .BoolOr,
603 .Div,
604 .EqualEqual,
605 .ErrorUnion,
606 .GreaterOrEqual,
607 .GreaterThan,
608 .LessOrEqual,
609 .LessThan,
610 .MergeErrorSets,
611 .Mod,
612 .Mul,
613 .MulWrap,
614 .Range,
615 .Period,
616 .Sub,
617 .SubWrap,
618 => false,
619
620 .ArrayInitializer,
621 .ArrayInitializerDot,
622 .StructInitializer,
623 .StructInitializerDot,
624 => true,
625
626 .GroupedExpression => nodeNeedsMemoryLocation(node.castTag(.GroupedExpression).?.expr),
627
628 .UnwrapOptional => @panic("TODO nodeNeedsMemoryLocation for UnwrapOptional"),
629 .Catch => @panic("TODO nodeNeedsMemoryLocation for Catch"),
630 .Await => @panic("TODO nodeNeedsMemoryLocation for Await"),
631 .Try => @panic("TODO nodeNeedsMemoryLocation for Try"),
632 .If => @panic("TODO nodeNeedsMemoryLocation for If"),
633 .SuffixOp => @panic("TODO nodeNeedsMemoryLocation for SuffixOp"),
634 .Call => @panic("TODO nodeNeedsMemoryLocation for Call"),
635 .Switch => @panic("TODO nodeNeedsMemoryLocation for Switch"),
636 .While => @panic("TODO nodeNeedsMemoryLocation for While"),
637 .For => @panic("TODO nodeNeedsMemoryLocation for For"),
638 .BuiltinCall => @panic("TODO nodeNeedsMemoryLocation for BuiltinCall"),
639 .Comptime => @panic("TODO nodeNeedsMemoryLocation for Comptime"),
640 .Nosuspend => @panic("TODO nodeNeedsMemoryLocation for Nosuspend"),
641 .Block => @panic("TODO nodeNeedsMemoryLocation for Block"),
642 };
643}
src-self-hosted/codegen.zig+5-1
......@@ -73,6 +73,7 @@ pub fn generateSymbol(
7373 .code = code,
7474 .err_msg = null,
7575 .args = mc_args,
76 .arg_index = 0,
7677 .branch_stack = &branch_stack,
7778 .src = src,
7879 };
......@@ -255,6 +256,7 @@ const Function = struct {
255256 code: *std.ArrayList(u8),
256257 err_msg: ?*ErrorMsg,
257258 args: []MCValue,
259 arg_index: usize,
258260 src: usize,
259261
260262 /// Whenever there is a runtime branch, we push a Branch onto this stack,
......@@ -603,7 +605,9 @@ const Function = struct {
603605 }
604606
605607 fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue {
606 return self.args[inst.args.index];
608 const i = self.arg_index;
609 self.arg_index += 1;
610 return self.args[i];
607611 }
608612
609613 fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue {
src-self-hosted/ir.zig+1-4
......@@ -101,10 +101,7 @@ pub const Inst = struct {
101101 pub const Arg = struct {
102102 pub const base_tag = Tag.arg;
103103 base: Inst,
104
105 args: struct {
106 index: usize,
107 },
104 args: void,
108105 };
109106
110107 pub const Assembly = struct {
src-self-hosted/translate_c.zig+117-71
......@@ -1103,11 +1103,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
11031103 const enum_ident = try transCreateNodeIdentifier(c, name);
11041104 const period_tok = try appendToken(c, .Period, ".");
11051105 const field_ident = try transCreateNodeIdentifier(c, field_name);
1106 const field_access_node = try c.arena.create(ast.Node.InfixOp);
1106 const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp);
11071107 field_access_node.* = .{
1108 .base = .{ .tag = .Period },
11081109 .op_token = period_tok,
11091110 .lhs = enum_ident,
1110 .op = .Period,
11111111 .rhs = field_ident,
11121112 };
11131113 cast_node.params()[0] = &field_access_node.base;
......@@ -1219,7 +1219,7 @@ fn transStmt(
12191219 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
12201220 .ParenExprClass => {
12211221 const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue);
1222 if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1222 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
12231223 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
12241224 node.* = .{
12251225 .lparen = try appendToken(rp.c, .LParen, "("),
......@@ -1264,7 +1264,7 @@ fn transStmt(
12641264 .OpaqueValueExprClass => {
12651265 const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?;
12661266 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);
1267 if (expr.id == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1267 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
12681268 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
12691269 node.* = .{
12701270 .lparen = try appendToken(rp.c, .LParen, "("),
......@@ -1294,7 +1294,7 @@ fn transBinaryOperator(
12941294 const op = ZigClangBinaryOperator_getOpcode(stmt);
12951295 const qt = ZigClangBinaryOperator_getType(stmt);
12961296 var op_token: ast.TokenIndex = undefined;
1297 var op_id: ast.Node.InfixOp.Op = undefined;
1297 var op_id: ast.Node.Tag = undefined;
12981298 switch (op) {
12991299 .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),
13001300 .Comma => {
......@@ -1693,7 +1693,7 @@ fn transBoolExpr(
16931693 var res = try transExpr(rp, scope, expr, used, lrvalue);
16941694
16951695 if (isBoolRes(res)) {
1696 if (!grouped and res.id == .GroupedExpression) {
1696 if (!grouped and res.tag == .GroupedExpression) {
16971697 const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res);
16981698 res = group.expr;
16991699 // get zig fmt to work properly
......@@ -1736,26 +1736,23 @@ fn exprIsStringLiteral(expr: *const ZigClangExpr) bool {
17361736}
17371737
17381738fn isBoolRes(res: *ast.Node) bool {
1739 switch (res.id) {
1740 .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
1741 .BoolOr,
1742 .BoolAnd,
1743 .EqualEqual,
1744 .BangEqual,
1745 .LessThan,
1746 .GreaterThan,
1747 .LessOrEqual,
1748 .GreaterOrEqual,
1749 => return true,
1739 switch (res.tag) {
1740 .BoolOr,
1741 .BoolAnd,
1742 .EqualEqual,
1743 .BangEqual,
1744 .LessThan,
1745 .GreaterThan,
1746 .LessOrEqual,
1747 .GreaterOrEqual,
1748 .BoolNot,
1749 .BoolLiteral,
1750 => return true,
17501751
1751 else => {},
1752 },
1753 .BoolNot => return true,
1754 .BoolLiteral => return true,
17551752 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
1756 else => {},
1753
1754 else => return false,
17571755 }
1758 return false;
17591756}
17601757
17611758fn finishBoolExpr(
......@@ -2312,11 +2309,11 @@ fn transInitListExprArray(
23122309 &filler_init_node.base
23132310 else blk: {
23142311 const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");
2315 const mul_node = try rp.c.arena.create(ast.Node.InfixOp);
2312 const mul_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
23162313 mul_node.* = .{
2314 .base = .{ .tag = .ArrayMult },
23172315 .op_token = mul_tok,
23182316 .lhs = &filler_init_node.base,
2319 .op = .ArrayMult,
23202317 .rhs = try transCreateNodeInt(rp.c, leftover_count),
23212318 };
23222319 break :blk &mul_node.base;
......@@ -2326,11 +2323,11 @@ fn transInitListExprArray(
23262323 return rhs_node;
23272324 }
23282325
2329 const cat_node = try rp.c.arena.create(ast.Node.InfixOp);
2326 const cat_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
23302327 cat_node.* = .{
2328 .base = .{ .tag = .ArrayCat },
23312329 .op_token = cat_tok,
23322330 .lhs = &init_node.base,
2333 .op = .ArrayCat,
23342331 .rhs = rhs_node,
23352332 };
23362333 return &cat_node.base;
......@@ -2723,11 +2720,11 @@ fn transCase(
27232720 const ellips = try appendToken(rp.c, .Ellipsis3, "...");
27242721 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
27252722
2726 const node = try rp.c.arena.create(ast.Node.InfixOp);
2723 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
27272724 node.* = .{
2725 .base = .{ .tag = .Range },
27282726 .op_token = ellips,
27292727 .lhs = lhs_node,
2730 .op = .Range,
27312728 .rhs = rhs_node,
27322729 };
27332730 break :blk &node.base;
......@@ -3153,7 +3150,7 @@ fn transCreatePreCrement(
31533150 rp: RestorePoint,
31543151 scope: *Scope,
31553152 stmt: *const ZigClangUnaryOperator,
3156 op: ast.Node.InfixOp.Op,
3153 op: ast.Node.Tag,
31573154 op_tok_id: std.zig.Token.Id,
31583155 bytes: []const u8,
31593156 used: ResultUsed,
......@@ -3227,7 +3224,7 @@ fn transCreatePostCrement(
32273224 rp: RestorePoint,
32283225 scope: *Scope,
32293226 stmt: *const ZigClangUnaryOperator,
3230 op: ast.Node.InfixOp.Op,
3227 op: ast.Node.Tag,
32313228 op_tok_id: std.zig.Token.Id,
32323229 bytes: []const u8,
32333230 used: ResultUsed,
......@@ -3349,10 +3346,10 @@ fn transCreateCompoundAssign(
33493346 rp: RestorePoint,
33503347 scope: *Scope,
33513348 stmt: *const ZigClangCompoundAssignOperator,
3352 assign_op: ast.Node.InfixOp.Op,
3349 assign_op: ast.Node.Tag,
33533350 assign_tok_id: std.zig.Token.Id,
33543351 assign_bytes: []const u8,
3355 bin_op: ast.Node.InfixOp.Op,
3352 bin_op: ast.Node.Tag,
33563353 bin_tok_id: std.zig.Token.Id,
33573354 bin_bytes: []const u8,
33583355 used: ResultUsed,
......@@ -3377,7 +3374,7 @@ fn transCreateCompoundAssign(
33773374 // zig: lhs += rhs
33783375 if ((is_mod or is_div) and is_signed) {
33793376 const op_token = try appendToken(rp.c, .Equal, "=");
3380 const op_node = try rp.c.arena.create(ast.Node.InfixOp);
3377 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
33813378 const builtin = if (is_mod) "@rem" else "@divTrunc";
33823379 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
33833380 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
......@@ -3386,9 +3383,9 @@ fn transCreateCompoundAssign(
33863383 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);
33873384 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
33883385 op_node.* = .{
3386 .base = .{ .tag = .Assign },
33893387 .op_token = op_token,
33903388 .lhs = lhs_node,
3391 .op = .Assign,
33923389 .rhs = &builtin_node.base,
33933390 };
33943391 _ = try appendToken(rp.c, .Semicolon, ";");
......@@ -3452,7 +3449,7 @@ fn transCreateCompoundAssign(
34523449
34533450 if ((is_mod or is_div) and is_signed) {
34543451 const op_token = try appendToken(rp.c, .Equal, "=");
3455 const op_node = try rp.c.arena.create(ast.Node.InfixOp);
3452 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
34563453 const builtin = if (is_mod) "@rem" else "@divTrunc";
34573454 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
34583455 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);
......@@ -3461,9 +3458,9 @@ fn transCreateCompoundAssign(
34613458 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
34623459 _ = try appendToken(rp.c, .Semicolon, ";");
34633460 op_node.* = .{
3461 .base = .{ .tag = .Assign },
34643462 .op_token = op_token,
34653463 .lhs = ref_node,
3466 .op = .Assign,
34673464 .rhs = &builtin_node.base,
34683465 };
34693466 _ = try appendToken(rp.c, .Semicolon, ";");
......@@ -3716,11 +3713,11 @@ fn maybeSuppressResult(
37163713 }
37173714 const lhs = try transCreateNodeIdentifier(rp.c, "_");
37183715 const op_token = try appendToken(rp.c, .Equal, "=");
3719 const op_node = try rp.c.arena.create(ast.Node.InfixOp);
3716 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
37203717 op_node.* = .{
3718 .base = .{ .tag = .Assign },
37213719 .op_token = op_token,
37223720 .lhs = lhs,
3723 .op = .Assign,
37243721 .rhs = result,
37253722 };
37263723 return &op_node.base;
......@@ -4095,11 +4092,11 @@ fn transCreateNodeAssign(
40954092}
40964093
40974094fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
4098 const field_access_node = try c.arena.create(ast.Node.InfixOp);
4095 const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp);
40994096 field_access_node.* = .{
4097 .base = .{ .tag = .Period },
41004098 .op_token = try appendToken(c, .Period, "."),
41014099 .lhs = container,
4102 .op = .Period,
41034100 .rhs = try transCreateNodeIdentifier(c, field_name),
41044101 };
41054102 return &field_access_node.base;
......@@ -4107,12 +4104,13 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c
41074104
41084105fn transCreateNodeSimplePrefixOp(
41094106 c: *Context,
4110 comptime tag: ast.Node.Id,
4107 comptime tag: ast.Node.Tag,
41114108 op_tok_id: std.zig.Token.Id,
41124109 bytes: []const u8,
4113) !*ast.Node.SimplePrefixOp(tag) {
4114 const node = try c.arena.create(ast.Node.SimplePrefixOp(tag));
4110) !*ast.Node.SimplePrefixOp {
4111 const node = try c.arena.create(ast.Node.SimplePrefixOp);
41154112 node.* = .{
4113 .base = .{ .tag = tag },
41164114 .op_token = try appendToken(c, op_tok_id, bytes),
41174115 .rhs = undefined, // translate and set afterward
41184116 };
......@@ -4123,7 +4121,7 @@ fn transCreateNodeInfixOp(
41234121 rp: RestorePoint,
41244122 scope: *Scope,
41254123 lhs_node: *ast.Node,
4126 op: ast.Node.InfixOp.Op,
4124 op: ast.Node.Tag,
41274125 op_token: ast.TokenIndex,
41284126 rhs_node: *ast.Node,
41294127 used: ResultUsed,
......@@ -4133,11 +4131,11 @@ fn transCreateNodeInfixOp(
41334131 try appendToken(rp.c, .LParen, "(")
41344132 else
41354133 null;
4136 const node = try rp.c.arena.create(ast.Node.InfixOp);
4134 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
41374135 node.* = .{
4136 .base = .{ .tag = op },
41384137 .op_token = op_token,
41394138 .lhs = lhs_node,
4140 .op = op,
41414139 .rhs = rhs_node,
41424140 };
41434141 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
......@@ -4155,7 +4153,7 @@ fn transCreateNodeBoolInfixOp(
41554153 rp: RestorePoint,
41564154 scope: *Scope,
41574155 stmt: *const ZigClangBinaryOperator,
4158 op: ast.Node.InfixOp.Op,
4156 op: ast.Node.Tag,
41594157 used: ResultUsed,
41604158 grouped: bool,
41614159) !*ast.Node {
......@@ -4535,7 +4533,7 @@ fn transCreateNodeShiftOp(
45354533 rp: RestorePoint,
45364534 scope: *Scope,
45374535 stmt: *const ZigClangBinaryOperator,
4538 op: ast.Node.InfixOp.Op,
4536 op: ast.Node.Tag,
45394537 op_tok_id: std.zig.Token.Id,
45404538 bytes: []const u8,
45414539) !*ast.Node {
......@@ -4557,11 +4555,11 @@ fn transCreateNodeShiftOp(
45574555 cast_node.params()[1] = rhs;
45584556 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
45594557
4560 const node = try rp.c.arena.create(ast.Node.InfixOp);
4558 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
45614559 node.* = .{
4560 .base = .{ .tag = op },
45624561 .op_token = op_token,
45634562 .lhs = lhs,
4564 .op = op,
45654563 .rhs = &cast_node.base,
45664564 };
45674565
......@@ -5338,10 +5336,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
53385336 .{@tagName(last.id)},
53395337 );
53405338 _ = try appendToken(c, .Semicolon, ";");
5341 const type_of_arg = if (expr.id != .Block) expr else blk: {
5339 const type_of_arg = if (expr.tag != .Block) expr else blk: {
53425340 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
53435341 const blk_last = blk.statements()[blk.statements_len - 1];
5344 std.debug.assert(blk_last.id == .ControlFlowExpression);
5342 std.debug.assert(blk_last.tag == .ControlFlowExpression);
53455343 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);
53465344 break :blk br.rhs.?;
53475345 };
......@@ -5403,11 +5401,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
54035401 // suppress result
54045402 const lhs = try transCreateNodeIdentifier(c, "_");
54055403 const op_token = try appendToken(c, .Equal, "=");
5406 const op_node = try c.arena.create(ast.Node.InfixOp);
5404 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
54075405 op_node.* = .{
5406 .base = .{ .tag = .Assign },
54085407 .op_token = op_token,
54095408 .lhs = lhs,
5410 .op = .Assign,
54115409 .rhs = last,
54125410 };
54135411 try block_scope.statements.append(&op_node.base);
......@@ -5786,9 +5784,60 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
57865784 }
57875785}
57885786
5787fn nodeIsInfixOp(tag: ast.Node.Tag) bool {
5788 return switch (tag) {
5789 .Add,
5790 .AddWrap,
5791 .ArrayCat,
5792 .ArrayMult,
5793 .Assign,
5794 .AssignBitAnd,
5795 .AssignBitOr,
5796 .AssignBitShiftLeft,
5797 .AssignBitShiftRight,
5798 .AssignBitXor,
5799 .AssignDiv,
5800 .AssignSub,
5801 .AssignSubWrap,
5802 .AssignMod,
5803 .AssignAdd,
5804 .AssignAddWrap,
5805 .AssignMul,
5806 .AssignMulWrap,
5807 .BangEqual,
5808 .BitAnd,
5809 .BitOr,
5810 .BitShiftLeft,
5811 .BitShiftRight,
5812 .BitXor,
5813 .BoolAnd,
5814 .BoolOr,
5815 .Div,
5816 .EqualEqual,
5817 .ErrorUnion,
5818 .GreaterOrEqual,
5819 .GreaterThan,
5820 .LessOrEqual,
5821 .LessThan,
5822 .MergeErrorSets,
5823 .Mod,
5824 .Mul,
5825 .MulWrap,
5826 .Period,
5827 .Range,
5828 .Sub,
5829 .SubWrap,
5830 .UnwrapOptional,
5831 .Catch,
5832 => true,
5833
5834 else => false,
5835 };
5836}
5837
57895838fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
57905839 if (!isBoolRes(node)) {
5791 if (node.id != .InfixOp) return node;
5840 if (!nodeIsInfixOp(node.tag)) return node;
57925841
57935842 const group_node = try c.arena.create(ast.Node.GroupedExpression);
57945843 group_node.* = .{
......@@ -5807,7 +5856,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
58075856
58085857fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
58095858 if (isBoolRes(node)) {
5810 if (node.id != .InfixOp) return node;
5859 if (!nodeIsInfixOp(node.tag)) return node;
58115860
58125861 const group_node = try c.arena.create(ast.Node.GroupedExpression);
58135862 group_node.* = .{
......@@ -5820,11 +5869,11 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
58205869
58215870 const op_token = try appendToken(c, .BangEqual, "!=");
58225871 const zero = try transCreateNodeInt(c, 0);
5823 const res = try c.arena.create(ast.Node.InfixOp);
5872 const res = try c.arena.create(ast.Node.SimpleInfixOp);
58245873 res.* = .{
5874 .base = .{ .tag = .BangEqual },
58255875 .op_token = op_token,
58265876 .lhs = node,
5827 .op = .BangEqual,
58285877 .rhs = zero,
58295878 };
58305879 const group_node = try c.arena.create(ast.Node.GroupedExpression);
......@@ -5841,7 +5890,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
58415890 while (true) {
58425891 const tok = it.next().?;
58435892 var op_token: ast.TokenIndex = undefined;
5844 var op_id: ast.Node.InfixOp.Op = undefined;
5893 var op_id: ast.Node.Tag = undefined;
58455894 var bool_op = false;
58465895 switch (tok.id) {
58475896 .Period => {
......@@ -6048,11 +6097,11 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
60486097 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
60496098 const lhs_node = try cast_fn(c, node);
60506099 const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
6051 const op_node = try c.arena.create(ast.Node.InfixOp);
6100 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
60526101 op_node.* = .{
6102 .base = .{ .tag = op_id },
60536103 .op_token = op_token,
60546104 .lhs = lhs_node,
6055 .op = op_id,
60566105 .rhs = try cast_fn(c, rhs_node),
60576106 };
60586107 node = &op_node.base;
......@@ -6105,7 +6154,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
61056154}
61066155
61076156fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6108 switch (node.id) {
6157 switch (node.tag) {
61096158 .ContainerDecl,
61106159 .AddressOf,
61116160 .Await,
......@@ -6130,10 +6179,9 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
61306179 }
61316180 },
61326181
6133 .InfixOp => {
6134 const infix = node.cast(ast.Node.InfixOp).?;
6135 if (infix.op != .Period)
6136 return null;
6182 .Period => {
6183 const infix = node.castTag(.Period).?;
6184
61376185 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
61386186 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
61396187 for (container.fieldsAndDecls()) |field_ref| {
......@@ -6160,9 +6208,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
61606208 return getContainer(c, ty);
61616209 }
61626210 }
6163 } else if (ref.cast(ast.Node.InfixOp)) |infix| {
6164 if (infix.op != .Period)
6165 return null;
6211 } else if (ref.castTag(.Period)) |infix| {
61666212 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
61676213 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
61686214 for (container.fieldsAndDecls()) |field_ref| {
......@@ -6182,7 +6228,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
61826228fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
61836229 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null;
61846230 if (getContainerTypeOf(c, init)) |ty_node| {
6185 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {
6231 if (ty_node.castTag(.OptionalType)) |prefix| {
61866232 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
61876233 return fn_proto;
61886234 }
src-self-hosted/zir.zig+8-7
......@@ -34,7 +34,8 @@ pub const Inst = struct {
3434
3535 /// These names are used directly as the instruction names in the text format.
3636 pub const Tag = enum {
37 /// Function parameter value.
37 /// Function parameter value. These must be first in a function's main block,
38 /// in respective order with the parameters.
3839 arg,
3940 /// A labeled block of code, which can return a value.
4041 block,
......@@ -184,9 +185,7 @@ pub const Inst = struct {
184185 pub const base_tag = Tag.arg;
185186 base: Inst,
186187
187 positionals: struct {
188 index: usize,
189 },
188 positionals: struct {},
190189 kw_args: struct {},
191190 };
192191
......@@ -1384,15 +1383,17 @@ const EmitZIR = struct {
13841383 for (src_decls.items) |ir_decl| {
13851384 switch (ir_decl.analysis) {
13861385 .unreferenced => continue,
1386
13871387 .complete => {},
1388 .codegen_failure => {}, // We still can emit the ZIR.
1389 .codegen_failure_retryable => {}, // We still can emit the ZIR.
1390
13881391 .in_progress => unreachable,
13891392 .outdated => unreachable,
13901393
13911394 .sema_failure,
13921395 .sema_failure_retryable,
1393 .codegen_failure,
13941396 .dependency_failure,
1395 .codegen_failure_retryable,
13961397 => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {
13971398 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
13981399 fail_inst.* = .{
......@@ -1728,7 +1729,7 @@ const EmitZIR = struct {
17281729 .src = inst.src,
17291730 .tag = Inst.Arg.base_tag,
17301731 },
1731 .positionals = .{ .index = old_inst.args.index },
1732 .positionals = .{},
17321733 .kw_args = .{},
17331734 };
17341735 break :blk &new_inst.base;