authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-20 16:21:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-07-21 10:52:24-07:00
log7a1a92478878f591abbadcd5735f03c817c6eb53
tree6ee2180f07905856f0f16864708352087fcf3e7b
parent1ac28eed839663a7d12bbbf131596b6abd8b0744

stage2: AST: (breaking) flatten out suffix operations


5 files changed, 246 insertions(+), 310 deletions(-)

lib/std/zig/ast.zig+78-43
......@@ -471,9 +471,14 @@ pub const Node = struct {
471471 ArrayTypeSentinel,
472472 PtrType,
473473 SliceType,
474 /// Not all suffix operations are under this tag. To save memory, some
475 /// suffix operations have dedicated Node tags.
476 SuffixOp,
474 /// `a[b..c]`
475 Slice,
476 /// `a.*`
477 Deref,
478 /// `a.?`
479 UnwrapOptional,
480 /// `a[b]`
481 ArrayAccess,
477482 /// `T{a, b}`
478483 ArrayInitializer,
479484 /// ArrayInitializer but with `.` instead of a left-hand-side operand.
......@@ -601,7 +606,9 @@ pub const Node = struct {
601606
602607 .PtrType => PtrType,
603608 .SliceType => SliceType,
604 .SuffixOp => SuffixOp,
609 .Slice => Slice,
610 .Deref, .UnwrapOptional => SimpleSuffixOp,
611 .ArrayAccess => ArrayAccess,
605612
606613 .ArrayInitializer => ArrayInitializer,
607614 .ArrayInitializerDot => ArrayInitializerDot,
......@@ -2398,8 +2405,8 @@ pub const Node = struct {
23982405 /// Parameter nodes directly follow Call in memory.
23992406 pub const Call = struct {
24002407 base: Node = Node{ .tag = .Call },
2401 lhs: *Node,
24022408 rtoken: TokenIndex,
2409 lhs: *Node,
24032410 params_len: NodeIndex,
24042411 async_token: ?TokenIndex,
24052412
......@@ -2450,62 +2457,90 @@ pub const Node = struct {
24502457 }
24512458 };
24522459
2453 pub const SuffixOp = struct {
2454 base: Node = Node{ .tag = .SuffixOp },
2455 op: Op,
2460 pub const ArrayAccess = struct {
2461 base: Node = Node{ .tag = .ArrayAccess },
2462 rtoken: TokenIndex,
24562463 lhs: *Node,
2464 index_expr: *Node,
2465
2466 pub fn iterate(self: *const ArrayAccess, index: usize) ?*Node {
2467 var i = index;
2468
2469 if (i < 1) return self.lhs;
2470 i -= 1;
2471
2472 if (i < 1) return self.index_expr;
2473 i -= 1;
2474
2475 return null;
2476 }
2477
2478 pub fn firstToken(self: *const ArrayAccess) TokenIndex {
2479 return self.lhs.firstToken();
2480 }
2481
2482 pub fn lastToken(self: *const ArrayAccess) TokenIndex {
2483 return self.rtoken;
2484 }
2485 };
2486
2487 pub const SimpleSuffixOp = struct {
2488 base: Node,
24572489 rtoken: TokenIndex,
2490 lhs: *Node,
24582491
2459 pub const Op = union(enum) {
2460 ArrayAccess: *Node,
2461 Slice: Slice,
2462 Deref,
2463 UnwrapOptional,
2492 pub fn iterate(self: *const SimpleSuffixOp, index: usize) ?*Node {
2493 var i = index;
24642494
2465 pub const Slice = struct {
2466 start: *Node,
2467 end: ?*Node,
2468 sentinel: ?*Node,
2469 };
2470 };
2495 if (i < 1) return self.lhs;
2496 i -= 1;
24712497
2472 pub fn iterate(self: *const SuffixOp, index: usize) ?*Node {
2498 return null;
2499 }
2500
2501 pub fn firstToken(self: *const SimpleSuffixOp) TokenIndex {
2502 return self.lhs.firstToken();
2503 }
2504
2505 pub fn lastToken(self: *const SimpleSuffixOp) TokenIndex {
2506 return self.rtoken;
2507 }
2508 };
2509
2510 pub const Slice = struct {
2511 base: Node = Node{ .tag = .Slice },
2512 rtoken: TokenIndex,
2513 lhs: *Node,
2514 start: *Node,
2515 end: ?*Node,
2516 sentinel: ?*Node,
2517
2518 pub fn iterate(self: *const Slice, index: usize) ?*Node {
24732519 var i = index;
24742520
2475 if (i == 0) return self.lhs;
2521 if (i < 1) return self.lhs;
24762522 i -= 1;
24772523
2478 switch (self.op) {
2479 .ArrayAccess => |index_expr| {
2480 if (i < 1) return index_expr;
2481 i -= 1;
2482 },
2483 .Slice => |range| {
2484 if (i < 1) return range.start;
2485 i -= 1;
2524 if (i < 1) return self.start;
2525 i -= 1;
24862526
2487 if (range.end) |end| {
2488 if (i < 1) return end;
2489 i -= 1;
2490 }
2491 if (range.sentinel) |sentinel| {
2492 if (i < 1) return sentinel;
2493 i -= 1;
2494 }
2495 },
2496 .UnwrapOptional,
2497 .Deref,
2498 => {},
2527 if (self.end) |end| {
2528 if (i < 1) return end;
2529 i -= 1;
2530 }
2531 if (self.sentinel) |sentinel| {
2532 if (i < 1) return sentinel;
2533 i -= 1;
24992534 }
25002535
25012536 return null;
25022537 }
25032538
2504 pub fn firstToken(self: *const SuffixOp) TokenIndex {
2539 pub fn firstToken(self: *const Slice) TokenIndex {
25052540 return self.lhs.firstToken();
25062541 }
25072542
2508 pub fn lastToken(self: *const SuffixOp) TokenIndex {
2543 pub fn lastToken(self: *const Slice) TokenIndex {
25092544 return self.rtoken;
25102545 }
25112546 };
lib/std/zig/parse.zig+65-167
......@@ -1439,58 +1439,7 @@ const Parser = struct {
14391439 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
14401440 });
14411441
1442 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
1443 while (try p.parseSuffixOp()) |node| {
1444 switch (node.tag) {
1445 .SuffixOp => node.cast(Node.SuffixOp).?.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 .OrElse,
1490 => node.cast(Node.SimpleInfixOp).?.lhs = res,
1491
1492 else => unreachable,
1493 }
1442 while (try p.parseSuffixOp(res)) |node| {
14941443 res = node;
14951444 }
14961445
......@@ -1516,57 +1465,7 @@ const Parser = struct {
15161465 var res = expr;
15171466
15181467 while (true) {
1519 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.
1520 if (try p.parseSuffixOp()) |node| {
1521 switch (node.tag) {
1522 .SuffixOp => node.cast(Node.SuffixOp).?.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 .OrElse,
1567 => node.cast(Node.SimpleInfixOp).?.lhs = res,
1568 else => unreachable,
1569 }
1468 if (try p.parseSuffixOp(res)) |node| {
15701469 res = node;
15711470 continue;
15721471 }
......@@ -2733,78 +2632,77 @@ const Parser = struct {
27332632 /// / DOT IDENTIFIER
27342633 /// / DOTASTERISK
27352634 /// / DOTQUESTIONMARK
2736 fn parseSuffixOp(p: *Parser) !?*Node {
2737 const OpAndToken = struct {
2738 op: Node.SuffixOp.Op,
2739 token: TokenIndex,
2740 };
2741 const op_and_token: OpAndToken = blk: {
2742 if (p.eatToken(.LBracket)) |_| {
2743 const index_expr = try p.expectNode(parseExpr, .{
2744 .ExpectedExpr = .{ .token = p.tok_i },
2745 });
2746
2747 if (p.eatToken(.Ellipsis2) != null) {
2748 const end_expr = try p.parseExpr();
2749 const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
2750 try p.parseExpr()
2751 else
2752 null;
2753 break :blk .{
2754 .op = .{
2755 .Slice = .{
2756 .start = index_expr,
2757 .end = end_expr,
2758 .sentinel = sentinel,
2759 },
2760 },
2761 .token = try p.expectToken(.RBracket),
2762 };
2763 }
2635 fn parseSuffixOp(p: *Parser, lhs: *Node) !?*Node {
2636 if (p.eatToken(.LBracket)) |_| {
2637 const index_expr = try p.expectNode(parseExpr, .{
2638 .ExpectedExpr = .{ .token = p.tok_i },
2639 });
27642640
2765 break :blk .{
2766 .op = .{ .ArrayAccess = index_expr },
2767 .token = try p.expectToken(.RBracket),
2641 if (p.eatToken(.Ellipsis2) != null) {
2642 const end_expr = try p.parseExpr();
2643 const sentinel: ?*Node = if (p.eatToken(.Colon) != null)
2644 try p.parseExpr()
2645 else
2646 null;
2647 const rtoken = try p.expectToken(.RBracket);
2648 const node = try p.arena.allocator.create(Node.Slice);
2649 node.* = .{
2650 .lhs = lhs,
2651 .rtoken = rtoken,
2652 .start = index_expr,
2653 .end = end_expr,
2654 .sentinel = sentinel,
27682655 };
2656 return &node.base;
27692657 }
27702658
2771 if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
2772 break :blk .{ .op = .Deref, .token = period_asterisk };
2773 }
2659 const rtoken = try p.expectToken(.RBracket);
2660 const node = try p.arena.allocator.create(Node.ArrayAccess);
2661 node.* = .{
2662 .lhs = lhs,
2663 .rtoken = rtoken,
2664 .index_expr = index_expr,
2665 };
2666 return &node.base;
2667 }
27742668
2775 if (p.eatToken(.Period)) |period| {
2776 if (try p.parseIdentifier()) |identifier| {
2777 // TODO: It's a bit weird to return a SimpleInfixOp from the SuffixOp parser.
2778 // Should there be an Node.SuffixOp.FieldAccess variant? Or should
2779 // this grammar rule be altered?
2780 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
2781 node.* = .{
2782 .base = Node{ .tag = .Period },
2783 .op_token = period,
2784 .lhs = undefined, // set by caller
2785 .rhs = identifier,
2786 };
2787 return &node.base;
2788 }
2789 if (p.eatToken(.QuestionMark)) |question_mark| {
2790 break :blk .{ .op = .UnwrapOptional, .token = question_mark };
2791 }
2792 try p.errors.append(p.gpa, .{
2793 .ExpectedSuffixOp = .{ .token = p.tok_i },
2794 });
2795 return null;
2796 }
2669 if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
2670 const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
2671 node.* = .{
2672 .base = .{ .tag = .Deref },
2673 .lhs = lhs,
2674 .rtoken = period_asterisk,
2675 };
2676 return &node.base;
2677 }
27972678
2679 if (p.eatToken(.Period)) |period| {
2680 if (try p.parseIdentifier()) |identifier| {
2681 const node = try p.arena.allocator.create(Node.SimpleInfixOp);
2682 node.* = .{
2683 .base = Node{ .tag = .Period },
2684 .op_token = period,
2685 .lhs = lhs,
2686 .rhs = identifier,
2687 };
2688 return &node.base;
2689 }
2690 if (p.eatToken(.QuestionMark)) |question_mark| {
2691 const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
2692 node.* = .{
2693 .base = .{ .tag = .UnwrapOptional },
2694 .lhs = lhs,
2695 .rtoken = question_mark,
2696 };
2697 return &node.base;
2698 }
2699 try p.errors.append(p.gpa, .{
2700 .ExpectedSuffixOp = .{ .token = p.tok_i },
2701 });
27982702 return null;
2799 };
2703 }
28002704
2801 const node = try p.arena.allocator.create(Node.SuffixOp);
2802 node.* = .{
2803 .lhs = undefined, // set by caller
2804 .op = op_and_token.op,
2805 .rtoken = op_and_token.token,
2806 };
2807 return &node.base;
2705 return null;
28082706 }
28092707
28102708 /// FnCallArguments <- LPAREN ExprList RPAREN
lib/std/zig/render.zig+54-55
......@@ -1044,68 +1044,67 @@ fn renderExpression(
10441044 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
10451045 },
10461046
1047 .SuffixOp => {
1048 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
1049
1050 switch (suffix_op.op) {
1051 .ArrayAccess => |index_expr| {
1052 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
1053 const rbracket = tree.nextToken(index_expr.lastToken());
1054
1055 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1056 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1057
1058 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
1059 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
1060 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
1061 const new_space = if (ends_with_comment) Space.Newline else Space.None;
1062 try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space);
1063 if (starts_with_comment) {
1064 try stream.writeByte('\n');
1065 }
1066 if (ends_with_comment or starts_with_comment) {
1067 try stream.writeByteNTimes(' ', indent);
1068 }
1069 return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
1070 },
1047 .ArrayAccess => {
1048 const suffix_op = base.castTag(.ArrayAccess).?;
10711049
1072 .Deref => {
1073 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1074 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
1075 },
1050 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
1051 const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
10761052
1077 .UnwrapOptional => {
1078 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1079 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
1080 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
1081 },
1053 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1054 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1055
1056 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
1057 const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment;
1058 const new_indent = if (ends_with_comment) indent + indent_delta else indent;
1059 const new_space = if (ends_with_comment) Space.Newline else Space.None;
1060 try renderExpression(allocator, stream, tree, new_indent, start_col, suffix_op.index_expr, new_space);
1061 if (starts_with_comment) {
1062 try stream.writeByte('\n');
1063 }
1064 if (ends_with_comment or starts_with_comment) {
1065 try stream.writeByteNTimes(' ', indent);
1066 }
1067 return renderToken(tree, stream, rbracket, indent, start_col, space); // ]
1068 },
1069 .Slice => {
1070 const suffix_op = base.castTag(.Slice).?;
10821071
1083 .Slice => |range| {
1084 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1072 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
10851073
1086 const lbracket = tree.prevToken(range.start.firstToken());
1087 const dotdot = tree.nextToken(range.start.lastToken());
1074 const lbracket = tree.prevToken(suffix_op.start.firstToken());
1075 const dotdot = tree.nextToken(suffix_op.start.lastToken());
10881076
1089 const after_start_space_bool = nodeCausesSliceOpSpace(range.start) or
1090 (if (range.end) |end| nodeCausesSliceOpSpace(end) else false);
1091 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
1092 const after_op_space = if (range.end != null) after_start_space else Space.None;
1077 const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or
1078 (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false);
1079 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;
1080 const after_op_space = if (suffix_op.end != null) after_start_space else Space.None;
10931081
1094 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1095 try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);
1096 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
1097 if (range.end) |end| {
1098 const after_end_space = if (range.sentinel != null) Space.Space else Space.None;
1099 try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
1100 }
1101 if (range.sentinel) |sentinel| {
1102 const colon = tree.prevToken(sentinel.firstToken());
1103 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1104 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
1105 }
1106 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
1107 },
1082 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1083 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space);
1084 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
1085 if (suffix_op.end) |end| {
1086 const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
1087 try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);
11081088 }
1089 if (suffix_op.sentinel) |sentinel| {
1090 const colon = tree.prevToken(sentinel.firstToken());
1091 try renderToken(tree, stream, colon, indent, start_col, Space.None); // :
1092 try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None);
1093 }
1094 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ]
1095 },
1096 .Deref => {
1097 const suffix_op = base.castTag(.Deref).?;
1098
1099 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1100 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
1101 },
1102 .UnwrapOptional => {
1103 const suffix_op = base.castTag(.UnwrapOptional).?;
1104
1105 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1106 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .
1107 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?
11091108 },
11101109
11111110 .ControlFlowExpression => {
src-self-hosted/astgen.zig+39-32
......@@ -34,7 +34,7 @@ pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
3434 .LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt),
3535 .LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte),
3636 .Period => return field(mod, scope, node.castTag(.Period).?),
37 .SuffixOp => return suffixOp(mod, scope, node.castTag(.SuffixOp).?),
37 .Deref => return deref(mod, scope, node.castTag(.Deref).?),
3838 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),
3939 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
4040 }
......@@ -73,32 +73,41 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop
7373 if (node.getTrailer("align_node")) |align_node| {
7474 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
7575 }
76 if (node.getTrailer("type_node")) |type_node| {
77 return mod.failNode(scope, type_node, "TODO implement typed locals", .{});
78 }
7976 const tree = scope.tree();
8077 switch (tree.token_ids[node.mut_token]) {
81 .Keyword_const => {},
78 .Keyword_const => {
79 if (node.getTrailer("type_node")) |type_node| {
80 return mod.failNode(scope, type_node, "TODO implement typed const locals", .{});
81 }
82 // Depending on the type of AST the initialization expression is, we may need an lvalue
83 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
84 // the variable, no memory location needed.
85 const init_node = node.getTrailer("init_node").?;
86 if (nodeMayNeedMemoryLocation(init_node)) {
87 return mod.failNode(scope, init_node, "TODO implement result locations", .{});
88 }
89 const init_inst = try expr(mod, scope, init_node);
90 const ident_name = try identifierTokenString(mod, scope, node.name_token);
91 return Scope.LocalVar{
92 .parent = scope,
93 .gen_zir = scope.getGenZIR(),
94 .name = ident_name,
95 .inst = init_inst,
96 };
97 },
8298 .Keyword_var => {
83 return mod.failTok(scope, node.mut_token, "TODO implement mutable locals", .{});
99 return mod.failNode(scope, &node.base, "TODO implement local vars", .{});
100 //const src = tree.token_locs[node.name_token].start;
101 //const alloc = mod.addZIRInst(scope, src, zir.Inst.Alloc, .{}, .{});
102 //if (node.getTrailer("type_node")) |type_node| {
103 // const type_inst = try expr(mod, scope, type_node);
104 // return mod.failNode(scope, type_node, "TODO implement typed var locals", .{});
105 //} else {
106 // return mod.failTok(scope, node.mut_token, "TODO implement mutable type-inferred locals", .{});
107 //}
84108 },
85109 else => unreachable,
86110 }
87 // Depending on the type of AST the initialization expression is, we may need an lvalue
88 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
89 // the variable, no memory location needed.
90 const init_node = node.getTrailer("init_node").?;
91 if (nodeMayNeedMemoryLocation(init_node)) {
92 return mod.failNode(scope, init_node, "TODO implement result locations", .{});
93 }
94 const init_inst = try expr(mod, scope, init_node);
95 const ident_name = try identifierTokenString(mod, scope, node.name_token);
96 return Scope.LocalVar{
97 .parent = scope,
98 .gen_zir = scope.getGenZIR(),
99 .name = ident_name,
100 .inst = init_inst,
101 };
102111}
103112
104113fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
......@@ -163,18 +172,13 @@ fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!
163172 return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = pointer }, .{});
164173}
165174
166fn suffixOp(mod: *Module, scope: *Scope, node: *ast.Node.SuffixOp) InnerError!*zir.Inst {
167 switch (node.op) {
168 .Deref => {
169 const tree = scope.tree();
170 const src = tree.token_locs[node.rtoken].start;
175fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
176 const tree = scope.tree();
177 const src = tree.token_locs[node.rtoken].start;
171178
172 const lhs = try expr(mod, scope, node.lhs);
179 const lhs = try expr(mod, scope, node.lhs);
173180
174 return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = lhs }, .{});
175 },
176 else => return mod.failNode(scope, &node.base, "TODO implement astGenExpr for suffixOp {}", .{node.op}),
177 }
181 return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = lhs }, .{});
178182}
179183
180184fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
......@@ -672,6 +676,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
672676 .Period,
673677 .Sub,
674678 .SubWrap,
679 .Slice,
680 .Deref,
681 .ArrayAccess,
675682 => return false,
676683
677684 // Forward the question to a sub-expression.
......@@ -682,6 +689,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
682689 .OrElse => node = node.castTag(.OrElse).?.rhs,
683690 .Comptime => node = node.castTag(.Comptime).?.expr,
684691 .Nosuspend => node = node.castTag(.Nosuspend).?.expr,
692 .UnwrapOptional => node = node.castTag(.UnwrapOptional).?.lhs,
685693
686694 // True because these are exactly the expressions we need memory locations for.
687695 .ArrayInitializer,
......@@ -697,7 +705,6 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
697705 .Switch,
698706 .Call,
699707 .BuiltinCall, // TODO some of these can return false
700 .SuffixOp, // TODO this should be split up
701708 => return true,
702709
703710 // Depending on AST properties, they may need memory locations.
src-self-hosted/translate_c.zig+10-13
......@@ -2962,9 +2962,9 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
29622962 cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);
29632963 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
29642964 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2965 node.op.ArrayAccess = &cast_node.base;
2965 node.index_expr = &cast_node.base;
29662966 } else {
2967 node.op.ArrayAccess = try transExpr(rp, scope, subscr_expr, .used, .r_value);
2967 node.index_expr = try transExpr(rp, scope, subscr_expr, .used, .r_value);
29682968 node.rtoken = try appendToken(rp.c, .RBrace, "]");
29692969 }
29702970 return maybeSuppressResult(rp, scope, result_used, &node.base);
......@@ -4405,9 +4405,9 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
44054405fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
44064406 _ = try appendToken(c, .Period, ".");
44074407 const qm = try appendToken(c, .QuestionMark, "?");
4408 const node = try c.arena.create(ast.Node.SuffixOp);
4408 const node = try c.arena.create(ast.Node.SimpleSuffixOp);
44094409 node.* = .{
4410 .op = .UnwrapOptional,
4410 .base = .{ .tag = .UnwrapOptional },
44114411 .lhs = wrapped,
44124412 .rtoken = qm,
44134413 };
......@@ -4567,23 +4567,21 @@ fn transCreateNodeShiftOp(
45674567}
45684568
45694569fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
4570 const node = try c.arena.create(ast.Node.SuffixOp);
4570 const node = try c.arena.create(ast.Node.SimpleSuffixOp);
45714571 node.* = .{
4572 .base = .{ .tag = .Deref },
45724573 .lhs = lhs,
4573 .op = .Deref,
45744574 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
45754575 };
45764576 return &node.base;
45774577}
45784578
4579fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {
4579fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAccess {
45804580 _ = try appendToken(c, .LBrace, "[");
4581 const node = try c.arena.create(ast.Node.SuffixOp);
4581 const node = try c.arena.create(ast.Node.ArrayAccess);
45824582 node.* = .{
45834583 .lhs = lhs,
4584 .op = .{
4585 .ArrayAccess = undefined,
4586 },
4584 .index_expr = undefined,
45874585 .rtoken = undefined,
45884586 };
45894587 return node;
......@@ -6010,7 +6008,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
60106008 },
60116009 .LBracket => {
60126010 const arr_node = try transCreateNodeArrayAccess(c, node);
6013 arr_node.op.ArrayAccess = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
6011 arr_node.index_expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope);
60146012 arr_node.rtoken = try appendToken(c, .RBracket, "]");
60156013 node = &arr_node.base;
60166014 if (it.next().?.id != .RBracket) {
......@@ -6099,7 +6097,6 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
60996097 };
61006098 mem.copy(*ast.Node, tuple_node.list(), init_vals.items);
61016099
6102
61036100 //(@import("std").mem.zeroInit(T, .{x}))
61046101 const import_fn_call = try c.createBuiltinCall("@import", 1);
61056102 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");