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 {...@@ -471,9 +471,14 @@ pub const Node = struct {
471 ArrayTypeSentinel,471 ArrayTypeSentinel,
472 PtrType,472 PtrType,
473 SliceType,473 SliceType,
474 /// Not all suffix operations are under this tag. To save memory, some474 /// `a[b..c]`
475 /// suffix operations have dedicated Node tags.475 Slice,
476 SuffixOp,476 /// `a.*`
477 Deref,
478 /// `a.?`
479 UnwrapOptional,
480 /// `a[b]`
481 ArrayAccess,
477 /// `T{a, b}`482 /// `T{a, b}`
478 ArrayInitializer,483 ArrayInitializer,
479 /// ArrayInitializer but with `.` instead of a left-hand-side operand.484 /// ArrayInitializer but with `.` instead of a left-hand-side operand.
...@@ -601,7 +606,9 @@ pub const Node = struct {...@@ -601,7 +606,9 @@ pub const Node = struct {
601606
602 .PtrType => PtrType,607 .PtrType => PtrType,
603 .SliceType => SliceType,608 .SliceType => SliceType,
604 .SuffixOp => SuffixOp,609 .Slice => Slice,
610 .Deref, .UnwrapOptional => SimpleSuffixOp,
611 .ArrayAccess => ArrayAccess,
605612
606 .ArrayInitializer => ArrayInitializer,613 .ArrayInitializer => ArrayInitializer,
607 .ArrayInitializerDot => ArrayInitializerDot,614 .ArrayInitializerDot => ArrayInitializerDot,
...@@ -2398,8 +2405,8 @@ pub const Node = struct {...@@ -2398,8 +2405,8 @@ pub const Node = struct {
2398 /// Parameter nodes directly follow Call in memory.2405 /// Parameter nodes directly follow Call in memory.
2399 pub const Call = struct {2406 pub const Call = struct {
2400 base: Node = Node{ .tag = .Call },2407 base: Node = Node{ .tag = .Call },
2401 lhs: *Node,
2402 rtoken: TokenIndex,2408 rtoken: TokenIndex,
2409 lhs: *Node,
2403 params_len: NodeIndex,2410 params_len: NodeIndex,
2404 async_token: ?TokenIndex,2411 async_token: ?TokenIndex,
24052412
...@@ -2450,62 +2457,90 @@ pub const Node = struct {...@@ -2450,62 +2457,90 @@ pub const Node = struct {
2450 }2457 }
2451 };2458 };
24522459
2453 pub const SuffixOp = struct {2460 pub const ArrayAccess = struct {
2454 base: Node = Node{ .tag = .SuffixOp },2461 base: Node = Node{ .tag = .ArrayAccess },
2455 op: Op,2462 rtoken: TokenIndex,
2456 lhs: *Node,2463 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,
2457 rtoken: TokenIndex,2489 rtoken: TokenIndex,
2490 lhs: *Node,
24582491
2459 pub const Op = union(enum) {2492 pub fn iterate(self: *const SimpleSuffixOp, index: usize) ?*Node {
2460 ArrayAccess: *Node,2493 var i = index;
2461 Slice: Slice,
2462 Deref,
2463 UnwrapOptional,
24642494
2465 pub const Slice = struct {2495 if (i < 1) return self.lhs;
2466 start: *Node,2496 i -= 1;
2467 end: ?*Node,
2468 sentinel: ?*Node,
2469 };
2470 };
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 {
2473 var i = index;2519 var i = index;
24742520
2475 if (i == 0) return self.lhs;2521 if (i < 1) return self.lhs;
2476 i -= 1;2522 i -= 1;
24772523
2478 switch (self.op) {2524 if (i < 1) return self.start;
2479 .ArrayAccess => |index_expr| {2525 i -= 1;
2480 if (i < 1) return index_expr;
2481 i -= 1;
2482 },
2483 .Slice => |range| {
2484 if (i < 1) return range.start;
2485 i -= 1;
24862526
2487 if (range.end) |end| {2527 if (self.end) |end| {
2488 if (i < 1) return end;2528 if (i < 1) return end;
2489 i -= 1;2529 i -= 1;
2490 }2530 }
2491 if (range.sentinel) |sentinel| {2531 if (self.sentinel) |sentinel| {
2492 if (i < 1) return sentinel;2532 if (i < 1) return sentinel;
2493 i -= 1;2533 i -= 1;
2494 }
2495 },
2496 .UnwrapOptional,
2497 .Deref,
2498 => {},
2499 }2534 }
25002535
2501 return null;2536 return null;
2502 }2537 }
25032538
2504 pub fn firstToken(self: *const SuffixOp) TokenIndex {2539 pub fn firstToken(self: *const Slice) TokenIndex {
2505 return self.lhs.firstToken();2540 return self.lhs.firstToken();
2506 }2541 }
25072542
2508 pub fn lastToken(self: *const SuffixOp) TokenIndex {2543 pub fn lastToken(self: *const Slice) TokenIndex {
2509 return self.rtoken;2544 return self.rtoken;
2510 }2545 }
2511 };2546 };
lib/std/zig/parse.zig+65-167
...@@ -1439,58 +1439,7 @@ const Parser = struct {...@@ -1439,58 +1439,7 @@ const Parser = struct {
1439 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },1439 .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i },
1440 });1440 });
14411441
1442 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.1442 while (try p.parseSuffixOp(res)) |node| {
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 }
1494 res = node;1443 res = node;
1495 }1444 }
14961445
...@@ -1516,57 +1465,7 @@ const Parser = struct {...@@ -1516,57 +1465,7 @@ const Parser = struct {
1516 var res = expr;1465 var res = expr;
15171466
1518 while (true) {1467 while (true) {
1519 // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards.1468 if (try p.parseSuffixOp(res)) |node| {
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 }
1570 res = node;1469 res = node;
1571 continue;1470 continue;
1572 }1471 }
...@@ -2733,78 +2632,77 @@ const Parser = struct {...@@ -2733,78 +2632,77 @@ const Parser = struct {
2733 /// / DOT IDENTIFIER2632 /// / DOT IDENTIFIER
2734 /// / DOTASTERISK2633 /// / DOTASTERISK
2735 /// / DOTQUESTIONMARK2634 /// / DOTQUESTIONMARK
2736 fn parseSuffixOp(p: *Parser) !?*Node {2635 fn parseSuffixOp(p: *Parser, lhs: *Node) !?*Node {
2737 const OpAndToken = struct {2636 if (p.eatToken(.LBracket)) |_| {
2738 op: Node.SuffixOp.Op,2637 const index_expr = try p.expectNode(parseExpr, .{
2739 token: TokenIndex,2638 .ExpectedExpr = .{ .token = p.tok_i },
2740 };2639 });
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 }
27642640
2765 break :blk .{2641 if (p.eatToken(.Ellipsis2) != null) {
2766 .op = .{ .ArrayAccess = index_expr },2642 const end_expr = try p.parseExpr();
2767 .token = try p.expectToken(.RBracket),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,
2768 };2655 };
2656 return &node.base;
2769 }2657 }
27702658
2771 if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {2659 const rtoken = try p.expectToken(.RBracket);
2772 break :blk .{ .op = .Deref, .token = period_asterisk };2660 const node = try p.arena.allocator.create(Node.ArrayAccess);
2773 }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| {2669 if (p.eatToken(.PeriodAsterisk)) |period_asterisk| {
2776 if (try p.parseIdentifier()) |identifier| {2670 const node = try p.arena.allocator.create(Node.SimpleSuffixOp);
2777 // TODO: It's a bit weird to return a SimpleInfixOp from the SuffixOp parser.2671 node.* = .{
2778 // Should there be an Node.SuffixOp.FieldAccess variant? Or should2672 .base = .{ .tag = .Deref },
2779 // this grammar rule be altered?2673 .lhs = lhs,
2780 const node = try p.arena.allocator.create(Node.SimpleInfixOp);2674 .rtoken = period_asterisk,
2781 node.* = .{2675 };
2782 .base = Node{ .tag = .Period },2676 return &node.base;
2783 .op_token = period,2677 }
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 }
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 });
2798 return null;2702 return null;
2799 };2703 }
28002704
2801 const node = try p.arena.allocator.create(Node.SuffixOp);2705 return null;
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;
2808 }2706 }
28092707
2810 /// FnCallArguments <- LPAREN ExprList RPAREN2708 /// FnCallArguments <- LPAREN ExprList RPAREN
lib/std/zig/render.zig+54-55
...@@ -1044,68 +1044,67 @@ fn renderExpression(...@@ -1044,68 +1044,67 @@ fn renderExpression(
1044 return renderToken(tree, stream, call.rtoken, indent, start_col, space);1044 return renderToken(tree, stream, call.rtoken, indent, start_col, space);
1045 },1045 },
10461046
1047 .SuffixOp => {1047 .ArrayAccess => {
1048 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);1048 const suffix_op = base.castTag(.ArrayAccess).?;
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 },
10711049
1072 .Deref => {1050 const lbracket = tree.nextToken(suffix_op.lhs.lastToken());
1073 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);1051 const rbracket = tree.nextToken(suffix_op.index_expr.lastToken());
1074 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .*
1075 },
10761052
1077 .UnwrapOptional => {1053 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1078 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);1054 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1079 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // .1055
1080 return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ?1056 const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment;
1081 },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| {1072 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
1084 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None);
10851073
1086 const lbracket = tree.prevToken(range.start.firstToken());1074 const lbracket = tree.prevToken(suffix_op.start.firstToken());
1087 const dotdot = tree.nextToken(range.start.lastToken());1075 const dotdot = tree.nextToken(suffix_op.start.lastToken());
10881076
1089 const after_start_space_bool = nodeCausesSliceOpSpace(range.start) or1077 const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or
1090 (if (range.end) |end| nodeCausesSliceOpSpace(end) else false);1078 (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false);
1091 const after_start_space = if (after_start_space_bool) Space.Space else Space.None;1079 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;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); // [1082 try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [
1095 try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space);1083 try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space);
1096 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..1084 try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // ..
1097 if (range.end) |end| {1085 if (suffix_op.end) |end| {
1098 const after_end_space = if (range.sentinel != null) Space.Space else Space.None;1086 const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None;
1099 try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space);1087 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 },
1108 }1088 }
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); // ?
1109 },1108 },
11101109
1111 .ControlFlowExpression => {1110 .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 {...@@ -34,7 +34,7 @@ pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst {
34 .LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt),34 .LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt),
35 .LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte),35 .LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte),
36 .Period => return field(mod, scope, node.castTag(.Period).?),36 .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).?),
38 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),38 .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?),
39 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),39 else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
40 }40 }
...@@ -73,32 +73,41 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop...@@ -73,32 +73,41 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop
73 if (node.getTrailer("align_node")) |align_node| {73 if (node.getTrailer("align_node")) |align_node| {
74 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});74 return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{});
75 }75 }
76 if (node.getTrailer("type_node")) |type_node| {
77 return mod.failNode(scope, type_node, "TODO implement typed locals", .{});
78 }
79 const tree = scope.tree();76 const tree = scope.tree();
80 switch (tree.token_ids[node.mut_token]) {77 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 },
82 .Keyword_var => {98 .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 //}
84 },108 },
85 else => unreachable,109 else => unreachable,
86 }110 }
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 };
102}111}
103112
104fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {113fn 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!...@@ -163,18 +172,13 @@ fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!
163 return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = pointer }, .{});172 return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = pointer }, .{});
164}173}
165174
166fn suffixOp(mod: *Module, scope: *Scope, node: *ast.Node.SuffixOp) InnerError!*zir.Inst {175fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
167 switch (node.op) {176 const tree = scope.tree();
168 .Deref => {177 const src = tree.token_locs[node.rtoken].start;
169 const tree = scope.tree();
170 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 }, .{});181 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 }
178}182}
179183
180fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {184fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
...@@ -672,6 +676,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {...@@ -672,6 +676,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
672 .Period,676 .Period,
673 .Sub,677 .Sub,
674 .SubWrap,678 .SubWrap,
679 .Slice,
680 .Deref,
681 .ArrayAccess,
675 => return false,682 => return false,
676683
677 // Forward the question to a sub-expression.684 // Forward the question to a sub-expression.
...@@ -682,6 +689,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {...@@ -682,6 +689,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
682 .OrElse => node = node.castTag(.OrElse).?.rhs,689 .OrElse => node = node.castTag(.OrElse).?.rhs,
683 .Comptime => node = node.castTag(.Comptime).?.expr,690 .Comptime => node = node.castTag(.Comptime).?.expr,
684 .Nosuspend => node = node.castTag(.Nosuspend).?.expr,691 .Nosuspend => node = node.castTag(.Nosuspend).?.expr,
692 .UnwrapOptional => node = node.castTag(.UnwrapOptional).?.lhs,
685693
686 // True because these are exactly the expressions we need memory locations for.694 // True because these are exactly the expressions we need memory locations for.
687 .ArrayInitializer,695 .ArrayInitializer,
...@@ -697,7 +705,6 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {...@@ -697,7 +705,6 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool {
697 .Switch,705 .Switch,
698 .Call,706 .Call,
699 .BuiltinCall, // TODO some of these can return false707 .BuiltinCall, // TODO some of these can return false
700 .SuffixOp, // TODO this should be split up
701 => return true,708 => return true,
702709
703 // Depending on AST properties, they may need memory locations.710 // 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...@@ -2962,9 +2962,9 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS
2962 cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);2962 cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);
2963 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");2963 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2964 node.rtoken = try appendToken(rp.c, .RBrace, "]");2964 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2965 node.op.ArrayAccess = &cast_node.base;2965 node.index_expr = &cast_node.base;
2966 } else {2966 } 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);
2968 node.rtoken = try appendToken(rp.c, .RBrace, "]");2968 node.rtoken = try appendToken(rp.c, .RBrace, "]");
2969 }2969 }
2970 return maybeSuppressResult(rp, scope, result_used, &node.base);2970 return maybeSuppressResult(rp, scope, result_used, &node.base);
...@@ -4405,9 +4405,9 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a...@@ -4405,9 +4405,9 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a
4405fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {4405fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
4406 _ = try appendToken(c, .Period, ".");4406 _ = try appendToken(c, .Period, ".");
4407 const qm = try appendToken(c, .QuestionMark, "?");4407 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);
4409 node.* = .{4409 node.* = .{
4410 .op = .UnwrapOptional,4410 .base = .{ .tag = .UnwrapOptional },
4411 .lhs = wrapped,4411 .lhs = wrapped,
4412 .rtoken = qm,4412 .rtoken = qm,
4413 };4413 };
...@@ -4567,23 +4567,21 @@ fn transCreateNodeShiftOp(...@@ -4567,23 +4567,21 @@ fn transCreateNodeShiftOp(
4567}4567}
45684568
4569fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {4569fn 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);
4571 node.* = .{4571 node.* = .{
4572 .base = .{ .tag = .Deref },
4572 .lhs = lhs,4573 .lhs = lhs,
4573 .op = .Deref,
4574 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),4574 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
4575 };4575 };
4576 return &node.base;4576 return &node.base;
4577}4577}
45784578
4579fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp {4579fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAccess {
4580 _ = try appendToken(c, .LBrace, "[");4580 _ = try appendToken(c, .LBrace, "[");
4581 const node = try c.arena.create(ast.Node.SuffixOp);4581 const node = try c.arena.create(ast.Node.ArrayAccess);
4582 node.* = .{4582 node.* = .{
4583 .lhs = lhs,4583 .lhs = lhs,
4584 .op = .{4584 .index_expr = undefined,
4585 .ArrayAccess = undefined,
4586 },
4587 .rtoken = undefined,4585 .rtoken = undefined,
4588 };4586 };
4589 return node;4587 return node;
...@@ -6010,7 +6008,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -6010,7 +6008,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
6010 },6008 },
6011 .LBracket => {6009 .LBracket => {
6012 const arr_node = try transCreateNodeArrayAccess(c, node);6010 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);
6014 arr_node.rtoken = try appendToken(c, .RBracket, "]");6012 arr_node.rtoken = try appendToken(c, .RBracket, "]");
6015 node = &arr_node.base;6013 node = &arr_node.base;
6016 if (it.next().?.id != .RBracket) {6014 if (it.next().?.id != .RBracket) {
...@@ -6099,7 +6097,6 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,...@@ -6099,7 +6097,6 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8,
6099 };6097 };
6100 mem.copy(*ast.Node, tuple_node.list(), init_vals.items);6098 mem.copy(*ast.Node, tuple_node.list(), init_vals.items);
61016099
6102
6103 //(@import("std").mem.zeroInit(T, .{x}))6100 //(@import("std").mem.zeroInit(T, .{x}))
6104 const import_fn_call = try c.createBuiltinCall("@import", 1);6101 const import_fn_call = try c.createBuiltinCall("@import", 1);
6105 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");6102 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");