diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 7fee55c71e..2b42342f1e 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -471,9 +471,14 @@ pub const Node = struct { ArrayTypeSentinel, PtrType, SliceType, - /// Not all suffix operations are under this tag. To save memory, some - /// suffix operations have dedicated Node tags. - SuffixOp, + /// `a[b..c]` + Slice, + /// `a.*` + Deref, + /// `a.?` + UnwrapOptional, + /// `a[b]` + ArrayAccess, /// `T{a, b}` ArrayInitializer, /// ArrayInitializer but with `.` instead of a left-hand-side operand. @@ -601,7 +606,9 @@ pub const Node = struct { .PtrType => PtrType, .SliceType => SliceType, - .SuffixOp => SuffixOp, + .Slice => Slice, + .Deref, .UnwrapOptional => SimpleSuffixOp, + .ArrayAccess => ArrayAccess, .ArrayInitializer => ArrayInitializer, .ArrayInitializerDot => ArrayInitializerDot, @@ -2398,8 +2405,8 @@ pub const Node = struct { /// Parameter nodes directly follow Call in memory. pub const Call = struct { base: Node = Node{ .tag = .Call }, - lhs: *Node, rtoken: TokenIndex, + lhs: *Node, params_len: NodeIndex, async_token: ?TokenIndex, @@ -2450,62 +2457,90 @@ pub const Node = struct { } }; - pub const SuffixOp = struct { - base: Node = Node{ .tag = .SuffixOp }, - op: Op, - lhs: *Node, + pub const ArrayAccess = struct { + base: Node = Node{ .tag = .ArrayAccess }, rtoken: TokenIndex, + lhs: *Node, + index_expr: *Node, - pub const Op = union(enum) { - ArrayAccess: *Node, - Slice: Slice, - Deref, - UnwrapOptional, - - pub const Slice = struct { - start: *Node, - end: ?*Node, - sentinel: ?*Node, - }; - }; - - pub fn iterate(self: *const SuffixOp, index: usize) ?*Node { + pub fn iterate(self: *const ArrayAccess, index: usize) ?*Node { var i = index; - if (i == 0) return self.lhs; + if (i < 1) return self.lhs; i -= 1; - switch (self.op) { - .ArrayAccess => |index_expr| { - if (i < 1) return index_expr; - i -= 1; - }, - .Slice => |range| { - if (i < 1) return range.start; - i -= 1; + if (i < 1) return self.index_expr; + i -= 1; - if (range.end) |end| { - if (i < 1) return end; - i -= 1; - } - if (range.sentinel) |sentinel| { - if (i < 1) return sentinel; - i -= 1; - } - }, - .UnwrapOptional, - .Deref, - => {}, + return null; + } + + pub fn firstToken(self: *const ArrayAccess) TokenIndex { + return self.lhs.firstToken(); + } + + pub fn lastToken(self: *const ArrayAccess) TokenIndex { + return self.rtoken; + } + }; + + pub const SimpleSuffixOp = struct { + base: Node, + rtoken: TokenIndex, + lhs: *Node, + + pub fn iterate(self: *const SimpleSuffixOp, index: usize) ?*Node { + var i = index; + + if (i < 1) return self.lhs; + i -= 1; + + return null; + } + + pub fn firstToken(self: *const SimpleSuffixOp) TokenIndex { + return self.lhs.firstToken(); + } + + pub fn lastToken(self: *const SimpleSuffixOp) TokenIndex { + return self.rtoken; + } + }; + + pub const Slice = struct { + base: Node = Node{ .tag = .Slice }, + rtoken: TokenIndex, + lhs: *Node, + start: *Node, + end: ?*Node, + sentinel: ?*Node, + + pub fn iterate(self: *const Slice, index: usize) ?*Node { + var i = index; + + if (i < 1) return self.lhs; + i -= 1; + + if (i < 1) return self.start; + i -= 1; + + if (self.end) |end| { + if (i < 1) return end; + i -= 1; + } + if (self.sentinel) |sentinel| { + if (i < 1) return sentinel; + i -= 1; } return null; } - pub fn firstToken(self: *const SuffixOp) TokenIndex { + pub fn firstToken(self: *const Slice) TokenIndex { return self.lhs.firstToken(); } - pub fn lastToken(self: *const SuffixOp) TokenIndex { + pub fn lastToken(self: *const Slice) TokenIndex { return self.rtoken; } }; diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index c6d48c946d..0e1af4e8a1 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1439,58 +1439,7 @@ const Parser = struct { .ExpectedPrimaryTypeExpr = .{ .token = p.tok_i }, }); - // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards. - while (try p.parseSuffixOp()) |node| { - switch (node.tag) { - .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, - .Catch => node.castTag(.Catch).?.lhs = res, - - .Add, - .AddWrap, - .ArrayCat, - .ArrayMult, - .Assign, - .AssignBitAnd, - .AssignBitOr, - .AssignBitShiftLeft, - .AssignBitShiftRight, - .AssignBitXor, - .AssignDiv, - .AssignSub, - .AssignSubWrap, - .AssignMod, - .AssignAdd, - .AssignAddWrap, - .AssignMul, - .AssignMulWrap, - .BangEqual, - .BitAnd, - .BitOr, - .BitShiftLeft, - .BitShiftRight, - .BitXor, - .BoolAnd, - .BoolOr, - .Div, - .EqualEqual, - .ErrorUnion, - .GreaterOrEqual, - .GreaterThan, - .LessOrEqual, - .LessThan, - .MergeErrorSets, - .Mod, - .Mul, - .MulWrap, - .Period, - .Range, - .Sub, - .SubWrap, - .OrElse, - => node.cast(Node.SimpleInfixOp).?.lhs = res, - - else => unreachable, - } + while (try p.parseSuffixOp(res)) |node| { res = node; } @@ -1516,57 +1465,7 @@ const Parser = struct { var res = expr; while (true) { - // TODO pass `res` into `parseSuffixOp` rather than patching it up afterwards. - if (try p.parseSuffixOp()) |node| { - switch (node.tag) { - .SuffixOp => node.cast(Node.SuffixOp).?.lhs = res, - .Catch => node.castTag(.Catch).?.lhs = res, - - .Add, - .AddWrap, - .ArrayCat, - .ArrayMult, - .Assign, - .AssignBitAnd, - .AssignBitOr, - .AssignBitShiftLeft, - .AssignBitShiftRight, - .AssignBitXor, - .AssignDiv, - .AssignSub, - .AssignSubWrap, - .AssignMod, - .AssignAdd, - .AssignAddWrap, - .AssignMul, - .AssignMulWrap, - .BangEqual, - .BitAnd, - .BitOr, - .BitShiftLeft, - .BitShiftRight, - .BitXor, - .BoolAnd, - .BoolOr, - .Div, - .EqualEqual, - .ErrorUnion, - .GreaterOrEqual, - .GreaterThan, - .LessOrEqual, - .LessThan, - .MergeErrorSets, - .Mod, - .Mul, - .MulWrap, - .Period, - .Range, - .Sub, - .SubWrap, - .OrElse, - => node.cast(Node.SimpleInfixOp).?.lhs = res, - else => unreachable, - } + if (try p.parseSuffixOp(res)) |node| { res = node; continue; } @@ -2733,78 +2632,77 @@ const Parser = struct { /// / DOT IDENTIFIER /// / DOTASTERISK /// / DOTQUESTIONMARK - fn parseSuffixOp(p: *Parser) !?*Node { - const OpAndToken = struct { - op: Node.SuffixOp.Op, - token: TokenIndex, - }; - const op_and_token: OpAndToken = blk: { - if (p.eatToken(.LBracket)) |_| { - const index_expr = try p.expectNode(parseExpr, .{ - .ExpectedExpr = .{ .token = p.tok_i }, - }); + fn parseSuffixOp(p: *Parser, lhs: *Node) !?*Node { + if (p.eatToken(.LBracket)) |_| { + const index_expr = try p.expectNode(parseExpr, .{ + .ExpectedExpr = .{ .token = p.tok_i }, + }); - if (p.eatToken(.Ellipsis2) != null) { - const end_expr = try p.parseExpr(); - const sentinel: ?*Node = if (p.eatToken(.Colon) != null) - try p.parseExpr() - else - null; - break :blk .{ - .op = .{ - .Slice = .{ - .start = index_expr, - .end = end_expr, - .sentinel = sentinel, - }, - }, - .token = try p.expectToken(.RBracket), - }; - } - - break :blk .{ - .op = .{ .ArrayAccess = index_expr }, - .token = try p.expectToken(.RBracket), + if (p.eatToken(.Ellipsis2) != null) { + const end_expr = try p.parseExpr(); + const sentinel: ?*Node = if (p.eatToken(.Colon) != null) + try p.parseExpr() + else + null; + const rtoken = try p.expectToken(.RBracket); + const node = try p.arena.allocator.create(Node.Slice); + node.* = .{ + .lhs = lhs, + .rtoken = rtoken, + .start = index_expr, + .end = end_expr, + .sentinel = sentinel, }; + return &node.base; } - if (p.eatToken(.PeriodAsterisk)) |period_asterisk| { - break :blk .{ .op = .Deref, .token = period_asterisk }; - } + const rtoken = try p.expectToken(.RBracket); + const node = try p.arena.allocator.create(Node.ArrayAccess); + node.* = .{ + .lhs = lhs, + .rtoken = rtoken, + .index_expr = index_expr, + }; + return &node.base; + } - if (p.eatToken(.Period)) |period| { - if (try p.parseIdentifier()) |identifier| { - // TODO: It's a bit weird to return a SimpleInfixOp from the SuffixOp parser. - // Should there be an Node.SuffixOp.FieldAccess variant? Or should - // this grammar rule be altered? - const node = try p.arena.allocator.create(Node.SimpleInfixOp); - node.* = .{ - .base = Node{ .tag = .Period }, - .op_token = period, - .lhs = undefined, // set by caller - .rhs = identifier, - }; - return &node.base; - } - if (p.eatToken(.QuestionMark)) |question_mark| { - break :blk .{ .op = .UnwrapOptional, .token = question_mark }; - } - try p.errors.append(p.gpa, .{ - .ExpectedSuffixOp = .{ .token = p.tok_i }, - }); - return null; - } + if (p.eatToken(.PeriodAsterisk)) |period_asterisk| { + const node = try p.arena.allocator.create(Node.SimpleSuffixOp); + node.* = .{ + .base = .{ .tag = .Deref }, + .lhs = lhs, + .rtoken = period_asterisk, + }; + return &node.base; + } + if (p.eatToken(.Period)) |period| { + if (try p.parseIdentifier()) |identifier| { + const node = try p.arena.allocator.create(Node.SimpleInfixOp); + node.* = .{ + .base = Node{ .tag = .Period }, + .op_token = period, + .lhs = lhs, + .rhs = identifier, + }; + return &node.base; + } + if (p.eatToken(.QuestionMark)) |question_mark| { + const node = try p.arena.allocator.create(Node.SimpleSuffixOp); + node.* = .{ + .base = .{ .tag = .UnwrapOptional }, + .lhs = lhs, + .rtoken = question_mark, + }; + return &node.base; + } + try p.errors.append(p.gpa, .{ + .ExpectedSuffixOp = .{ .token = p.tok_i }, + }); return null; - }; + } - const node = try p.arena.allocator.create(Node.SuffixOp); - node.* = .{ - .lhs = undefined, // set by caller - .op = op_and_token.op, - .rtoken = op_and_token.token, - }; - return &node.base; + return null; } /// FnCallArguments <- LPAREN ExprList RPAREN diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index c805178523..3b3fbd10b7 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1044,68 +1044,67 @@ fn renderExpression( return renderToken(tree, stream, call.rtoken, indent, start_col, space); }, - .SuffixOp => { - const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base); + .ArrayAccess => { + const suffix_op = base.castTag(.ArrayAccess).?; - switch (suffix_op.op) { - .ArrayAccess => |index_expr| { - const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); - const rbracket = tree.nextToken(index_expr.lastToken()); + const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); + const rbracket = tree.nextToken(suffix_op.index_expr.lastToken()); - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); - try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ - const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment; - const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment; - const new_indent = if (ends_with_comment) indent + indent_delta else indent; - const new_space = if (ends_with_comment) Space.Newline else Space.None; - try renderExpression(allocator, stream, tree, new_indent, start_col, index_expr, new_space); - if (starts_with_comment) { - try stream.writeByte('\n'); - } - if (ends_with_comment or starts_with_comment) { - try stream.writeByteNTimes(' ', indent); - } - return renderToken(tree, stream, rbracket, indent, start_col, space); // ] - }, - - .Deref => { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); - return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* - }, - - .UnwrapOptional => { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); - try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . - return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? - }, - - .Slice => |range| { - try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); - - const lbracket = tree.prevToken(range.start.firstToken()); - const dotdot = tree.nextToken(range.start.lastToken()); - - const after_start_space_bool = nodeCausesSliceOpSpace(range.start) or - (if (range.end) |end| nodeCausesSliceOpSpace(end) else false); - const after_start_space = if (after_start_space_bool) Space.Space else Space.None; - const after_op_space = if (range.end != null) after_start_space else Space.None; - - try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ - try renderExpression(allocator, stream, tree, indent, start_col, range.start, after_start_space); - try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // .. - if (range.end) |end| { - const after_end_space = if (range.sentinel != null) Space.Space else Space.None; - try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space); - } - if (range.sentinel) |sentinel| { - const colon = tree.prevToken(sentinel.firstToken()); - try renderToken(tree, stream, colon, indent, start_col, Space.None); // : - try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None); - } - return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ] - }, + const starts_with_comment = tree.token_ids[lbracket + 1] == .LineComment; + const ends_with_comment = tree.token_ids[rbracket - 1] == .LineComment; + const new_indent = if (ends_with_comment) indent + indent_delta else indent; + const new_space = if (ends_with_comment) Space.Newline else Space.None; + try renderExpression(allocator, stream, tree, new_indent, start_col, suffix_op.index_expr, new_space); + if (starts_with_comment) { + try stream.writeByte('\n'); } + if (ends_with_comment or starts_with_comment) { + try stream.writeByteNTimes(' ', indent); + } + return renderToken(tree, stream, rbracket, indent, start_col, space); // ] + }, + .Slice => { + const suffix_op = base.castTag(.Slice).?; + + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + + const lbracket = tree.prevToken(suffix_op.start.firstToken()); + const dotdot = tree.nextToken(suffix_op.start.lastToken()); + + const after_start_space_bool = nodeCausesSliceOpSpace(suffix_op.start) or + (if (suffix_op.end) |end| nodeCausesSliceOpSpace(end) else false); + const after_start_space = if (after_start_space_bool) Space.Space else Space.None; + const after_op_space = if (suffix_op.end != null) after_start_space else Space.None; + + try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.start, after_start_space); + try renderToken(tree, stream, dotdot, indent, start_col, after_op_space); // .. + if (suffix_op.end) |end| { + const after_end_space = if (suffix_op.sentinel != null) Space.Space else Space.None; + try renderExpression(allocator, stream, tree, indent, start_col, end, after_end_space); + } + if (suffix_op.sentinel) |sentinel| { + const colon = tree.prevToken(sentinel.firstToken()); + try renderToken(tree, stream, colon, indent, start_col, Space.None); // : + try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None); + } + return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ] + }, + .Deref => { + const suffix_op = base.castTag(.Deref).?; + + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* + }, + .UnwrapOptional => { + const suffix_op = base.castTag(.UnwrapOptional).?; + + try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); + try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . + return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? }, .ControlFlowExpression => { diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 917fa009bb..aca80abab3 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -34,7 +34,7 @@ pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { .LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt), .LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte), .Period => return field(mod, scope, node.castTag(.Period).?), - .SuffixOp => return suffixOp(mod, scope, node.castTag(.SuffixOp).?), + .Deref => return deref(mod, scope, node.castTag(.Deref).?), .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?), else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}), } @@ -73,32 +73,41 @@ fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scop if (node.getTrailer("align_node")) |align_node| { return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{}); } - if (node.getTrailer("type_node")) |type_node| { - return mod.failNode(scope, type_node, "TODO implement typed locals", .{}); - } const tree = scope.tree(); switch (tree.token_ids[node.mut_token]) { - .Keyword_const => {}, + .Keyword_const => { + if (node.getTrailer("type_node")) |type_node| { + return mod.failNode(scope, type_node, "TODO implement typed const locals", .{}); + } + // Depending on the type of AST the initialization expression is, we may need an lvalue + // or an rvalue as a result location. If it is an rvalue, we can use the instruction as + // the variable, no memory location needed. + const init_node = node.getTrailer("init_node").?; + if (nodeMayNeedMemoryLocation(init_node)) { + return mod.failNode(scope, init_node, "TODO implement result locations", .{}); + } + const init_inst = try expr(mod, scope, init_node); + const ident_name = try identifierTokenString(mod, scope, node.name_token); + return Scope.LocalVar{ + .parent = scope, + .gen_zir = scope.getGenZIR(), + .name = ident_name, + .inst = init_inst, + }; + }, .Keyword_var => { - return mod.failTok(scope, node.mut_token, "TODO implement mutable locals", .{}); + return mod.failNode(scope, &node.base, "TODO implement local vars", .{}); + //const src = tree.token_locs[node.name_token].start; + //const alloc = mod.addZIRInst(scope, src, zir.Inst.Alloc, .{}, .{}); + //if (node.getTrailer("type_node")) |type_node| { + // const type_inst = try expr(mod, scope, type_node); + // return mod.failNode(scope, type_node, "TODO implement typed var locals", .{}); + //} else { + // return mod.failTok(scope, node.mut_token, "TODO implement mutable type-inferred locals", .{}); + //} }, else => unreachable, } - // Depending on the type of AST the initialization expression is, we may need an lvalue - // or an rvalue as a result location. If it is an rvalue, we can use the instruction as - // the variable, no memory location needed. - const init_node = node.getTrailer("init_node").?; - if (nodeMayNeedMemoryLocation(init_node)) { - return mod.failNode(scope, init_node, "TODO implement result locations", .{}); - } - const init_inst = try expr(mod, scope, init_node); - const ident_name = try identifierTokenString(mod, scope, node.name_token); - return Scope.LocalVar{ - .parent = scope, - .gen_zir = scope.getGenZIR(), - .name = ident_name, - .inst = init_inst, - }; } fn 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! return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = pointer }, .{}); } -fn suffixOp(mod: *Module, scope: *Scope, node: *ast.Node.SuffixOp) InnerError!*zir.Inst { - switch (node.op) { - .Deref => { - const tree = scope.tree(); - const src = tree.token_locs[node.rtoken].start; +fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.rtoken].start; - const lhs = try expr(mod, scope, node.lhs); + const lhs = try expr(mod, scope, node.lhs); - return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = lhs }, .{}); - }, - else => return mod.failNode(scope, &node.base, "TODO implement astGenExpr for suffixOp {}", .{node.op}), - } + return mod.addZIRInst(scope, src, zir.Inst.Deref, .{ .ptr = lhs }, .{}); } fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { @@ -672,6 +676,9 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool { .Period, .Sub, .SubWrap, + .Slice, + .Deref, + .ArrayAccess, => return false, // Forward the question to a sub-expression. @@ -682,6 +689,7 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool { .OrElse => node = node.castTag(.OrElse).?.rhs, .Comptime => node = node.castTag(.Comptime).?.expr, .Nosuspend => node = node.castTag(.Nosuspend).?.expr, + .UnwrapOptional => node = node.castTag(.UnwrapOptional).?.lhs, // True because these are exactly the expressions we need memory locations for. .ArrayInitializer, @@ -697,7 +705,6 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node) bool { .Switch, .Call, .BuiltinCall, // TODO some of these can return false - .SuffixOp, // TODO this should be split up => return true, // Depending on AST properties, they may need memory locations. diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 46f33dd0ff..cc0587d92a 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -2962,9 +2962,9 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); node.rtoken = try appendToken(rp.c, .RBrace, "]"); - node.op.ArrayAccess = &cast_node.base; + node.index_expr = &cast_node.base; } else { - node.op.ArrayAccess = try transExpr(rp, scope, subscr_expr, .used, .r_value); + node.index_expr = try transExpr(rp, scope, subscr_expr, .used, .r_value); node.rtoken = try appendToken(rp.c, .RBrace, "]"); } return maybeSuppressResult(rp, scope, result_used, &node.base); @@ -4405,9 +4405,9 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node { _ = try appendToken(c, .Period, "."); const qm = try appendToken(c, .QuestionMark, "?"); - const node = try c.arena.create(ast.Node.SuffixOp); + const node = try c.arena.create(ast.Node.SimpleSuffixOp); node.* = .{ - .op = .UnwrapOptional, + .base = .{ .tag = .UnwrapOptional }, .lhs = wrapped, .rtoken = qm, }; @@ -4567,23 +4567,21 @@ fn transCreateNodeShiftOp( } fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node { - const node = try c.arena.create(ast.Node.SuffixOp); + const node = try c.arena.create(ast.Node.SimpleSuffixOp); node.* = .{ + .base = .{ .tag = .Deref }, .lhs = lhs, - .op = .Deref, .rtoken = try appendToken(c, .PeriodAsterisk, ".*"), }; return &node.base; } -fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.SuffixOp { +fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAccess { _ = try appendToken(c, .LBrace, "["); - const node = try c.arena.create(ast.Node.SuffixOp); + const node = try c.arena.create(ast.Node.ArrayAccess); node.* = .{ .lhs = lhs, - .op = .{ - .ArrayAccess = undefined, - }, + .index_expr = undefined, .rtoken = undefined, }; return node; @@ -6010,7 +6008,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, }, .LBracket => { const arr_node = try transCreateNodeArrayAccess(c, node); - arr_node.op.ArrayAccess = try parseCPrefixOpExpr(c, it, source, source_loc, scope); + arr_node.index_expr = try parseCPrefixOpExpr(c, it, source, source_loc, scope); arr_node.rtoken = try appendToken(c, .RBracket, "]"); node = &arr_node.base; if (it.next().?.id != .RBracket) { @@ -6099,7 +6097,6 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, }; mem.copy(*ast.Node, tuple_node.list(), init_vals.items); - //(@import("std").mem.zeroInit(T, .{x})) const import_fn_call = try c.createBuiltinCall("@import", 1); const std_node = try transCreateNodeStringLiteral(c, "\"std\"");