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) {...@@ -323,8 +323,8 @@ pub const Error = union(enum) {
323 node: *Node,323 node: *Node,
324324
325 pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: anytype) !void {325 pub fn render(self: *const ExpectedCall, tokens: []const Token.Id, stream: anytype) !void {
326 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ ", found {}", .{326 return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ ", found {}", .{
327 @tagName(self.node.id),327 @tagName(self.node.tag),
328 });328 });
329 }329 }
330 };330 };
...@@ -333,8 +333,8 @@ pub const Error = union(enum) {...@@ -333,8 +333,8 @@ pub const Error = union(enum) {
333 node: *Node,333 node: *Node,
334334
335 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: anytype) !void {335 pub fn render(self: *const ExpectedCallOrFnProto, tokens: []const Token.Id, stream: anytype) !void {
336 return stream.print("expected " ++ @tagName(Node.Id.Call) ++ " or " ++336 return stream.print("expected " ++ @tagName(Node.Tag.Call) ++ " or " ++
337 @tagName(Node.Id.FnProto) ++ ", found {}", .{@tagName(self.node.id)});337 @tagName(Node.Tag.FnProto) ++ ", found {}", .{@tagName(self.node.tag)});
338 }338 }
339 };339 };
340340
...@@ -396,9 +396,9 @@ pub const Error = union(enum) {...@@ -396,9 +396,9 @@ pub const Error = union(enum) {
396};396};
397397
398pub const Node = struct {398pub const Node = struct {
399 id: Id,399 tag: Tag,
400400
401 pub const Id = enum {401 pub const Tag = enum {
402 // Top level402 // Top level
403 Root,403 Root,
404 Use,404 Use,
...@@ -408,8 +408,54 @@ pub const Node = struct {...@@ -408,8 +408,54 @@ pub const Node = struct {
408 VarDecl,408 VarDecl,
409 Defer,409 Defer,
410410
411 // Operators411 // Infix operators
412 InfixOp,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
413 AddressOf,459 AddressOf,
414 Await,460 Await,
415 BitNot,461 BitNot,
...@@ -419,6 +465,7 @@ pub const Node = struct {...@@ -419,6 +465,7 @@ pub const Node = struct {
419 NegationWrap,465 NegationWrap,
420 Resume,466 Resume,
421 Try,467 Try,
468
422 ArrayType,469 ArrayType,
423 /// ArrayType but has a sentinel node.470 /// ArrayType but has a sentinel node.
424 ArrayTypeSentinel,471 ArrayTypeSentinel,
...@@ -484,49 +531,177 @@ pub const Node = struct {...@@ -484,49 +531,177 @@ pub const Node = struct {
484 ContainerField,531 ContainerField,
485 ErrorTag,532 ErrorTag,
486 FieldInitializer,533 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 }
487 };654 };
488655
656 /// Prefer `castTag` to this.
489 pub fn cast(base: *Node, comptime T: type) ?*T {657 pub fn cast(base: *Node, comptime T: type) ?*T {
490 if (base.id == comptime typeToId(T)) {658 if (std.meta.fieldInfo(T, "base").default_value) |default_base| {
491 return @fieldParentPtr(T, "base", 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);
492 }676 }
493 return null;677 return null;
494 }678 }
495679
496 pub fn iterate(base: *Node, index: usize) ?*Node {680 pub fn iterate(base: *Node, index: usize) ?*Node {
497 inline for (@typeInfo(Id).Enum.fields) |f| {681 inline for (@typeInfo(Tag).Enum.fields) |field| {
498 if (base.id == @field(Id, f.name)) {682 const tag = @intToEnum(Tag, field.value);
499 const T = @field(Node, f.name);683 if (base.tag == tag) {
500 return @fieldParentPtr(T, "base", base).iterate(index);684 return @fieldParentPtr(tag.Type(), "base", base).iterate(index);
501 }685 }
502 }686 }
503 unreachable;687 unreachable;
504 }688 }
505689
506 pub fn firstToken(base: *const Node) TokenIndex {690 pub fn firstToken(base: *const Node) TokenIndex {
507 inline for (@typeInfo(Id).Enum.fields) |f| {691 inline for (@typeInfo(Tag).Enum.fields) |field| {
508 if (base.id == @field(Id, f.name)) {692 const tag = @intToEnum(Tag, field.value);
509 const T = @field(Node, f.name);693 if (base.tag == tag) {
510 return @fieldParentPtr(T, "base", base).firstToken();694 return @fieldParentPtr(tag.Type(), "base", base).firstToken();
511 }695 }
512 }696 }
513 unreachable;697 unreachable;
514 }698 }
515699
516 pub fn lastToken(base: *const Node) TokenIndex {700 pub fn lastToken(base: *const Node) TokenIndex {
517 inline for (@typeInfo(Id).Enum.fields) |f| {701 inline for (@typeInfo(Tag).Enum.fields) |field| {
518 if (base.id == @field(Id, f.name)) {702 const tag = @intToEnum(Tag, field.value);
519 const T = @field(Node, f.name);703 if (base.tag == tag) {
520 return @fieldParentPtr(T, "base", base).lastToken();704 return @fieldParentPtr(tag.Type(), "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);
530 }705 }
531 }706 }
532 unreachable;707 unreachable;
...@@ -535,7 +710,7 @@ pub const Node = struct {...@@ -535,7 +710,7 @@ pub const Node = struct {
535 pub fn requireSemiColon(base: *const Node) bool {710 pub fn requireSemiColon(base: *const Node) bool {
536 var n = base;711 var n = base;
537 while (true) {712 while (true) {
538 switch (n.id) {713 switch (n.tag) {
539 .Root,714 .Root,
540 .ContainerField,715 .ContainerField,
541 .Block,716 .Block,
...@@ -556,7 +731,7 @@ pub const Node = struct {...@@ -556,7 +731,7 @@ pub const Node = struct {
556 continue;731 continue;
557 }732 }
558733
559 return while_node.body.id != .Block;734 return while_node.body.tag != .Block;
560 },735 },
561 .For => {736 .For => {
562 const for_node = @fieldParentPtr(For, "base", n);737 const for_node = @fieldParentPtr(For, "base", n);
...@@ -565,7 +740,7 @@ pub const Node = struct {...@@ -565,7 +740,7 @@ pub const Node = struct {
565 continue;740 continue;
566 }741 }
567742
568 return for_node.body.id != .Block;743 return for_node.body.tag != .Block;
569 },744 },
570 .If => {745 .If => {
571 const if_node = @fieldParentPtr(If, "base", n);746 const if_node = @fieldParentPtr(If, "base", n);
...@@ -574,7 +749,7 @@ pub const Node = struct {...@@ -574,7 +749,7 @@ pub const Node = struct {
574 continue;749 continue;
575 }750 }
576751
577 return if_node.body.id != .Block;752 return if_node.body.tag != .Block;
578 },753 },
579 .Else => {754 .Else => {
580 const else_node = @fieldParentPtr(Else, "base", n);755 const else_node = @fieldParentPtr(Else, "base", n);
...@@ -583,23 +758,23 @@ pub const Node = struct {...@@ -583,23 +758,23 @@ pub const Node = struct {
583 },758 },
584 .Defer => {759 .Defer => {
585 const defer_node = @fieldParentPtr(Defer, "base", n);760 const defer_node = @fieldParentPtr(Defer, "base", n);
586 return defer_node.expr.id != .Block;761 return defer_node.expr.tag != .Block;
587 },762 },
588 .Comptime => {763 .Comptime => {
589 const comptime_node = @fieldParentPtr(Comptime, "base", n);764 const comptime_node = @fieldParentPtr(Comptime, "base", n);
590 return comptime_node.expr.id != .Block;765 return comptime_node.expr.tag != .Block;
591 },766 },
592 .Suspend => {767 .Suspend => {
593 const suspend_node = @fieldParentPtr(Suspend, "base", n);768 const suspend_node = @fieldParentPtr(Suspend, "base", n);
594 if (suspend_node.body) |body| {769 if (suspend_node.body) |body| {
595 return body.id != .Block;770 return body.tag != .Block;
596 }771 }
597772
598 return true;773 return true;
599 },774 },
600 .Nosuspend => {775 .Nosuspend => {
601 const nosuspend_node = @fieldParentPtr(Nosuspend, "base", n);776 const nosuspend_node = @fieldParentPtr(Nosuspend, "base", n);
602 return nosuspend_node.expr.id != .Block;777 return nosuspend_node.expr.tag != .Block;
603 },778 },
604 else => return true,779 else => return true,
605 }780 }
...@@ -613,7 +788,7 @@ pub const Node = struct {...@@ -613,7 +788,7 @@ pub const Node = struct {
613 std.debug.warn(" ", .{});788 std.debug.warn(" ", .{});
614 }789 }
615 }790 }
616 std.debug.warn("{}\n", .{@tagName(self.id)});791 std.debug.warn("{}\n", .{@tagName(self.tag)});
617792
618 var child_i: usize = 0;793 var child_i: usize = 0;
619 while (self.iterate(child_i)) |child| : (child_i += 1) {794 while (self.iterate(child_i)) |child| : (child_i += 1) {
...@@ -623,7 +798,7 @@ pub const Node = struct {...@@ -623,7 +798,7 @@ pub const Node = struct {
623798
624 /// The decls data follows this struct in memory as an array of Node pointers.799 /// The decls data follows this struct in memory as an array of Node pointers.
625 pub const Root = struct {800 pub const Root = struct {
626 base: Node = Node{ .id = .Root },801 base: Node = Node{ .tag = .Root },
627 eof_token: TokenIndex,802 eof_token: TokenIndex,
628 decls_len: NodeIndex,803 decls_len: NodeIndex,
629804
...@@ -678,7 +853,7 @@ pub const Node = struct {...@@ -678,7 +853,7 @@ pub const Node = struct {
678 /// Trailed in memory by possibly many things, with each optional thing853 /// Trailed in memory by possibly many things, with each optional thing
679 /// determined by a bit in `trailer_flags`.854 /// determined by a bit in `trailer_flags`.
680 pub const VarDecl = struct {855 pub const VarDecl = struct {
681 base: Node = Node{ .id = .VarDecl },856 base: Node = Node{ .tag = .VarDecl },
682 trailer_flags: TrailerFlags,857 trailer_flags: TrailerFlags,
683 mut_token: TokenIndex,858 mut_token: TokenIndex,
684 name_token: TokenIndex,859 name_token: TokenIndex,
...@@ -779,7 +954,7 @@ pub const Node = struct {...@@ -779,7 +954,7 @@ pub const Node = struct {
779 };954 };
780955
781 pub const Use = struct {956 pub const Use = struct {
782 base: Node = Node{ .id = .Use },957 base: Node = Node{ .tag = .Use },
783 doc_comments: ?*DocComment,958 doc_comments: ?*DocComment,
784 visib_token: ?TokenIndex,959 visib_token: ?TokenIndex,
785 use_token: TokenIndex,960 use_token: TokenIndex,
...@@ -806,7 +981,7 @@ pub const Node = struct {...@@ -806,7 +981,7 @@ pub const Node = struct {
806 };981 };
807982
808 pub const ErrorSetDecl = struct {983 pub const ErrorSetDecl = struct {
809 base: Node = Node{ .id = .ErrorSetDecl },984 base: Node = Node{ .tag = .ErrorSetDecl },
810 error_token: TokenIndex,985 error_token: TokenIndex,
811 rbrace_token: TokenIndex,986 rbrace_token: TokenIndex,
812 decls_len: NodeIndex,987 decls_len: NodeIndex,
...@@ -856,7 +1031,7 @@ pub const Node = struct {...@@ -856,7 +1031,7 @@ pub const Node = struct {
8561031
857 /// The fields and decls Node pointers directly follow this struct in memory.1032 /// The fields and decls Node pointers directly follow this struct in memory.
858 pub const ContainerDecl = struct {1033 pub const ContainerDecl = struct {
859 base: Node = Node{ .id = .ContainerDecl },1034 base: Node = Node{ .tag = .ContainerDecl },
860 kind_token: TokenIndex,1035 kind_token: TokenIndex,
861 layout_token: ?TokenIndex,1036 layout_token: ?TokenIndex,
862 lbrace_token: TokenIndex,1037 lbrace_token: TokenIndex,
...@@ -925,7 +1100,7 @@ pub const Node = struct {...@@ -925,7 +1100,7 @@ pub const Node = struct {
925 };1100 };
9261101
927 pub const ContainerField = struct {1102 pub const ContainerField = struct {
928 base: Node = Node{ .id = .ContainerField },1103 base: Node = Node{ .tag = .ContainerField },
929 doc_comments: ?*DocComment,1104 doc_comments: ?*DocComment,
930 comptime_token: ?TokenIndex,1105 comptime_token: ?TokenIndex,
931 name_token: TokenIndex,1106 name_token: TokenIndex,
...@@ -976,7 +1151,7 @@ pub const Node = struct {...@@ -976,7 +1151,7 @@ pub const Node = struct {
976 };1151 };
9771152
978 pub const ErrorTag = struct {1153 pub const ErrorTag = struct {
979 base: Node = Node{ .id = .ErrorTag },1154 base: Node = Node{ .tag = .ErrorTag },
980 doc_comments: ?*DocComment,1155 doc_comments: ?*DocComment,
981 name_token: TokenIndex,1156 name_token: TokenIndex,
9821157
...@@ -1001,7 +1176,7 @@ pub const Node = struct {...@@ -1001,7 +1176,7 @@ pub const Node = struct {
1001 };1176 };
10021177
1003 pub const Identifier = struct {1178 pub const Identifier = struct {
1004 base: Node = Node{ .id = .Identifier },1179 base: Node = Node{ .tag = .Identifier },
1005 token: TokenIndex,1180 token: TokenIndex,
10061181
1007 pub fn iterate(self: *const Identifier, index: usize) ?*Node {1182 pub fn iterate(self: *const Identifier, index: usize) ?*Node {
...@@ -1020,7 +1195,7 @@ pub const Node = struct {...@@ -1020,7 +1195,7 @@ pub const Node = struct {
1020 /// The params are directly after the FnProto in memory.1195 /// The params are directly after the FnProto in memory.
1021 /// Next, each optional thing determined by a bit in `trailer_flags`.1196 /// Next, each optional thing determined by a bit in `trailer_flags`.
1022 pub const FnProto = struct {1197 pub const FnProto = struct {
1023 base: Node = Node{ .id = .FnProto },1198 base: Node = Node{ .tag = .FnProto },
1024 trailer_flags: TrailerFlags,1199 trailer_flags: TrailerFlags,
1025 fn_token: TokenIndex,1200 fn_token: TokenIndex,
1026 params_len: NodeIndex,1201 params_len: NodeIndex,
...@@ -1230,7 +1405,7 @@ pub const Node = struct {...@@ -1230,7 +1405,7 @@ pub const Node = struct {
1230 };1405 };
12311406
1232 pub const AnyFrameType = struct {1407 pub const AnyFrameType = struct {
1233 base: Node = Node{ .id = .AnyFrameType },1408 base: Node = Node{ .tag = .AnyFrameType },
1234 anyframe_token: TokenIndex,1409 anyframe_token: TokenIndex,
1235 result: ?Result,1410 result: ?Result,
12361411
...@@ -1262,7 +1437,7 @@ pub const Node = struct {...@@ -1262,7 +1437,7 @@ pub const Node = struct {
12621437
1263 /// The statements of the block follow Block directly in memory.1438 /// The statements of the block follow Block directly in memory.
1264 pub const Block = struct {1439 pub const Block = struct {
1265 base: Node = Node{ .id = .Block },1440 base: Node = Node{ .tag = .Block },
1266 statements_len: NodeIndex,1441 statements_len: NodeIndex,
1267 lbrace: TokenIndex,1442 lbrace: TokenIndex,
1268 rbrace: TokenIndex,1443 rbrace: TokenIndex,
...@@ -1316,7 +1491,7 @@ pub const Node = struct {...@@ -1316,7 +1491,7 @@ pub const Node = struct {
1316 };1491 };
13171492
1318 pub const Defer = struct {1493 pub const Defer = struct {
1319 base: Node = Node{ .id = .Defer },1494 base: Node = Node{ .tag = .Defer },
1320 defer_token: TokenIndex,1495 defer_token: TokenIndex,
1321 payload: ?*Node,1496 payload: ?*Node,
1322 expr: *Node,1497 expr: *Node,
...@@ -1340,7 +1515,7 @@ pub const Node = struct {...@@ -1340,7 +1515,7 @@ pub const Node = struct {
1340 };1515 };
13411516
1342 pub const Comptime = struct {1517 pub const Comptime = struct {
1343 base: Node = Node{ .id = .Comptime },1518 base: Node = Node{ .tag = .Comptime },
1344 doc_comments: ?*DocComment,1519 doc_comments: ?*DocComment,
1345 comptime_token: TokenIndex,1520 comptime_token: TokenIndex,
1346 expr: *Node,1521 expr: *Node,
...@@ -1364,7 +1539,7 @@ pub const Node = struct {...@@ -1364,7 +1539,7 @@ pub const Node = struct {
1364 };1539 };
13651540
1366 pub const Nosuspend = struct {1541 pub const Nosuspend = struct {
1367 base: Node = Node{ .id = .Nosuspend },1542 base: Node = Node{ .tag = .Nosuspend },
1368 nosuspend_token: TokenIndex,1543 nosuspend_token: TokenIndex,
1369 expr: *Node,1544 expr: *Node,
13701545
...@@ -1387,7 +1562,7 @@ pub const Node = struct {...@@ -1387,7 +1562,7 @@ pub const Node = struct {
1387 };1562 };
13881563
1389 pub const Payload = struct {1564 pub const Payload = struct {
1390 base: Node = Node{ .id = .Payload },1565 base: Node = Node{ .tag = .Payload },
1391 lpipe: TokenIndex,1566 lpipe: TokenIndex,
1392 error_symbol: *Node,1567 error_symbol: *Node,
1393 rpipe: TokenIndex,1568 rpipe: TokenIndex,
...@@ -1411,7 +1586,7 @@ pub const Node = struct {...@@ -1411,7 +1586,7 @@ pub const Node = struct {
1411 };1586 };
14121587
1413 pub const PointerPayload = struct {1588 pub const PointerPayload = struct {
1414 base: Node = Node{ .id = .PointerPayload },1589 base: Node = Node{ .tag = .PointerPayload },
1415 lpipe: TokenIndex,1590 lpipe: TokenIndex,
1416 ptr_token: ?TokenIndex,1591 ptr_token: ?TokenIndex,
1417 value_symbol: *Node,1592 value_symbol: *Node,
...@@ -1436,7 +1611,7 @@ pub const Node = struct {...@@ -1436,7 +1611,7 @@ pub const Node = struct {
1436 };1611 };
14371612
1438 pub const PointerIndexPayload = struct {1613 pub const PointerIndexPayload = struct {
1439 base: Node = Node{ .id = .PointerIndexPayload },1614 base: Node = Node{ .tag = .PointerIndexPayload },
1440 lpipe: TokenIndex,1615 lpipe: TokenIndex,
1441 ptr_token: ?TokenIndex,1616 ptr_token: ?TokenIndex,
1442 value_symbol: *Node,1617 value_symbol: *Node,
...@@ -1467,7 +1642,7 @@ pub const Node = struct {...@@ -1467,7 +1642,7 @@ pub const Node = struct {
1467 };1642 };
14681643
1469 pub const Else = struct {1644 pub const Else = struct {
1470 base: Node = Node{ .id = .Else },1645 base: Node = Node{ .tag = .Else },
1471 else_token: TokenIndex,1646 else_token: TokenIndex,
1472 payload: ?*Node,1647 payload: ?*Node,
1473 body: *Node,1648 body: *Node,
...@@ -1498,7 +1673,7 @@ pub const Node = struct {...@@ -1498,7 +1673,7 @@ pub const Node = struct {
1498 /// The cases node pointers are found in memory after Switch.1673 /// The cases node pointers are found in memory after Switch.
1499 /// They must be SwitchCase or SwitchElse nodes.1674 /// They must be SwitchCase or SwitchElse nodes.
1500 pub const Switch = struct {1675 pub const Switch = struct {
1501 base: Node = Node{ .id = .Switch },1676 base: Node = Node{ .tag = .Switch },
1502 switch_token: TokenIndex,1677 switch_token: TokenIndex,
1503 rbrace: TokenIndex,1678 rbrace: TokenIndex,
1504 cases_len: NodeIndex,1679 cases_len: NodeIndex,
...@@ -1552,7 +1727,7 @@ pub const Node = struct {...@@ -1552,7 +1727,7 @@ pub const Node = struct {
15521727
1553 /// Items sub-nodes appear in memory directly following SwitchCase.1728 /// Items sub-nodes appear in memory directly following SwitchCase.
1554 pub const SwitchCase = struct {1729 pub const SwitchCase = struct {
1555 base: Node = Node{ .id = .SwitchCase },1730 base: Node = Node{ .tag = .SwitchCase },
1556 arrow_token: TokenIndex,1731 arrow_token: TokenIndex,
1557 payload: ?*Node,1732 payload: ?*Node,
1558 expr: *Node,1733 expr: *Node,
...@@ -1610,7 +1785,7 @@ pub const Node = struct {...@@ -1610,7 +1785,7 @@ pub const Node = struct {
1610 };1785 };
16111786
1612 pub const SwitchElse = struct {1787 pub const SwitchElse = struct {
1613 base: Node = Node{ .id = .SwitchElse },1788 base: Node = Node{ .tag = .SwitchElse },
1614 token: TokenIndex,1789 token: TokenIndex,
16151790
1616 pub fn iterate(self: *const SwitchElse, index: usize) ?*Node {1791 pub fn iterate(self: *const SwitchElse, index: usize) ?*Node {
...@@ -1627,7 +1802,7 @@ pub const Node = struct {...@@ -1627,7 +1802,7 @@ pub const Node = struct {
1627 };1802 };
16281803
1629 pub const While = struct {1804 pub const While = struct {
1630 base: Node = Node{ .id = .While },1805 base: Node = Node{ .tag = .While },
1631 label: ?TokenIndex,1806 label: ?TokenIndex,
1632 inline_token: ?TokenIndex,1807 inline_token: ?TokenIndex,
1633 while_token: TokenIndex,1808 while_token: TokenIndex,
...@@ -1686,7 +1861,7 @@ pub const Node = struct {...@@ -1686,7 +1861,7 @@ pub const Node = struct {
1686 };1861 };
16871862
1688 pub const For = struct {1863 pub const For = struct {
1689 base: Node = Node{ .id = .For },1864 base: Node = Node{ .tag = .For },
1690 label: ?TokenIndex,1865 label: ?TokenIndex,
1691 inline_token: ?TokenIndex,1866 inline_token: ?TokenIndex,
1692 for_token: TokenIndex,1867 for_token: TokenIndex,
...@@ -1737,7 +1912,7 @@ pub const Node = struct {...@@ -1737,7 +1912,7 @@ pub const Node = struct {
1737 };1912 };
17381913
1739 pub const If = struct {1914 pub const If = struct {
1740 base: Node = Node{ .id = .If },1915 base: Node = Node{ .tag = .If },
1741 if_token: TokenIndex,1916 if_token: TokenIndex,
1742 condition: *Node,1917 condition: *Node,
1743 payload: ?*Node,1918 payload: ?*Node,
...@@ -1779,116 +1954,22 @@ pub const Node = struct {...@@ -1779,116 +1954,22 @@ pub const Node = struct {
1779 }1954 }
1780 };1955 };
17811956
1782 pub const InfixOp = struct {1957 pub const Catch = struct {
1783 base: Node = Node{ .id = .InfixOp },1958 base: Node = Node{ .tag = .Catch },
1784 op_token: TokenIndex,1959 op_token: TokenIndex,
1785 lhs: *Node,1960 lhs: *Node,
1786 op: Op,
1787 rhs: *Node,1961 rhs: *Node,
1962 payload: ?*Node,
17881963
1789 pub const Op = union(enum) {1964 pub fn iterate(self: *const Catch, index: usize) ?*Node {
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 {
1836 var i = index;1965 var i = index;
18371966
1838 if (i < 1) return self.lhs;1967 if (i < 1) return self.lhs;
1839 i -= 1;1968 i -= 1;
18401969
1841 switch (self.op) {1970 if (self.payload) |payload| {
1842 .Catch => |maybe_payload| {1971 if (i < 1) return payload;
1843 if (maybe_payload) |payload| {1972 i -= 1;
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 => {},
1892 }1973 }
18931974
1894 if (i < 1) return self.rhs;1975 if (i < 1) return self.rhs;
...@@ -1897,50 +1978,65 @@ pub const Node = struct {...@@ -1897,50 +1978,65 @@ pub const Node = struct {
1897 return null;1978 return null;
1898 }1979 }
18991980
1900 pub fn firstToken(self: *const InfixOp) TokenIndex {1981 pub fn firstToken(self: *const Catch) TokenIndex {
1901 return self.lhs.firstToken();1982 return self.lhs.firstToken();
1902 }1983 }
19031984
1904 pub fn lastToken(self: *const InfixOp) TokenIndex {1985 pub fn lastToken(self: *const Catch) TokenIndex {
1905 return self.rhs.lastToken();1986 return self.rhs.lastToken();
1906 }1987 }
1907 };1988 };
19081989
1909 pub const AddressOf = SimplePrefixOp(.AddressOf);1990 pub const SimpleInfixOp = struct {
1910 pub const Await = SimplePrefixOp(.Await);1991 base: Node,
1911 pub const BitNot = SimplePrefixOp(.BitNot);1992 op_token: TokenIndex,
1912 pub const BoolNot = SimplePrefixOp(.BoolNot);1993 lhs: *Node,
1913 pub const OptionalType = SimplePrefixOp(.OptionalType);1994 rhs: *Node,
1914 pub const Negation = SimplePrefixOp(.Negation);
1915 pub const NegationWrap = SimplePrefixOp(.NegationWrap);
1916 pub const Resume = SimplePrefixOp(.Resume);
1917 pub const Try = SimplePrefixOp(.Try);
19181995
1919 pub fn SimplePrefixOp(comptime tag: Id) type {1996 pub fn iterate(self: *const SimpleInfixOp, index: usize) ?*Node {
1920 return struct {1997 var i = index;
1921 base: Node = Node{ .id = tag },
1922 op_token: TokenIndex,
1923 rhs: *Node,
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 {2002 if (i < 1) return self.rhs;
1928 if (index == 0) return self.rhs;2003 i -= 1;
1929 return null;
1930 }
19312004
1932 pub fn firstToken(self: *const Self) TokenIndex {2005 return null;
1933 return self.op_token;2006 }
1934 }
19352007
1936 pub fn lastToken(self: *const Self) TokenIndex {2008 pub fn firstToken(self: *const SimpleInfixOp) TokenIndex {
1937 return self.rhs.lastToken();2009 return self.lhs.firstToken();
1938 }2010 }
1939 };2011
1940 }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
1942 pub const ArrayType = struct {2038 pub const ArrayType = struct {
1943 base: Node = Node{ .id = .ArrayType },2039 base: Node = Node{ .tag = .ArrayType },
1944 op_token: TokenIndex,2040 op_token: TokenIndex,
1945 rhs: *Node,2041 rhs: *Node,
1946 len_expr: *Node,2042 len_expr: *Node,
...@@ -1967,7 +2063,7 @@ pub const Node = struct {...@@ -1967,7 +2063,7 @@ pub const Node = struct {
1967 };2063 };
19682064
1969 pub const ArrayTypeSentinel = struct {2065 pub const ArrayTypeSentinel = struct {
1970 base: Node = Node{ .id = .ArrayTypeSentinel },2066 base: Node = Node{ .tag = .ArrayTypeSentinel },
1971 op_token: TokenIndex,2067 op_token: TokenIndex,
1972 rhs: *Node,2068 rhs: *Node,
1973 len_expr: *Node,2069 len_expr: *Node,
...@@ -1998,7 +2094,7 @@ pub const Node = struct {...@@ -1998,7 +2094,7 @@ pub const Node = struct {
1998 };2094 };
19992095
2000 pub const PtrType = struct {2096 pub const PtrType = struct {
2001 base: Node = Node{ .id = .PtrType },2097 base: Node = Node{ .tag = .PtrType },
2002 op_token: TokenIndex,2098 op_token: TokenIndex,
2003 rhs: *Node,2099 rhs: *Node,
2004 /// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents2100 /// 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 {...@@ -2034,7 +2130,7 @@ pub const Node = struct {
2034 };2130 };
20352131
2036 pub const SliceType = struct {2132 pub const SliceType = struct {
2037 base: Node = Node{ .id = .SliceType },2133 base: Node = Node{ .tag = .SliceType },
2038 op_token: TokenIndex,2134 op_token: TokenIndex,
2039 rhs: *Node,2135 rhs: *Node,
2040 /// TODO Add a u8 flags field to Node where it would otherwise be padding, and each bit represents2136 /// 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 {...@@ -2070,7 +2166,7 @@ pub const Node = struct {
2070 };2166 };
20712167
2072 pub const FieldInitializer = struct {2168 pub const FieldInitializer = struct {
2073 base: Node = Node{ .id = .FieldInitializer },2169 base: Node = Node{ .tag = .FieldInitializer },
2074 period_token: TokenIndex,2170 period_token: TokenIndex,
2075 name_token: TokenIndex,2171 name_token: TokenIndex,
2076 expr: *Node,2172 expr: *Node,
...@@ -2095,7 +2191,7 @@ pub const Node = struct {...@@ -2095,7 +2191,7 @@ pub const Node = struct {
20952191
2096 /// Elements occur directly in memory after ArrayInitializer.2192 /// Elements occur directly in memory after ArrayInitializer.
2097 pub const ArrayInitializer = struct {2193 pub const ArrayInitializer = struct {
2098 base: Node = Node{ .id = .ArrayInitializer },2194 base: Node = Node{ .tag = .ArrayInitializer },
2099 rtoken: TokenIndex,2195 rtoken: TokenIndex,
2100 list_len: NodeIndex,2196 list_len: NodeIndex,
2101 lhs: *Node,2197 lhs: *Node,
...@@ -2148,7 +2244,7 @@ pub const Node = struct {...@@ -2148,7 +2244,7 @@ pub const Node = struct {
21482244
2149 /// Elements occur directly in memory after ArrayInitializerDot.2245 /// Elements occur directly in memory after ArrayInitializerDot.
2150 pub const ArrayInitializerDot = struct {2246 pub const ArrayInitializerDot = struct {
2151 base: Node = Node{ .id = .ArrayInitializerDot },2247 base: Node = Node{ .tag = .ArrayInitializerDot },
2152 dot: TokenIndex,2248 dot: TokenIndex,
2153 rtoken: TokenIndex,2249 rtoken: TokenIndex,
2154 list_len: NodeIndex,2250 list_len: NodeIndex,
...@@ -2198,7 +2294,7 @@ pub const Node = struct {...@@ -2198,7 +2294,7 @@ pub const Node = struct {
21982294
2199 /// Elements occur directly in memory after StructInitializer.2295 /// Elements occur directly in memory after StructInitializer.
2200 pub const StructInitializer = struct {2296 pub const StructInitializer = struct {
2201 base: Node = Node{ .id = .StructInitializer },2297 base: Node = Node{ .tag = .StructInitializer },
2202 rtoken: TokenIndex,2298 rtoken: TokenIndex,
2203 list_len: NodeIndex,2299 list_len: NodeIndex,
2204 lhs: *Node,2300 lhs: *Node,
...@@ -2251,7 +2347,7 @@ pub const Node = struct {...@@ -2251,7 +2347,7 @@ pub const Node = struct {
22512347
2252 /// Elements occur directly in memory after StructInitializerDot.2348 /// Elements occur directly in memory after StructInitializerDot.
2253 pub const StructInitializerDot = struct {2349 pub const StructInitializerDot = struct {
2254 base: Node = Node{ .id = .StructInitializerDot },2350 base: Node = Node{ .tag = .StructInitializerDot },
2255 dot: TokenIndex,2351 dot: TokenIndex,
2256 rtoken: TokenIndex,2352 rtoken: TokenIndex,
2257 list_len: NodeIndex,2353 list_len: NodeIndex,
...@@ -2301,7 +2397,7 @@ pub const Node = struct {...@@ -2301,7 +2397,7 @@ pub const Node = struct {
23012397
2302 /// Parameter nodes directly follow Call in memory.2398 /// Parameter nodes directly follow Call in memory.
2303 pub const Call = struct {2399 pub const Call = struct {
2304 base: Node = Node{ .id = .Call },2400 base: Node = Node{ .tag = .Call },
2305 lhs: *Node,2401 lhs: *Node,
2306 rtoken: TokenIndex,2402 rtoken: TokenIndex,
2307 params_len: NodeIndex,2403 params_len: NodeIndex,
...@@ -2355,7 +2451,7 @@ pub const Node = struct {...@@ -2355,7 +2451,7 @@ pub const Node = struct {
2355 };2451 };
23562452
2357 pub const SuffixOp = struct {2453 pub const SuffixOp = struct {
2358 base: Node = Node{ .id = .SuffixOp },2454 base: Node = Node{ .tag = .SuffixOp },
2359 op: Op,2455 op: Op,
2360 lhs: *Node,2456 lhs: *Node,
2361 rtoken: TokenIndex,2457 rtoken: TokenIndex,
...@@ -2415,7 +2511,7 @@ pub const Node = struct {...@@ -2415,7 +2511,7 @@ pub const Node = struct {
2415 };2511 };
24162512
2417 pub const GroupedExpression = struct {2513 pub const GroupedExpression = struct {
2418 base: Node = Node{ .id = .GroupedExpression },2514 base: Node = Node{ .tag = .GroupedExpression },
2419 lparen: TokenIndex,2515 lparen: TokenIndex,
2420 expr: *Node,2516 expr: *Node,
2421 rparen: TokenIndex,2517 rparen: TokenIndex,
...@@ -2441,7 +2537,7 @@ pub const Node = struct {...@@ -2441,7 +2537,7 @@ pub const Node = struct {
2441 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.2537 /// TODO break this into separate Break, Continue, Return AST Nodes to save memory.
2442 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.2538 /// Could be further broken into LabeledBreak, LabeledContinue, and ReturnVoid to save even more.
2443 pub const ControlFlowExpression = struct {2539 pub const ControlFlowExpression = struct {
2444 base: Node = Node{ .id = .ControlFlowExpression },2540 base: Node = Node{ .tag = .ControlFlowExpression },
2445 ltoken: TokenIndex,2541 ltoken: TokenIndex,
2446 kind: Kind,2542 kind: Kind,
2447 rhs: ?*Node,2543 rhs: ?*Node,
...@@ -2496,7 +2592,7 @@ pub const Node = struct {...@@ -2496,7 +2592,7 @@ pub const Node = struct {
2496 };2592 };
24972593
2498 pub const Suspend = struct {2594 pub const Suspend = struct {
2499 base: Node = Node{ .id = .Suspend },2595 base: Node = Node{ .tag = .Suspend },
2500 suspend_token: TokenIndex,2596 suspend_token: TokenIndex,
2501 body: ?*Node,2597 body: ?*Node,
25022598
...@@ -2525,7 +2621,7 @@ pub const Node = struct {...@@ -2525,7 +2621,7 @@ pub const Node = struct {
2525 };2621 };
25262622
2527 pub const IntegerLiteral = struct {2623 pub const IntegerLiteral = struct {
2528 base: Node = Node{ .id = .IntegerLiteral },2624 base: Node = Node{ .tag = .IntegerLiteral },
2529 token: TokenIndex,2625 token: TokenIndex,
25302626
2531 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {2627 pub fn iterate(self: *const IntegerLiteral, index: usize) ?*Node {
...@@ -2542,7 +2638,7 @@ pub const Node = struct {...@@ -2542,7 +2638,7 @@ pub const Node = struct {
2542 };2638 };
25432639
2544 pub const EnumLiteral = struct {2640 pub const EnumLiteral = struct {
2545 base: Node = Node{ .id = .EnumLiteral },2641 base: Node = Node{ .tag = .EnumLiteral },
2546 dot: TokenIndex,2642 dot: TokenIndex,
2547 name: TokenIndex,2643 name: TokenIndex,
25482644
...@@ -2560,7 +2656,7 @@ pub const Node = struct {...@@ -2560,7 +2656,7 @@ pub const Node = struct {
2560 };2656 };
25612657
2562 pub const FloatLiteral = struct {2658 pub const FloatLiteral = struct {
2563 base: Node = Node{ .id = .FloatLiteral },2659 base: Node = Node{ .tag = .FloatLiteral },
2564 token: TokenIndex,2660 token: TokenIndex,
25652661
2566 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {2662 pub fn iterate(self: *const FloatLiteral, index: usize) ?*Node {
...@@ -2578,7 +2674,7 @@ pub const Node = struct {...@@ -2578,7 +2674,7 @@ pub const Node = struct {
25782674
2579 /// Parameters are in memory following BuiltinCall.2675 /// Parameters are in memory following BuiltinCall.
2580 pub const BuiltinCall = struct {2676 pub const BuiltinCall = struct {
2581 base: Node = Node{ .id = .BuiltinCall },2677 base: Node = Node{ .tag = .BuiltinCall },
2582 params_len: NodeIndex,2678 params_len: NodeIndex,
2583 builtin_token: TokenIndex,2679 builtin_token: TokenIndex,
2584 rparen_token: TokenIndex,2680 rparen_token: TokenIndex,
...@@ -2627,7 +2723,7 @@ pub const Node = struct {...@@ -2627,7 +2723,7 @@ pub const Node = struct {
2627 };2723 };
26282724
2629 pub const StringLiteral = struct {2725 pub const StringLiteral = struct {
2630 base: Node = Node{ .id = .StringLiteral },2726 base: Node = Node{ .tag = .StringLiteral },
2631 token: TokenIndex,2727 token: TokenIndex,
26322728
2633 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {2729 pub fn iterate(self: *const StringLiteral, index: usize) ?*Node {
...@@ -2645,7 +2741,7 @@ pub const Node = struct {...@@ -2645,7 +2741,7 @@ pub const Node = struct {
26452741
2646 /// The string literal tokens appear directly in memory after MultilineStringLiteral.2742 /// The string literal tokens appear directly in memory after MultilineStringLiteral.
2647 pub const MultilineStringLiteral = struct {2743 pub const MultilineStringLiteral = struct {
2648 base: Node = Node{ .id = .MultilineStringLiteral },2744 base: Node = Node{ .tag = .MultilineStringLiteral },
2649 lines_len: TokenIndex,2745 lines_len: TokenIndex,
26502746
2651 /// After this the caller must initialize the lines list.2747 /// After this the caller must initialize the lines list.
...@@ -2687,7 +2783,7 @@ pub const Node = struct {...@@ -2687,7 +2783,7 @@ pub const Node = struct {
2687 };2783 };
26882784
2689 pub const CharLiteral = struct {2785 pub const CharLiteral = struct {
2690 base: Node = Node{ .id = .CharLiteral },2786 base: Node = Node{ .tag = .CharLiteral },
2691 token: TokenIndex,2787 token: TokenIndex,
26922788
2693 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {2789 pub fn iterate(self: *const CharLiteral, index: usize) ?*Node {
...@@ -2704,7 +2800,7 @@ pub const Node = struct {...@@ -2704,7 +2800,7 @@ pub const Node = struct {
2704 };2800 };
27052801
2706 pub const BoolLiteral = struct {2802 pub const BoolLiteral = struct {
2707 base: Node = Node{ .id = .BoolLiteral },2803 base: Node = Node{ .tag = .BoolLiteral },
2708 token: TokenIndex,2804 token: TokenIndex,
27092805
2710 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {2806 pub fn iterate(self: *const BoolLiteral, index: usize) ?*Node {
...@@ -2721,7 +2817,7 @@ pub const Node = struct {...@@ -2721,7 +2817,7 @@ pub const Node = struct {
2721 };2817 };
27222818
2723 pub const NullLiteral = struct {2819 pub const NullLiteral = struct {
2724 base: Node = Node{ .id = .NullLiteral },2820 base: Node = Node{ .tag = .NullLiteral },
2725 token: TokenIndex,2821 token: TokenIndex,
27262822
2727 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {2823 pub fn iterate(self: *const NullLiteral, index: usize) ?*Node {
...@@ -2738,7 +2834,7 @@ pub const Node = struct {...@@ -2738,7 +2834,7 @@ pub const Node = struct {
2738 };2834 };
27392835
2740 pub const UndefinedLiteral = struct {2836 pub const UndefinedLiteral = struct {
2741 base: Node = Node{ .id = .UndefinedLiteral },2837 base: Node = Node{ .tag = .UndefinedLiteral },
2742 token: TokenIndex,2838 token: TokenIndex,
27432839
2744 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {2840 pub fn iterate(self: *const UndefinedLiteral, index: usize) ?*Node {
...@@ -2755,7 +2851,7 @@ pub const Node = struct {...@@ -2755,7 +2851,7 @@ pub const Node = struct {
2755 };2851 };
27562852
2757 pub const Asm = struct {2853 pub const Asm = struct {
2758 base: Node = Node{ .id = .Asm },2854 base: Node = Node{ .tag = .Asm },
2759 asm_token: TokenIndex,2855 asm_token: TokenIndex,
2760 rparen: TokenIndex,2856 rparen: TokenIndex,
2761 volatile_token: ?TokenIndex,2857 volatile_token: ?TokenIndex,
...@@ -2875,7 +2971,7 @@ pub const Node = struct {...@@ -2875,7 +2971,7 @@ pub const Node = struct {
2875 };2971 };
28762972
2877 pub const Unreachable = struct {2973 pub const Unreachable = struct {
2878 base: Node = Node{ .id = .Unreachable },2974 base: Node = Node{ .tag = .Unreachable },
2879 token: TokenIndex,2975 token: TokenIndex,
28802976
2881 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {2977 pub fn iterate(self: *const Unreachable, index: usize) ?*Node {
...@@ -2892,7 +2988,7 @@ pub const Node = struct {...@@ -2892,7 +2988,7 @@ pub const Node = struct {
2892 };2988 };
28932989
2894 pub const ErrorType = struct {2990 pub const ErrorType = struct {
2895 base: Node = Node{ .id = .ErrorType },2991 base: Node = Node{ .tag = .ErrorType },
2896 token: TokenIndex,2992 token: TokenIndex,
28972993
2898 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {2994 pub fn iterate(self: *const ErrorType, index: usize) ?*Node {
...@@ -2909,7 +3005,7 @@ pub const Node = struct {...@@ -2909,7 +3005,7 @@ pub const Node = struct {
2909 };3005 };
29103006
2911 pub const AnyType = struct {3007 pub const AnyType = struct {
2912 base: Node = Node{ .id = .AnyType },3008 base: Node = Node{ .tag = .AnyType },
2913 token: TokenIndex,3009 token: TokenIndex,
29143010
2915 pub fn iterate(self: *const AnyType, index: usize) ?*Node {3011 pub fn iterate(self: *const AnyType, index: usize) ?*Node {
...@@ -2929,7 +3025,7 @@ pub const Node = struct {...@@ -2929,7 +3025,7 @@ pub const Node = struct {
2929 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()3025 /// TODO actually maybe remove entirely in favor of iterating backward from Node.firstToken()
2930 /// and forwards to find same-line doc comments.3026 /// and forwards to find same-line doc comments.
2931 pub const DocComment = struct {3027 pub const DocComment = struct {
2932 base: Node = Node{ .id = .DocComment },3028 base: Node = Node{ .tag = .DocComment },
2933 /// Points to the first doc comment token. API users are expected to iterate over the3029 /// Points to the first doc comment token. API users are expected to iterate over the
2934 /// tokens array, looking for more doc comments, ignoring line comments, and stopping3030 /// tokens array, looking for more doc comments, ignoring line comments, and stopping
2935 /// at the first other token.3031 /// at the first other token.
...@@ -2951,7 +3047,7 @@ pub const Node = struct {...@@ -2951,7 +3047,7 @@ pub const Node = struct {
2951 };3047 };
29523048
2953 pub const TestDecl = struct {3049 pub const TestDecl = struct {
2954 base: Node = Node{ .id = .TestDecl },3050 base: Node = Node{ .tag = .TestDecl },
2955 doc_comments: ?*DocComment,3051 doc_comments: ?*DocComment,
2956 test_token: TokenIndex,3052 test_token: TokenIndex,
2957 name: *Node,3053 name: *Node,
...@@ -2996,7 +3092,7 @@ pub const PtrInfo = struct {...@@ -2996,7 +3092,7 @@ pub const PtrInfo = struct {
29963092
2997test "iterate" {3093test "iterate" {
2998 var root = Node.Root{3094 var root = Node.Root{
2999 .base = Node{ .id = Node.Id.Root },3095 .base = Node{ .tag = Node.Tag.Root },
3000 .decls_len = 0,3096 .decls_len = 0,
3001 .eof_token = 0,3097 .eof_token = 0,
3002 };3098 };
lib/std/zig/parse.zig+172-142
...@@ -1015,7 +1015,7 @@ const Parser = struct {...@@ -1015,7 +1015,7 @@ const Parser = struct {
1015 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*1015 /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)*
1016 fn parseBoolOrExpr(p: *Parser) !?*Node {1016 fn parseBoolOrExpr(p: *Parser) !?*Node {
1017 return p.parseBinOpExpr(1017 return p.parseBinOpExpr(
1018 SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr),1018 SimpleBinOpParseFn(.Keyword_or, .BoolOr),
1019 parseBoolAndExpr,1019 parseBoolAndExpr,
1020 .Infinitely,1020 .Infinitely,
1021 );1021 );
...@@ -1128,8 +1128,9 @@ const Parser = struct {...@@ -1128,8 +1128,9 @@ const Parser = struct {
1128 const expr_node = try p.expectNode(parseExpr, .{1128 const expr_node = try p.expectNode(parseExpr, .{
1129 .ExpectedExpr = .{ .token = p.tok_i },1129 .ExpectedExpr = .{ .token = p.tok_i },
1130 });1130 });
1131 const node = try p.arena.allocator.create(Node.Resume);1131 const node = try p.arena.allocator.create(Node.SimplePrefixOp);
1132 node.* = .{1132 node.* = .{
1133 .base = .{ .tag = .Resume },
1133 .op_token = token,1134 .op_token = token,
1134 .rhs = expr_node,1135 .rhs = expr_node,
1135 };1136 };
...@@ -1404,8 +1405,8 @@ const Parser = struct {...@@ -1404,8 +1405,8 @@ const Parser = struct {
1404 fn parseErrorUnionExpr(p: *Parser) !?*Node {1405 fn parseErrorUnionExpr(p: *Parser) !?*Node {
1405 const suffix_expr = (try p.parseSuffixExpr()) orelse return null;1406 const suffix_expr = (try p.parseSuffixExpr()) orelse return null;
14061407
1407 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(p)) |node| {1408 if (try SimpleBinOpParseFn(.Bang, .ErrorUnion)(p)) |node| {
1408 const error_union = node.cast(Node.InfixOp).?;1409 const error_union = node.castTag(.ErrorUnion).?;
1409 const type_expr = try p.expectNode(parseTypeExpr, .{1410 const type_expr = try p.expectNode(parseTypeExpr, .{
1410 .ExpectedTypeExpr = .{ .token = p.tok_i },1411 .ExpectedTypeExpr = .{ .token = p.tok_i },
1411 });1412 });
...@@ -1438,10 +1439,56 @@ const Parser = struct {...@@ -1438,10 +1439,56 @@ const Parser = struct {
1438 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },1439 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
1439 });1440 });
14401441
1442 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
1441 while (try p.parseSuffixOp()) |node| {1443 while (try p.parseSuffixOp()) |node| {
1442 switch (node.id) {1444 switch (node.tag) {
1443 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,1445 .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
1445 else => unreachable,1492 else => unreachable,
1446 }1493 }
1447 res = node;1494 res = node;
...@@ -1469,10 +1516,55 @@ const Parser = struct {...@@ -1469,10 +1516,55 @@ const Parser = struct {
1469 var res = expr;1516 var res = expr;
14701517
1471 while (true) {1518 while (true) {
1519 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
1472 if (try p.parseSuffixOp()) |node| {1520 if (try p.parseSuffixOp()) |node| {
1473 switch (node.id) {1521 switch (node.tag) {
1474 .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res,1522 .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,
1476 else => unreachable,1568 else => unreachable,
1477 }1569 }
1478 res = node;1570 res = node;
...@@ -1559,11 +1651,11 @@ const Parser = struct {...@@ -1559,11 +1651,11 @@ const Parser = struct {
1559 const global_error_set = try p.createLiteral(Node.ErrorType, token);1651 const global_error_set = try p.createLiteral(Node.ErrorType, token);
1560 if (period == null or identifier == null) return global_error_set;1652 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);
1563 node.* = .{1655 node.* = .{
1656 .base = Node{ .tag = .Period },
1564 .op_token = period.?,1657 .op_token = period.?,
1565 .lhs = global_error_set,1658 .lhs = global_error_set,
1566 .op = .Period,
1567 .rhs = identifier.?,1659 .rhs = identifier.?,
1568 };1660 };
1569 return &node.base;1661 return &node.base;
...@@ -1660,7 +1752,7 @@ const Parser = struct {...@@ -1660,7 +1752,7 @@ const Parser = struct {
1660 }1752 }
16611753
1662 if (try p.parseLoopTypeExpr()) |node| {1754 if (try p.parseLoopTypeExpr()) |node| {
1663 switch (node.id) {1755 switch (node.tag) {
1664 .For => node.cast(Node.For).?.label = label,1756 .For => node.cast(Node.For).?.label = label,
1665 .While => node.cast(Node.While).?.label = label,1757 .While => node.cast(Node.While).?.label = label,
1666 else => unreachable,1758 else => unreachable,
...@@ -2236,11 +2328,11 @@ const Parser = struct {...@@ -2236,11 +2328,11 @@ const Parser = struct {
2236 .ExpectedExpr = .{ .token = p.tok_i },2328 .ExpectedExpr = .{ .token = p.tok_i },
2237 });2329 });
22382330
2239 const node = try p.arena.allocator.create(Node.InfixOp);2331 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
2240 node.* = .{2332 node.* = .{
2333 .base = Node{ .tag = .Range },
2241 .op_token = token,2334 .op_token = token,
2242 .lhs = expr,2335 .lhs = expr,
2243 .op = .Range,
2244 .rhs = range_end,2336 .rhs = range_end,
2245 };2337 };
2246 return &node.base;2338 return &node.base;
...@@ -2265,7 +2357,7 @@ const Parser = struct {...@@ -2265,7 +2357,7 @@ const Parser = struct {
2265 /// / EQUAL2357 /// / EQUAL
2266 fn parseAssignOp(p: *Parser) !?*Node {2358 fn parseAssignOp(p: *Parser) !?*Node {
2267 const token = p.nextToken();2359 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]) {
2269 .AsteriskEqual => .AssignMul,2361 .AsteriskEqual => .AssignMul,
2270 .SlashEqual => .AssignDiv,2362 .SlashEqual => .AssignDiv,
2271 .PercentEqual => .AssignMod,2363 .PercentEqual => .AssignMod,
...@@ -2286,11 +2378,11 @@ const Parser = struct {...@@ -2286,11 +2378,11 @@ const Parser = struct {
2286 },2378 },
2287 };2379 };
22882380
2289 const node = try p.arena.allocator.create(Node.InfixOp);2381 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
2290 node.* = .{2382 node.* = .{
2383 .base = .{ .tag = op },
2291 .op_token = token,2384 .op_token = token,
2292 .lhs = undefined, // set by caller2385 .lhs = undefined, // set by caller
2293 .op = op,
2294 .rhs = undefined, // set by caller2386 .rhs = undefined, // set by caller
2295 };2387 };
2296 return &node.base;2388 return &node.base;
...@@ -2305,7 +2397,7 @@ const Parser = struct {...@@ -2305,7 +2397,7 @@ const Parser = struct {
2305 /// / RARROWEQUAL2397 /// / RARROWEQUAL
2306 fn parseCompareOp(p: *Parser) !?*Node {2398 fn parseCompareOp(p: *Parser) !?*Node {
2307 const token = p.nextToken();2399 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]) {
2309 .EqualEqual => .EqualEqual,2401 .EqualEqual => .EqualEqual,
2310 .BangEqual => .BangEqual,2402 .BangEqual => .BangEqual,
2311 .AngleBracketLeft => .LessThan,2403 .AngleBracketLeft => .LessThan,
...@@ -2329,12 +2421,22 @@ const Parser = struct {...@@ -2329,12 +2421,22 @@ const Parser = struct {
2329 /// / KEYWORD_catch Payload?2421 /// / KEYWORD_catch Payload?
2330 fn parseBitwiseOp(p: *Parser) !?*Node {2422 fn parseBitwiseOp(p: *Parser) !?*Node {
2331 const token = p.nextToken();2423 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]) {
2333 .Ampersand => .BitAnd,2425 .Ampersand => .BitAnd,
2334 .Caret => .BitXor,2426 .Caret => .BitXor,
2335 .Pipe => .BitOr,2427 .Pipe => .BitOr,
2336 .Keyword_orelse => .UnwrapOptional,2428 .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 },
2338 else => {2440 else => {
2339 p.putBackToken(token);2441 p.putBackToken(token);
2340 return null;2442 return null;
...@@ -2349,7 +2451,7 @@ const Parser = struct {...@@ -2349,7 +2451,7 @@ const Parser = struct {
2349 /// / RARROW22451 /// / RARROW2
2350 fn parseBitShiftOp(p: *Parser) !?*Node {2452 fn parseBitShiftOp(p: *Parser) !?*Node {
2351 const token = p.nextToken();2453 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]) {
2353 .AngleBracketAngleBracketLeft => .BitShiftLeft,2455 .AngleBracketAngleBracketLeft => .BitShiftLeft,
2354 .AngleBracketAngleBracketRight => .BitShiftRight,2456 .AngleBracketAngleBracketRight => .BitShiftRight,
2355 else => {2457 else => {
...@@ -2369,7 +2471,7 @@ const Parser = struct {...@@ -2369,7 +2471,7 @@ const Parser = struct {
2369 /// / MINUSPERCENT2471 /// / MINUSPERCENT
2370 fn parseAdditionOp(p: *Parser) !?*Node {2472 fn parseAdditionOp(p: *Parser) !?*Node {
2371 const token = p.nextToken();2473 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]) {
2373 .Plus => .Add,2475 .Plus => .Add,
2374 .Minus => .Sub,2476 .Minus => .Sub,
2375 .PlusPlus => .ArrayCat,2477 .PlusPlus => .ArrayCat,
...@@ -2393,7 +2495,7 @@ const Parser = struct {...@@ -2393,7 +2495,7 @@ const Parser = struct {
2393 /// / ASTERISKPERCENT2495 /// / ASTERISKPERCENT
2394 fn parseMultiplyOp(p: *Parser) !?*Node {2496 fn parseMultiplyOp(p: *Parser) !?*Node {
2395 const token = p.nextToken();2497 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]) {
2397 .PipePipe => .MergeErrorSets,2499 .PipePipe => .MergeErrorSets,
2398 .Asterisk => .Mul,2500 .Asterisk => .Mul,
2399 .Slash => .Div,2501 .Slash => .Div,
...@@ -2434,9 +2536,10 @@ const Parser = struct {...@@ -2434,9 +2536,10 @@ const Parser = struct {
2434 }2536 }
2435 }2537 }
24362538
2437 fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Id, token: TokenIndex) !?*Node {2539 fn allocSimplePrefixOp(p: *Parser, comptime tag: Node.Tag, token: TokenIndex) !?*Node {
2438 const node = try p.arena.allocator.create(Node.SimplePrefixOp(tag));2540 const node = try p.arena.allocator.create(Node.SimplePrefixOp);
2439 node.* = .{2541 node.* = .{
2542 .base = .{ .tag = tag },
2440 .op_token = token,2543 .op_token = token,
2441 .rhs = undefined, // set by caller2544 .rhs = undefined, // set by caller
2442 };2545 };
...@@ -2457,8 +2560,9 @@ const Parser = struct {...@@ -2457,8 +2560,9 @@ const Parser = struct {
2457 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*2560 /// / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
2458 fn parsePrefixTypeOp(p: *Parser) !?*Node {2561 fn parsePrefixTypeOp(p: *Parser) !?*Node {
2459 if (p.eatToken(.QuestionMark)) |token| {2562 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);
2461 node.* = .{2564 node.* = .{
2565 .base = .{ .tag = .OptionalType },
2462 .op_token = token,2566 .op_token = token,
2463 .rhs = undefined, // set by caller2567 .rhs = undefined, // set by caller
2464 };2568 };
...@@ -2670,14 +2774,14 @@ const Parser = struct {...@@ -2670,14 +2774,14 @@ const Parser = struct {
26702774
2671 if (p.eatToken(.Period)) |period| {2775 if (p.eatToken(.Period)) |period| {
2672 if (try p.parseIdentifier()) |identifier| {2776 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.
2674 // Should there be an Node.SuffixOp.FieldAccess variant? Or should2778 // Should there be an Node.SuffixOp.FieldAccess variant? Or should
2675 // this grammar rule be altered?2779 // 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);
2677 node.* = .{2781 node.* = .{
2782 .base = Node{ .tag = .Period },
2678 .op_token = period,2783 .op_token = period,
2679 .lhs = undefined, // set by caller2784 .lhs = undefined, // set by caller
2680 .op = .Period,
2681 .rhs = identifier,2785 .rhs = identifier,
2682 };2786 };
2683 return &node.base;2787 return &node.base;
...@@ -2984,7 +3088,7 @@ const Parser = struct {...@@ -2984,7 +3088,7 @@ const Parser = struct {
2984 }.parse;3088 }.parse;
2985 }3089 }
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 {
2988 return struct {3092 return struct {
2989 pub fn parse(p: *Parser) Error!?*Node {3093 pub fn parse(p: *Parser) Error!?*Node {
2990 const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {3094 const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) {
...@@ -2998,11 +3102,11 @@ const Parser = struct {...@@ -2998,11 +3102,11 @@ const Parser = struct {
2998 else => return null,3102 else => return null,
2999 } else p.eatToken(token) orelse return null;3103 } 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);
3002 node.* = .{3106 node.* = .{
3107 .base = .{ .tag = op },
3003 .op_token = op_token,3108 .op_token = op_token,
3004 .lhs = undefined, // set by caller3109 .lhs = undefined, // set by caller
3005 .op = op,
3006 .rhs = undefined, // set by caller3110 .rhs = undefined, // set by caller
3007 };3111 };
3008 return &node.base;3112 return &node.base;
...@@ -3072,7 +3176,6 @@ const Parser = struct {...@@ -3072,7 +3176,6 @@ const Parser = struct {
3072 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {3176 fn createLiteral(p: *Parser, comptime T: type, token: TokenIndex) !*Node {
3073 const result = try p.arena.allocator.create(T);3177 const result = try p.arena.allocator.create(T);
3074 result.* = T{3178 result.* = T{
3075 .base = Node{ .id = Node.typeToId(T) },
3076 .token = token,3179 .token = token,
3077 };3180 };
3078 return &result.base;3181 return &result.base;
...@@ -3148,8 +3251,9 @@ const Parser = struct {...@@ -3148,8 +3251,9 @@ const Parser = struct {
31483251
3149 fn parseTry(p: *Parser) !?*Node {3252 fn parseTry(p: *Parser) !?*Node {
3150 const token = p.eatToken(.Keyword_try) orelse return null;3253 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);
3152 node.* = .{3255 node.* = .{
3256 .base = .{ .tag = .Try },
3153 .op_token = token,3257 .op_token = token,
3154 .rhs = undefined, // set by caller3258 .rhs = undefined, // set by caller
3155 };3259 };
...@@ -3213,58 +3317,19 @@ const Parser = struct {...@@ -3213,58 +3317,19 @@ const Parser = struct {
3213 if (try opParseFn(p)) |first_op| {3317 if (try opParseFn(p)) |first_op| {
3214 var rightmost_op = first_op;3318 var rightmost_op = first_op;
3215 while (true) {3319 while (true) {
3216 switch (rightmost_op.id) {3320 switch (rightmost_op.tag) {
3217 .AddressOf => {3321 .AddressOf,
3218 if (try opParseFn(p)) |rhs| {3322 .Await,
3219 rightmost_op.cast(Node.AddressOf).?.rhs = rhs;3323 .BitNot,
3220 rightmost_op = rhs;3324 .BoolNot,
3221 } else break;3325 .OptionalType,
3222 },3326 .Negation,
3223 .Await => {3327 .NegationWrap,
3224 if (try opParseFn(p)) |rhs| {3328 .Resume,
3225 rightmost_op.cast(Node.Await).?.rhs = rhs;3329 .Try,
3226 rightmost_op = rhs;3330 => {
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 => {
3248 if (try opParseFn(p)) |rhs| {3331 if (try opParseFn(p)) |rhs| {
3249 rightmost_op.cast(Node.Negation).?.rhs = rhs;3332 rightmost_op.cast(Node.SimplePrefixOp).?.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;
3268 rightmost_op = rhs;3333 rightmost_op = rhs;
3269 } else break;3334 } else break;
3270 },3335 },
...@@ -3310,57 +3375,18 @@ const Parser = struct {...@@ -3310,57 +3375,18 @@ const Parser = struct {
3310 }3375 }
33113376
3312 // If any prefix op existed, a child node on the RHS is required3377 // If any prefix op existed, a child node on the RHS is required
3313 switch (rightmost_op.id) {3378 switch (rightmost_op.tag) {
3314 .AddressOf => {3379 .AddressOf,
3315 const prefix_op = rightmost_op.cast(Node.AddressOf).?;3380 .Await,
3316 prefix_op.rhs = try p.expectNode(childParseFn, .{3381 .BitNot,
3317 .InvalidToken = .{ .token = p.tok_i },3382 .BoolNot,
3318 });3383 .OptionalType,
3319 },3384 .Negation,
3320 .Await => {3385 .NegationWrap,
3321 const prefix_op = rightmost_op.cast(Node.Await).?;3386 .Resume,
3322 prefix_op.rhs = try p.expectNode(childParseFn, .{3387 .Try,
3323 .InvalidToken = .{ .token = p.tok_i },3388 => {
3324 });3389 const prefix_op = rightmost_op.cast(Node.SimplePrefixOp).?;
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).?;
3364 prefix_op.rhs = try p.expectNode(childParseFn, .{3390 prefix_op.rhs = try p.expectNode(childParseFn, .{
3365 .InvalidToken = .{ .token = p.tok_i },3391 .InvalidToken = .{ .token = p.tok_i },
3366 });3392 });
...@@ -3425,9 +3451,13 @@ const Parser = struct {...@@ -3425,9 +3451,13 @@ const Parser = struct {
3425 const left = res;3451 const left = res;
3426 res = node;3452 res = node;
34273453
3428 const op = node.cast(Node.InfixOp).?;3454 if (node.castTag(.Catch)) |op| {
3429 op.*.lhs = left;3455 op.lhs = left;
3430 op.*.rhs = right;3456 op.rhs = right;
3457 } else if (node.cast(Node.SimpleInfixOp)) |op| {
3458 op.lhs = left;
3459 op.rhs = right;
3460 }
34313461
3432 switch (chain) {3462 switch (chain) {
3433 .Once => break,3463 .Once => break,
...@@ -3438,12 +3468,12 @@ const Parser = struct {...@@ -3438,12 +3468,12 @@ const Parser = struct {
3438 return res;3468 return res;
3439 }3469 }
34403470
3441 fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node {3471 fn createInfixOp(p: *Parser, op_token: TokenIndex, tag: Node.Tag) !*Node {
3442 const node = try p.arena.allocator.create(Node.InfixOp);3472 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
3443 node.* = .{3473 node.* = .{
3444 .op_token = index,3474 .base = Node{ .tag = tag },
3475 .op_token = op_token,
3445 .lhs = undefined, // set by caller3476 .lhs = undefined, // set by caller
3446 .op = op,
3447 .rhs = undefined, // set by caller3477 .rhs = undefined, // set by caller
3448 };3478 };
3449 return &node.base;3479 return &node.base;
lib/std/zig/render.zig+150-72
...@@ -223,7 +223,7 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tre...@@ -223,7 +223,7 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tre
223}223}
224224
225fn renderContainerDecl(allocator: *mem.Allocator, stream: anytype, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Error || Error)!void {225fn 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) {
227 .FnProto => {227 .FnProto => {
228 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);228 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
229229
...@@ -365,7 +365,7 @@ fn renderExpression(...@@ -365,7 +365,7 @@ fn renderExpression(
365 base: *ast.Node,365 base: *ast.Node,
366 space: Space,366 space: Space,
367) (@TypeOf(stream).Error || Error)!void {367) (@TypeOf(stream).Error || Error)!void {
368 switch (base.id) {368 switch (base.tag) {
369 .Identifier => {369 .Identifier => {
370 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);370 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
371 return renderToken(tree, stream, identifier.token, indent, start_col, space);371 return renderToken(tree, stream, identifier.token, indent, start_col, space);
...@@ -436,13 +436,10 @@ fn renderExpression(...@@ -436,13 +436,10 @@ fn renderExpression(
436 }436 }
437 },437 },
438438
439 .InfixOp => {439 .Catch => {
440 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);440 const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base);
441441
442 const op_space = switch (infix_op_node.op) {442 const op_space = Space.Space;
443 ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion, ast.Node.InfixOp.Op.Range => Space.None,
444 else => Space.Space,
445 };
446 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);443 try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space);
447444
448 const after_op_space = blk: {445 const after_op_space = blk: {
...@@ -458,60 +455,99 @@ fn renderExpression(...@@ -458,60 +455,99 @@ fn renderExpression(
458 start_col.* = indent + indent_delta;455 start_col.* = indent + indent_delta;
459 }456 }
460457
461 switch (infix_op_node.op) {458 if (infix_op_node.payload) |payload| {
462 ast.Node.InfixOp.Op.Catch => |maybe_payload| if (maybe_payload) |payload| {459 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
463 try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space);
464 },
465 else => {},
466 }460 }
467461
468 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);462 return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space);
469 },463 },
470464
471 .BitNot => {465 .Add,
472 const bit_not = @fieldParentPtr(ast.Node.BitNot, "base", base);466 .AddWrap,
473 try renderToken(tree, stream, bit_not.op_token, indent, start_col, Space.None);467 .ArrayCat,
474 return renderExpression(allocator, stream, tree, indent, start_col, bit_not.rhs, space);468 .ArrayMult,
475 },469 .Assign,
476 .BoolNot => {470 .AssignBitAnd,
477 const bool_not = @fieldParentPtr(ast.Node.BoolNot, "base", base);471 .AssignBitOr,
478 try renderToken(tree, stream, bool_not.op_token, indent, start_col, Space.None);472 .AssignBitShiftLeft,
479 return renderExpression(allocator, stream, tree, indent, start_col, bool_not.rhs, space);473 .AssignBitShiftRight,
480 },474 .AssignBitXor,
481 .Negation => {475 .AssignDiv,
482 const negation = @fieldParentPtr(ast.Node.Negation, "base", base);476 .AssignSub,
483 try renderToken(tree, stream, negation.op_token, indent, start_col, Space.None);477 .AssignSubWrap,
484 return renderExpression(allocator, stream, tree, indent, start_col, negation.rhs, space);478 .AssignMod,
485 },479 .AssignAdd,
486 .NegationWrap => {480 .AssignAddWrap,
487 const negation_wrap = @fieldParentPtr(ast.Node.NegationWrap, "base", base);481 .AssignMul,
488 try renderToken(tree, stream, negation_wrap.op_token, indent, start_col, Space.None);482 .AssignMulWrap,
489 return renderExpression(allocator, stream, tree, indent, start_col, negation_wrap.rhs, space);483 .BangEqual,
490 },484 .BitAnd,
491 .OptionalType => {485 .BitOr,
492 const opt_type = @fieldParentPtr(ast.Node.OptionalType, "base", base);486 .BitShiftLeft,
493 try renderToken(tree, stream, opt_type.op_token, indent, start_col, Space.None);487 .BitShiftRight,
494 return renderExpression(allocator, stream, tree, indent, start_col, opt_type.rhs, space);488 .BitXor,
495 },489 .BoolAnd,
496 .AddressOf => {490 .BoolOr,
497 const addr_of = @fieldParentPtr(ast.Node.AddressOf, "base", base);491 .Div,
498 try renderToken(tree, stream, addr_of.op_token, indent, start_col, Space.None);492 .EqualEqual,
499 return renderExpression(allocator, stream, tree, indent, start_col, addr_of.rhs, space);493 .ErrorUnion,
500 },494 .GreaterOrEqual,
501 .Try => {495 .GreaterThan,
502 const try_node = @fieldParentPtr(ast.Node.Try, "base", base);496 .LessOrEqual,
503 try renderToken(tree, stream, try_node.op_token, indent, start_col, Space.Space);497 .LessThan,
504 return renderExpression(allocator, stream, tree, indent, start_col, try_node.rhs, space);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);
505 },530 },
506 .Resume => {531
507 const resume_node = @fieldParentPtr(ast.Node.Resume, "base", base);532 .BitNot,
508 try renderToken(tree, stream, resume_node.op_token, indent, start_col, Space.Space);533 .BoolNot,
509 return renderExpression(allocator, stream, tree, indent, start_col, resume_node.rhs, space);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);
510 },542 },
511 .Await => {543
512 const await_node = @fieldParentPtr(ast.Node.Await, "base", base);544 .Try,
513 try renderToken(tree, stream, await_node.op_token, indent, start_col, Space.Space);545 .Resume,
514 return renderExpression(allocator, stream, tree, indent, start_col, await_node.rhs, space);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);
515 },551 },
516552
517 .ArrayType => {553 .ArrayType => {
...@@ -659,7 +695,7 @@ fn renderExpression(...@@ -659,7 +695,7 @@ fn renderExpression(
659 .ArrayInitializer, .ArrayInitializerDot => {695 .ArrayInitializer, .ArrayInitializerDot => {
660 var rtoken: ast.TokenIndex = undefined;696 var rtoken: ast.TokenIndex = undefined;
661 var exprs: []*ast.Node = undefined;697 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) {
663 .ArrayInitializerDot => blk: {699 .ArrayInitializerDot => blk: {
664 const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);700 const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base);
665 rtoken = casted.rtoken;701 rtoken = casted.rtoken;
...@@ -793,14 +829,14 @@ fn renderExpression(...@@ -793,14 +829,14 @@ fn renderExpression(
793 }829 }
794830
795 try renderExtraNewline(tree, stream, start_col, next_expr);831 try renderExtraNewline(tree, stream, start_col, next_expr);
796 if (next_expr.id != .MultilineStringLiteral) {832 if (next_expr.tag != .MultilineStringLiteral) {
797 try stream.writeByteNTimes(' ', new_indent);833 try stream.writeByteNTimes(' ', new_indent);
798 }834 }
799 } else {835 } else {
800 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // ,836 try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // ,
801 }837 }
802 }838 }
803 if (exprs[exprs.len - 1].id != .MultilineStringLiteral) {839 if (exprs[exprs.len - 1].tag != .MultilineStringLiteral) {
804 try stream.writeByteNTimes(' ', indent);840 try stream.writeByteNTimes(' ', indent);
805 }841 }
806 return renderToken(tree, stream, rtoken, indent, start_col, space);842 return renderToken(tree, stream, rtoken, indent, start_col, space);
...@@ -823,7 +859,7 @@ fn renderExpression(...@@ -823,7 +859,7 @@ fn renderExpression(
823 .StructInitializer, .StructInitializerDot => {859 .StructInitializer, .StructInitializerDot => {
824 var rtoken: ast.TokenIndex = undefined;860 var rtoken: ast.TokenIndex = undefined;
825 var field_inits: []*ast.Node = undefined;861 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) {
827 .StructInitializerDot => blk: {863 .StructInitializerDot => blk: {
828 const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);864 const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);
829 rtoken = casted.rtoken;865 rtoken = casted.rtoken;
...@@ -877,7 +913,7 @@ fn renderExpression(...@@ -877,7 +913,7 @@ fn renderExpression(
877 if (field_inits.len == 1) blk: {913 if (field_inits.len == 1) blk: {
878 const field_init = field_inits[0].cast(ast.Node.FieldInitializer).?;914 const field_init = field_inits[0].cast(ast.Node.FieldInitializer).?;
879915
880 switch (field_init.expr.id) {916 switch (field_init.expr.tag) {
881 .StructInitializer,917 .StructInitializer,
882 .StructInitializerDot,918 .StructInitializerDot,
883 => break :blk,919 => break :blk,
...@@ -974,7 +1010,7 @@ fn renderExpression(...@@ -974,7 +1010,7 @@ fn renderExpression(
9741010
975 const params = call.params();1011 const params = call.params();
976 for (params) |param_node, i| {1012 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: {
978 break :blk indent;1014 break :blk indent;
979 } else blk: {1015 } else blk: {
980 try stream.writeByteNTimes(' ', new_indent);1016 try stream.writeByteNTimes(' ', new_indent);
...@@ -1284,7 +1320,7 @@ fn renderExpression(...@@ -1284,7 +1320,7 @@ fn renderExpression(
1284 // declarations inside are fields1320 // declarations inside are fields
1285 const src_has_only_fields = blk: {1321 const src_has_only_fields = blk: {
1286 for (fields_and_decls) |decl| {1322 for (fields_and_decls) |decl| {
1287 if (decl.id != .ContainerField) break :blk false;1323 if (decl.tag != .ContainerField) break :blk false;
1288 }1324 }
1289 break :blk true;1325 break :blk true;
1290 };1326 };
...@@ -1831,7 +1867,7 @@ fn renderExpression(...@@ -1831,7 +1867,7 @@ fn renderExpression(
18311867
1832 const rparen = tree.nextToken(for_node.array_expr.lastToken());1868 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;
1835 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());1871 const src_one_line_to_body = !body_is_block and tree.tokensOnSameLine(rparen, for_node.body.firstToken());
1836 const body_on_same_line = body_is_block or src_one_line_to_body;1872 const body_on_same_line = body_is_block or src_one_line_to_body;
18371873
...@@ -1874,7 +1910,7 @@ fn renderExpression(...@@ -1874,7 +1910,7 @@ fn renderExpression(
18741910
1875 try renderExpression(allocator, stream, tree, indent, start_col, if_node.condition, Space.None); // condition1911 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;
1878 const body_is_block = nodeIsBlock(if_node.body);1914 const body_is_block = nodeIsBlock(if_node.body);
18791915
1880 if (body_is_if_block) {1916 if (body_is_if_block) {
...@@ -1978,7 +2014,7 @@ fn renderExpression(...@@ -1978,7 +2014,7 @@ fn renderExpression(
19782014
1979 const indent_once = indent + indent_delta;2015 const indent_once = indent + indent_delta;
19802016
1981 if (asm_node.template.id == .MultilineStringLiteral) {2017 if (asm_node.template.tag == .MultilineStringLiteral) {
1982 // After rendering a multiline string literal the cursor is2018 // After rendering a multiline string literal the cursor is
1983 // already offset by indent2019 // already offset by indent
1984 try stream.writeByteNTimes(' ', indent_delta);2020 try stream.writeByteNTimes(' ', indent_delta);
...@@ -2245,7 +2281,7 @@ fn renderVarDecl(...@@ -2245,7 +2281,7 @@ fn renderVarDecl(
2245 }2281 }
22462282
2247 if (var_decl.getTrailer("init_node")) |init_node| {2283 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;
2249 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =2285 try renderToken(tree, stream, var_decl.getTrailer("eq_token").?, indent, start_col, s); // =
2250 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);2286 try renderExpression(allocator, stream, tree, indent, start_col, init_node, Space.None);
2251 }2287 }
...@@ -2287,7 +2323,7 @@ fn renderStatement(...@@ -2287,7 +2323,7 @@ fn renderStatement(
2287 start_col: *usize,2323 start_col: *usize,
2288 base: *ast.Node,2324 base: *ast.Node,
2289) (@TypeOf(stream).Error || Error)!void {2325) (@TypeOf(stream).Error || Error)!void {
2290 switch (base.id) {2326 switch (base.tag) {
2291 .VarDecl => {2327 .VarDecl => {
2292 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);2328 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
2293 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);2329 try renderVarDecl(allocator, stream, tree, indent, start_col, var_decl);
...@@ -2566,7 +2602,7 @@ fn renderDocCommentsToken(...@@ -2566,7 +2602,7 @@ fn renderDocCommentsToken(
2566}2602}
25672603
2568fn nodeIsBlock(base: *const ast.Node) bool {2604fn nodeIsBlock(base: *const ast.Node) bool {
2569 return switch (base.id) {2605 return switch (base.tag) {
2570 .Block,2606 .Block,
2571 .If,2607 .If,
2572 .For,2608 .For,
...@@ -2578,10 +2614,52 @@ fn nodeIsBlock(base: *const ast.Node) bool {...@@ -2578,10 +2614,52 @@ fn nodeIsBlock(base: *const ast.Node) bool {
2578}2614}
25792615
2580fn nodeCausesSliceOpSpace(base: *ast.Node) bool {2616fn nodeCausesSliceOpSpace(base: *ast.Node) bool {
2581 const infix_op = base.cast(ast.Node.InfixOp) orelse return false;2617 return switch (base.tag) {
2582 return switch (infix_op.op) {2618 .Catch,
2583 ast.Node.InfixOp.Op.Period => false,2619 .Add,
2584 else => true,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,
2585 };2663 };
2586}2664}
25872665
src-self-hosted/Module.zig+87-480
...@@ -19,6 +19,7 @@ const Body = ir.Body;...@@ -19,6 +19,7 @@ const Body = ir.Body;
19const ast = std.zig.ast;19const ast = std.zig.ast;
20const trace = @import("tracy.zig").trace;20const trace = @import("tracy.zig").trace;
21const liveness = @import("liveness.zig");21const liveness = @import("liveness.zig");
22const astgen = @import("astgen.zig");
2223
23/// General-purpose allocator. Used for both temporary and long-term storage.24/// General-purpose allocator. Used for both temporary and long-term storage.
24gpa: *Allocator,25gpa: *Allocator,
...@@ -76,6 +77,8 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},...@@ -76,6 +77,8 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
7677
77keep_source_files_loaded: bool,78keep_source_files_loaded: bool,
7879
80pub const InnerError = error{ OutOfMemory, AnalysisFail };
81
79const WorkItem = union(enum) {82const WorkItem = union(enum) {
80 /// Write the machine code for a Decl to the output file.83 /// Write the machine code for a Decl to the output file.
81 codegen_decl: *Decl,84 codegen_decl: *Decl,
...@@ -209,6 +212,7 @@ pub const Decl = struct {...@@ -209,6 +212,7 @@ pub const Decl = struct {
209 },212 },
210 .block => unreachable,213 .block => unreachable,
211 .gen_zir => unreachable,214 .gen_zir => unreachable,
215 .local_var => unreachable,
212 .decl => unreachable,216 .decl => unreachable,
213 }217 }
214 }218 }
...@@ -304,6 +308,7 @@ pub const Scope = struct {...@@ -304,6 +308,7 @@ pub const Scope = struct {
304 .block => return self.cast(Block).?.arena,308 .block => return self.cast(Block).?.arena,
305 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,309 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
306 .gen_zir => return self.cast(GenZIR).?.arena,310 .gen_zir => return self.cast(GenZIR).?.arena,
311 .local_var => return self.cast(LocalVar).?.gen_zir.arena,
307 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,312 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
308 .file => unreachable,313 .file => unreachable,
309 }314 }
...@@ -315,6 +320,7 @@ pub const Scope = struct {...@@ -315,6 +320,7 @@ pub const Scope = struct {
315 return switch (self.tag) {320 return switch (self.tag) {
316 .block => self.cast(Block).?.decl,321 .block => self.cast(Block).?.decl,
317 .gen_zir => self.cast(GenZIR).?.decl,322 .gen_zir => self.cast(GenZIR).?.decl,
323 .local_var => return self.cast(LocalVar).?.gen_zir.decl,
318 .decl => self.cast(DeclAnalysis).?.decl,324 .decl => self.cast(DeclAnalysis).?.decl,
319 .zir_module => null,325 .zir_module => null,
320 .file => null,326 .file => null,
...@@ -327,6 +333,7 @@ pub const Scope = struct {...@@ -327,6 +333,7 @@ pub const Scope = struct {
327 switch (self.tag) {333 switch (self.tag) {
328 .block => return self.cast(Block).?.decl.scope,334 .block => return self.cast(Block).?.decl.scope,
329 .gen_zir => return self.cast(GenZIR).?.decl.scope,335 .gen_zir => return self.cast(GenZIR).?.decl.scope,
336 .local_var => return self.cast(LocalVar).?.gen_zir.decl.scope,
330 .decl => return self.cast(DeclAnalysis).?.decl.scope,337 .decl => return self.cast(DeclAnalysis).?.decl.scope,
331 .zir_module, .file => return self,338 .zir_module, .file => return self,
332 }339 }
...@@ -339,6 +346,7 @@ pub const Scope = struct {...@@ -339,6 +346,7 @@ pub const Scope = struct {
339 switch (self.tag) {346 switch (self.tag) {
340 .block => unreachable,347 .block => unreachable,
341 .gen_zir => unreachable,348 .gen_zir => unreachable,
349 .local_var => unreachable,
342 .decl => unreachable,350 .decl => unreachable,
343 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),351 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
344 .file => return self.cast(File).?.fullyQualifiedNameHash(name),352 .file => return self.cast(File).?.fullyQualifiedNameHash(name),
...@@ -353,9 +361,22 @@ pub const Scope = struct {...@@ -353,9 +361,22 @@ pub const Scope = struct {
353 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,361 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree,
354 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,362 .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree,
355 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(File).?.contents.tree,363 .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,
356 }365 }
357 }366 }
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
359 pub fn dumpInst(self: *Scope, inst: *Inst) void {380 pub fn dumpInst(self: *Scope, inst: *Inst) void {
360 const zir_module = self.namespace();381 const zir_module = self.namespace();
361 const loc = std.zig.findLineColumn(zir_module.source.bytes, inst.src);382 const loc = std.zig.findLineColumn(zir_module.source.bytes, inst.src);
...@@ -376,6 +397,7 @@ pub const Scope = struct {...@@ -376,6 +397,7 @@ pub const Scope = struct {
376 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,397 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
377 .block => unreachable,398 .block => unreachable,
378 .gen_zir => unreachable,399 .gen_zir => unreachable,
400 .local_var => unreachable,
379 .decl => unreachable,401 .decl => unreachable,
380 }402 }
381 }403 }
...@@ -386,6 +408,7 @@ pub const Scope = struct {...@@ -386,6 +408,7 @@ pub const Scope = struct {
386 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),408 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
387 .block => unreachable,409 .block => unreachable,
388 .gen_zir => unreachable,410 .gen_zir => unreachable,
411 .local_var => unreachable,
389 .decl => unreachable,412 .decl => unreachable,
390 }413 }
391 }414 }
...@@ -395,6 +418,7 @@ pub const Scope = struct {...@@ -395,6 +418,7 @@ pub const Scope = struct {
395 .file => return @fieldParentPtr(File, "base", base).getSource(module),418 .file => return @fieldParentPtr(File, "base", base).getSource(module),
396 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),419 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
397 .gen_zir => unreachable,420 .gen_zir => unreachable,
421 .local_var => unreachable,
398 .block => unreachable,422 .block => unreachable,
399 .decl => unreachable,423 .decl => unreachable,
400 }424 }
...@@ -407,6 +431,7 @@ pub const Scope = struct {...@@ -407,6 +431,7 @@ pub const Scope = struct {
407 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),431 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
408 .block => unreachable,432 .block => unreachable,
409 .gen_zir => unreachable,433 .gen_zir => unreachable,
434 .local_var => unreachable,
410 .decl => unreachable,435 .decl => unreachable,
411 }436 }
412 }437 }
...@@ -426,6 +451,7 @@ pub const Scope = struct {...@@ -426,6 +451,7 @@ pub const Scope = struct {
426 },451 },
427 .block => unreachable,452 .block => unreachable,
428 .gen_zir => unreachable,453 .gen_zir => unreachable,
454 .local_var => unreachable,
429 .decl => unreachable,455 .decl => unreachable,
430 }456 }
431 }457 }
...@@ -446,6 +472,7 @@ pub const Scope = struct {...@@ -446,6 +472,7 @@ pub const Scope = struct {
446 block,472 block,
447 decl,473 decl,
448 gen_zir,474 gen_zir,
475 local_var,
449 };476 };
450477
451 pub const File = struct {478 pub const File = struct {
...@@ -673,10 +700,25 @@ pub const Scope = struct {...@@ -673,10 +700,25 @@ pub const Scope = struct {
673 pub const GenZIR = struct {700 pub const GenZIR = struct {
674 pub const base_tag: Tag = .gen_zir;701 pub const base_tag: Tag = .gen_zir;
675 base: Scope = Scope{ .tag = base_tag },702 base: Scope = Scope{ .tag = base_tag },
703 /// Parents can be: `GenZIR`, `ZIRModule`, `File`
704 parent: *Scope,
676 decl: *Decl,705 decl: *Decl,
677 arena: *Allocator,706 arena: *Allocator,
707 /// The first N instructions in a function body ZIR are arg instructions.
678 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},708 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
679 };709 };
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 };
680};722};
681723
682pub const AllErrors = struct {724pub const AllErrors = struct {
...@@ -944,8 +986,6 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {...@@ -944,8 +986,6 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
944 };986 };
945}987}
946988
947const InnerError = error{ OutOfMemory, AnalysisFail };
948
949pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {989pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
950 while (self.work_queue.readItem()) |work_item| switch (work_item) {990 while (self.work_queue.readItem()) |work_item| switch (work_item) {
951 .codegen_decl => |decl| switch (decl.analysis) {991 .codegen_decl => |decl| switch (decl.analysis) {
...@@ -1113,7 +1153,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1113,7 +1153,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1113 const file_scope = decl.scope.cast(Scope.File).?;1153 const file_scope = decl.scope.cast(Scope.File).?;
1114 const tree = try self.getAstTree(file_scope);1154 const tree = try self.getAstTree(file_scope);
1115 const ast_node = tree.root_node.decls()[decl.src_index];1155 const ast_node = tree.root_node.decls()[decl.src_index];
1116 switch (ast_node.id) {1156 switch (ast_node.tag) {
1117 .FnProto => {1157 .FnProto => {
1118 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);1158 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
11191159
...@@ -1127,6 +1167,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1127,6 +1167,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1127 var fn_type_scope: Scope.GenZIR = .{1167 var fn_type_scope: Scope.GenZIR = .{
1128 .decl = decl,1168 .decl = decl,
1129 .arena = &fn_type_scope_arena.allocator,1169 .arena = &fn_type_scope_arena.allocator,
1170 .parent = decl.scope,
1130 };1171 };
1131 defer fn_type_scope.instructions.deinit(self.gpa);1172 defer fn_type_scope.instructions.deinit(self.gpa);
11321173
...@@ -1140,7 +1181,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1140,7 +1181,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1140 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),1181 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
1141 .type_expr => |node| node,1182 .type_expr => |node| node,
1142 };1183 };
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);
1144 }1185 }
1145 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {1186 if (fn_proto.getTrailer("var_args_token")) |var_args_token| {
1146 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});1187 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 {...@@ -1168,7 +1209,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1168 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),1209 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
1169 };1210 };
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);
1172 const fn_src = tree.token_locs[fn_proto.fn_token].start;1213 const fn_src = tree.token_locs[fn_proto.fn_token].start;
1173 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{1214 const fn_type_inst = try self.addZIRInst(&fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1174 .return_type = return_type_inst,1215 .return_type = return_type_inst,
...@@ -1204,12 +1245,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1204,12 +1245,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1204 var gen_scope: Scope.GenZIR = .{1245 var gen_scope: Scope.GenZIR = .{
1205 .decl = decl,1246 .decl = decl,
1206 .arena = &gen_scope_arena.allocator,1247 .arena = &gen_scope_arena.allocator,
1248 .parent = decl.scope,
1207 };1249 };
1208 defer gen_scope.instructions.deinit(self.gpa);1250 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
1210 const body_block = body_node.cast(ast.Node.Block).?;1271 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
1214 if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or1275 if (!fn_type.fnReturnType().isNoReturn() and (gen_scope.instructions.items.len == 0 or
1215 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()))1276 !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...@@ -1298,465 +1359,6 @@ fn analyzeBodyValueAsType(self: *Module, block_scope: *Scope.Block, body: zir.Mo
1298 unreachable;1359 unreachable;
1299}1360}
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
1760fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {1362fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
1761 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);1363 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);
1762 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);1364 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);
...@@ -2368,7 +1970,7 @@ fn newZIRInst(...@@ -2368,7 +1970,7 @@ fn newZIRInst(
2368 return inst;1970 return inst;
2369}1971}
23701972
2371fn addZIRInstSpecial(1973pub fn addZIRInstSpecial(
2372 self: *Module,1974 self: *Module,
2373 scope: *Scope,1975 scope: *Scope,
2374 src: usize,1976 src: usize,
...@@ -2376,14 +1978,14 @@ fn addZIRInstSpecial(...@@ -2376,14 +1978,14 @@ fn addZIRInstSpecial(
2376 positionals: std.meta.fieldInfo(T, "positionals").field_type,1978 positionals: std.meta.fieldInfo(T, "positionals").field_type,
2377 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,1979 kw_args: std.meta.fieldInfo(T, "kw_args").field_type,
2378) !*T {1980) !*T {
2379 const gen_zir = scope.cast(Scope.GenZIR).?;1981 const gen_zir = scope.getGenZIR();
2380 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);1982 try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1);
2381 const inst = try newZIRInst(gen_zir.arena, src, T, positionals, kw_args);1983 const inst = try newZIRInst(gen_zir.arena, src, T, positionals, kw_args);
2382 gen_zir.instructions.appendAssumeCapacity(&inst.base);1984 gen_zir.instructions.appendAssumeCapacity(&inst.base);
2383 return inst;1985 return inst;
2384}1986}
23851987
2386fn addZIRInst(1988pub fn addZIRInst(
2387 self: *Module,1989 self: *Module,
2388 scope: *Scope,1990 scope: *Scope,
2389 src: usize,1991 src: usize,
...@@ -2396,13 +1998,13 @@ fn addZIRInst(...@@ -2396,13 +1998,13 @@ fn addZIRInst(
2396}1998}
23971999
2398/// TODO The existence of this function is a workaround for a bug in stage1.2000/// 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 {
2400 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;2002 const P = std.meta.fieldInfo(zir.Inst.Const, "positionals").field_type;
2401 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});2003 return self.addZIRInst(scope, src, zir.Inst.Const, P{ .typed_value = typed_value }, .{});
2402}2004}
24032005
2404/// TODO The existence of this function is a workaround for a bug in stage1.2006/// 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 {
2406 const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type;2008 const P = std.meta.fieldInfo(zir.Inst.Block, "positionals").field_type;
2407 return self.addZIRInstSpecial(scope, src, zir.Inst.Block, P{ .body = body }, .{});2009 return self.addZIRInstSpecial(scope, src, zir.Inst.Block, P{ .body = body }, .{});
2408}2010}
...@@ -2637,7 +2239,7 @@ fn getNextAnonNameIndex(self: *Module) usize {...@@ -2637,7 +2239,7 @@ fn getNextAnonNameIndex(self: *Module) usize {
2637 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);2239 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
2638}2240}
26392241
2640fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {2242pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
2641 const namespace = scope.namespace();2243 const namespace = scope.namespace();
2642 const name_hash = namespace.fullyQualifiedNameHash(ident_name);2244 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2643 return self.decl_table.get(name_hash);2245 return self.decl_table.get(name_hash);
...@@ -2658,17 +2260,16 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile...@@ -2658,17 +2260,16 @@ fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.Compile
2658fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {2260fn analyzeInstArg(self: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
2659 const b = try self.requireRuntimeBlock(scope, inst.base.src);2261 const b = try self.requireRuntimeBlock(scope, inst.base.src);
2660 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;2262 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
2263 const param_index = b.instructions.items.len;
2661 const param_count = fn_ty.fnParamLen();2264 const param_count = fn_ty.fnParamLen();
2662 if (inst.positionals.index >= param_count) {2265 if (param_index >= param_count) {
2663 return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{2266 return self.fail(scope, inst.base.src, "parameter index {} outside list of length {}", .{
2664 inst.positionals.index,2267 param_index,
2665 param_count,2268 param_count,
2666 });2269 });
2667 }2270 }
2668 const param_type = fn_ty.fnParamType(inst.positionals.index);2271 const param_type = fn_ty.fnParamType(param_index);
2669 return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, .{2272 return self.addNewInstArgs(b, inst.base.src, param_type, Inst.Arg, {});
2670 .index = inst.positionals.index,
2671 });
2672}2273}
26732274
2674fn analyzeInstBlock(self: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {2275fn 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...@@ -3646,13 +3247,13 @@ fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *I
3646 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});3247 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
3647}3248}
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 {
3650 @setCold(true);3251 @setCold(true);
3651 const err_msg = try ErrorMsg.create(self.gpa, src, format, args);3252 const err_msg = try ErrorMsg.create(self.gpa, src, format, args);
3652 return self.failWithOwnedErrorMsg(scope, src, err_msg);3253 return self.failWithOwnedErrorMsg(scope, src, err_msg);
3653}3254}
36543255
3655fn failTok(3256pub fn failTok(
3656 self: *Module,3257 self: *Module,
3657 scope: *Scope,3258 scope: *Scope,
3658 token_index: ast.TokenIndex,3259 token_index: ast.TokenIndex,
...@@ -3664,7 +3265,7 @@ fn failTok(...@@ -3664,7 +3265,7 @@ fn failTok(
3664 return self.fail(scope, src, format, args);3265 return self.fail(scope, src, format, args);
3665}3266}
36663267
3667fn failNode(3268pub fn failNode(
3668 self: *Module,3269 self: *Module,
3669 scope: *Scope,3270 scope: *Scope,
3670 ast_node: *ast.Node,3271 ast_node: *ast.Node,
...@@ -3705,6 +3306,12 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err...@@ -3705,6 +3306,12 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err
3705 gen_zir.decl.generation = self.generation;3306 gen_zir.decl.generation = self.generation;
3706 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3307 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3707 },3308 },
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 },
3708 .zir_module => {3315 .zir_module => {
3709 const zir_module = scope.cast(Scope.ZIRModule).?;3316 const zir_module = scope.cast(Scope.ZIRModule).?;
3710 zir_module.status = .loaded_sema_failure;3317 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(...@@ -73,6 +73,7 @@ pub fn generateSymbol(
73 .code = code,73 .code = code,
74 .err_msg = null,74 .err_msg = null,
75 .args = mc_args,75 .args = mc_args,
76 .arg_index = 0,
76 .branch_stack = &branch_stack,77 .branch_stack = &branch_stack,
77 .src = src,78 .src = src,
78 };79 };
...@@ -255,6 +256,7 @@ const Function = struct {...@@ -255,6 +256,7 @@ const Function = struct {
255 code: *std.ArrayList(u8),256 code: *std.ArrayList(u8),
256 err_msg: ?*ErrorMsg,257 err_msg: ?*ErrorMsg,
257 args: []MCValue,258 args: []MCValue,
259 arg_index: usize,
258 src: usize,260 src: usize,
259261
260 /// Whenever there is a runtime branch, we push a Branch onto this stack,262 /// Whenever there is a runtime branch, we push a Branch onto this stack,
...@@ -603,7 +605,9 @@ const Function = struct {...@@ -603,7 +605,9 @@ const Function = struct {
603 }605 }
604606
605 fn genArg(self: *Function, inst: *ir.Inst.Arg) !MCValue {607 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];
607 }611 }
608612
609 fn genBreakpoint(self: *Function, src: usize, comptime arch: std.Target.Cpu.Arch) !MCValue {613 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 {...@@ -101,10 +101,7 @@ pub const Inst = struct {
101 pub const Arg = struct {101 pub const Arg = struct {
102 pub const base_tag = Tag.arg;102 pub const base_tag = Tag.arg;
103 base: Inst,103 base: Inst,
104104 args: void,
105 args: struct {
106 index: usize,
107 },
108 };105 };
109106
110 pub const Assembly = struct {107 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...@@ -1103,11 +1103,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
1103 const enum_ident = try transCreateNodeIdentifier(c, name);1103 const enum_ident = try transCreateNodeIdentifier(c, name);
1104 const period_tok = try appendToken(c, .Period, ".");1104 const period_tok = try appendToken(c, .Period, ".");
1105 const field_ident = try transCreateNodeIdentifier(c, field_name);1105 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);
1107 field_access_node.* = .{1107 field_access_node.* = .{
1108 .base = .{ .tag = .Period },
1108 .op_token = period_tok,1109 .op_token = period_tok,
1109 .lhs = enum_ident,1110 .lhs = enum_ident,
1110 .op = .Period,
1111 .rhs = field_ident,1111 .rhs = field_ident,
1112 };1112 };
1113 cast_node.params()[0] = &field_access_node.base;1113 cast_node.params()[0] = &field_access_node.base;
...@@ -1219,7 +1219,7 @@ fn transStmt(...@@ -1219,7 +1219,7 @@ fn transStmt(
1219 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),1219 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used),
1220 .ParenExprClass => {1220 .ParenExprClass => {
1221 const expr = try transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), .used, lrvalue);1221 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);
1223 const node = try rp.c.arena.create(ast.Node.GroupedExpression);1223 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1224 node.* = .{1224 node.* = .{
1225 .lparen = try appendToken(rp.c, .LParen, "("),1225 .lparen = try appendToken(rp.c, .LParen, "("),
...@@ -1264,7 +1264,7 @@ fn transStmt(...@@ -1264,7 +1264,7 @@ fn transStmt(
1264 .OpaqueValueExprClass => {1264 .OpaqueValueExprClass => {
1265 const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?;1265 const source_expr = ZigClangOpaqueValueExpr_getSourceExpr(@ptrCast(*const ZigClangOpaqueValueExpr, stmt)).?;
1266 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);1266 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);
1268 const node = try rp.c.arena.create(ast.Node.GroupedExpression);1268 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1269 node.* = .{1269 node.* = .{
1270 .lparen = try appendToken(rp.c, .LParen, "("),1270 .lparen = try appendToken(rp.c, .LParen, "("),
...@@ -1294,7 +1294,7 @@ fn transBinaryOperator(...@@ -1294,7 +1294,7 @@ fn transBinaryOperator(
1294 const op = ZigClangBinaryOperator_getOpcode(stmt);1294 const op = ZigClangBinaryOperator_getOpcode(stmt);
1295 const qt = ZigClangBinaryOperator_getType(stmt);1295 const qt = ZigClangBinaryOperator_getType(stmt);
1296 var op_token: ast.TokenIndex = undefined;1296 var op_token: ast.TokenIndex = undefined;
1297 var op_id: ast.Node.InfixOp.Op = undefined;1297 var op_id: ast.Node.Tag = undefined;
1298 switch (op) {1298 switch (op) {
1299 .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),1299 .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)),
1300 .Comma => {1300 .Comma => {
...@@ -1693,7 +1693,7 @@ fn transBoolExpr(...@@ -1693,7 +1693,7 @@ fn transBoolExpr(
1693 var res = try transExpr(rp, scope, expr, used, lrvalue);1693 var res = try transExpr(rp, scope, expr, used, lrvalue);
16941694
1695 if (isBoolRes(res)) {1695 if (isBoolRes(res)) {
1696 if (!grouped and res.id == .GroupedExpression) {1696 if (!grouped and res.tag == .GroupedExpression) {
1697 const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res);1697 const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res);
1698 res = group.expr;1698 res = group.expr;
1699 // get zig fmt to work properly1699 // get zig fmt to work properly
...@@ -1736,26 +1736,23 @@ fn exprIsStringLiteral(expr: *const ZigClangExpr) bool {...@@ -1736,26 +1736,23 @@ fn exprIsStringLiteral(expr: *const ZigClangExpr) bool {
1736}1736}
17371737
1738fn isBoolRes(res: *ast.Node) bool {1738fn isBoolRes(res: *ast.Node) bool {
1739 switch (res.id) {1739 switch (res.tag) {
1740 .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {1740 .BoolOr,
1741 .BoolOr,1741 .BoolAnd,
1742 .BoolAnd,1742 .EqualEqual,
1743 .EqualEqual,1743 .BangEqual,
1744 .BangEqual,1744 .LessThan,
1745 .LessThan,1745 .GreaterThan,
1746 .GreaterThan,1746 .LessOrEqual,
1747 .LessOrEqual,1747 .GreaterOrEqual,
1748 .GreaterOrEqual,1748 .BoolNot,
1749 => return true,1749 .BoolLiteral,
1750 => return true,
17501751
1751 else => {},
1752 },
1753 .BoolNot => return true,
1754 .BoolLiteral => return true,
1755 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),1752 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
1756 else => {},1753
1754 else => return false,
1757 }1755 }
1758 return false;
1759}1756}
17601757
1761fn finishBoolExpr(1758fn finishBoolExpr(
...@@ -2312,11 +2309,11 @@ fn transInitListExprArray(...@@ -2312,11 +2309,11 @@ fn transInitListExprArray(
2312 &filler_init_node.base2309 &filler_init_node.base
2313 else blk: {2310 else blk: {
2314 const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");2311 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);
2316 mul_node.* = .{2313 mul_node.* = .{
2314 .base = .{ .tag = .ArrayMult },
2317 .op_token = mul_tok,2315 .op_token = mul_tok,
2318 .lhs = &filler_init_node.base,2316 .lhs = &filler_init_node.base,
2319 .op = .ArrayMult,
2320 .rhs = try transCreateNodeInt(rp.c, leftover_count),2317 .rhs = try transCreateNodeInt(rp.c, leftover_count),
2321 };2318 };
2322 break :blk &mul_node.base;2319 break :blk &mul_node.base;
...@@ -2326,11 +2323,11 @@ fn transInitListExprArray(...@@ -2326,11 +2323,11 @@ fn transInitListExprArray(
2326 return rhs_node;2323 return rhs_node;
2327 }2324 }
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);
2330 cat_node.* = .{2327 cat_node.* = .{
2328 .base = .{ .tag = .ArrayCat },
2331 .op_token = cat_tok,2329 .op_token = cat_tok,
2332 .lhs = &init_node.base,2330 .lhs = &init_node.base,
2333 .op = .ArrayCat,
2334 .rhs = rhs_node,2331 .rhs = rhs_node,
2335 };2332 };
2336 return &cat_node.base;2333 return &cat_node.base;
...@@ -2723,11 +2720,11 @@ fn transCase(...@@ -2723,11 +2720,11 @@ fn transCase(
2723 const ellips = try appendToken(rp.c, .Ellipsis3, "...");2720 const ellips = try appendToken(rp.c, .Ellipsis3, "...");
2724 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);2721 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);
2727 node.* = .{2724 node.* = .{
2725 .base = .{ .tag = .Range },
2728 .op_token = ellips,2726 .op_token = ellips,
2729 .lhs = lhs_node,2727 .lhs = lhs_node,
2730 .op = .Range,
2731 .rhs = rhs_node,2728 .rhs = rhs_node,
2732 };2729 };
2733 break :blk &node.base;2730 break :blk &node.base;
...@@ -3153,7 +3150,7 @@ fn transCreatePreCrement(...@@ -3153,7 +3150,7 @@ fn transCreatePreCrement(
3153 rp: RestorePoint,3150 rp: RestorePoint,
3154 scope: *Scope,3151 scope: *Scope,
3155 stmt: *const ZigClangUnaryOperator,3152 stmt: *const ZigClangUnaryOperator,
3156 op: ast.Node.InfixOp.Op,3153 op: ast.Node.Tag,
3157 op_tok_id: std.zig.Token.Id,3154 op_tok_id: std.zig.Token.Id,
3158 bytes: []const u8,3155 bytes: []const u8,
3159 used: ResultUsed,3156 used: ResultUsed,
...@@ -3227,7 +3224,7 @@ fn transCreatePostCrement(...@@ -3227,7 +3224,7 @@ fn transCreatePostCrement(
3227 rp: RestorePoint,3224 rp: RestorePoint,
3228 scope: *Scope,3225 scope: *Scope,
3229 stmt: *const ZigClangUnaryOperator,3226 stmt: *const ZigClangUnaryOperator,
3230 op: ast.Node.InfixOp.Op,3227 op: ast.Node.Tag,
3231 op_tok_id: std.zig.Token.Id,3228 op_tok_id: std.zig.Token.Id,
3232 bytes: []const u8,3229 bytes: []const u8,
3233 used: ResultUsed,3230 used: ResultUsed,
...@@ -3349,10 +3346,10 @@ fn transCreateCompoundAssign(...@@ -3349,10 +3346,10 @@ fn transCreateCompoundAssign(
3349 rp: RestorePoint,3346 rp: RestorePoint,
3350 scope: *Scope,3347 scope: *Scope,
3351 stmt: *const ZigClangCompoundAssignOperator,3348 stmt: *const ZigClangCompoundAssignOperator,
3352 assign_op: ast.Node.InfixOp.Op,3349 assign_op: ast.Node.Tag,
3353 assign_tok_id: std.zig.Token.Id,3350 assign_tok_id: std.zig.Token.Id,
3354 assign_bytes: []const u8,3351 assign_bytes: []const u8,
3355 bin_op: ast.Node.InfixOp.Op,3352 bin_op: ast.Node.Tag,
3356 bin_tok_id: std.zig.Token.Id,3353 bin_tok_id: std.zig.Token.Id,
3357 bin_bytes: []const u8,3354 bin_bytes: []const u8,
3358 used: ResultUsed,3355 used: ResultUsed,
...@@ -3377,7 +3374,7 @@ fn transCreateCompoundAssign(...@@ -3377,7 +3374,7 @@ fn transCreateCompoundAssign(
3377 // zig: lhs += rhs3374 // zig: lhs += rhs
3378 if ((is_mod or is_div) and is_signed) {3375 if ((is_mod or is_div) and is_signed) {
3379 const op_token = try appendToken(rp.c, .Equal, "=");3376 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);
3381 const builtin = if (is_mod) "@rem" else "@divTrunc";3378 const builtin = if (is_mod) "@rem" else "@divTrunc";
3382 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);3379 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3383 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);3380 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
...@@ -3386,9 +3383,9 @@ fn transCreateCompoundAssign(...@@ -3386,9 +3383,9 @@ fn transCreateCompoundAssign(
3386 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);3383 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);
3387 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");3384 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3388 op_node.* = .{3385 op_node.* = .{
3386 .base = .{ .tag = .Assign },
3389 .op_token = op_token,3387 .op_token = op_token,
3390 .lhs = lhs_node,3388 .lhs = lhs_node,
3391 .op = .Assign,
3392 .rhs = &builtin_node.base,3389 .rhs = &builtin_node.base,
3393 };3390 };
3394 _ = try appendToken(rp.c, .Semicolon, ";");3391 _ = try appendToken(rp.c, .Semicolon, ";");
...@@ -3452,7 +3449,7 @@ fn transCreateCompoundAssign(...@@ -3452,7 +3449,7 @@ fn transCreateCompoundAssign(
34523449
3453 if ((is_mod or is_div) and is_signed) {3450 if ((is_mod or is_div) and is_signed) {
3454 const op_token = try appendToken(rp.c, .Equal, "=");3451 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);
3456 const builtin = if (is_mod) "@rem" else "@divTrunc";3453 const builtin = if (is_mod) "@rem" else "@divTrunc";
3457 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);3454 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3458 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);3455 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);
...@@ -3461,9 +3458,9 @@ fn transCreateCompoundAssign(...@@ -3461,9 +3458,9 @@ fn transCreateCompoundAssign(
3461 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");3458 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3462 _ = try appendToken(rp.c, .Semicolon, ";");3459 _ = try appendToken(rp.c, .Semicolon, ";");
3463 op_node.* = .{3460 op_node.* = .{
3461 .base = .{ .tag = .Assign },
3464 .op_token = op_token,3462 .op_token = op_token,
3465 .lhs = ref_node,3463 .lhs = ref_node,
3466 .op = .Assign,
3467 .rhs = &builtin_node.base,3464 .rhs = &builtin_node.base,
3468 };3465 };
3469 _ = try appendToken(rp.c, .Semicolon, ";");3466 _ = try appendToken(rp.c, .Semicolon, ";");
...@@ -3716,11 +3713,11 @@ fn maybeSuppressResult(...@@ -3716,11 +3713,11 @@ fn maybeSuppressResult(
3716 }3713 }
3717 const lhs = try transCreateNodeIdentifier(rp.c, "_");3714 const lhs = try transCreateNodeIdentifier(rp.c, "_");
3718 const op_token = try appendToken(rp.c, .Equal, "=");3715 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);
3720 op_node.* = .{3717 op_node.* = .{
3718 .base = .{ .tag = .Assign },
3721 .op_token = op_token,3719 .op_token = op_token,
3722 .lhs = lhs,3720 .lhs = lhs,
3723 .op = .Assign,
3724 .rhs = result,3721 .rhs = result,
3725 };3722 };
3726 return &op_node.base;3723 return &op_node.base;
...@@ -4095,11 +4092,11 @@ fn transCreateNodeAssign(...@@ -4095,11 +4092,11 @@ fn transCreateNodeAssign(
4095}4092}
40964093
4097fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {4094fn 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);
4099 field_access_node.* = .{4096 field_access_node.* = .{
4097 .base = .{ .tag = .Period },
4100 .op_token = try appendToken(c, .Period, "."),4098 .op_token = try appendToken(c, .Period, "."),
4101 .lhs = container,4099 .lhs = container,
4102 .op = .Period,
4103 .rhs = try transCreateNodeIdentifier(c, field_name),4100 .rhs = try transCreateNodeIdentifier(c, field_name),
4104 };4101 };
4105 return &field_access_node.base;4102 return &field_access_node.base;
...@@ -4107,12 +4104,13 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c...@@ -4107,12 +4104,13 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c
41074104
4108fn transCreateNodeSimplePrefixOp(4105fn transCreateNodeSimplePrefixOp(
4109 c: *Context,4106 c: *Context,
4110 comptime tag: ast.Node.Id,4107 comptime tag: ast.Node.Tag,
4111 op_tok_id: std.zig.Token.Id,4108 op_tok_id: std.zig.Token.Id,
4112 bytes: []const u8,4109 bytes: []const u8,
4113) !*ast.Node.SimplePrefixOp(tag) {4110) !*ast.Node.SimplePrefixOp {
4114 const node = try c.arena.create(ast.Node.SimplePrefixOp(tag));4111 const node = try c.arena.create(ast.Node.SimplePrefixOp);
4115 node.* = .{4112 node.* = .{
4113 .base = .{ .tag = tag },
4116 .op_token = try appendToken(c, op_tok_id, bytes),4114 .op_token = try appendToken(c, op_tok_id, bytes),
4117 .rhs = undefined, // translate and set afterward4115 .rhs = undefined, // translate and set afterward
4118 };4116 };
...@@ -4123,7 +4121,7 @@ fn transCreateNodeInfixOp(...@@ -4123,7 +4121,7 @@ fn transCreateNodeInfixOp(
4123 rp: RestorePoint,4121 rp: RestorePoint,
4124 scope: *Scope,4122 scope: *Scope,
4125 lhs_node: *ast.Node,4123 lhs_node: *ast.Node,
4126 op: ast.Node.InfixOp.Op,4124 op: ast.Node.Tag,
4127 op_token: ast.TokenIndex,4125 op_token: ast.TokenIndex,
4128 rhs_node: *ast.Node,4126 rhs_node: *ast.Node,
4129 used: ResultUsed,4127 used: ResultUsed,
...@@ -4133,11 +4131,11 @@ fn transCreateNodeInfixOp(...@@ -4133,11 +4131,11 @@ fn transCreateNodeInfixOp(
4133 try appendToken(rp.c, .LParen, "(")4131 try appendToken(rp.c, .LParen, "(")
4134 else4132 else
4135 null;4133 null;
4136 const node = try rp.c.arena.create(ast.Node.InfixOp);4134 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4137 node.* = .{4135 node.* = .{
4136 .base = .{ .tag = op },
4138 .op_token = op_token,4137 .op_token = op_token,
4139 .lhs = lhs_node,4138 .lhs = lhs_node,
4140 .op = op,
4141 .rhs = rhs_node,4139 .rhs = rhs_node,
4142 };4140 };
4143 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);4141 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
...@@ -4155,7 +4153,7 @@ fn transCreateNodeBoolInfixOp(...@@ -4155,7 +4153,7 @@ fn transCreateNodeBoolInfixOp(
4155 rp: RestorePoint,4153 rp: RestorePoint,
4156 scope: *Scope,4154 scope: *Scope,
4157 stmt: *const ZigClangBinaryOperator,4155 stmt: *const ZigClangBinaryOperator,
4158 op: ast.Node.InfixOp.Op,4156 op: ast.Node.Tag,
4159 used: ResultUsed,4157 used: ResultUsed,
4160 grouped: bool,4158 grouped: bool,
4161) !*ast.Node {4159) !*ast.Node {
...@@ -4535,7 +4533,7 @@ fn transCreateNodeShiftOp(...@@ -4535,7 +4533,7 @@ fn transCreateNodeShiftOp(
4535 rp: RestorePoint,4533 rp: RestorePoint,
4536 scope: *Scope,4534 scope: *Scope,
4537 stmt: *const ZigClangBinaryOperator,4535 stmt: *const ZigClangBinaryOperator,
4538 op: ast.Node.InfixOp.Op,4536 op: ast.Node.Tag,
4539 op_tok_id: std.zig.Token.Id,4537 op_tok_id: std.zig.Token.Id,
4540 bytes: []const u8,4538 bytes: []const u8,
4541) !*ast.Node {4539) !*ast.Node {
...@@ -4557,11 +4555,11 @@ fn transCreateNodeShiftOp(...@@ -4557,11 +4555,11 @@ fn transCreateNodeShiftOp(
4557 cast_node.params()[1] = rhs;4555 cast_node.params()[1] = rhs;
4558 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");4556 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);
4561 node.* = .{4559 node.* = .{
4560 .base = .{ .tag = op },
4562 .op_token = op_token,4561 .op_token = op_token,
4563 .lhs = lhs,4562 .lhs = lhs,
4564 .op = op,
4565 .rhs = &cast_node.base,4563 .rhs = &cast_node.base,
4566 };4564 };
45674565
...@@ -5338,10 +5336,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5338,10 +5336,10 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5338 .{@tagName(last.id)},5336 .{@tagName(last.id)},
5339 );5337 );
5340 _ = try appendToken(c, .Semicolon, ";");5338 _ = 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: {
5342 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);5340 const blk = @fieldParentPtr(ast.Node.Block, "base", expr);
5343 const blk_last = blk.statements()[blk.statements_len - 1];5341 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);
5345 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);5343 const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last);
5346 break :blk br.rhs.?;5344 break :blk br.rhs.?;
5347 };5345 };
...@@ -5403,11 +5401,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_...@@ -5403,11 +5401,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_
5403 // suppress result5401 // suppress result
5404 const lhs = try transCreateNodeIdentifier(c, "_");5402 const lhs = try transCreateNodeIdentifier(c, "_");
5405 const op_token = try appendToken(c, .Equal, "=");5403 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);
5407 op_node.* = .{5405 op_node.* = .{
5406 .base = .{ .tag = .Assign },
5408 .op_token = op_token,5407 .op_token = op_token,
5409 .lhs = lhs,5408 .lhs = lhs,
5410 .op = .Assign,
5411 .rhs = last,5409 .rhs = last,
5412 };5410 };
5413 try block_scope.statements.append(&op_node.base);5411 try block_scope.statements.append(&op_node.base);
...@@ -5786,9 +5784,60 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5786,9 +5784,60 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5786 }5784 }
5787}5785}
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
5789fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {5838fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
5790 if (!isBoolRes(node)) {5839 if (!isBoolRes(node)) {
5791 if (node.id != .InfixOp) return node;5840 if (!nodeIsInfixOp(node.tag)) return node;
57925841
5793 const group_node = try c.arena.create(ast.Node.GroupedExpression);5842 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5794 group_node.* = .{5843 group_node.* = .{
...@@ -5807,7 +5856,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {...@@ -5807,7 +5856,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
58075856
5808fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {5857fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
5809 if (isBoolRes(node)) {5858 if (isBoolRes(node)) {
5810 if (node.id != .InfixOp) return node;5859 if (!nodeIsInfixOp(node.tag)) return node;
58115860
5812 const group_node = try c.arena.create(ast.Node.GroupedExpression);5861 const group_node = try c.arena.create(ast.Node.GroupedExpression);
5813 group_node.* = .{5862 group_node.* = .{
...@@ -5820,11 +5869,11 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {...@@ -5820,11 +5869,11 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
58205869
5821 const op_token = try appendToken(c, .BangEqual, "!=");5870 const op_token = try appendToken(c, .BangEqual, "!=");
5822 const zero = try transCreateNodeInt(c, 0);5871 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);
5824 res.* = .{5873 res.* = .{
5874 .base = .{ .tag = .BangEqual },
5825 .op_token = op_token,5875 .op_token = op_token,
5826 .lhs = node,5876 .lhs = node,
5827 .op = .BangEqual,
5828 .rhs = zero,5877 .rhs = zero,
5829 };5878 };
5830 const group_node = try c.arena.create(ast.Node.GroupedExpression);5879 const group_node = try c.arena.create(ast.Node.GroupedExpression);
...@@ -5841,7 +5890,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -5841,7 +5890,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
5841 while (true) {5890 while (true) {
5842 const tok = it.next().?;5891 const tok = it.next().?;
5843 var op_token: ast.TokenIndex = undefined;5892 var op_token: ast.TokenIndex = undefined;
5844 var op_id: ast.Node.InfixOp.Op = undefined;5893 var op_id: ast.Node.Tag = undefined;
5845 var bool_op = false;5894 var bool_op = false;
5846 switch (tok.id) {5895 switch (tok.id) {
5847 .Period => {5896 .Period => {
...@@ -6048,11 +6097,11 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -6048,11 +6097,11 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
6048 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;6097 const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt;
6049 const lhs_node = try cast_fn(c, node);6098 const lhs_node = try cast_fn(c, node);
6050 const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope);6099 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);
6052 op_node.* = .{6101 op_node.* = .{
6102 .base = .{ .tag = op_id },
6053 .op_token = op_token,6103 .op_token = op_token,
6054 .lhs = lhs_node,6104 .lhs = lhs_node,
6055 .op = op_id,
6056 .rhs = try cast_fn(c, rhs_node),6105 .rhs = try cast_fn(c, rhs_node),
6057 };6106 };
6058 node = &op_node.base;6107 node = &op_node.base;
...@@ -6105,7 +6154,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {...@@ -6105,7 +6154,7 @@ fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
6105}6154}
61066155
6107fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {6156fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6108 switch (node.id) {6157 switch (node.tag) {
6109 .ContainerDecl,6158 .ContainerDecl,
6110 .AddressOf,6159 .AddressOf,
6111 .Await,6160 .Await,
...@@ -6130,10 +6179,9 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6130,10 +6179,9 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6130 }6179 }
6131 },6180 },
61326181
6133 .InfixOp => {6182 .Period => {
6134 const infix = node.cast(ast.Node.InfixOp).?;6183 const infix = node.castTag(.Period).?;
6135 if (infix.op != .Period)6184
6136 return null;
6137 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {6185 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6138 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6186 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6139 for (container.fieldsAndDecls()) |field_ref| {6187 for (container.fieldsAndDecls()) |field_ref| {
...@@ -6160,9 +6208,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6160,9 +6208,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6160 return getContainer(c, ty);6208 return getContainer(c, ty);
6161 }6209 }
6162 }6210 }
6163 } else if (ref.cast(ast.Node.InfixOp)) |infix| {6211 } else if (ref.castTag(.Period)) |infix| {
6164 if (infix.op != .Period)
6165 return null;
6166 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {6212 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6167 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {6213 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6168 for (container.fieldsAndDecls()) |field_ref| {6214 for (container.fieldsAndDecls()) |field_ref| {
...@@ -6182,7 +6228,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6182,7 +6228,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6182fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {6228fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
6183 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null;6229 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getTrailer("init_node").? else return null;
6184 if (getContainerTypeOf(c, init)) |ty_node| {6230 if (getContainerTypeOf(c, init)) |ty_node| {
6185 if (ty_node.cast(ast.Node.OptionalType)) |prefix| {6231 if (ty_node.castTag(.OptionalType)) |prefix| {
6186 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {6232 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
6187 return fn_proto;6233 return fn_proto;
6188 }6234 }
src-self-hosted/zir.zig+8-7
...@@ -34,7 +34,8 @@ pub const Inst = struct {...@@ -34,7 +34,8 @@ pub const Inst = struct {
3434
35 /// These names are used directly as the instruction names in the text format.35 /// These names are used directly as the instruction names in the text format.
36 pub const Tag = enum {36 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.
38 arg,39 arg,
39 /// A labeled block of code, which can return a value.40 /// A labeled block of code, which can return a value.
40 block,41 block,
...@@ -184,9 +185,7 @@ pub const Inst = struct {...@@ -184,9 +185,7 @@ pub const Inst = struct {
184 pub const base_tag = Tag.arg;185 pub const base_tag = Tag.arg;
185 base: Inst,186 base: Inst,
186187
187 positionals: struct {188 positionals: struct {},
188 index: usize,
189 },
190 kw_args: struct {},189 kw_args: struct {},
191 };190 };
192191
...@@ -1384,15 +1383,17 @@ const EmitZIR = struct {...@@ -1384,15 +1383,17 @@ const EmitZIR = struct {
1384 for (src_decls.items) |ir_decl| {1383 for (src_decls.items) |ir_decl| {
1385 switch (ir_decl.analysis) {1384 switch (ir_decl.analysis) {
1386 .unreferenced => continue,1385 .unreferenced => continue,
1386
1387 .complete => {},1387 .complete => {},
1388 .codegen_failure => {}, // We still can emit the ZIR.
1389 .codegen_failure_retryable => {}, // We still can emit the ZIR.
1390
1388 .in_progress => unreachable,1391 .in_progress => unreachable,
1389 .outdated => unreachable,1392 .outdated => unreachable,
13901393
1391 .sema_failure,1394 .sema_failure,
1392 .sema_failure_retryable,1395 .sema_failure_retryable,
1393 .codegen_failure,
1394 .dependency_failure,1396 .dependency_failure,
1395 .codegen_failure_retryable,
1396 => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {1397 => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {
1397 const fail_inst = try self.arena.allocator.create(Inst.CompileError);1398 const fail_inst = try self.arena.allocator.create(Inst.CompileError);
1398 fail_inst.* = .{1399 fail_inst.* = .{
...@@ -1728,7 +1729,7 @@ const EmitZIR = struct {...@@ -1728,7 +1729,7 @@ const EmitZIR = struct {
1728 .src = inst.src,1729 .src = inst.src,
1729 .tag = Inst.Arg.base_tag,1730 .tag = Inst.Arg.base_tag,
1730 },1731 },
1731 .positionals = .{ .index = old_inst.args.index },1732 .positionals = .{},
1732 .kw_args = .{},1733 .kw_args = .{},
1733 };1734 };
1734 break :blk &new_inst.base;1735 break :blk &new_inst.base;