diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 16173c4237..b91cac7865 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -408,8 +408,54 @@ pub const Node = struct { VarDecl, Defer, - // Operators - InfixOp, + // Infix operators + Catch, + + // SimpleInfixOp + 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, + UnwrapOptional, + + // SimplePrefixOp AddressOf, Await, BitNot, @@ -419,6 +465,7 @@ pub const Node = struct { NegationWrap, Resume, Try, + ArrayType, /// ArrayType but has a sentinel node. ArrayTypeSentinel, @@ -492,7 +539,51 @@ pub const Node = struct { .TestDecl => TestDecl, .VarDecl => VarDecl, .Defer => Defer, - .InfixOp => InfixOp, + .Catch => Catch, + + .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, + .UnwrapOptional, + => SimpleInfixOp, .AddressOf, .Await, @@ -507,13 +598,17 @@ pub const Node = struct { .ArrayType => ArrayType, .ArrayTypeSentinel => ArrayTypeSentinel, + .PtrType => PtrType, .SliceType => SliceType, .SuffixOp => SuffixOp, + .ArrayInitializer => ArrayInitializer, .ArrayInitializerDot => ArrayInitializerDot, + .StructInitializer => StructInitializer, .StructInitializerDot => StructInitializerDot, + .Call => Call, .Switch => Switch, .While => While, @@ -1859,117 +1954,22 @@ pub const Node = struct { } }; - /// TODO split up and make every op its own AST Node tag - pub const InfixOp = struct { - base: Node = Node{ .tag = .InfixOp }, + pub const Catch = struct { + base: Node = Node{ .tag = .Catch }, op_token: TokenIndex, lhs: *Node, - op: Op, rhs: *Node, + payload: ?*Node, - pub const Op = union(enum) { - 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, - Catch: ?*Node, - Div, - EqualEqual, - ErrorUnion, - GreaterOrEqual, - GreaterThan, - LessOrEqual, - LessThan, - MergeErrorSets, - Mod, - Mul, - MulWrap, - Period, - Range, - Sub, - SubWrap, - UnwrapOptional, - }; - - pub fn iterate(self: *const InfixOp, index: usize) ?*Node { + pub fn iterate(self: *const Catch, index: usize) ?*Node { var i = index; if (i < 1) return self.lhs; i -= 1; - switch (self.op) { - .Catch => |maybe_payload| { - if (maybe_payload) |payload| { - if (i < 1) return payload; - i -= 1; - } - }, - - .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, - .UnwrapOptional, - => {}, + if (self.payload) |payload| { + if (i < 1) return payload; + i -= 1; } if (i < 1) return self.rhs; @@ -1978,11 +1978,38 @@ pub const Node = struct { return null; } - pub fn firstToken(self: *const InfixOp) TokenIndex { + pub fn firstToken(self: *const Catch) TokenIndex { return self.lhs.firstToken(); } - pub fn lastToken(self: *const InfixOp) TokenIndex { + pub fn lastToken(self: *const Catch) TokenIndex { + return self.rhs.lastToken(); + } + }; + + pub const SimpleInfixOp = struct { + base: Node, + op_token: TokenIndex, + lhs: *Node, + rhs: *Node, + + pub fn iterate(self: *const SimpleInfixOp, index: usize) ?*Node { + var i = index; + + if (i < 1) return self.lhs; + i -= 1; + + if (i < 1) return self.rhs; + i -= 1; + + return null; + } + + pub fn firstToken(self: *const SimpleInfixOp) TokenIndex { + return self.lhs.firstToken(); + } + + pub fn lastToken(self: *const SimpleInfixOp) TokenIndex { return self.rhs.lastToken(); } }; diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 6eb3742c0e..b02cdcc1fd 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1015,7 +1015,7 @@ const Parser = struct { /// BoolOrExpr <- BoolAndExpr (KEYWORD_or BoolAndExpr)* fn parseBoolOrExpr(p: *Parser) !?*Node { return p.parseBinOpExpr( - SimpleBinOpParseFn(.Keyword_or, Node.InfixOp.Op.BoolOr), + SimpleBinOpParseFn(.Keyword_or, .BoolOr), parseBoolAndExpr, .Infinitely, ); @@ -1405,8 +1405,8 @@ const Parser = struct { fn parseErrorUnionExpr(p: *Parser) !?*Node { const suffix_expr = (try p.parseSuffixExpr()) orelse return null; - if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(p)) |node| { - const error_union = node.cast(Node.InfixOp).?; + if (try SimpleBinOpParseFn(.Bang, .ErrorUnion)(p)) |node| { + const error_union = node.castTag(.ErrorUnion).?; const type_expr = try p.expectNode(parseTypeExpr, .{ .ExpectedTypeExpr = .{ .token = p.tok_i }, }); @@ -1439,10 +1439,56 @@ 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, - .InfixOp => node.cast(Node.InfixOp).?.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, + .UnwrapOptional, + => node.cast(Node.SimpleInfixOp).?.lhs = res, + else => unreachable, } res = node; @@ -1470,10 +1516,55 @@ 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, - .InfixOp => node.cast(Node.InfixOp).?.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, + .UnwrapOptional, + => node.cast(Node.SimpleInfixOp).?.lhs = res, else => unreachable, } res = node; @@ -1560,11 +1651,11 @@ const Parser = struct { const global_error_set = try p.createLiteral(Node.ErrorType, token); if (period == null or identifier == null) return global_error_set; - const node = try p.arena.allocator.create(Node.InfixOp); + const node = try p.arena.allocator.create(Node.SimpleInfixOp); node.* = .{ + .base = Node{ .tag = .Period }, .op_token = period.?, .lhs = global_error_set, - .op = .Period, .rhs = identifier.?, }; return &node.base; @@ -2237,11 +2328,11 @@ const Parser = struct { .ExpectedExpr = .{ .token = p.tok_i }, }); - const node = try p.arena.allocator.create(Node.InfixOp); + const node = try p.arena.allocator.create(Node.SimpleInfixOp); node.* = .{ + .base = Node{ .tag = .Range }, .op_token = token, .lhs = expr, - .op = .Range, .rhs = range_end, }; return &node.base; @@ -2266,7 +2357,7 @@ const Parser = struct { /// / EQUAL fn parseAssignOp(p: *Parser) !?*Node { const token = p.nextToken(); - const op: Node.InfixOp.Op = switch (p.token_ids[token]) { + const op: Node.Tag = switch (p.token_ids[token]) { .AsteriskEqual => .AssignMul, .SlashEqual => .AssignDiv, .PercentEqual => .AssignMod, @@ -2287,11 +2378,11 @@ const Parser = struct { }, }; - const node = try p.arena.allocator.create(Node.InfixOp); + const node = try p.arena.allocator.create(Node.SimpleInfixOp); node.* = .{ + .base = .{ .tag = op }, .op_token = token, .lhs = undefined, // set by caller - .op = op, .rhs = undefined, // set by caller }; return &node.base; @@ -2306,7 +2397,7 @@ const Parser = struct { /// / RARROWEQUAL fn parseCompareOp(p: *Parser) !?*Node { const token = p.nextToken(); - const op: Node.InfixOp.Op = switch (p.token_ids[token]) { + const op: Node.Tag = switch (p.token_ids[token]) { .EqualEqual => .EqualEqual, .BangEqual => .BangEqual, .AngleBracketLeft => .LessThan, @@ -2330,12 +2421,22 @@ const Parser = struct { /// / KEYWORD_catch Payload? fn parseBitwiseOp(p: *Parser) !?*Node { const token = p.nextToken(); - const op: Node.InfixOp.Op = switch (p.token_ids[token]) { + const op: Node.Tag = switch (p.token_ids[token]) { .Ampersand => .BitAnd, .Caret => .BitXor, .Pipe => .BitOr, .Keyword_orelse => .UnwrapOptional, - .Keyword_catch => .{ .Catch = try p.parsePayload() }, + .Keyword_catch => { + const payload = try p.parsePayload(); + const node = try p.arena.allocator.create(Node.Catch); + node.* = .{ + .op_token = token, + .lhs = undefined, // set by caller + .rhs = undefined, // set by caller + .payload = payload, + }; + return &node.base; + }, else => { p.putBackToken(token); return null; @@ -2350,7 +2451,7 @@ const Parser = struct { /// / RARROW2 fn parseBitShiftOp(p: *Parser) !?*Node { const token = p.nextToken(); - const op: Node.InfixOp.Op = switch (p.token_ids[token]) { + const op: Node.Tag = switch (p.token_ids[token]) { .AngleBracketAngleBracketLeft => .BitShiftLeft, .AngleBracketAngleBracketRight => .BitShiftRight, else => { @@ -2370,7 +2471,7 @@ const Parser = struct { /// / MINUSPERCENT fn parseAdditionOp(p: *Parser) !?*Node { const token = p.nextToken(); - const op: Node.InfixOp.Op = switch (p.token_ids[token]) { + const op: Node.Tag = switch (p.token_ids[token]) { .Plus => .Add, .Minus => .Sub, .PlusPlus => .ArrayCat, @@ -2394,7 +2495,7 @@ const Parser = struct { /// / ASTERISKPERCENT fn parseMultiplyOp(p: *Parser) !?*Node { const token = p.nextToken(); - const op: Node.InfixOp.Op = switch (p.token_ids[token]) { + const op: Node.Tag = switch (p.token_ids[token]) { .PipePipe => .MergeErrorSets, .Asterisk => .Mul, .Slash => .Div, @@ -2673,14 +2774,14 @@ const Parser = struct { if (p.eatToken(.Period)) |period| { if (try p.parseIdentifier()) |identifier| { - // TODO: It's a bit weird to return an InfixOp from the SuffixOp parser. + // 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.InfixOp); + const node = try p.arena.allocator.create(Node.SimpleInfixOp); node.* = .{ + .base = Node{ .tag = .Period }, .op_token = period, .lhs = undefined, // set by caller - .op = .Period, .rhs = identifier, }; return &node.base; @@ -2987,7 +3088,7 @@ const Parser = struct { }.parse; } - fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) NodeParseFn { + fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.Tag) NodeParseFn { return struct { pub fn parse(p: *Parser) Error!?*Node { const op_token = if (token == .Keyword_and) switch (p.token_ids[p.tok_i]) { @@ -3001,11 +3102,11 @@ const Parser = struct { else => return null, } else p.eatToken(token) orelse return null; - const node = try p.arena.allocator.create(Node.InfixOp); + const node = try p.arena.allocator.create(Node.SimpleInfixOp); node.* = .{ + .base = .{ .tag = op }, .op_token = op_token, .lhs = undefined, // set by caller - .op = op, .rhs = undefined, // set by caller }; return &node.base; @@ -3350,9 +3451,13 @@ const Parser = struct { const left = res; res = node; - const op = node.cast(Node.InfixOp).?; - op.*.lhs = left; - op.*.rhs = right; + if (node.castTag(.Catch)) |op| { + op.lhs = left; + op.rhs = right; + } else if (node.cast(Node.SimpleInfixOp)) |op| { + op.lhs = left; + op.rhs = right; + } switch (chain) { .Once => break, @@ -3363,12 +3468,12 @@ const Parser = struct { return res; } - fn createInfixOp(p: *Parser, index: TokenIndex, op: Node.InfixOp.Op) !*Node { - const node = try p.arena.allocator.create(Node.InfixOp); + fn createInfixOp(p: *Parser, op_token: TokenIndex, tag: Node.Tag) !*Node { + const node = try p.arena.allocator.create(Node.SimpleInfixOp); node.* = .{ - .op_token = index, + .base = Node{ .tag = tag }, + .op_token = op_token, .lhs = undefined, // set by caller - .op = op, .rhs = undefined, // set by caller }; return &node.base; diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 67d73c92a6..7f8a18299b 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -436,13 +436,10 @@ fn renderExpression( } }, - .InfixOp => { - const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base); + .Catch => { + const infix_op_node = @fieldParentPtr(ast.Node.Catch, "base", base); - const op_space = switch (infix_op_node.op) { - ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion, ast.Node.InfixOp.Op.Range => Space.None, - else => Space.Space, - }; + const op_space = Space.Space; try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space); const after_op_space = blk: { @@ -458,11 +455,75 @@ fn renderExpression( start_col.* = indent + indent_delta; } - switch (infix_op_node.op) { - ast.Node.InfixOp.Op.Catch => |maybe_payload| if (maybe_payload) |payload| { - try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space); - }, - else => {}, + if (infix_op_node.payload) |payload| { + try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space); + } + + return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space); + }, + + .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, + .UnwrapOptional, + => { + const infix_op_node = @fieldParentPtr(ast.Node.SimpleInfixOp, "base", base); + + const op_space = switch (base.tag) { + .Period, .ErrorUnion, .Range => Space.None, + else => Space.Space, + }; + try renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.lhs, op_space); + + const after_op_space = blk: { + const loc = tree.tokenLocation(tree.token_locs[infix_op_node.op_token].end, tree.nextToken(infix_op_node.op_token)); + break :blk if (loc.line == 0) op_space else Space.Newline; + }; + + try renderToken(tree, stream, infix_op_node.op_token, indent, start_col, after_op_space); + if (after_op_space == Space.Newline and + tree.token_ids[tree.nextToken(infix_op_node.op_token)] != .MultilineStringLiteralLine) + { + try stream.writeByteNTimes(' ', indent + indent_delta); + start_col.* = indent + indent_delta; } return renderExpression(allocator, stream, tree, indent, start_col, infix_op_node.rhs, space); @@ -2553,10 +2614,52 @@ fn nodeIsBlock(base: *const ast.Node) bool { } fn nodeCausesSliceOpSpace(base: *ast.Node) bool { - const infix_op = base.cast(ast.Node.InfixOp) orelse return false; - return switch (infix_op.op) { - ast.Node.InfixOp.Op.Period => false, - else => true, + return switch (base.tag) { + .Catch, + .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, + .Range, + .Sub, + .SubWrap, + .UnwrapOptional, + => true, + + else => false, }; } diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 050588f3df..42a30a1d20 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1954,7 +1954,7 @@ pub fn addZIRInstSpecial( positionals: std.meta.fieldInfo(T, "positionals").field_type, kw_args: std.meta.fieldInfo(T, "kw_args").field_type, ) !*T { - const gen_zir = scope.cast(Scope.GenZIR).?; + const gen_zir = scope.getGenZIR(); try gen_zir.instructions.ensureCapacity(self.gpa, gen_zir.instructions.items.len + 1); const inst = try newZIRInst(gen_zir.arena, src, T, positionals, kw_args); gen_zir.instructions.appendAssumeCapacity(&inst.base); diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index f75097575d..1f157e6389 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -12,22 +12,29 @@ const Scope = Module.Scope; const InnerError = Module.InnerError; /// Turn Zig AST into untyped ZIR istructions. -pub fn expr(mod: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst { - switch (ast_node.tag) { +pub fn expr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { + switch (node.tag) { .VarDecl => unreachable, // Handled in `blockExpr`. - .Identifier => return identifier(mod, scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)), - .Asm => return assembly(mod, scope, @fieldParentPtr(ast.Node.Asm, "base", ast_node)), - .StringLiteral => return stringLiteral(mod, scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)), - .IntegerLiteral => return integerLiteral(mod, scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)), - .BuiltinCall => return builtinCall(mod, scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)), - .Call => return callExpr(mod, scope, @fieldParentPtr(ast.Node.Call, "base", ast_node)), - .Unreachable => return unreach(mod, scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)), - .ControlFlowExpression => return controlFlowExpr(mod, scope, @fieldParentPtr(ast.Node.ControlFlowExpression, "base", ast_node)), - .If => return ifExpr(mod, scope, @fieldParentPtr(ast.Node.If, "base", ast_node)), - .InfixOp => return infixOp(mod, scope, @fieldParentPtr(ast.Node.InfixOp, "base", ast_node)), - .BoolNot => return boolNot(mod, scope, @fieldParentPtr(ast.Node.SimplePrefixOp, "base", ast_node)), - else => return mod.failNode(scope, ast_node, "TODO implement astgen.Expr for {}", .{@tagName(ast_node.tag)}), + .Identifier => return identifier(mod, scope, node.castTag(.Identifier).?), + .Asm => return assembly(mod, scope, node.castTag(.Asm).?), + .StringLiteral => return stringLiteral(mod, scope, node.castTag(.StringLiteral).?), + .IntegerLiteral => return integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?), + .BuiltinCall => return builtinCall(mod, scope, node.castTag(.BuiltinCall).?), + .Call => return callExpr(mod, scope, node.castTag(.Call).?), + .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), + .ControlFlowExpression => return controlFlowExpr(mod, scope, node.castTag(.ControlFlowExpression).?), + .If => return ifExpr(mod, scope, node.castTag(.If).?), + .Assign => return assign(mod, scope, node.castTag(.Assign).?), + .Add => return add(mod, scope, node.castTag(.Add).?), + .BangEqual => return cmp(mod, scope, node.castTag(.BangEqual).?, .neq), + .EqualEqual => return cmp(mod, scope, node.castTag(.EqualEqual).?, .eq), + .GreaterThan => return cmp(mod, scope, node.castTag(.GreaterThan).?, .gt), + .GreaterOrEqual => return cmp(mod, scope, node.castTag(.GreaterOrEqual).?, .gte), + .LessThan => return cmp(mod, scope, node.castTag(.LessThan).?, .lt), + .LessOrEqual => return cmp(mod, scope, node.castTag(.LessOrEqual).?, .lte), + .BoolNot => return boolNot(mod, scope, node.castTag(.BoolNot).?), + else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}), } } @@ -57,6 +64,7 @@ pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block } fn varDecl(mod: *Module, scope: *Scope, node: *ast.Node.VarDecl) InnerError!Scope.LocalVar { + // TODO implement detection of shadowing if (node.getTrailer("comptime_token")) |comptime_token| { return mod.failTok(scope, comptime_token, "TODO implement comptime locals", .{}); } @@ -98,66 +106,50 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr return mod.addZIRInst(scope, src, zir.Inst.BoolNot, .{ .operand = operand }, .{}); } -fn infixOp(mod: *Module, scope: *Scope, infix_node: *ast.Node.InfixOp) InnerError!*zir.Inst { - switch (infix_node.op) { - .Assign => { - if (infix_node.lhs.tag == .Identifier) { - const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs); - const tree = scope.tree(); - const ident_name = tree.tokenSlice(ident.token); - if (std.mem.eql(u8, ident_name, "_")) { - return expr(mod, scope, infix_node.rhs); - } else { - return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{}); - } - } else { - return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{}); - } - }, - .Add => { - const lhs = try expr(mod, scope, infix_node.lhs); - const rhs = try expr(mod, scope, infix_node.rhs); - - const tree = scope.tree(); - const src = tree.token_locs[infix_node.op_token].start; - - return mod.addZIRInst(scope, src, zir.Inst.Add, .{ .lhs = lhs, .rhs = rhs }, .{}); - }, - .BangEqual, - .EqualEqual, - .GreaterThan, - .GreaterOrEqual, - .LessThan, - .LessOrEqual, - => { - const lhs = try expr(mod, scope, infix_node.lhs); - const rhs = try expr(mod, scope, infix_node.rhs); - - const tree = scope.tree(); - const src = tree.token_locs[infix_node.op_token].start; - - const op: std.math.CompareOperator = switch (infix_node.op) { - .BangEqual => .neq, - .EqualEqual => .eq, - .GreaterThan => .gt, - .GreaterOrEqual => .gte, - .LessThan => .lt, - .LessOrEqual => .lte, - else => unreachable, - }; - - return mod.addZIRInst(scope, src, zir.Inst.Cmp, .{ - .lhs = lhs, - .op = op, - .rhs = rhs, - }, .{}); - }, - else => |op| { - return mod.failNode(scope, &infix_node.base, "TODO implement infix operator {}", .{op}); - }, +fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { + if (infix_node.lhs.tag == .Identifier) { + const ident = @fieldParentPtr(ast.Node.Identifier, "base", infix_node.lhs); + const tree = scope.tree(); + const ident_name = tree.tokenSlice(ident.token); + if (std.mem.eql(u8, ident_name, "_")) { + return expr(mod, scope, infix_node.rhs); + } else { + return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{}); + } + } else { + return mod.failNode(scope, &infix_node.base, "TODO implement infix operator assign", .{}); } } +fn add(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst { + const lhs = try expr(mod, scope, infix_node.lhs); + const rhs = try expr(mod, scope, infix_node.rhs); + + const tree = scope.tree(); + const src = tree.token_locs[infix_node.op_token].start; + + return mod.addZIRInst(scope, src, zir.Inst.Add, .{ .lhs = lhs, .rhs = rhs }, .{}); +} + +fn cmp( + mod: *Module, + scope: *Scope, + infix_node: *ast.Node.SimpleInfixOp, + op: std.math.CompareOperator, +) InnerError!*zir.Inst { + const lhs = try expr(mod, scope, infix_node.lhs); + const rhs = try expr(mod, scope, infix_node.rhs); + + const tree = scope.tree(); + const src = tree.token_locs[infix_node.op_token].start; + + return mod.addZIRInst(scope, src, zir.Inst.Cmp, .{ + .lhs = lhs, + .op = op, + .rhs = rhs, + }, .{}); +} + fn ifExpr(mod: *Module, scope: *Scope, if_node: *ast.Node.If) InnerError!*zir.Inst { if (if_node.payload) |payload| { return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{}); @@ -571,6 +563,47 @@ fn nodeNeedsMemoryLocation(node: *ast.Node) bool { .ErrorSetDecl, .ContainerDecl, .Asm, + .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, + .Range, + .Period, + .Sub, + .SubWrap, => false, .ArrayInitializer, @@ -579,9 +612,10 @@ fn nodeNeedsMemoryLocation(node: *ast.Node) bool { .StructInitializerDot, => true, - .GroupedExpression => nodeNeedsMemoryLocation(node.cast(ast.Node.GroupedExpression).?.expr), + .GroupedExpression => nodeNeedsMemoryLocation(node.castTag(.GroupedExpression).?.expr), - .InfixOp => @panic("TODO nodeNeedsMemoryLocation for InfixOp"), + .UnwrapOptional => @panic("TODO nodeNeedsMemoryLocation for UnwrapOptional"), + .Catch => @panic("TODO nodeNeedsMemoryLocation for Catch"), .Await => @panic("TODO nodeNeedsMemoryLocation for Await"), .Try => @panic("TODO nodeNeedsMemoryLocation for Try"), .If => @panic("TODO nodeNeedsMemoryLocation for If"), diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index b04528a3d3..1da52cda96 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1103,11 +1103,11 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No const enum_ident = try transCreateNodeIdentifier(c, name); const period_tok = try appendToken(c, .Period, "."); const field_ident = try transCreateNodeIdentifier(c, field_name); - const field_access_node = try c.arena.create(ast.Node.InfixOp); + const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp); field_access_node.* = .{ + .base = .{ .tag = .Period }, .op_token = period_tok, .lhs = enum_ident, - .op = .Period, .rhs = field_ident, }; cast_node.params()[0] = &field_access_node.base; @@ -1294,7 +1294,7 @@ fn transBinaryOperator( const op = ZigClangBinaryOperator_getOpcode(stmt); const qt = ZigClangBinaryOperator_getType(stmt); var op_token: ast.TokenIndex = undefined; - var op_id: ast.Node.InfixOp.Op = undefined; + var op_id: ast.Node.Tag = undefined; switch (op) { .Assign => return try transCreateNodeAssign(rp, scope, result_used, ZigClangBinaryOperator_getLHS(stmt), ZigClangBinaryOperator_getRHS(stmt)), .Comma => { @@ -1737,25 +1737,22 @@ fn exprIsStringLiteral(expr: *const ZigClangExpr) bool { fn isBoolRes(res: *ast.Node) bool { switch (res.tag) { - .InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) { - .BoolOr, - .BoolAnd, - .EqualEqual, - .BangEqual, - .LessThan, - .GreaterThan, - .LessOrEqual, - .GreaterOrEqual, - => return true, + .BoolOr, + .BoolAnd, + .EqualEqual, + .BangEqual, + .LessThan, + .GreaterThan, + .LessOrEqual, + .GreaterOrEqual, + .BoolNot, + .BoolLiteral, + => return true, - else => {}, - }, - .BoolNot => return true, - .BoolLiteral => return true, .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr), - else => {}, + + else => return false, } - return false; } fn finishBoolExpr( @@ -2312,11 +2309,11 @@ fn transInitListExprArray( &filler_init_node.base else blk: { const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**"); - const mul_node = try rp.c.arena.create(ast.Node.InfixOp); + const mul_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); mul_node.* = .{ + .base = .{ .tag = .ArrayMult }, .op_token = mul_tok, .lhs = &filler_init_node.base, - .op = .ArrayMult, .rhs = try transCreateNodeInt(rp.c, leftover_count), }; break :blk &mul_node.base; @@ -2326,11 +2323,11 @@ fn transInitListExprArray( return rhs_node; } - const cat_node = try rp.c.arena.create(ast.Node.InfixOp); + const cat_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); cat_node.* = .{ + .base = .{ .tag = .ArrayCat }, .op_token = cat_tok, .lhs = &init_node.base, - .op = .ArrayCat, .rhs = rhs_node, }; return &cat_node.base; @@ -2723,11 +2720,11 @@ fn transCase( const ellips = try appendToken(rp.c, .Ellipsis3, "..."); const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); - const node = try rp.c.arena.create(ast.Node.InfixOp); + const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); node.* = .{ + .base = .{ .tag = .Range }, .op_token = ellips, .lhs = lhs_node, - .op = .Range, .rhs = rhs_node, }; break :blk &node.base; @@ -3153,7 +3150,7 @@ fn transCreatePreCrement( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, - op: ast.Node.InfixOp.Op, + op: ast.Node.Tag, op_tok_id: std.zig.Token.Id, bytes: []const u8, used: ResultUsed, @@ -3227,7 +3224,7 @@ fn transCreatePostCrement( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangUnaryOperator, - op: ast.Node.InfixOp.Op, + op: ast.Node.Tag, op_tok_id: std.zig.Token.Id, bytes: []const u8, used: ResultUsed, @@ -3349,10 +3346,10 @@ fn transCreateCompoundAssign( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundAssignOperator, - assign_op: ast.Node.InfixOp.Op, + assign_op: ast.Node.Tag, assign_tok_id: std.zig.Token.Id, assign_bytes: []const u8, - bin_op: ast.Node.InfixOp.Op, + bin_op: ast.Node.Tag, bin_tok_id: std.zig.Token.Id, bin_bytes: []const u8, used: ResultUsed, @@ -3377,7 +3374,7 @@ fn transCreateCompoundAssign( // zig: lhs += rhs if ((is_mod or is_div) and is_signed) { const op_token = try appendToken(rp.c, .Equal, "="); - const op_node = try rp.c.arena.create(ast.Node.InfixOp); + const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); const builtin = if (is_mod) "@rem" else "@divTrunc"; const builtin_node = try rp.c.createBuiltinCall(builtin, 2); const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); @@ -3386,9 +3383,9 @@ fn transCreateCompoundAssign( builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); op_node.* = .{ + .base = .{ .tag = .Assign }, .op_token = op_token, .lhs = lhs_node, - .op = .Assign, .rhs = &builtin_node.base, }; _ = try appendToken(rp.c, .Semicolon, ";"); @@ -3452,7 +3449,7 @@ fn transCreateCompoundAssign( if ((is_mod or is_div) and is_signed) { const op_token = try appendToken(rp.c, .Equal, "="); - const op_node = try rp.c.arena.create(ast.Node.InfixOp); + const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); const builtin = if (is_mod) "@rem" else "@divTrunc"; const builtin_node = try rp.c.createBuiltinCall(builtin, 2); builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node); @@ -3461,9 +3458,9 @@ fn transCreateCompoundAssign( builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); _ = try appendToken(rp.c, .Semicolon, ";"); op_node.* = .{ + .base = .{ .tag = .Assign }, .op_token = op_token, .lhs = ref_node, - .op = .Assign, .rhs = &builtin_node.base, }; _ = try appendToken(rp.c, .Semicolon, ";"); @@ -3716,11 +3713,11 @@ fn maybeSuppressResult( } const lhs = try transCreateNodeIdentifier(rp.c, "_"); const op_token = try appendToken(rp.c, .Equal, "="); - const op_node = try rp.c.arena.create(ast.Node.InfixOp); + const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp); op_node.* = .{ + .base = .{ .tag = .Assign }, .op_token = op_token, .lhs = lhs, - .op = .Assign, .rhs = result, }; return &op_node.base; @@ -4095,11 +4092,11 @@ fn transCreateNodeAssign( } fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node { - const field_access_node = try c.arena.create(ast.Node.InfixOp); + const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp); field_access_node.* = .{ + .base = .{ .tag = .Period }, .op_token = try appendToken(c, .Period, "."), .lhs = container, - .op = .Period, .rhs = try transCreateNodeIdentifier(c, field_name), }; return &field_access_node.base; @@ -4124,7 +4121,7 @@ fn transCreateNodeInfixOp( rp: RestorePoint, scope: *Scope, lhs_node: *ast.Node, - op: ast.Node.InfixOp.Op, + op: ast.Node.Tag, op_token: ast.TokenIndex, rhs_node: *ast.Node, used: ResultUsed, @@ -4134,11 +4131,11 @@ fn transCreateNodeInfixOp( try appendToken(rp.c, .LParen, "(") else null; - const node = try rp.c.arena.create(ast.Node.InfixOp); + const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); node.* = .{ + .base = .{ .tag = op }, .op_token = op_token, .lhs = lhs_node, - .op = op, .rhs = rhs_node, }; if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base); @@ -4156,7 +4153,7 @@ fn transCreateNodeBoolInfixOp( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangBinaryOperator, - op: ast.Node.InfixOp.Op, + op: ast.Node.Tag, used: ResultUsed, grouped: bool, ) !*ast.Node { @@ -4536,7 +4533,7 @@ fn transCreateNodeShiftOp( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangBinaryOperator, - op: ast.Node.InfixOp.Op, + op: ast.Node.Tag, op_tok_id: std.zig.Token.Id, bytes: []const u8, ) !*ast.Node { @@ -4558,11 +4555,11 @@ fn transCreateNodeShiftOp( cast_node.params()[1] = rhs; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - const node = try rp.c.arena.create(ast.Node.InfixOp); + const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); node.* = .{ + .base = .{ .tag = op }, .op_token = op_token, .lhs = lhs, - .op = op, .rhs = &cast_node.base, }; @@ -5404,11 +5401,11 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ // suppress result const lhs = try transCreateNodeIdentifier(c, "_"); const op_token = try appendToken(c, .Equal, "="); - const op_node = try c.arena.create(ast.Node.InfixOp); + const op_node = try c.arena.create(ast.Node.SimpleInfixOp); op_node.* = .{ + .base = .{ .tag = .Assign }, .op_token = op_token, .lhs = lhs, - .op = .Assign, .rhs = last, }; try block_scope.statements.append(&op_node.base); @@ -5787,9 +5784,60 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, } } +fn nodeIsInfixOp(tag: ast.Node.Tag) bool { + return switch (tag) { + .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, + .UnwrapOptional, + .Catch, + => true, + + else => false, + }; +} + fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { if (!isBoolRes(node)) { - if (node.tag != .InfixOp) return node; + if (!nodeIsInfixOp(node.tag)) return node; const group_node = try c.arena.create(ast.Node.GroupedExpression); group_node.* = .{ @@ -5808,7 +5856,7 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node { if (isBoolRes(node)) { - if (node.tag != .InfixOp) return node; + if (!nodeIsInfixOp(node.tag)) return node; const group_node = try c.arena.create(ast.Node.GroupedExpression); group_node.* = .{ @@ -5821,11 +5869,11 @@ fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node { const op_token = try appendToken(c, .BangEqual, "!="); const zero = try transCreateNodeInt(c, 0); - const res = try c.arena.create(ast.Node.InfixOp); + const res = try c.arena.create(ast.Node.SimpleInfixOp); res.* = .{ + .base = .{ .tag = .BangEqual }, .op_token = op_token, .lhs = node, - .op = .BangEqual, .rhs = zero, }; const group_node = try c.arena.create(ast.Node.GroupedExpression); @@ -5842,7 +5890,7 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, while (true) { const tok = it.next().?; var op_token: ast.TokenIndex = undefined; - var op_id: ast.Node.InfixOp.Op = undefined; + var op_id: ast.Node.Tag = undefined; var bool_op = false; switch (tok.id) { .Period => { @@ -6049,11 +6097,11 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, const cast_fn = if (bool_op) macroIntToBool else macroBoolToInt; const lhs_node = try cast_fn(c, node); const rhs_node = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - const op_node = try c.arena.create(ast.Node.InfixOp); + const op_node = try c.arena.create(ast.Node.SimpleInfixOp); op_node.* = .{ + .base = .{ .tag = op_id }, .op_token = op_token, .lhs = lhs_node, - .op = op_id, .rhs = try cast_fn(c, rhs_node), }; node = &op_node.base; @@ -6131,10 +6179,9 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node { } }, - .InfixOp => { - const infix = node.cast(ast.Node.InfixOp).?; - if (infix.op != .Period) - return null; + .Period => { + const infix = node.castTag(.Period).?; + if (getContainerTypeOf(c, infix.lhs)) |ty_node| { if (ty_node.cast(ast.Node.ContainerDecl)) |container| { for (container.fieldsAndDecls()) |field_ref| { @@ -6161,9 +6208,7 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node { return getContainer(c, ty); } } - } else if (ref.cast(ast.Node.InfixOp)) |infix| { - if (infix.op != .Period) - return null; + } else if (ref.castTag(.Period)) |infix| { if (getContainerTypeOf(c, infix.lhs)) |ty_node| { if (ty_node.cast(ast.Node.ContainerDecl)) |container| { for (container.fieldsAndDecls()) |field_ref| {