diff options
| author | Veikka Tuominen <git@vexu.eu> | 2021-02-12 11:23:15 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2021-02-16 16:40:06 +0200 |
| commit | 2a74a1ebaace8b5de1796b1756f65e421eb479a4 (patch) | |
| tree | 94967e6c0d2016ccb370c29845e04a4150a1cd76 /src | |
| parent | 66bbd75a8346b8a292f0d95d4b60a5d7d11b73b2 (diff) | |
| download | zig-2a74a1ebaace8b5de1796b1756f65e421eb479a4.tar.gz zig-2a74a1ebaace8b5de1796b1756f65e421eb479a4.zip | |
translate-c: bunch of small fixes to get it compiling
Diffstat (limited to 'src')
| -rw-r--r-- | src/translate_c.zig | 1190 | ||||
| -rw-r--r-- | src/translate_c/ast.zig | 108 | ||||
| -rw-r--r-- | src/type.zig | 4 |
3 files changed, 647 insertions, 655 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig index 9ef4788ba7..c7a30ff919 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -10,12 +10,13 @@ const mem = std.mem; const math = std.math; const ast = @import("translate_c/ast.zig"); const Node = ast.Node; +const Tag = Node.Tag; const CallingConvention = std.builtin.CallingConvention; pub const ClangErrMsg = clang.Stage2ErrorMsg; -pub const Error = error{OutOfMemory}; +pub const Error = std.mem.Allocator.Error; const TypeError = Error || error{UnsupportedType}; const TransError = TypeError || error{UnsupportedTranslation}; @@ -30,11 +31,11 @@ const Scope = struct { parent: ?*Scope, const Id = enum { - Switch, - Block, - Root, - Condition, - Loop, + @"switch", + block, + root, + condition, + loop, }; /// Represents an in-progress Node.Switch. This struct is stack-allocated. @@ -44,7 +45,6 @@ const Scope = struct { base: Scope, pending_block: Block, cases: std.ArrayList(Node), - case_index: usize, switch_label: ?[]const u8, default_label: ?[]const u8, }; @@ -84,7 +84,7 @@ const Scope = struct { fn init(c: *Context, parent: *Scope, labeled: bool) !Block { var blk = Block{ .base = .{ - .id = .Block, + .id = .block, .parent = parent, }, .statements = std.ArrayList(Node).init(c.gpa), @@ -105,12 +105,12 @@ const Scope = struct { fn complete(self: *Block, c: *Context) !Node { // We reserve 1 extra statement if the parent is a Loop. This is in case of // do while, we want to put `if (cond) break;` at the end. - const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop); - const stmts = try c.arena.alloc(Node, alloc_len); + const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .loop); + var stmts = try c.arena.alloc(Node, alloc_len); stmts.len -= 1; mem.copy(Node, stmts, self.statements.items); - return Node.block.create(c.arena, .{ - .lable = self.label, + return Tag.block.create(c.arena, .{ + .label = self.label, .stmts = stmts, }); } @@ -161,7 +161,7 @@ const Scope = struct { fn init(c: *Context) Root { return .{ .base = .{ - .id = .Root, + .id = .root, .parent = null, }, .sym_table = SymbolTable.init(c.gpa), @@ -195,9 +195,9 @@ const Scope = struct { var scope = inner; while (true) { switch (scope.id) { - .Root => unreachable, - .Block => return @fieldParentPtr(Block, "base", scope), - .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c), + .root => unreachable, + .block => return @fieldParentPtr(Block, "base", scope), + .condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c), else => scope = scope.parent.?, } } @@ -207,8 +207,8 @@ const Scope = struct { var scope = inner; while (true) { switch (scope.id) { - .Root => unreachable, - .Block => { + .root => unreachable, + .block => { const block = @fieldParentPtr(Block, "base", scope); if (block.return_type) |qt| return qt; scope = scope.parent.?; @@ -220,17 +220,17 @@ const Scope = struct { fn getAlias(scope: *Scope, name: []const u8) []const u8 { return switch (scope.id) { - .Root => return name, - .Block => @fieldParentPtr(Block, "base", scope).getAlias(name), - .Switch, .Loop, .Condition => scope.parent.?.getAlias(name), + .root => return name, + .block => @fieldParentPtr(Block, "base", scope).getAlias(name), + .@"switch", .loop, .condition => scope.parent.?.getAlias(name), }; } fn contains(scope: *Scope, name: []const u8) bool { return switch (scope.id) { - .Root => @fieldParentPtr(Root, "base", scope).contains(name), - .Block => @fieldParentPtr(Block, "base", scope).contains(name), - .Switch, .Loop, .Condition => scope.parent.?.contains(name), + .root => @fieldParentPtr(Root, "base", scope).contains(name), + .block => @fieldParentPtr(Block, "base", scope).contains(name), + .@"switch", .loop, .condition => scope.parent.?.contains(name), }; } @@ -238,9 +238,9 @@ const Scope = struct { var scope = inner; while (true) { switch (scope.id) { - .Root => unreachable, - .Switch => return scope, - .Loop => return scope, + .root => unreachable, + .@"switch" => return scope, + .loop => return scope, else => scope = scope.parent.?, } } @@ -250,24 +250,24 @@ const Scope = struct { var scope = inner; while (true) { switch (scope.id) { - .Root => unreachable, - .Switch => return @fieldParentPtr(Switch, "base", scope), + .root => unreachable, + .@"switch" => return @fieldParentPtr(Switch, "base", scope), else => scope = scope.parent.?, } } } /// Appends a node to the first block scope if inside a function, or to the root tree if not. - fn appendNode(scope: *Scope, node: Node) !void { + fn appendNode(inner: *Scope, node: Node) !void { var scope = inner; while (true) { switch (scope.id) { - .Root => { - const root = @fieldParentPtr(Root, "base", scope).contains(name); + .root => { + const root = @fieldParentPtr(Root, "base", scope); return root.nodes.append(node); }, - .Block => { - const block = @fieldParentPtr(Block, "base", scope).contains(name); + .block => { + const block = @fieldParentPtr(Block, "base", scope); return block.statements.append(node); }, else => scope = scope.parent.?, @@ -321,7 +321,7 @@ pub fn translate( args_end: [*]?[*]const u8, errors: *[]ClangErrMsg, resources_path: [*:0]const u8, -) !ast.Tree { +) !std.zig.ast.Tree { const ast_unit = clang.LoadFromCommandLine( args_begin, args_end, @@ -339,14 +339,6 @@ pub fn translate( var arena = std.heap.ArenaAllocator.init(gpa); errdefer arena.deinit(); - if (true) { - var x = false; - if (x) { - return error.OutOfMemory; - } - @panic("TODO update translate-c"); - } - var context = Context{ .gpa = gpa, .arena = &arena.allocator, @@ -361,15 +353,15 @@ pub fn translate( context.alias_list.deinit(); context.global_names.deinit(gpa); context.opaque_demotes.deinit(gpa); - context.global_scope.deini(); + context.global_scope.deinit(); } - try context.global_scope.nodes.append(try Node.usingnamespace_builtins.init()); + try context.global_scope.nodes.append(Tag.usingnamespace_builtins.init()); try prepopulateGlobalNameTable(ast_unit, &context); if (!ast_unit.visitLocalTopLevelDecls(&context, declVisitorC)) { - return context.err; + return error.OutOfMemory; } try transPreprocessorEntities(&context, ast_unit); @@ -377,16 +369,17 @@ pub fn translate( try addMacros(&context); for (context.alias_list.items) |alias| { if (!context.global_scope.sym_table.contains(alias.alias)) { - try createAlias(&context, alias); + const node = try Tag.alias.create(context.arena, .{ .actual = alias.alias, .mangled = alias.name }); + try addTopLevelDecl(&context, alias.alias, node); } } - return ast.render(context.global_scope.nodes.items); + return ast.render(gpa, context.global_scope.nodes.items); } fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) { - return c.err; + return error.OutOfMemory; } // TODO if we see #undef, delete it from the table @@ -409,19 +402,13 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool { const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); - declVisitorNamesOnly(c, decl) catch |err| { - c.err = err; - return false; - }; + declVisitorNamesOnly(c, decl) catch return false; return true; } fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool { const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context)); - declVisitor(c, decl) catch |err| { - c.err = err; - return false; - }; + declVisitor(c, decl) catch return false; return true; } @@ -454,7 +441,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void { }, else => { const decl_name = try c.str(decl.getDeclKindName()); - try warn(c, decl.getLocation(), "ignoring {s} declaration", .{decl_name}); + try warn(c, &c.global_scope.base, decl.getLocation(), "ignoring {s} declaration", .{decl_name}); }, } } @@ -513,7 +500,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { decl_ctx.has_body = false; decl_ctx.storage_class = .Extern; decl_ctx.is_export = false; - try warn(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{}); + try warn(c, &c.global_scope.base, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{}); } break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) { error.UnsupportedType => { @@ -535,7 +522,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { }; if (!decl_ctx.has_body) { - return addTopLevelDecl(c, fn_name, &proto_node.base); + return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base)); } // actual function definition with body @@ -547,10 +534,8 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { var scope = &block_scope.base; var param_id: c_uint = 0; - for (proto_node.params()) |*param, i| { - const param_name = if (param.name_token) |name_tok| - tokenSlice(c, name_tok) - else + for (proto_node.data.params) |*param, i| { + const param_name = param.name orelse return failDecl(c, fn_decl_loc, fn_name, "function {s} parameter has no name", .{fn_name}); const c_param = fn_decl.getParamDecl(param_id); @@ -565,7 +550,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { const arg_name = try block_scope.makeMangledName(c, bare_arg_name); param.name = arg_name; - const redecl_node = try Node.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name }); + const redecl_node = try Tag.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name }); try block_scope.statements.append(redecl_node); } @@ -607,12 +592,12 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void { error.UnsupportedType, => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}), }; - const ret = try Node.@"return".create(c.arena, rhs); + const ret = try Tag.@"return".create(c.arena, rhs); try block_scope.statements.append(ret); } - proto_node.body = try block_scope.complete(c); - return addTopLevelDecl(c, fn_name, &proto_node.base); + proto_node.data.body = try block_scope.complete(c); + return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base)); } fn transQualTypeMaybeInitialized(c: *Context, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!Node { @@ -668,7 +653,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co const node_or_error = if (expr.getStmtClass() == .StringLiteralClass) transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(c, type_node) catch 0) else - transExprCoercing(c, scope, expr, .used, .r_value); + transExprCoercing(c, scope, expr, .used); init_node = node_or_error catch |err| switch (err) { error.UnsupportedTranslation, error.UnsupportedType, @@ -677,18 +662,18 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co }, error.OutOfMemory => |e| return e, }; - if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { - init_node = try Node.bool_to_int.create(c.arena, init_node); + if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node.?)) { + init_node = try Tag.bool_to_int.create(c.arena, init_node.?); } } else { - init_node = Node.undefined_literal.init(); + init_node = Tag.undefined_literal.init(); } } else if (storage_class != .Extern) { // The C language specification states that variables with static or threadlocal // storage without an initializer are initialized to a zero value. // @import("std").mem.zeroes(T) - init_node = try Node.std_mem_zeroes.create(c.arena, type_node); + init_node = try Tag.std_mem_zeroes.create(c.arena, type_node); } const linksection_string = blk: { @@ -708,7 +693,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co break :blk null; }; - const node = try Node.var_decl.create(c.arena, .{ + const node = try Tag.var_decl.create(c.arena, .{ .is_pub = is_pub, .is_const = is_const, .is_extern = is_extern, @@ -719,12 +704,12 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co .type = type_node, .init = init_node, }); - return addTopLevelDecl(c, checked_name, &node.base); + return addTopLevelDecl(c, checked_name, node); } fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !Node { _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name); - return Node.identifier.create(c.arena, builtin_name); + return Tag.identifier.create(c.arena, builtin_name); } const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{ @@ -744,7 +729,7 @@ const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{ fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?Node { if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name| - return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice + return try Tag.identifier.create(c.arena, name); // Avoid processing this decl twice const typedef_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin()); @@ -753,17 +738,17 @@ fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_lev const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ typedef_name, c.getMangle() }) else typedef_name; if (builtin_typedef_map.get(checked_name)) |builtin| { _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin); - return Node.identifier.create(c.arena, builtin); + return try Tag.identifier.create(c.arena, builtin); } if (!top_level_visit) { - return transCreateNodeIdentifier(c, checked_name); + return try Tag.identifier.create(c.arena, checked_name); } _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), checked_name); const node = (try transCreateNodeTypedef(c, typedef_decl, true, checked_name)) orelse return null; try addTopLevelDecl(c, checked_name, node); - return transCreateNodeIdentifier(c, checked_name); + return try Tag.identifier.create(c.arena, checked_name); } fn transCreateNodeTypedef( @@ -782,9 +767,9 @@ fn transCreateNodeTypedef( error.OutOfMemory => |e| return e, }; - const payload = try c.arena.create(ast.Payload.Typedef); + const payload = try c.arena.create(ast.Payload.SimpleVarDecl); payload.* = .{ - .base = .{ .tag = ([2]ast.Node.Tag{ .typedef, .pub_typedef })[@boolToInt(toplevel)] }, + .base = .{ .tag = ([2]Tag{ .typedef, .pub_typedef })[@boolToInt(toplevel)] }, .data = .{ .name = checked_name, .init = init_node, @@ -795,7 +780,7 @@ fn transCreateNodeTypedef( fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Node { if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name| - return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice + return try Tag.identifier.create(c.arena, name); // Avoid processing this decl twice const record_loc = record_decl.getLocation(); var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin()); @@ -815,7 +800,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod } else if (record_decl.isStruct()) { container_kind_name = "struct"; } else { - try warn(c, record_loc, "record {s} is not a struct or union", .{bare_name}); + try warn(c, &c.global_scope.base, record_loc, "record {s} is not a struct or union", .{bare_name}); return null; } @@ -826,7 +811,7 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod const init_node = blk: { const record_def = record_decl.getDefinition() orelse { _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); - break :blk Node.opaque_literal.init(); + break :blk Tag.opaque_literal.init(); }; const is_packed = record_decl.getPackedAttribute(); @@ -843,14 +828,14 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod if (field_decl.isBitField()) { _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); - try warn(c, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name}); - break :blk Node.opaque_literal.init(); + try warn(c, &c.global_scope.base, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name}); + break :blk Tag.opaque_literal.init(); } if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) { _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); - try warn(c, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name}); - break :blk Node.opaque_literal.init(); + try warn(c, &c.global_scope.base, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name}); + break :blk Tag.opaque_literal.init(); } var is_anon = false; @@ -864,8 +849,8 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod const field_type = transQualType(c, field_qt, field_loc) catch |err| switch (err) { error.UnsupportedType => { _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); - try warn(c, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, raw_name }); - break :blk Node.opaque_literal.init(); + try warn(c, &c.global_scope.base, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name }); + break :blk Tag.opaque_literal.init(); }, else => |e| return e, }; @@ -890,20 +875,20 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod }); } - const payload = try c.arena.create(ast.Payload.Record); - container_node.* = .{ - .base = .{ .tag = ([2]ast.Node.Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] }, + const record_payload = try c.arena.create(ast.Payload.Record); + record_payload.* = .{ + .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] }, .data = .{ .is_packed = is_packed, .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items), }, }; - break :blk Node.initPayload(&container_node.base); + break :blk Node.initPayload(&record_payload.base); }; const payload = try c.arena.create(ast.Payload.SimpleVarDecl); payload.* = .{ - .base = .{ .tag = ([2]ast.Node.Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] }, + .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] }, .data = .{ .name = name, .init = init_node, @@ -913,12 +898,12 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?Nod try addTopLevelDecl(c, name, Node.initPayload(&payload.base)); if (!is_unnamed) try c.alias_list.append(.{ .alias = bare_name, .name = name }); - return Node.identifier.create(c.arena, name); + return try Tag.identifier.create(c.arena, name); } fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node { if (c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |name| - return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice + return try Tag.identifier.create(c.arena, name); // Avoid processing this decl twice const enum_loc = enum_decl.getLocation(); var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin()); @@ -965,7 +950,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node { else => |e| return e, } else - try Node.type.create(c.arena, "c_int"); + try Tag.type.create(c.arena, "c_int"); it = enum_def.enumerator_begin(); end_it = enum_def.enumerator_end(); @@ -983,29 +968,29 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node { else null; - try fields_and_decls.append(.{ + try fields.append(.{ .name = field_name, .value = int_node, }); // In C each enum value is in the global namespace. So we put them there too. // At this point we can rely on the enum emitting successfully. - try addTopLevelDecl(c, field_name, try Node.enum_redecl.create(c.arena, .{ + try addTopLevelDecl(c, field_name, try Tag.enum_redecl.create(c.arena, .{ .enum_val_name = enum_val_name, .field_name = field_name, .enum_name = name, })); } - break :blk try Node.@"enum".create(c.arena, try c.arena.dupe(ast.Payload.Enum.Field, fields.items)); + break :blk try Tag.@"enum".create(c.arena, try c.arena.dupe(ast.Payload.Enum.Field, fields.items)); } else blk: { _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {}); - break :blk Node.opaque_literal.init(); + break :blk Tag.opaque_literal.init(); }; const payload = try c.arena.create(ast.Payload.SimpleVarDecl); payload.* = .{ - .base = .{ .tag = ([2]ast.Node.Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] }, + .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] }, .data = .{ .name = name, .init = init_node, @@ -1015,7 +1000,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?Node { try addTopLevelDecl(c, name, Node.initPayload(&payload.base)); if (!is_unnamed) try c.alias_list.append(.{ .alias = bare_name, .name = name }); - return transCreateNodeIdentifier(c, name); + return try Tag.identifier.create(c.arena, name); } const ResultUsed = enum { @@ -1023,31 +1008,25 @@ const ResultUsed = enum { unused, }; -const LRValue = enum { - l_value, - r_value, -}; - fn transStmt( c: *Context, scope: *Scope, stmt: *const clang.Stmt, result_used: ResultUsed, - lrvalue: LRValue, ) TransError!Node { const sc = stmt.getStmtClass(); switch (sc) { .BinaryOperatorClass => return transBinaryOperator(c, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used), .CompoundStmtClass => return transCompoundStmt(c, scope, @ptrCast(*const clang.CompoundStmt, stmt)), - .CStyleCastExprClass => return transCStyleCastExprClass(c, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue), + .CStyleCastExprClass => return transCStyleCastExprClass(c, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used), .DeclStmtClass => return transDeclStmt(c, scope, @ptrCast(*const clang.DeclStmt, stmt)), - .DeclRefExprClass => return transDeclRefExpr(c, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue), + .DeclRefExprClass => return transDeclRefExpr(c, scope, @ptrCast(*const clang.DeclRefExpr, stmt)), .ImplicitCastExprClass => return transImplicitCastExpr(c, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used), .IntegerLiteralClass => return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as), .ReturnStmtClass => return transReturnStmt(c, scope, @ptrCast(*const clang.ReturnStmt, stmt)), .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used), .ParenExprClass => { - const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue); + const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used); return maybeSuppressResult(c, scope, result_used, expr); }, .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used), @@ -1056,9 +1035,9 @@ fn transStmt( .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)), .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)), .NullStmtClass => { - return Node.empty_block.init(); + return Tag.empty_block.init(); }, - .ContinueStmtClass => return try transCreateNodeContinue(c), + .ContinueStmtClass => return Tag.@"continue".init(), .BreakStmtClass => return transBreak(c, scope), .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)), .FloatingLiteralClass => return transFloatingLiteral(c, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used), @@ -1083,12 +1062,12 @@ fn transStmt( .CompoundAssignOperatorClass => return transCompoundAssignOperator(c, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used), .OpaqueValueExprClass => { const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?; - const expr = try transExpr(c, scope, source_expr, .used, lrvalue); + const expr = try transExpr(c, scope, source_expr, .used); return maybeSuppressResult(c, scope, result_used, expr); }, else => { return fail( - rp, + c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", @@ -1109,37 +1088,36 @@ fn transBinaryOperator( switch (op) { .Assign => return try transCreateNodeAssign(c, scope, result_used, stmt.getLHS(), stmt.getRHS()), .Comma => { - var block_scope = try Scope.Block.init(rp.c, scope, true); + var block_scope = try Scope.Block.init(c, scope, true); defer block_scope.deinit(); - - const lhs = try transExpr(c, &block_scope.base, stmt.getLHS(), .unused, .r_value); + const lhs = try transExpr(c, &block_scope.base, stmt.getLHS(), .unused); try block_scope.statements.append(lhs); - const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value); - const break_node = try Node.break_val.create(c.arena, .{ + const rhs = try transExpr(c, &block_scope.base, stmt.getRHS(), .used); + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, .val = rhs, }); try block_scope.statements.append(break_node); - const block_node = try block_scope.complete(rp.c); - return maybeSuppressResult(rp, scope, result_used, block_node); + const block_node = try block_scope.complete(c); + return maybeSuppressResult(c, scope, result_used, block_node); }, .Div => { if (cIsSignedInteger(qt)) { // signed integer division uses @divTrunc - const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); - const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); - const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + const lhs = try transExpr(c, scope, stmt.getLHS(), .used); + const rhs = try transExpr(c, scope, stmt.getRHS(), .used); + const div_trunc = try Tag.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); return maybeSuppressResult(c, scope, result_used, div_trunc); } }, .Rem => { if (cIsSignedInteger(qt)) { // signed integer division uses @rem - const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); - const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); - const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + const lhs = try transExpr(c, scope, stmt.getLHS(), .used); + const rhs = try transExpr(c, scope, stmt.getRHS(), .used); + const rem = try Tag.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); return maybeSuppressResult(c, scope, result_used, rem); } }, @@ -1150,14 +1128,14 @@ fn transBinaryOperator( return transCreateNodeShiftOp(c, scope, stmt, .shr, result_used); }, .LAnd => { - return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_and, result_used); + return transCreateNodeBoolInfixOp(c, scope, stmt, .@"and", result_used); }, .LOr => { - return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_or, result_used); + return transCreateNodeBoolInfixOp(c, scope, stmt, .@"or", result_used); }, else => {}, } - var op_id: Node.Tag = undefined; + var op_id: Tag = undefined; switch (op) { .Add => { if (cIsUnsignedInteger(qt)) { @@ -1218,20 +1196,20 @@ fn transBinaryOperator( else => unreachable, } - const lhs_uncasted = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); - const rhs_uncasted = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); + const lhs_uncasted = try transExpr(c, scope, stmt.getLHS(), .used); + const rhs_uncasted = try transExpr(c, scope, stmt.getRHS(), .used); const lhs = if (isBoolRes(lhs_uncasted)) - try Node.bool_to_int.create(c.arena, lhs_uncasted) + try Tag.bool_to_int.create(c.arena, lhs_uncasted) else lhs_uncasted; const rhs = if (isBoolRes(rhs_uncasted)) - try Node.bool_to_int.create(c.arena, rhs_uncasted) + try Tag.bool_to_int.create(c.arena, rhs_uncasted) else rhs_uncasted; - return transCreateNodeInfixOp(c, scope, op_id, lhs, rhs, used); + return transCreateNodeInfixOp(c, scope, op_id, lhs, rhs, result_used); } fn transCompoundStmtInline( @@ -1243,7 +1221,7 @@ fn transCompoundStmtInline( var it = stmt.body_begin(); const end_it = stmt.body_end(); while (it != end_it) : (it += 1) { - const result = try transStmt(c, parent_scope, it[0], .unused, .r_value); + const result = try transStmt(c, parent_scope, it[0], .unused); try block.statements.append(result); } } @@ -1260,7 +1238,6 @@ fn transCStyleCastExprClass( scope: *Scope, stmt: *const clang.CStyleCastExpr, result_used: ResultUsed, - lrvalue: LRValue, ) TransError!Node { const sub_expr = stmt.getSubExpr(); const cast_node = (try transCCast( @@ -1269,7 +1246,7 @@ fn transCStyleCastExprClass( stmt.getBeginLoc(), stmt.getType(), sub_expr.getType(), - try transExpr(c, scope, sub_expr, .used, lrvalue), + try transExpr(c, scope, sub_expr, .used), )); return maybeSuppressResult(c, scope, result_used, cast_node); } @@ -1294,7 +1271,7 @@ fn transDeclStmtOne( // This is actually a global variable, put it in the global scope and reference it. // `_ = mangled_name;` try visitVarDecl(c, var_decl, mangled_name); - return try maybeSuppressResult(c, scope, .unused, try Node.identifier.create(c.arena, mangled_name)); + return try maybeSuppressResult(c, scope, .unused, try Tag.identifier.create(c.arena, mangled_name)); }, else => {}, } @@ -1308,13 +1285,13 @@ fn transDeclStmtOne( if (expr.getStmtClass() == .StringLiteralClass) try transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(c, type_node)) else - try transExprCoercing(c, scope, expr, .used, .r_value) + try transExprCoercing(c, scope, expr, .used) else - try transCreateNodeUndefinedLiteral(c); + Tag.undefined_literal.init(); if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { - init_node = try Node.bool_to_int.create(c.arena, init_node); + init_node = try Tag.bool_to_int.create(c.arena, init_node); } - return Node.var_decl.create(c.arena, .{ + return Tag.var_decl.create(c.arena, .{ .is_pub = false, .is_const = is_const, .is_extern = false, @@ -1339,7 +1316,7 @@ fn transDeclStmtOne( return node; }, else => |kind| return fail( - rp, + c, error.UnsupportedTranslation, decl.getLocation(), "TODO implement translation of DeclStmt kind {s}", @@ -1370,12 +1347,11 @@ fn transDeclRefExpr( c: *Context, scope: *Scope, expr: *const clang.DeclRefExpr, - lrvalue: LRValue, ) TransError!Node { const value_decl = expr.getDecl(); const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin()); const mangled_name = scope.getAlias(name); - return Node.identifier.create(c.arena, mangled_name); + return Tag.identifier.create(c.arena, mangled_name); } fn transImplicitCastExpr( @@ -1389,49 +1365,49 @@ fn transImplicitCastExpr( const src_type = getExprQualType(c, sub_expr); switch (expr.getCastKind()) { .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => { - const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value); + const sub_expr_node = try transExpr(c, scope, sub_expr, .used); const casted = try transCCast(c, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node); return maybeSuppressResult(c, scope, result_used, casted); }, .LValueToRValue, .NoOp, .FunctionToPointerDecay => { - const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value); + const sub_expr_node = try transExpr(c, scope, sub_expr, .used); return maybeSuppressResult(c, scope, result_used, sub_expr_node); }, .ArrayToPointerDecay => { if (exprIsNarrowStringLiteral(sub_expr)) { - const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value); + const sub_expr_node = try transExpr(c, scope, sub_expr, .used); return maybeSuppressResult(c, scope, result_used, sub_expr_node); } - const addr = try Node.address_of.create(c.arena, try transExpr(c, scope, sub_expr, .used, .r_value)); + const addr = try Tag.address_of.create(c.arena, try transExpr(c, scope, sub_expr, .used)); return maybeSuppressResult(c, scope, result_used, addr); }, .NullToPointer => { - return Node.null_literal.init(); + return Tag.null_literal.init(); }, .PointerToBoolean => { // @ptrToInt(val) != 0 - const ptr_to_int = try Node.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used, .r_value)); + const ptr_to_int = try Tag.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used)); - const ne = try Node.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Node.zero_literal.init() }); + const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() }); return maybeSuppressResult(c, scope, result_used, ne); }, .IntegralToBoolean => { - const sub_expr_node = try transExpr(c, scope, sub_expr, .used, .r_value); + const sub_expr_node = try transExpr(c, scope, sub_expr, .used); // The expression is already a boolean one, return it as-is if (isBoolRes(sub_expr_node)) return maybeSuppressResult(c, scope, result_used, sub_expr_node); // val != 0 - const ne = try Node.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Node.zero_literal.init() }); + const ne = try Tag.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Tag.zero_literal.init() }); return maybeSuppressResult(c, scope, result_used, ne); }, .BuiltinFnToFnPtr => { - return transExpr(rp, scope, sub_expr, result_used, .r_value); + return transExpr(c, scope, sub_expr, result_used); }, else => |kind| return fail( - rp, + c, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, expr).getBeginLoc(), "TODO implement translation of CastKind {s}", @@ -1445,17 +1421,16 @@ fn transBoolExpr( scope: *Scope, expr: *const clang.Expr, used: ResultUsed, - lrvalue: LRValue, ) TransError!Node { if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { var is_zero: bool = undefined; if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); } - return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)] }; + return Node{ .tag_if_small_enough = @enumToInt(([2]Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)]) }; } - var res = try transExpr(c, scope, expr, used, lrvalue); + var res = try transExpr(c, scope, expr, used); if (isBoolRes(res)) { return maybeSuppressResult(c, scope, used, res); } @@ -1494,7 +1469,7 @@ fn isBoolRes(res: Node) bool { .@"or", .@"and", .equal, - .note_equal, + .not_equal, .less_than, .less_than_equal, .greater_than, @@ -1547,18 +1522,18 @@ fn finishBoolExpr( .Float16, => { // node != 0 - return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init() }); + return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() }); }, .NullPtr => { // node == null - return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init() }); + return Tag.equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() }); }, else => {}, } }, .Pointer => { // node == null - return Node.equal.create(c.arena, .{ .lhs = node, .rhs = Node.null_literal.init() }); + return Tag.equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() }); }, .Typedef => { const typedef_ty = @ptrCast(*const clang.TypedefType, ty); @@ -1568,8 +1543,7 @@ fn finishBoolExpr( }, .Enum => { // node != 0 - return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init() }); - const op_token = try appendToken(c, .BangEqual, "!="); + return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() }); }, .Elaborated => { const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty); @@ -1614,9 +1588,10 @@ fn transIntegerLiteral( // But the first step is to be correct, and the next step is to make the output more elegant. // @as(T, x) + const expr_base = @ptrCast(*const clang.Expr, expr); const ty_node = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()); const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt()); - const as = try Node.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs }); + const as = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs }); return maybeSuppressResult(c, scope, result_used, as); } @@ -1624,16 +1599,16 @@ fn transReturnStmt( c: *Context, scope: *Scope, expr: *const clang.ReturnStmt, -) TransError!*ast.Node { +) TransError!Node { const val_expr = expr.getRetValue() orelse - return Node.return_void.init(); + return Tag.return_void.init(); - var rhs = try transExprCoercing(c, scope, val_expr, .used, .r_value); + var rhs = try transExprCoercing(c, scope, val_expr, .used); const return_qt = scope.findBlockReturnType(c); if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) { - rhs = try Node.bool_to_int.create(c.arena, rhs); + rhs = try Tag.bool_to_int.create(c.arena, rhs); } - return Node.@"return".create(c.arena, rhs); + return Tag.@"return".create(c.arena, rhs); } fn transStringLiteral( @@ -1647,10 +1622,9 @@ fn transStringLiteral( .Ascii, .UTF8 => { var len: usize = undefined; const bytes_ptr = stmt.getString_bytes_begin_size(&len); - const str = bytes_ptr[0..len]; - const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(str)}); - const node = try Node.string_literal.create(c.arena, str); + const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])}); + const node = try Tag.string_literal.create(c.arena, str); return maybeSuppressResult(c, scope, result_used, node); }, .UTF16, .UTF32, .Wide => { @@ -1658,9 +1632,9 @@ fn transStringLiteral( const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() }); const lit_array = try transStringLiteralAsArray(c, scope, stmt, stmt.getLength() + 1); - const decl = try Node.var_simple.create(c.arena, .{ .name = name, .init = lit_array }); - try scope.appendNode(name, decl); - const node = try Node.identifier.create(c.arena, name); + const decl = try Tag.var_simple.create(c.arena, .{ .name = name, .init = lit_array }); + try scope.appendNode(decl); + const node = try Tag.identifier.create(c.arena, name); return maybeSuppressResult(c, scope, result_used, node); }, } @@ -1669,9 +1643,7 @@ fn transStringLiteral( /// Parse the size of an array back out from an ast Node. fn zigArraySize(c: *Context, node: Node) TransError!usize { if (node.castTag(.array_type)) |array| { - if (array.data.len.castTag(.int_literal)) |int_lit| { - return std.fmt.parseUnsigned(usize, int_lit.data, 10) catch error.UnsupportedTranslation; - } + return array.data.len; } return error.UnsupportedTranslation; } @@ -1709,7 +1681,7 @@ fn transStringLiteralAsArray( init_list[i] = try transCreateNodeNumber(c, 0); } - return Node.array_init.create(c.arena, init_list); + return Tag.array_init.create(c.arena, init_list); } fn cIsEnum(qt: clang.QualType) bool { @@ -1747,89 +1719,77 @@ fn transCCast( // 3. Bit-cast to correct signed-ness const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type); const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type); - var src_int_expr = if (cIsInteger(src_type)) expr else Node.enum_to_int.create(c.arena, expr); + var src_int_expr = if (cIsInteger(src_type)) expr else try Tag.enum_to_int.create(c.arena, expr); if (isBoolRes(src_int_expr)) { - src_int_expr = try Node.bool_to_int.create(c.arena, src_int_expr); + src_int_expr = try Tag.bool_to_int.create(c.arena, src_int_expr); } switch (cIntTypeCmp(dst_type, src_int_type)) { .lt => { // @truncate(SameSignSmallerInt, src_int_expr) const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed); - src_int_expr = try Node.truncate.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr }); + src_int_expr = try Tag.truncate.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr }); }, .gt => { // @as(SameSignBiggerInt, src_int_expr) const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed); - src_int_expr = try Node.as.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr }); + src_int_expr = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr }); }, .eq => { // src_int_expr = src_int_expr }, } // @bitCast(dest_type, intermediate_value) - return Node.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr }); + return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr }); } if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { // @intCast(dest_type, @ptrToInt(val)) - const ptr_to_int = try Node.ptr_to_int.create(c.arena, expr); - return Node.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int }); + const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr); + return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int }); } if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { // @intToPtr(dest_type, val) - return Node.int_to_ptr.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + return Tag.int_to_ptr.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); } if (cIsFloating(src_type) and cIsFloating(dst_type)) { // @floatCast(dest_type, val) - return Node.float_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + return Tag.float_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); } if (cIsFloating(src_type) and !cIsFloating(dst_type)) { // @floatToInt(dest_type, val) - return Node.float_to_int.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + return Tag.float_to_int.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); } if (!cIsFloating(src_type) and cIsFloating(dst_type)) { // @intToFloat(dest_type, val) - return Node.int_to_float.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + return Tag.int_to_float.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); } if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) { // @boolToInt returns either a comptime_int or a u1 // TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast // instead of @as - const bool_to_int = Node.bool_to_int.create(c.arena, expr); - return Node.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int }); + const bool_to_int = try Tag.bool_to_int.create(c.arena, expr); + return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int }); } if (cIsEnum(dst_type)) { // @intToEnum(dest_type, val) - return Node.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + return Tag.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); } if (cIsEnum(src_type) and !cIsEnum(dst_type)) { // @enumToInt(val) - return Node.enum_to_int.create(c.arena, expr); + return Tag.enum_to_int.create(c.arena, expr); } // @as(dest_type, val) - return Node.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); + return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr }); } -fn transExpr( - c: *Context, - scope: *Scope, - expr: *const clang.Expr, - used: ResultUsed, - lrvalue: LRValue, -) TransError!Node { - return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue); +fn transExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { + return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used); } /// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore /// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals. -fn transExprCoercing( - c: *Context, - scope: *Scope, - expr: *const clang.Expr, - used: ResultUsed, - lrvalue: LRValue, -) TransError!Node { +fn transExprCoercing(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) { .IntegerLiteralClass => { return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as); @@ -1840,12 +1800,12 @@ fn transExprCoercing( .UnaryOperatorClass => { const un_expr = @ptrCast(*const clang.UnaryOperator, expr); if (un_expr.getOpcode() == .Extension) { - return transExprCoercing(c, scope, un_expr.getSubExpr(), used, lrvalue); + return transExprCoercing(c, scope, un_expr.getSubExpr(), used); } }, else => {}, } - return transExpr(c, scope, expr, .used, .r_value); + return transExpr(c, scope, expr, .used); } fn transInitListExprRecord( @@ -1896,11 +1856,11 @@ fn transInitListExprRecord( try field_inits.append(.{ .name = raw_name, - .value = try transExpr(c, scope, elem_expr, .used, .r_value), + .value = try transExpr(c, scope, elem_expr, .used), }); } - return Node.container_init.create(c.arena, try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items)); + return Tag.container_init.create(c.arena, try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items)); } fn transInitListExprArray( @@ -1920,18 +1880,18 @@ fn transInitListExprArray( const leftover_count = all_count - init_count; if (all_count == 0) { - return Node.empty_array.create(c.arena, try transQualType(c, child_qt, source_loc)); + return Tag.empty_array.create(c.arena, try transQualType(c, child_qt, loc)); } - const ty_node = try transType(ty); + const ty_node = try transType(c, ty, loc); const init_node = if (init_count != 0) blk: { const init_list = try c.arena.alloc(Node, init_count); for (init_list) |*init, i| { - const elem_expr = expr.getInit(i); - init.* = try transExpr(c, scope, elem_expr, .used, .r_value); + const elem_expr = expr.getInit(@intCast(c_uint, i)); + init.* = try transExpr(c, scope, elem_expr, .used); } - const init_node = try Node.array_init.create(c.arena, init_list); + const init_node = try Tag.array_init.create(c.arena, init_list); if (leftover_count == 0) { return init_node; } @@ -1939,14 +1899,14 @@ fn transInitListExprArray( } else null; const filler_val_expr = expr.getArrayFiller(); - const filler_node = try Node.array_filler.create(c.arena, .{ + const filler_node = try Tag.array_filler.create(c.arena, .{ .type = ty_node, - .filler = try transExpr(c, scope, filler_val_expr, .used, .r_value), + .filler = try transExpr(c, scope, filler_val_expr, .used), .count = leftover_count, }); if (init_node) |some| { - return Node.array_cat.create(c.arena, some, filler_node); + return Tag.array_cat.create(c.arena, .{ .lhs = some, .rhs = filler_node }); } else { return filler_node; } @@ -1964,7 +1924,7 @@ fn transInitListExpr( if (qual_type.isRecordType()) { return maybeSuppressResult(c, scope, used, try transInitListExprRecord( - rp, + c, scope, source_loc, expr, @@ -1972,7 +1932,7 @@ fn transInitListExpr( )); } else if (qual_type.isArrayType()) { return maybeSuppressResult(c, scope, used, try transInitListExprArray( - rp, + c, scope, source_loc, expr, @@ -1994,7 +1954,7 @@ fn transZeroInitExpr( .Builtin => { const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); switch (builtin_ty.getKind()) { - .Bool => return Node.false_literal.init(), + .Bool => return Tag.false_literal.init(), .Char_U, .UChar, .Char_S, @@ -2015,11 +1975,11 @@ fn transZeroInitExpr( .Float128, .Float16, .LongDouble, - => return Node.zero_literal.init(), + => return Tag.zero_literal.init(), else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), } }, - .Pointer => return Node.null_literal.init(), + .Pointer => return Tag.null_literal.init(), .Typedef => { const typedef_ty = @ptrCast(*const clang.TypedefType, ty); const typedef_decl = typedef_ty.getDecl(); @@ -2058,19 +2018,19 @@ fn transIfStmt( var cond_scope = Scope.Condition{ .base = .{ .parent = scope, - .id = .Condition, + .id = .condition, }, }; defer cond_scope.deinit(); const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond()); - const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value); + const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); - const then_body = try transStmt(c, scope, stmt.getThen(), .unused, .r_value); + const then_body = try transStmt(c, scope, stmt.getThen(), .unused); const else_body = if (stmt.getElse()) |expr| - try transStmt(c, scope, expr, .unused, .r_value) + try transStmt(c, scope, expr, .unused) else null; - return Node.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body }); + return Tag.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body }); } fn transWhileLoop( @@ -2081,19 +2041,19 @@ fn transWhileLoop( var cond_scope = Scope.Condition{ .base = .{ .parent = scope, - .id = .Condition, + .id = .condition, }, }; defer cond_scope.deinit(); const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond()); - const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value); + const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); var loop_scope = Scope{ .parent = scope, - .id = .Loop, + .id = .loop, }; - const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value); - return Node.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null }); + const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused); + return Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null }); } fn transDoWhileLoop( @@ -2103,20 +2063,19 @@ fn transDoWhileLoop( ) TransError!Node { var loop_scope = Scope{ .parent = scope, - .id = .Loop, + .id = .loop, }; // if (!cond) break; - const if_node = try transCreateNodeIf(c); var cond_scope = Scope.Condition{ .base = .{ .parent = scope, - .id = .Condition, + .id = .condition, }, }; defer cond_scope.deinit(); - const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value); - const if_not_break = try Node.if_not_break.create(c.arena, cond); + const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used); + const if_not_break = try Tag.if_not_break.create(c.arena, cond); const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: { // there's already a block in C, so we'll append our condition to it. @@ -2129,8 +2088,8 @@ fn transDoWhileLoop( // zig: b; // zig: if (!cond) break; // zig: } - const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value); - const block = node.castTag(.block); + const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused); + const block = node.castTag(.block).?; block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete. block.data.stmts[block.data.stmts.len - 1] = if_not_break; break :blk node; @@ -2143,12 +2102,12 @@ fn transDoWhileLoop( // zig: a; // zig: if (!cond) break; // zig: } - const statements = try c.arena.create(Node, 2); - statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value); + const statements = try c.arena.alloc(Node, 2); + statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused); statements[1] = if_not_break; - break :blk try Node.block.create(c.arena, .{ .label = null, .stmts = statements }); + break :blk try Tag.block.create(c.arena, .{ .label = null, .stmts = statements }); }; - return Node.while_true.create(c.arena, body_node); + return Tag.while_true.create(c.arena, body_node); } fn transForLoop( @@ -2158,7 +2117,7 @@ fn transForLoop( ) TransError!Node { var loop_scope = Scope{ .parent = scope, - .id = .Loop, + .id = .loop, }; var block_scope: ?Scope.Block = null; @@ -2167,29 +2126,29 @@ fn transForLoop( if (stmt.getInit()) |init| { block_scope = try Scope.Block.init(c, scope, false); loop_scope.parent = &block_scope.?.base; - const init_node = try transStmt(c, &block_scope.?.base, init, .unused, .r_value); + const init_node = try transStmt(c, &block_scope.?.base, init, .unused); try block_scope.?.statements.append(init_node); } var cond_scope = Scope.Condition{ .base = .{ .parent = &loop_scope, - .id = .Condition, + .id = .condition, }, }; defer cond_scope.deinit(); const cond = if (stmt.getCond()) |cond| - try transBoolExpr(c, &cond_scope.base, cond, .used, .r_value) + try transBoolExpr(c, &cond_scope.base, cond, .used) else - Node.true_literal.init(); + Tag.true_literal.init(); const cont_expr = if (stmt.getInc()) |incr| - try transExpr(c, &cond_scope.base, incr, .unused, .r_value) + try transExpr(c, &cond_scope.base, incr, .unused) else null; - const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value); - const while_node = try Node.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr }); + const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused); + const while_node = try Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr }); if (block_scope) |*bs| { try bs.statements.append(while_node); return try bs.complete(c); @@ -2206,13 +2165,14 @@ fn transSwitch( var cond_scope = Scope.Condition{ .base = .{ .parent = scope, - .id = .Condition, + .id = .condition, }, }; defer cond_scope.deinit(); - const switch_expr = try transExpr(c, &cond_scope.base, stmt.getCond(), .used, .r_value); + const switch_expr = try transExpr(c, &cond_scope.base, stmt.getCond(), .used); const switch_node = try c.arena.create(ast.Payload.Switch); switch_node.* = .{ + .base = .{ .tag = .@"switch" }, .data = .{ .cond = switch_expr, .cases = undefined, // set later @@ -2221,7 +2181,7 @@ fn transSwitch( var switch_scope = Scope.Switch{ .base = .{ - .id = .Switch, + .id = .@"switch", .parent = scope, }, .cases = std.ArrayList(Node).init(c.gpa), @@ -2229,11 +2189,7 @@ fn transSwitch( .default_label = null, .switch_label = null, }; - defer { - switch_node.data.cases = try c.arena.dupe(Node, switch_scope.cases.items); - switch_node.data.default = switch_scope.switch_label; - switch_scope.cases.deinit(); - } + defer switch_scope.cases.deinit(); // tmp block that all statements will go before being picked up by a case or default var block_scope = try Scope.Block.init(c, &switch_scope.base, false); @@ -2246,7 +2202,7 @@ fn transSwitch( switch_scope.pending_block = try Scope.Block.init(c, scope, false); try switch_scope.pending_block.statements.append(Node.initPayload(&switch_node.base)); - const last = try transStmt(c, &block_scope.base, stmt.getBody(), .unused, .r_value); + const last = try transStmt(c, &block_scope.base, stmt.getBody(), .unused); // take all pending statements const last_block_stmts = last.castTag(.block).?.data.stmts; @@ -2264,13 +2220,14 @@ fn transSwitch( switch_scope.pending_block.label = l; } if (switch_scope.default_label == null) { - const else_prong = try Node.switch_else.create( + const else_prong = try Tag.switch_else.create( c.arena, - try Node.@"break".create(c.arena, switch_scope.switch_label.?), + try Tag.@"break".create(c.arena, switch_scope.switch_label.?), ); - switch_scope.cases.append(else_prong); + try switch_scope.cases.append(else_prong); } + switch_node.data.cases = try c.arena.dupe(Node, switch_scope.cases.items); const result_node = try switch_scope.pending_block.complete(c); switch_scope.pending_block.deinit(); return result_node; @@ -2286,18 +2243,18 @@ fn transCase( const label = try block_scope.makeMangledName(c, "case"); const expr = if (stmt.getRHS()) |rhs| blk: { - const lhs_node = try transExpr(c, scope, stmt.getLHS(), .used, .r_value); - const rhs_node = try transExpr(c, scope, rhs, .used, .r_value); + const lhs_node = try transExpr(c, scope, stmt.getLHS(), .used); + const rhs_node = try transExpr(c, scope, rhs, .used); - break :blk Node.ellipsis3.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); + break :blk try Tag.ellipsis3.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); } else - try transExpr(c, scope, stmt.getLHS(), .used, .r_value); + try transExpr(c, scope, stmt.getLHS(), .used); - const switch_prong = try Node.switch_prong.create( - c.arena, - try Node.@"break".create(c.arena, label), - ); - switch_scope.cases.append(switch_prong); + const switch_prong = try Tag.switch_prong.create(c.arena, .{ + .lhs = expr, + .rhs = try Tag.@"break".create(c.arena, label), + }); + try switch_scope.cases.append(switch_prong); switch_scope.pending_block.label = label; @@ -2311,7 +2268,7 @@ fn transCase( try switch_scope.pending_block.statements.append(pending_node); - return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value); + return transStmt(c, scope, stmt.getSubStmt(), .unused); } fn transDefault( @@ -2323,12 +2280,12 @@ fn transDefault( const switch_scope = scope.getSwitch(); switch_scope.default_label = try block_scope.makeMangledName(c, "default"); - const else_prong = try Node.switch_else.create( + const else_prong = try Tag.switch_else.create( c.arena, - try Node.@"break".create(c.arena, switch_scope.default_label.?), + try Tag.@"break".create(c.arena, switch_scope.default_label.?), ); - switch_scope.cases.append(else_prong); - switch_scope.pending_block.label = try appendIdentifier(c, switch_scope.default_label.?); + try switch_scope.cases.append(else_prong); + switch_scope.pending_block.label = switch_scope.default_label.?; // take all pending statements try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); @@ -2339,7 +2296,7 @@ fn transDefault( switch_scope.pending_block = try Scope.Block.init(c, scope, false); try switch_scope.pending_block.statements.append(pending_node); - return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value); + return transStmt(c, scope, stmt.getSubStmt(), .unused); } fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { @@ -2352,7 +2309,7 @@ fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: // See comment in `transIntegerLiteral` for why this code is here. // @as(T, x) const expr_base = @ptrCast(*const clang.Expr, expr); - const as_node = try Node.as.create(c.arena, .{ + const as_node = try Tag.as.create(c.arena, .{ .lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()), .rhs = try transCreateNodeAPInt(c, result.Val.getInt()), }); @@ -2369,10 +2326,10 @@ fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.Predefined } fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node { - return Node.char_literal.create(c.arena, if (narrow) - try std.fmt.bufPrint(c.arena, "'{}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})}) + return Tag.char_literal.create(c.arena, if (narrow) + try std.fmt.allocPrint(c.arena, "'{s}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})}) else - try std.fmt.bufPrint(c.arena, "'\\u{{{x}}}'", .{val})); + try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val})); } fn transCharLiteral( @@ -2398,7 +2355,7 @@ fn transCharLiteral( // See comment in `transIntegerLiteral` for why this code is here. // @as(T, x) const expr_base = @ptrCast(*const clang.Expr, stmt); - const as_node = Node.as.create(c.arena, .{ + const as_node = try Tag.as.create(c.arena, .{ .lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()), .rhs = int_lit_node, }); @@ -2416,12 +2373,12 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: var it = comp.body_begin(); const end_it = comp.body_end(); while (it != end_it - 1) : (it += 1) { - const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); + const result = try transStmt(c, &block_scope.base, it[0], .unused); try block_scope.statements.append(result); } - const break_node = try Node.break_val.create(c.arena, .{ - .label = block_scope.label, - .val = try transStmt(c, &block_scope.base, it[0], .used, .r_value), + const break_node = try Tag.break_val.create(c.arena, .{ + .label = block_scope.label, + .val = try transStmt(c, &block_scope.base, it[0], .used), }); try block_scope.statements.append(break_node); const res = try block_scope.complete(c); @@ -2429,10 +2386,10 @@ fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: } fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node { - var container_node = try transExpr(c, scope, stmt.getBase(), .used, .r_value); + var container_node = try transExpr(c, scope, stmt.getBase(), .used); if (stmt.isArrow()) { - container_node = try Node.deref.create(c.arena, container_node); + container_node = try Tag.deref.create(c.arena, container_node); } const member_decl = stmt.getMemberDecl(); @@ -2450,9 +2407,9 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re const decl = @ptrCast(*const clang.NamedDecl, member_decl); break :blk try c.str(decl.getName_bytes_begin()); }; - const ident = try Node.identifier.create(c.arena, name); + const ident = try Tag.identifier.create(c.arena, name); - const node = try Node.field_access.create(c.arena, .{ .lhs = container_node, .rhs = ident}); + const node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .rhs = ident }); return maybeSuppressResult(c, scope, result_used, node); } @@ -2469,7 +2426,7 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip } } - const container_node = try transExpr(c, scope, base_stmt, .used, .r_value); + const container_node = try transExpr(c, scope, base_stmt, .used); // cast if the index is long long or signed const subscr_expr = stmt.getIdx(); @@ -2477,14 +2434,17 @@ fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscrip const is_longlong = cIsLongLongInteger(qt); const is_signed = cIsSignedInteger(qt); - - const node = try Node.array_access.create(c.arena, .{ .lhs = container_node, .rhs = if (is_longlong or is_signed) blk: { - const cast_node = try c.createBuiltinCall("@intCast", 2); + const rhs = if (is_longlong or is_signed) blk: { // check if long long first so that signed long long doesn't just become unsigned long long - var typeid_node = if (is_longlong) try transCreateNodeIdentifier(c, "usize") else try transQualTypeIntWidthOf(c, qt, false); - break :blk try Node.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used, .r_value)}); + var typeid_node = if (is_longlong) try Tag.identifier.create(c.arena, "usize") else try transQualTypeIntWidthOf(c, qt, false); + break :blk try Tag.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used) }); } else - try transExpr(c, scope, subscr_expr, .used, .r_value)}); + try transExpr(c, scope, subscr_expr, .used); + + const node = try Tag.array_access.create(c.arena, .{ + .lhs = container_node, + .rhs = rhs, + }); return maybeSuppressResult(c, scope, result_used, node); } @@ -2522,23 +2482,23 @@ fn cIsFunctionDeclRef(expr: *const clang.Expr) bool { fn transCallExpr(c: *Context, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!Node { const callee = stmt.getCallee(); - var raw_fn_expr = try transExpr(c, scope, callee, .used, .r_value); + var raw_fn_expr = try transExpr(c, scope, callee, .used); var is_ptr = false; const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr); const fn_expr = if (is_ptr and fn_ty != null and !cIsFunctionDeclRef(callee)) - try transCreateNodeUnwrapNull(rp.c, raw_fn_expr) + try Tag.unwrap.create(c.arena, raw_fn_expr) else raw_fn_expr; const num_args = stmt.getNumArgs(); - const call_params = try c.arena.alloc(Node, num_args); + const args = try c.arena.alloc(Node, num_args); - const args = stmt.getArgs(); + const c_args = stmt.getArgs(); var i: usize = 0; while (i < num_args) : (i += 1) { - var call_param = try transExpr(c, scope, args[i], .used, .r_value); + var arg = try transExpr(c, scope, c_args[i], .used); // In C the result type of a boolean expression is int. If this result is passed as // an argument to a function whose parameter is also int, there is no cast. Therefore @@ -2549,17 +2509,17 @@ fn transCallExpr(c: *Context, scope: *Scope, stmt: *const clang.CallExpr, result const param_count = fn_proto.getNumParams(); if (i < param_count) { const param_qt = fn_proto.getParamType(@intCast(c_uint, i)); - if (isBoolRes(call_param) and cIsNativeInt(param_qt)) { - call_param = try Node.bool_to_int.create(c.arena, call_param); + if (isBoolRes(arg) and cIsNativeInt(param_qt)) { + arg = try Tag.bool_to_int.create(c.arena, arg); } } }, else => {}, } } - call_params[i] = call_param; + args[i] = arg; } - const node = try Node.call.create(c.arena, .{ .lhs = fn_expr, .args = call_params }); + const node = try Tag.call.create(c.arena, .{ .lhs = fn_expr, .args = args }); if (fn_ty) |ty| { const canon = ty.getReturnType().getCanonicalType(); const ret_ty = canon.getTypePtr(); @@ -2609,17 +2569,17 @@ fn transUnaryExprOrTypeTraitExpr( result_used: ResultUsed, ) TransError!Node { const loc = stmt.getBeginLoc(); - const type_node = try transQualType(rp, stmt.getTypeOfArgument(), loc); + const type_node = try transQualType(c, stmt.getTypeOfArgument(), loc); const kind = stmt.getKind(); switch (kind) { - .SizeOf => return Node.sizeof.create(c.arena, type_node), - .AlignOf => return Node.alignof.create(c.arena, type_node), + .SizeOf => return Tag.sizeof.create(c.arena, type_node), + .AlignOf => return Tag.alignof.create(c.arena, type_node), .PreferredAlignOf, .VecStep, .OpenMPRequiredSimdAlign, - => return revertAndWarn( - rp, + => return fail( + c, error.UnsupportedTranslation, loc, "Unsupported type trait kind {}", @@ -2642,53 +2602,54 @@ fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperat const op_expr = stmt.getSubExpr(); switch (stmt.getOpcode()) { .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreatePostCrement(c, scope, stmt, .assign_add_wrap, used) + return transCreatePostCrement(c, scope, stmt, .add_wrap_assign, used) else - return transCreatePostCrement(c, scope, stmt, .assign_add, used), + return transCreatePostCrement(c, scope, stmt, .add_assign, used), .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreatePostCrement(c, scope, stmt, .assign_sub_wrap, used) + return transCreatePostCrement(c, scope, stmt, .sub_wrap_assign, used) else - return transCreatePostCrement(c, scope, stmt, .assign_sub, used), + return transCreatePostCrement(c, scope, stmt, .sub_assign, used), .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreatePreCrement(c, scope, stmt, .assign_add_wrap, used) + return transCreatePreCrement(c, scope, stmt, .add_wrap_assign, used) else - return transCreatePreCrement(c, scope, stmt, .assign_add, used), + return transCreatePreCrement(c, scope, stmt, .add_assign, used), .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreatePreCrement(c, scope, stmt, .assign_sub_wrap, used) + return transCreatePreCrement(c, scope, stmt, .sub_wrap_assign, used) else - return transCreatePreCrement(c, scope, stmt, .assign_sub, used), + return transCreatePreCrement(c, scope, stmt, .sub_assign, used), .AddrOf => { if (cIsFunctionDeclRef(op_expr)) { - return transExpr(rp, scope, op_expr, used, .r_value); + return transExpr(c, scope, op_expr, used); } - return Node.address_of.create(c.arena, try transExpr(c, scope, op_expr, used, .r_value)); + return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used)); }, .Deref => { - const node = try transExpr(c, scope, op_expr, used, .r_value); + const node = try transExpr(c, scope, op_expr, used); var is_ptr = false; const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr); if (fn_ty != null and is_ptr) return node; - return Node.unwrap_deref.create(c.arena, node); + const unwrapped = try Tag.unwrap.create(c.arena, node); + return Tag.deref.create(c.arena, unwrapped); }, - .Plus => return transExpr(c, scope, op_expr, used, .r_value), + .Plus => return transExpr(c, scope, op_expr, used), .Minus => { if (!qualTypeHasWrappingOverflow(op_expr.getType())) { - return Node.negate.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); + return Tag.negate.create(c.arena, try transExpr(c, scope, op_expr, .used)); } else if (cIsUnsignedInteger(op_expr.getType())) { // use -% x for unsigned integers - return Node.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); + return Tag.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used)); } else return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{}); }, .Not => { - return Node.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); + return Tag.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used)); }, .LNot => { - return Node.not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); + return Tag.not.create(c.arena, try transExpr(c, scope, op_expr, .used)); }, .Extension => { - return transExpr(c, scope, stmt.getSubExpr(), used, .l_value); + return transExpr(c, scope, stmt.getSubExpr(), used); }, else => return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}), } @@ -2698,7 +2659,7 @@ fn transCreatePreCrement( c: *Context, scope: *Scope, stmt: *const clang.UnaryOperator, - op: Node.Tag, + op: Tag, used: ResultUsed, ) TransError!Node { const op_expr = stmt.getSubExpr(); @@ -2707,8 +2668,8 @@ fn transCreatePreCrement( // common case // c: ++expr // zig: expr += 1 - const lhs = try transExpr(c, scope, op_expr, .used, .r_value); - const rhs = Node.one_literal.init(); + const lhs = try transExpr(c, scope, op_expr, .used); + const rhs = Tag.one_literal.init(); return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used); } // worst case @@ -2722,17 +2683,17 @@ fn transCreatePreCrement( defer block_scope.deinit(); const ref = try block_scope.makeMangledName(c, "ref"); - const expr = try transExpr(c, scope, op_expr, .used, .r_value); - const addr_of = try Node.address_of.create(c.arena, expr); - const ref_decl = try Node.var_simple.create(c.arena, .{ .name = ref, .init = addr_of}); + const expr = try transExpr(c, scope, op_expr, .used); + const addr_of = try Tag.address_of.create(c.arena, expr); + const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of }); try block_scope.statements.append(ref_decl); - const lhs_node = try Node.identifier.create(c.arena, ref); - const ref_node = try Node.deref.create(c.arena, lhs_node); - const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Node.one_literal.init(), .used); + const lhs_node = try Tag.identifier.create(c.arena, ref); + const ref_node = try Tag.deref.create(c.arena, lhs_node); + const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Tag.one_literal.init(), .used); try block_scope.statements.append(node); - const break_node = try Node.break_val.create(c.arena, .{ + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, .val = ref_node, }); @@ -2744,7 +2705,7 @@ fn transCreatePostCrement( c: *Context, scope: *Scope, stmt: *const clang.UnaryOperator, - op: Node.Tag, + op: Tag, used: ResultUsed, ) TransError!Node { const op_expr = stmt.getSubExpr(); @@ -2753,8 +2714,8 @@ fn transCreatePostCrement( // common case // c: expr++ // zig: expr += 1 - const lhs = try transExpr(c, scope, op_expr, .used, .r_value); - const rhs = Node.one_literal.init(); + const lhs = try transExpr(c, scope, op_expr, .used); + const rhs = Tag.one_literal.init(); return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used); } // worst case @@ -2769,24 +2730,24 @@ fn transCreatePostCrement( defer block_scope.deinit(); const ref = try block_scope.makeMangledName(c, "ref"); - const expr = try transExpr(c, scope, op_expr, .used, .r_value); - const addr_of = try Node.address_of.create(c.arena, expr); - const ref_decl = try Node.var_simple.create(c.arena, .{ .name = ref, .init = addr_of}); + const expr = try transExpr(c, scope, op_expr, .used); + const addr_of = try Tag.address_of.create(c.arena, expr); + const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of }); try block_scope.statements.append(ref_decl); - const lhs_node = try Node.identifier.create(c.arena, ref); - const ref_node = try Node.deref.create(c.arena, lhs_node); + const lhs_node = try Tag.identifier.create(c.arena, ref); + const ref_node = try Tag.deref.create(c.arena, lhs_node); const tmp = try block_scope.makeMangledName(c, "tmp"); - const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node}); + const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node }); try block_scope.statements.append(tmp_decl); - const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Node.one_literal.init(), .used); + const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Tag.one_literal.init(), .used); try block_scope.statements.append(node); - const break_node = try Node.break_val.create(c.arena, .{ + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, - .val = try Node.identifier.create(c.arena, tmp), + .val = try Tag.identifier.create(c.arena, tmp), }); try block_scope.statements.append(break_node); return block_scope.complete(c); @@ -2795,26 +2756,26 @@ fn transCreatePostCrement( fn transCompoundAssignOperator(c: *Context, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!Node { switch (stmt.getOpcode()) { .MulAssign => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreateCompoundAssign(c, scope, stmt, .assign_mul_wrap, used) + return transCreateCompoundAssign(c, scope, stmt, .mul_wrap_assign, used) else - return transCreateCompoundAssign(c, scope, stmt, .assign_mul, used), + return transCreateCompoundAssign(c, scope, stmt, .mul_assign, used), .AddAssign => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreateCompoundAssign(c, scope, stmt, .assign_add_wrap, used) + return transCreateCompoundAssign(c, scope, stmt, .add_wrap_assign, used) else - return transCreateCompoundAssign(c, scope, stmt, .assign_add, used), + return transCreateCompoundAssign(c, scope, stmt, .add_assign, used), .SubAssign => if (qualTypeHasWrappingOverflow(stmt.getType())) - return transCreateCompoundAssign(c, scope, stmt, .assign_sub_wrap, used) + return transCreateCompoundAssign(c, scope, stmt, .sub_wrap_assign, used) else - return transCreateCompoundAssign(c, scope, stmt, .assign_sub, used), - .DivAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_div, used), - .RemAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_mod, used), - .ShlAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_shl, used), - .ShrAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_shr, used), - .AndAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_and, used), - .XorAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_xor, used), - .OrAssign => return transCreateCompoundAssign(c, scope, stmt, .assign_bit_or, used), + return transCreateCompoundAssign(c, scope, stmt, .sub_assign, used), + .DivAssign => return transCreateCompoundAssign(c, scope, stmt, .div_assign, used), + .RemAssign => return transCreateCompoundAssign(c, scope, stmt, .mod_assign, used), + .ShlAssign => return transCreateCompoundAssign(c, scope, stmt, .shl_assign, used), + .ShrAssign => return transCreateCompoundAssign(c, scope, stmt, .shr_assign, used), + .AndAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_and_assign, used), + .XorAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_xor_assign, used), + .OrAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_or_assign, used), else => return fail( - rp, + c, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", @@ -2827,12 +2788,12 @@ fn transCreateCompoundAssign( c: *Context, scope: *Scope, stmt: *const clang.CompoundAssignOperator, - op: Node.Tag, + op: Tag, used: ResultUsed, ) TransError!Node { - const is_shift = op == .assign_shl or op == .assign_shr; - const is_div = op == .assign_div; - const is_mod = op == .assign_mod; + const is_shift = op == .shl_assign or op == .shr_assign; + const is_div = op == .div_assign; + const is_mod = op == .mod_assign; const lhs = stmt.getLHS(); const rhs = stmt.getRHS(); const loc = stmt.getBeginLoc(); @@ -2849,21 +2810,21 @@ fn transCreateCompoundAssign( // c: lhs += rhs // zig: lhs += rhs if ((is_mod or is_div) and is_signed) { - const lhs_node = try transExpr(c, scope, lhs, .used, .l_value); - const rhs_node = try transExpr(c, scope, rhs, .used, .r_value); + const lhs_node = try transExpr(c, scope, lhs, .used); + const rhs_node = try transExpr(c, scope, rhs, .used); const builtin = if (is_mod) - try Node.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) + try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) else - try Node.divTrunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); + try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used); } - const lhs_node = try transExpr(c, scope, lhs, .used, .l_value); + const lhs_node = try transExpr(c, scope, lhs, .used); var rhs_node = if (is_shift or requires_int_cast) - try transExprCoercing(c, scope, rhs, .used, .r_value) + try transExprCoercing(c, scope, rhs, .used) else - try transExpr(c, scope, rhs, .used, .r_value); + try transExpr(c, scope, rhs, .used); if (is_shift or requires_int_cast) { // @intCast(rhs) @@ -2871,11 +2832,11 @@ fn transCreateCompoundAssign( try qualTypeToLog2IntRef(c, getExprQualType(c, rhs), loc) else try transQualType(c, getExprQualType(c, lhs), loc); - - rhs_node = try Node.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); + + rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); } - return transCreateNodeInfixOp(c, scope, assign_op, lhs_node, rhs_node, .used); + return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used); } // worst case // c: lhs += rhs @@ -2888,25 +2849,25 @@ fn transCreateCompoundAssign( defer block_scope.deinit(); const ref = try block_scope.makeMangledName(c, "ref"); - const expr = try transExpr(c, scope, op_expr, .used, .r_value); - const addr_of = try Node.address_of.create(c.arena, expr); - const ref_decl = try Node.var_simple.create(c.arena, .{ .name = ref, .init = addr_of}); + const expr = try transExpr(c, scope, lhs, .used); + const addr_of = try Tag.address_of.create(c.arena, expr); + const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of }); try block_scope.statements.append(ref_decl); - const lhs_node = try Node.identifier.create(c.arena, ref); - const ref_node = try Node.deref.create(c.arena, lhs_node); + const lhs_node = try Tag.identifier.create(c.arena, ref); + const ref_node = try Tag.deref.create(c.arena, lhs_node); if ((is_mod or is_div) and is_signed) { - const rhs_node = try transExpr(c, scope, rhs, .used, .r_value); + const rhs_node = try transExpr(c, scope, rhs, .used); const builtin = if (is_mod) - try Node.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) + try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }) else - try Node.divTrunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); + try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); const assign = try transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used); try block_scope.statements.append(assign); } else { - var rhs_node = try transExpr(c, scope, rhs, .used, .r_value); + var rhs_node = try transExpr(c, scope, rhs, .used); if (is_shift or requires_int_cast) { // @intCast(rhs) @@ -2914,15 +2875,15 @@ fn transCreateCompoundAssign( try qualTypeToLog2IntRef(c, getExprQualType(c, rhs), loc) else try transQualType(c, getExprQualType(c, lhs), loc); - - rhs_node = try Node.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); + + rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node }); } const assign = try transCreateNodeInfixOp(c, scope, op, ref_node, rhs_node, .used); try block_scope.statements.append(assign); } - const break_node = try Node.break_val.create(c.arena, .{ + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, .val = ref_node, }); @@ -2941,7 +2902,7 @@ fn transCPtrCast( const child_type = ty.getPointeeType(); const src_ty = src_type.getTypePtr(); const src_child_type = src_ty.getPointeeType(); - const dst_type = try transType(c, ty, loc); + const dst_type_node = try transType(c, ty, loc); if ((src_child_type.isConstQualified() and !child_type.isConstQualified()) or @@ -2949,8 +2910,8 @@ fn transCPtrCast( !child_type.isVolatileQualified())) { // Casting away const or volatile requires us to use @intToPtr - const ptr_to_int = try Node.ptr_to_int.create(c.arena, expr); - const int_to_ptr = try Node.int_to_ptr.create(c.arena, .{ .lhs = dst_type, .rhs = ptr_to_int }); + const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr); + const int_to_ptr = try Tag.int_to_ptr.create(c.arena, .{ .lhs = dst_type_node, .rhs = ptr_to_int }); return int_to_ptr; } else { // Implicit downcasting from higher to lower alignment values is forbidden, @@ -2963,17 +2924,17 @@ fn transCPtrCast( expr else blk: { const child_type_node = try transQualType(c, child_type, loc); - const alignof = try Node.alignof.create(c.arena, child_type_node); - const align_cast = try Node.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr }); + const alignof = try Tag.alignof.create(c.arena, child_type_node); + const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr }); break :blk align_cast; }; - return Node.ptr_cast.create(c.arena, .{ .lhs = dst_type, .rhs = rhs }); + return Tag.ptr_cast.create(c.arena, .{ .lhs = dst_type_node, .rhs = rhs }); } } fn transBreak(c: *Context, scope: *Scope) TransError!Node { const break_scope = scope.getBreakableScope(); - const label_text: ?[]const u8 = if (break_scope.id == .Switch) blk: { + const label_text: ?[]const u8 = if (break_scope.id == .@"switch") blk: { const swtch = @fieldParentPtr(Scope.Switch, "base", break_scope); const block_scope = try scope.findBlockScope(c); swtch.switch_label = try block_scope.makeMangledName(c, "switch"); @@ -2981,20 +2942,20 @@ fn transBreak(c: *Context, scope: *Scope) TransError!Node { } else null; - return Node.@"break".create(c.arena, label_text); + return Tag.@"break".create(c.arena, label_text); } fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { // TODO use something more accurate const dbl = stmt.getValueAsApproximateDouble(); const node = try transCreateNodeNumber(c, dbl); - return maybeSuppressResult(c, scope, used, &node.base); + return maybeSuppressResult(c, scope, used, node); } fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!Node { // GNU extension of the ternary operator where the middle expression is // omitted, the conditition itself is returned if it evaluates to true - const qt = @ptrCast(*const clang.Stmt, stmt).getType(); + const qt = @ptrCast(*const clang.Expr, stmt).getType(); const res_is_bool = qualTypeIsBoolean(qt); const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt); const cond_expr = casted_stmt.getCond(); @@ -3010,26 +2971,33 @@ fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang defer block_scope.deinit(); const mangled_name = try block_scope.makeMangledName(c, "cond_temp"); - const init_node = try transExpr(c, &block_scope.base, cond_expr, .used, .r_value); - const ref_decl = try Node.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node}); + const init_node = try transExpr(c, &block_scope.base, cond_expr, .used); + const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node }); try block_scope.statements.append(ref_decl); + var cond_scope = Scope.Condition{ + .base = .{ + .parent = &block_scope.base, + .id = .condition, + }, + }; + defer cond_scope.deinit(); const cond_node = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); - var then_body = try Node.identifier.create(c.arena, mangled_name); + var then_body = try Tag.identifier.create(c.arena, mangled_name); if (!res_is_bool and isBoolRes(init_node)) { - then_body = try Node.bool_to_int.create(c.arena, then_body); + then_body = try Tag.bool_to_int.create(c.arena, then_body); } - var else_body = try transExpr(c, &block_scope.base, false_expr, .used, .r_value); + var else_body = try transExpr(c, &block_scope.base, false_expr, .used); if (!res_is_bool and isBoolRes(else_body)) { - else_body = try Node.bool_to_int.create(c.arena, else_body); + else_body = try Tag.bool_to_int.create(c.arena, else_body); } - const if_node = try Node.@"if".create(c.arena, .{ - .cond = cond, + const if_node = try Tag.@"if".create(c.arena, .{ + .cond = cond_node, .then = then_body, .@"else" = else_body, }); - const break_node = try Node.break_val.create(c.arena, .{ + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, .val = if_node, }); @@ -3042,31 +3010,31 @@ fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.Condi var cond_scope = Scope.Condition{ .base = .{ .parent = scope, - .id = .Condition, + .id = .condition, }, }; defer cond_scope.deinit(); - const qt = @ptrCast(*const clang.Stmt, stmt).getType(); + const qt = @ptrCast(*const clang.Expr, stmt).getType(); const res_is_bool = qualTypeIsBoolean(qt); const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt); const cond_expr = casted_stmt.getCond(); const true_expr = casted_stmt.getTrueExpr(); const false_expr = casted_stmt.getFalseExpr(); - const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value); + const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used); - var then_body = try transExpr(c, scope, true_expr, .used, .r_value); + var then_body = try transExpr(c, scope, true_expr, .used); if (!res_is_bool and isBoolRes(then_body)) { - then_body = try Node.bool_to_int.create(c.arena, then_body); + then_body = try Tag.bool_to_int.create(c.arena, then_body); } - var else_body = try transExpr(c, scope, false_expr, .used, .r_value); + var else_body = try transExpr(c, scope, false_expr, .used); if (!res_is_bool and isBoolRes(else_body)) { - else_body = try Node.bool_to_int.create(c.arena, else_body); + else_body = try Tag.bool_to_int.create(c.arena, else_body); } - const if_node = try Node.@"if".create(c.arena, .{ + const if_node = try Tag.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body, @@ -3081,7 +3049,7 @@ fn maybeSuppressResult( result: Node, ) TransError!Node { if (used == .used) return result; - return Node.ignore.create(c.arena, result); + return Tag.ignore.create(c.arena, result); } fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void { @@ -3100,19 +3068,19 @@ fn transQualTypeInitialized( const ty = qt.getTypePtr(); if (ty.getTypeClass() == .IncompleteArray) { const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty); - const elem_ty = incomplete_array_ty.getElementType().getTypePtr(); + const elem_ty = try transType(c, incomplete_array_ty.getElementType().getTypePtr(), source_loc); switch (decl_init.getStmtClass()) { .StringLiteralClass => { const string_lit = @ptrCast(*const clang.StringLiteral, decl_init); const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator const array_size = @intCast(usize, string_lit_size); - return Node.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty }); + return Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty }); }, .InitListExprClass => { const init_expr = @ptrCast(*const clang.InitListExpr, decl_init); const size = init_expr.getNumInits(); - return Node.array_type.create(c.arena, .{ .len = size, .elem_type = elem_ty }); + return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_ty }); }, else => {}, } @@ -3135,7 +3103,7 @@ fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) Typ fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!Node { assert(ty.getTypeClass() == .Builtin); const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); - return Node.type.create(c.arena, switch (builtin_ty.getKind()) { + return Tag.type.create(c.arena, switch (builtin_ty.getKind()) { .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8", .UShort, .Short => if (is_signed) "c_short" else "c_ushort", .UInt, .Int => if (is_signed) "c_int" else "c_uint", @@ -3214,11 +3182,11 @@ fn qualTypeToLog2IntRef(c: *Context, qt: clang.QualType, source_loc: clang.Sourc if (int_bit_width != 0) { // we can perform the log2 now. const cast_bit_width = math.log2_int(u64, int_bit_width); - return Node.log2_int_type.create(c.arena, cast_bit_width); + return Tag.log2_int_type.create(c.arena, cast_bit_width); } const zig_type = try transQualType(c, qt, source_loc); - return Node.std_math_Log2Int.create(c.arena, zig_type); + return Tag.std_math_Log2Int.create(c.arena, zig_type); } fn qualTypeChildIsFnProto(qt: clang.QualType) bool { @@ -3392,10 +3360,10 @@ fn transCreateNodeAssign( // c: lhs = rhs // zig: lhs = rhs if (result_used == .unused) { - const lhs_node = try transExpr(c, scope, lhs, .used, .l_value); - var rhs_node = try transExprCoercing(c, scope, rhs, .used, .r_value); + const lhs_node = try transExpr(c, scope, lhs, .used); + var rhs_node = try transExprCoercing(c, scope, rhs, .used); if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { - rhs_node = try Node.bool_to_int.create(c.arena, rhs_node); + rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node); } return transCreateNodeInfixOp(c, scope, .assign, lhs_node, rhs_node, .used); } @@ -3411,17 +3379,16 @@ fn transCreateNodeAssign( defer block_scope.deinit(); const tmp = try block_scope.makeMangledName(c, "tmp"); - const rhs = try transExpr(c, scope, op_expr, .used, .r_value); - const tmp_decl = try Node.var_simple.create(c.arena, .{ .name = tmp, .init = rhs}); + const rhs_node = try transExpr(c, scope, rhs, .used); + const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node }); try block_scope.statements.append(tmp_decl); - - const lhs = try transExpr(c, &block_scope.base, lhs, .used, .l_value); - const tmp_ident = try Node.identifier.create(c.arena, tmp); - const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs, tmp_iden, .used); + const lhs_node = try transExpr(c, &block_scope.base, lhs, .used); + const tmp_ident = try Tag.identifier.create(c.arena, tmp); + const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs_node, tmp_ident, .used); try block_scope.statements.append(assign); - const break_node = try Node.break_val.create(c.arena, .{ + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, .val = tmp_ident, }); @@ -3432,7 +3399,7 @@ fn transCreateNodeAssign( fn transCreateNodeInfixOp( c: *Context, scope: *Scope, - op: ast.Node.Tag, + op: Tag, lhs: Node, rhs: Node, used: ResultUsed, @@ -3452,13 +3419,13 @@ fn transCreateNodeBoolInfixOp( c: *Context, scope: *Scope, stmt: *const clang.BinaryOperator, - op: ast.Node.Tag, + op: Tag, used: ResultUsed, ) !Node { - std.debug.assert(op == .bool_and or op == .bool_or); + std.debug.assert(op == .@"and" or op == .@"or"); - const lhs = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value); - const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value); + const lhs = try transBoolExpr(c, scope, stmt.getLHS(), .used); + const rhs = try transBoolExpr(c, scope, stmt.getRHS(), .used); return transCreateNodeInfixOp(c, scope, op, lhs, rhs, used); } @@ -3503,22 +3470,22 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node { const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, }; - return Node.int_literal.create(c.arena, str); + return Tag.number_literal.create(c.arena, str); } fn transCreateNodeNumber(c: *Context, int: anytype) !Node { const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(int))) "{d}" else "{s}"; const str = try std.fmt.allocPrint(c.arena, fmt_s, .{int}); - return Node.int_literal.create(c.arena, str); + return Tag.number_literal.create(c.arena, str); } fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: Node, proto_alias: *ast.Payload.Func) !Node { const scope = &c.global_scope.base; - var fn_params = std.ArrayList(Node).init(c.gpa); + var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa); defer fn_params.deinit(); - for (proto_alias.params()) |param, i| { + for (proto_alias.data.params) |param, i| { const param_name = param.name orelse try std.fmt.allocPrint(c.arena, "arg_{d}", .{c.getMangle()}); @@ -3529,29 +3496,29 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: Node, proto_alias: }); } - const init = if (value.castTag(.var_decl)) |v| - v.data.init - else if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |v| + const init = if (ref.castTag(.var_decl)) |v| + v.data.init.? + else if (ref.castTag(.var_simple) orelse ref.castTag(.pub_var_simple)) |v| v.data.init else unreachable; - const unwrap_expr = try Node.unwrap.create(c.arena, init); - const call_params = try c.arena.alloc(Node, fn_params.items.len); + const unwrap_expr = try Tag.unwrap.create(c.arena, init); + const args = try c.arena.alloc(Node, fn_params.items.len); for (fn_params.items) |param, i| { - call_params[i] = try Node.identifier.create(c.arena, param.name); + args[i] = try Tag.identifier.create(c.arena, param.name.?); } - const call_expr = try Node.call.create(c.arean, .{ + const call_expr = try Tag.call.create(c.arena, .{ .lhs = unwrap_expr, - .args = call_params, + .args = args, }); - const return_expr = try Node.@"return".create(c.arean, call_expr); - const block = try Node.block_single.create(c.arean, return_expr); + const return_expr = try Tag.@"return".create(c.arena, call_expr); + const block = try Tag.block_single.create(c.arena, return_expr); - return Node.pub_inline_fn.create(c.arena, .{ + return Tag.pub_inline_fn.create(c.arena, .{ .name = name, - .params = try c.arena.dupe(ast.Node.Param, fn_params.items), - .return_type = proto_alias.return_type, + .params = try c.arena.dupe(ast.Payload.Param, fn_params.items), + .return_type = proto_alias.data.return_type, .body = block, }); } @@ -3560,7 +3527,7 @@ fn transCreateNodeShiftOp( c: *Context, scope: *Scope, stmt: *const clang.BinaryOperator, - op: Node.Tag, + op: Tag, used: ResultUsed, ) !Node { std.debug.assert(op == .shl or op == .shr); @@ -3570,11 +3537,11 @@ fn transCreateNodeShiftOp( const rhs_location = rhs_expr.getBeginLoc(); // lhs >> @as(u5, rh) - const lhs = try transExpr(c, scope, lhs_expr, .used, .l_value); + const lhs = try transExpr(c, scope, lhs_expr, .used); const rhs_type = try qualTypeToLog2IntRef(c, stmt.getType(), rhs_location); - const rhs = try transExprCoercing(c, scope, rhs_expr, .used, .r_value); - const rhs_casted = try Node.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type }); + const rhs = try transExprCoercing(c, scope, rhs_expr, .used); + const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs_type }); return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used); } @@ -3583,7 +3550,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio switch (ty.getTypeClass()) { .Builtin => { const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); - return Node.type.create(c.arena, switch (builtin_ty.getKind()) { + return Tag.type.create(c.arena, switch (builtin_ty.getKind()) { .Void => "c_void", .Bool => "bool", .Char_U, .UChar, .Char_S, .Char8 => "u8", @@ -3608,11 +3575,13 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio }, .FunctionProto => { const fn_proto_ty = @ptrCast(*const clang.FunctionProtoType, ty); - return transFnProto(c, null, fn_proto_ty, source_loc, null, false); + const fn_proto = try transFnProto(c, null, fn_proto_ty, source_loc, null, false); + return Node.initPayload(&fn_proto.base); }, .FunctionNoProto => { const fn_no_proto_ty = @ptrCast(*const clang.FunctionType, ty); - return transFnNoProto(c, fn_no_proto_ty, source_loc, null, false); + const fn_proto = try transFnNoProto(c, fn_no_proto_ty, source_loc, null, false); + return Node.initPayload(&fn_proto.base); }, .Paren => { const paren_ty = @ptrCast(*const clang.ParenType, ty); @@ -3621,16 +3590,16 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio .Pointer => { const child_qt = ty.getPointeeType(); if (qualTypeChildIsFnProto(child_qt)) { - return Node.optional_type.create(c.arena, try transQualType(c, child_qt, source_loc)); + return Tag.optional_type.create(c.arena, try transQualType(c, child_qt, source_loc)); } const is_const = child_qt.isConstQualified(); const is_volatile = child_qt.isVolatileQualified(); const elem_type = try transQualType(c, child_qt, source_loc); - if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) { - return Node.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); + if (typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(c, child_qt)) { + return Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); } - return Node.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); + return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); }, .ConstantArray => { const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty); @@ -3639,7 +3608,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio const size = size_ap_int.getLimitedValue(math.maxInt(usize)); const elem_type = try transType(c, const_arr_ty.getElementType().getTypePtr(), source_loc); - return Node.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type }); + return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type }); }, .IncompleteArray => { const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty); @@ -3649,7 +3618,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio const is_volatile = child_qt.isVolatileQualified(); const elem_type = try transQualType(c, child_qt, source_loc); - return Node.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); + return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); }, .Typedef => { const typedef_ty = @ptrCast(*const clang.TypedefType, ty); @@ -3690,7 +3659,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio }, else => { const type_name = c.str(ty.getTypeClassName()); - return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); + return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); }, } } @@ -3770,7 +3739,7 @@ fn transCC( .AAPCS => return CallingConvention.AAPCS, .AAPCS_VFP => return CallingConvention.AAPCSVFP, else => return fail( - rp, + c, error.UnsupportedType, source_loc, "unsupported calling convention: {s}", @@ -3786,7 +3755,7 @@ fn transFnProto( source_loc: clang.SourceLocation, fn_decl_context: ?FnDeclContext, is_pub: bool, -) !Node.FnProto { +) !*ast.Payload.Func { const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty); const cc = try transCC(c, fn_ty, source_loc); const is_var_args = fn_proto_ty.isVariadic(); @@ -3799,7 +3768,7 @@ fn transFnNoProto( source_loc: clang.SourceLocation, fn_decl_context: ?FnDeclContext, is_pub: bool, -) !Node.FnProto { +) !*ast.Payload.Func { const cc = try transCC(c, fn_ty, source_loc); const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true; return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub); @@ -3822,7 +3791,7 @@ fn finishTransFnProto( // TODO check for always_inline attribute // TODO check for align attribute - var fn_params = std.ArrayList(ast.Payload.Func.Param).init(c.gpa); + var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa); defer fn_params.deinit(); const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0; try fn_params.ensureCapacity(param_count); @@ -3861,7 +3830,7 @@ fn finishTransFnProto( break :blk null; }; - const alignment: c_uint = blk: { + const alignment = blk: { if (fn_decl) |decl| { const alignment = decl.getAlignedAttribute(c.clang_context); if (alignment != 0) { @@ -3876,16 +3845,16 @@ fn finishTransFnProto( const return_type_node = blk: { if (fn_ty.getNoReturnAttr()) { - break :blk Node.noreturn_type.init(); + break :blk Tag.noreturn_type.init(); } else { const return_qt = fn_ty.getReturnType(); if (isCVoid(return_qt)) { // convert primitive c_void to actual void (only for return type) - break :blk Node.void_type.init(); + break :blk Tag.void_type.init(); } else { break :blk transQualType(c, return_qt, source_loc) catch |err| switch (err) { error.UnsupportedType => { - try warn(c, source_loc, "unsupported function proto return type", .{}); + try warn(c, &c.global_scope.base, source_loc, "unsupported function proto return type", .{}); return err; }, error.OutOfMemory => |e| return e, @@ -3893,26 +3862,31 @@ fn finishTransFnProto( } } }; - - return Node.func.create(c.arena, .{ - .is_pub = is_pub, - .is_extern = is_extern, - .is_export = is_export, - .is_var_args = is_var_args, - .name = name, - .linksection_string = linksection_string, - .explicit_callconv = explicit_callconv, - .params = try c.arena.dupe(ast.Payload.Func.Param, fn_params.items), - .return_type = return_node, - .body = null, - .alignment = alignment, - }); + const name: ?[]const u8 = if (fn_decl_context) |ctx| ctx.fn_name else null; + const payload = try c.arena.create(ast.Payload.Func); + payload.* = .{ + .base = .{ .tag = .func }, + .data = .{ + .is_pub = is_pub, + .is_extern = is_extern, + .is_export = is_export, + .is_var_args = is_var_args, + .name = name, + .linksection_string = linksection_string, + .explicit_callconv = explicit_callconv, + .params = try c.arena.dupe(ast.Payload.Param, fn_params.items), + .return_type = return_type_node, + .body = null, + .alignment = alignment, + }, + }; + return payload; } fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void { const args_prefix = .{c.locStr(loc)}; - const value = std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, args_prefix ++ args); - try scope.appendNode(c.gpa, try Node.warning.create(c.arena, value)); + const value = try std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, args_prefix ++ args); + try scope.appendNode(try Tag.warning.create(c.arena, value)); } fn fail( @@ -3922,17 +3896,17 @@ fn fail( comptime format: []const u8, args: anytype, ) (@TypeOf(err) || error{OutOfMemory}) { - try warn(c, source_loc, format, args); + try warn(c, &c.global_scope.base, source_loc, format, args); return err; } -pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void { +pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) Error!void { // location // pub const name = @compileError(msg); - const location_comment = std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)}); - try c.global_scope.nodes.append(try Node.warning.create(c.arena, location_comment)); - const fail_msg = std.fmt.allocPrint(c.arena, format, args); - try c.global_scope.nodes.append(try Node.fail_decl.create(c.arena, fail_msg)); + const location_comment = try std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)}); + try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment)); + const fail_msg = try std.fmt.allocPrint(c.arena, format, args); + try c.global_scope.nodes.append(try Tag.fail_decl.create(c.arena, fail_msg)); } pub fn freeErrors(errors: []ClangErrMsg) void { @@ -4075,7 +4049,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { if (last != .Eof and last != .Nl) return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)}); - const var_decl = try Node.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); + const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); _ = try c.global_scope.macro_table.put(m.name, var_decl); } @@ -4099,7 +4073,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { try fn_params.append(.{ .is_noalias = false, .name = mangled_name, - .type = Node.@"anytype".init(), + .type = Tag.@"anytype".init(), }); if (m.peek().? != .Comma) break; @@ -4119,19 +4093,19 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { const stmts = some.data.stmts; const blk_last = stmts[stmts.len - 1]; const br = blk_last.castTag(.break_val).?; - break :blk br.data; + break :blk br.data.val; } else expr; - const typeof = try Node.typeof.create(c.arean, typeof_arg); - const return_expr = try Node.@"return".create(c.arena, expr); - try block_scope.statements.append(&return_expr.base); - - const fn_decl = try Node.pub_inline_fn.create(c.arena, .{ + const typeof = try Tag.typeof.create(c.arena, typeof_arg); + const return_expr = try Tag.@"return".create(c.arena, expr); + try block_scope.statements.append(return_expr); + + const fn_decl = try Tag.pub_inline_fn.create(c.arena, .{ .name = m.name, .params = try c.arena.dupe(ast.Payload.Param, fn_params.items), .return_type = typeof, .body = try block_scope.complete(c), }); - _ = try c.global_scope.macro_table.put(m.name, &fn_proto.base); + _ = try c.global_scope.macro_table.put(m.name, fn_decl); } const ParseError = Error || error{ParseError}; @@ -4149,7 +4123,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { var last = node; while (true) { // suppress result - const ignore = try Node.ignore.create(c.arena, last); + const ignore = try Tag.ignore.create(c.arena, last); try block_scope.statements.append(ignore); last = try parseCCondExpr(c, m, scope); @@ -4159,7 +4133,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { } } - const break_node = try Node.break_val.create(c.arena, .{ + const break_node = try Tag.break_val.create(c.arena, .{ .label = block_scope.label, .val = last, }); @@ -4190,7 +4164,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { return transCreateNodeNumber(c, lit_bytes); } - const type_node = try Node.type.create(c.arena, switch (suffix) { + const type_node = try Tag.type.create(c.arena, switch (suffix) { .u => "c_uint", .l => "c_long", .lu => "c_ulong", @@ -4205,7 +4179,7 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { else => unreachable, }]; const rhs = try transCreateNodeNumber(c, lit_bytes); - return Node.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); + return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); }, .FloatLiteral => |suffix| { if (lit_bytes[0] == '.') @@ -4213,13 +4187,13 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { if (suffix == .none) { return transCreateNodeNumber(c, lit_bytes); } - const type_node = try Node.type.create(c.arena, switch (suffix) { + const type_node = try Tag.type.create(c.arena, switch (suffix) { .f => "f32", .l => "c_longdouble", else => unreachable, }); const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1]); - return Node.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); + return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs }); }, else => unreachable, } @@ -4391,56 +4365,56 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N switch (tok) { .CharLiteral => { if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) { - return Node.char_literal.create(c.arena, try zigifyEscapeSequences(c, m)); + return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m)); } else { const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]}); - return Node.int_literal.create(c.arena, str); + return Tag.number_literal.create(c.arena, str); } }, .StringLiteral => { - return Node.string_literal.create(c.arena, try zigifyEscapeSequences(c, m)); + return Tag.string_literal.create(c.arena, try zigifyEscapeSequences(c, m)); }, .IntegerLiteral, .FloatLiteral => { return parseCNumLit(c, m); }, // eventually this will be replaced by std.c.parse which will handle these correctly - .Keyword_void => return Node.type.create(c.arena, "c_void"), - .Keyword_bool => return Node.type.create(c.arena, "bool"), - .Keyword_double => return Node.type.create(c.arena, "f64"), - .Keyword_long => return Node.type.create(c.arena, "c_long"), - .Keyword_int => return Node.type.create(c.arena, "c_int"), - .Keyword_float => return Node.type.create(c.arena, "f32"), - .Keyword_short => return Node.type.create(c.arena, "c_short"), - .Keyword_char => return Node.type.create(c.arena, "u8"), + .Keyword_void => return Tag.type.create(c.arena, "c_void"), + .Keyword_bool => return Tag.type.create(c.arena, "bool"), + .Keyword_double => return Tag.type.create(c.arena, "f64"), + .Keyword_long => return Tag.type.create(c.arena, "c_long"), + .Keyword_int => return Tag.type.create(c.arena, "c_int"), + .Keyword_float => return Tag.type.create(c.arena, "f32"), + .Keyword_short => return Tag.type.create(c.arena, "c_short"), + .Keyword_char => return Tag.type.create(c.arena, "u8"), .Keyword_unsigned => if (m.next()) |t| switch (t) { - .Keyword_char => return Node.type.create(c.arena, "u8"), - .Keyword_short => return Node.type.create(c.arena, "c_ushort"), - .Keyword_int => return Node.type.create(c.arena, "c_uint"), + .Keyword_char => return Tag.type.create(c.arena, "u8"), + .Keyword_short => return Tag.type.create(c.arena, "c_ushort"), + .Keyword_int => return Tag.type.create(c.arena, "c_uint"), .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) { _ = m.next(); - return Node.type.create(c.arena, "c_ulonglong"); - } else return Node.type.create(c.arena, "c_ulong"), + return Tag.type.create(c.arena, "c_ulonglong"); + } else return Tag.type.create(c.arena, "c_ulong"), else => { m.i -= 1; - return Node.type.create(c.arena, "c_uint"); + return Tag.type.create(c.arena, "c_uint"); }, } else { - return Node.type.create(c.arena, "c_uint"); + return Tag.type.create(c.arena, "c_uint"); }, .Keyword_signed => if (m.next()) |t| switch (t) { - .Keyword_char => return Node.type.create(c.arena, "i8"), - .Keyword_short => return Node.type.create(c.arena, "c_short"), - .Keyword_int => return Node.type.create(c.arena, "c_int"), + .Keyword_char => return Tag.type.create(c.arena, "i8"), + .Keyword_short => return Tag.type.create(c.arena, "c_short"), + .Keyword_int => return Tag.type.create(c.arena, "c_int"), .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) { _ = m.next(); - return Node.type.create(c.arena, "c_longlong"); - } else return Node.type.create(c.arena, "c_long"), + return Tag.type.create(c.arena, "c_longlong"); + } else return Tag.type.create(c.arena, "c_long"), else => { m.i -= 1; - return Node.type.create(c.arena, "c_int"); + return Tag.type.create(c.arena, "c_int"); }, } else { - return Node.type.create(c.arena, "c_int"); + return Tag.type.create(c.arena, "c_int"); }, .Keyword_enum, .Keyword_struct, .Keyword_union => { // struct Foo will be declared as struct_Foo by transRecordDecl @@ -4451,11 +4425,11 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N } const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() }); - return Node.identifier.create(c.arena, name); + return Tag.identifier.create(c.arena, name); }, .Identifier => { const mangled_name = scope.getAlias(slice); - return Node.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name); + return Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name); }, .LParen => { const inner_node = try parseCExpr(c, m, scope); @@ -4492,7 +4466,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!N return error.ParseError; } - return Node.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast }); + return Tag.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast }); }, else => { try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)}); @@ -4511,7 +4485,7 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { .StringLiteral, .Identifier => {}, else => break, } - node = try Node.array_cat.create(c.arena, .{ .lhs = node, .rhs = try parseCPrimaryExprInner(c, m, scope) }); + node = try Tag.array_cat.create(c.arena, .{ .lhs = node, .rhs = try parseCPrimaryExprInner(c, m, scope) }); } return node; } @@ -4521,7 +4495,7 @@ fn macroBoolToInt(c: *Context, node: Node) !Node { return node; } - return Node.bool_to_int.create(c.arena, node); + return Tag.bool_to_int.create(c.arena, node); } fn macroIntToBool(c: *Context, node: Node) !Node { @@ -4529,7 +4503,7 @@ fn macroIntToBool(c: *Context, node: Node) !Node { return node; } - return Node.not_equal.create(c.arena, .{ .lhs = node, .rhs = Node.zero_literal.init() }); + return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() }); } fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { @@ -4545,7 +4519,7 @@ fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { return error.ParseError; } const else_body = try parseCCondExpr(c, m, scope); - return Node.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body }); + return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body }); } fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { @@ -4553,7 +4527,7 @@ fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { while (m.next().? == .PipePipe) { const lhs = try macroIntToBool(c, node); const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope)); - node = try Node.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); } m.i -= 1; return node; @@ -4564,7 +4538,7 @@ fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { while (m.next().? == .AmpersandAmpersand) { const lhs = try macroIntToBool(c, node); const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope)); - node = try Node.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs }); } m.i -= 1; return node; @@ -4575,7 +4549,7 @@ fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { while (m.next().? == .Pipe) { const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCBitXorExpr(c, m, scope)); - node = try Node.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); } m.i -= 1; return node; @@ -4586,7 +4560,7 @@ fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { while (m.next().? == .Caret) { const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCBitAndExpr(c, m, scope)); - node = try Node.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); } m.i -= 1; return node; @@ -4597,7 +4571,7 @@ fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { while (m.next().? == .Ampersand) { const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCEqExpr(c, m, scope)); - node = try Node.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); } m.i -= 1; return node; @@ -4611,13 +4585,13 @@ fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCRelExpr(c, m, scope)); - node = try Node.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .EqualEqual => { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCRelExpr(c, m, scope)); - node = try Node.equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, else => return node, } @@ -4632,25 +4606,25 @@ fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope)); - node = try Node.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .AngleBracketRightEqual => { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope)); - node = try Node.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .AngleBracketLeft => { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope)); - node = try Node.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .AngleBracketLeftEqual => { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope)); - node = try Node.less_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.less_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, else => return node, } @@ -4665,13 +4639,13 @@ fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCAddSubExpr(c, m, scope)); - node = try Node.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .AngleBracketAngleBracketRight => { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCAddSubExpr(c, m, scope)); - node = try Node.shr.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.shr.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, else => return node, } @@ -4686,13 +4660,13 @@ fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCMulExpr(c, m, scope)); - node = try Node.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .Minus => { _ = m.next(); const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCMulExpr(c, m, scope)); - node = try Node.sub.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.sub.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, else => return node, } @@ -4711,14 +4685,14 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { const prev_id = m.list[m.i - 1].id; if (prev_id == .Keyword_void) { - const ptr = try Node.single_pointer.create(c.arena, .{ + const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = false, .is_volatile = false, .elem_type = node, }); - return Node.optional_type.create(c.arena, ptr); + return Tag.optional_type.create(c.arena, ptr); } else { - return Node.c_pointer.create(c.arena, .{ + return Tag.c_pointer.create(c.arena, .{ .is_const = false, .is_volatile = false, .elem_type = node, @@ -4728,18 +4702,18 @@ fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { // expr * expr const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope)); - node = try Node.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); } }, .Slash => { const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope)); - node = try Node.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, .Percent => { const lhs = try macroBoolToInt(c, node); const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope)); - node = try Node.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); + node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); }, else => { m.i -= 1; @@ -4759,8 +4733,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { return error.ParseError; } - const ident = try Node.identifier.create(c.arena, m.slice()); - node = try Node.field_access.create(c.arena, .{ .lhs = node, .rhs = ident }); + const ident = try Tag.identifier.create(c.arena, m.slice()); + node = try Tag.field_access.create(c.arena, .{ .lhs = node, .rhs = ident }); }, .Arrow => { if (m.next().? != .Identifier) { @@ -4768,20 +4742,20 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { return error.ParseError; } - const deref = try Node.deref.create(c.arena, node); - const ident = try Node.identifier.create(c.arena, m.slice()); - node = try Node.field_access.create(c.arena, .{ .lhs = deref, .rhs = ident }); + const deref = try Tag.deref.create(c.arena, node); + const ident = try Tag.identifier.create(c.arena, m.slice()); + node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .rhs = ident }); }, .LBracket => { const index = try macroBoolToInt(c, try parseCExpr(c, m, scope)); - node = try Node.array_access.create(c.arena, .{ .lhs = node, .rhs = index }); + node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index }); }, .LParen => { - var call_params = std.ArrayList(Node).init(c.gpa); - defer call_params.deinit(); + var args = std.ArrayList(Node).init(c.gpa); + defer args.deinit(); while (true) { const arg = try parseCCondExpr(c, m, scope); - try call_params.append(arg); + try args.append(arg); switch (m.next().?) { .Comma => {}, .RParen => break, @@ -4791,7 +4765,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { }, } } - node = try Node.call.create(c.arena, .{ .lhs = node, .rhs = try c.arena.dupe(Node, call_params.items) }); + node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) }); }, .LBrace => { var init_vals = std.ArrayList(Node).init(c.gpa); @@ -4809,8 +4783,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { }, } } - const tuple_node = try Node.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items)); - node = try Node.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node }); + const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items)); + node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node }); }, .PlusPlus, .MinusMinus => { try m.fail(c, "TODO postfix inc/dec expr", .{}); @@ -4828,24 +4802,24 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { switch (m.next().?) { .Bang => { const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope)); - return Node.not.create(c.arena, operand); + return Tag.not.create(c.arena, operand); }, .Minus => { const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope)); - return Node.negate.create(c.arena, operand); + return Tag.negate.create(c.arena, operand); }, .Plus => return try parseCUnaryExpr(c, m, scope), .Tilde => { const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope)); - return Node.bit_not.create(c.arena, operand); + return Tag.bit_not.create(c.arena, operand); }, .Asterisk => { const operand = try parseCUnaryExpr(c, m, scope); - return Node.deref.create(c.arena, operand); + return Tag.deref.create(c.arena, operand); }, .Ampersand => { const operand = try parseCUnaryExpr(c, m, scope); - return Node.address_of.create(c.arena, operand); + return Tag.address_of.create(c.arena, operand); }, .Keyword_sizeof => { const operand = if (m.peek().? == .LParen) blk: { @@ -4860,7 +4834,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { break :blk inner; } else try parseCUnaryExpr(c, m, scope); - return Node.std_meta_sizeof.create(c.arena, operand); + return Tag.std_meta_sizeof.create(c.arena, operand); }, .Keyword_alignof => { // TODO this won't work if using <stdalign.h>'s @@ -4877,7 +4851,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node { return error.ParseError; } - return Node.alignof.create(c.arena, operand); + return Tag.alignof.create(c.arena, operand); }, .PlusPlus, .MinusMinus => { try m.fail(c, "TODO unary inc/dec expr", .{}); @@ -4902,7 +4876,7 @@ fn getContainer(c: *Context, node: Node) ?Node { .negate, .negate_wrap, .array_type, - .c_pointer, + .c_pointer, .single_pointer, => return node, @@ -4910,7 +4884,7 @@ fn getContainer(c: *Context, node: Node) ?Node { const ident = node.castTag(.identifier).?; if (c.global_scope.sym_table.get(ident.data)) |value| { if (value.castTag(.var_decl)) |var_decl| - return getContainer(c, var_decl.data.init); + return getContainer(c, var_decl.data.init.?); if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |var_decl| return getContainer(c, var_decl.data.init); } @@ -4923,8 +4897,8 @@ fn getContainer(c: *Context, node: Node) ?Node { if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| { for (container.data.fields) |field| { const ident = infix.data.rhs.castTag(.identifier).?; - if (mem.eql(u8, field.data.name, field.data)) { - return getContainer(c, field.type_expr.?); + if (mem.eql(u8, field.name, ident.data)) { + return getContainer(c, field.type); } } } @@ -4960,9 +4934,9 @@ fn getContainerTypeOf(c: *Context, ref: Node) ?Node { } fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func { - const init = if (value.castTag(.var_decl)) |v| - v.data.init - else if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |v| + const init = if (ref.castTag(.var_decl)) |v| + v.data.init orelse return null + else if (ref.castTag(.var_simple) orelse ref.castTag(.pub_var_simple)) |v| v.data.init else return null; diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 1cf014e5dc..24689c89db 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Type = @import("../type.zig").Type; +const Allocator = std.mem.Allocator; pub const Node = extern union { /// If the tag value is less than Tag.no_payload_count, then no pointer @@ -20,6 +21,8 @@ pub const Node = extern union { one_literal, void_type, noreturn_type, + @"anytype", + @"continue", /// pub usingnamespace @import("std").c.builtins; usingnamespace_builtins, // After this, the tag requires a payload. @@ -40,7 +43,6 @@ pub const Node = extern union { switch_else, /// lhs => rhs, switch_prong, - @"continue", @"break", break_val, @"return", @@ -60,7 +62,6 @@ pub const Node = extern union { container_init, std_meta_cast, discard, - block, // a + b add, @@ -111,8 +112,11 @@ pub const Node = extern union { equal, not_equal, bit_and, + bit_and_assign, bit_or, + bit_or_assign, bit_xor, + bit_xor_assign, array_cat, ellipsis3, assign, @@ -126,7 +130,7 @@ pub const Node = extern union { rem, /// @divTrunc(lhs, rhs) div_trunc, - /// @boolToInt(lhs, rhs) + /// @boolToInt(operand) bool_to_int, /// @as(lhs, rhs) as, @@ -150,24 +154,26 @@ pub const Node = extern union { ptr_to_int, /// @alignCast(lhs, rhs) align_cast, + /// @ptrCast(lhs, rhs) + ptr_cast, negate, negate_wrap, bit_not, not, address_of, - /// operand.?.* - unwrap_deref, + /// .? + unwrap, /// .* deref, block, /// { operand } block_single, - @"break", sizeof, alignof, + typeof, type, optional_type, @@ -185,6 +191,8 @@ pub const Node = extern union { fail_decl, // var actual = mangled; arg_redecl, + /// pub const alias = actual; + alias, /// const name = init; typedef, var_simple, @@ -204,18 +212,17 @@ pub const Node = extern union { /// _ = operand; ignore, - @"anytype", pub const last_no_payload_tag = Tag.usingnamespace_builtins; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; - pub fn Type(tag: Tag) ?type { - return switch (tag) { + pub fn Type(comptime t: Tag) type { + return switch (t) { .null_literal, .undefined_literal, .opaque_literal, .true_literal, - .false_litral, + .false_literal, .empty_block, .usingnamespace_builtins, .return_void, @@ -224,6 +231,7 @@ pub const Node = extern union { .void_type, .noreturn_type, .@"anytype", + .@"continue", => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), .std_mem_zeroes, @@ -236,7 +244,7 @@ pub const Node = extern union { .not, .optional_type, .address_of, - .unwrap_deref, + .unwrap, .deref, .ptr_to_int, .enum_to_int, @@ -246,6 +254,11 @@ pub const Node = extern union { .switch_else, .ignore, .block_single, + .std_meta_sizeof, + .bool_to_int, + .sizeof, + .alignof, + .typeof, => Payload.UnOp, .add, @@ -294,12 +307,14 @@ pub const Node = extern union { .equal, .not_equal, .bit_and, + .bit_and_assign, .bit_or, + .bit_or_assign, .bit_xor, + .bit_xor_assign, .div_trunc, .rem, .int_cast, - .bool_to_int, .as, .truncate, .bit_cast, @@ -316,6 +331,7 @@ pub const Node = extern union { .align_cast, .array_access, .std_mem_zeroinit, + .ptr_cast, => Payload.BinOp, .number_literal, @@ -324,8 +340,6 @@ pub const Node = extern union { .identifier, .warning, .failed_decl, - .sizeof, - .alignof, .type, .fail_decl, => Payload.Value, @@ -345,7 +359,7 @@ pub const Node = extern union { .block => Payload.Block, .c_pointer, .single_pointer => Payload.Pointer, .array_type => Payload.Array, - .arg_redecl => Payload.ArgRedecl, + .arg_redecl, .alias => Payload.ArgRedecl, .log2_int_type => Payload.Log2IntType, .typedef, .pub_typedef, .var_simple, .pub_var_simple => Payload.SimpleVarDecl, .enum_redecl => Payload.EnumRedecl, @@ -375,7 +389,7 @@ pub const Node = extern union { pub fn tag(self: Node) Tag { if (self.tag_if_small_enough < Tag.no_payload_count) { - return @intToEnum(Tag, @intCast(@TagType(Tag), self.tag_if_small_enough)); + return @intToEnum(Tag, @intCast(std.meta.Tag(Tag), self.tag_if_small_enough)); } else { return self.ptr_otherwise.tag; } @@ -392,16 +406,16 @@ pub const Node = extern union { } pub fn initPayload(payload: *Payload) Node { - assert(@enumToInt(payload.tag) >= Tag.no_payload_count); + std.debug.assert(@enumToInt(payload.tag) >= Tag.no_payload_count); return .{ .ptr_otherwise = payload }; } }; pub const Payload = struct { - tag: Tag, + tag: Node.Tag, pub const Infix = struct { - base: Node, + base: Payload, data: struct { lhs: Node, rhs: Node, @@ -409,17 +423,17 @@ pub const Payload = struct { }; pub const Value = struct { - base: Node, + base: Payload, data: []const u8, }; pub const UnOp = struct { - base: Node, + base: Payload, data: Node, }; pub const BinOp = struct { - base: Node, + base: Payload, data: struct { lhs: Node, rhs: Node, @@ -427,7 +441,7 @@ pub const Payload = struct { }; pub const If = struct { - base: Node = .{ .tag = .@"if" }, + base: Payload, data: struct { cond: Node, then: Node, @@ -436,7 +450,7 @@ pub const Payload = struct { }; pub const While = struct { - base: Node = .{ .tag = .@"while" }, + base: Payload, data: struct { cond: Node, body: Node, @@ -445,7 +459,7 @@ pub const Payload = struct { }; pub const Switch = struct { - base: Node = .{ .tag = .@"switch" }, + base: Payload, data: struct { cond: Node, cases: []Node, @@ -453,12 +467,12 @@ pub const Payload = struct { }; pub const Break = struct { - base: Node = .{ .tag = .@"break" }, + base: Payload, data: ?[]const u8, }; pub const BreakVal = struct { - base: Node = .{ .tag = .break_val }, + base: Payload, data: struct { label: ?[]const u8, val: Node, @@ -466,7 +480,7 @@ pub const Payload = struct { }; pub const Call = struct { - base: Node = .{.call}, + base: Payload, data: struct { lhs: Node, args: []Node, @@ -474,7 +488,7 @@ pub const Payload = struct { }; pub const VarDecl = struct { - base: Node = .{ .tag = .var_decl }, + base: Payload, data: struct { is_pub: bool, is_const: bool, @@ -489,13 +503,13 @@ pub const Payload = struct { }; pub const Func = struct { - base: Node = .{.func}, + base: Payload, data: struct { is_pub: bool, is_extern: bool, is_export: bool, is_var_args: bool, - name: []const u8, + name: ?[]const u8, linksection_string: ?[]const u8, explicit_callconv: ?std.builtin.CallingConvention, params: []Param, @@ -512,7 +526,7 @@ pub const Payload = struct { }; pub const Enum = struct { - base: Node = .{ .tag = .@"enum" }, + base: Payload, data: []Field, pub const Field = struct { @@ -522,9 +536,9 @@ pub const Payload = struct { }; pub const Record = struct { - base: Node, + base: Payload, data: struct { - @"packed": bool, + is_packed: bool, fields: []Field, }, @@ -536,12 +550,12 @@ pub const Payload = struct { }; pub const ArrayInit = struct { - base: Node = .{ .tag = .array_init }, + base: Payload, data: []Node, }; pub const ContainerInit = struct { - base: Node = .{ .tag = .container_init }, + base: Payload, data: []Initializer, pub const Initializer = struct { @@ -551,7 +565,7 @@ pub const Payload = struct { }; pub const Block = struct { - base: Node, + base: Payload, data: struct { label: ?[]const u8, stmts: []Node @@ -559,15 +573,15 @@ pub const Payload = struct { }; pub const Array = struct { - base: Node, + base: Payload, data: struct { elem_type: Node, - len: Node, + len: usize, }, }; pub const Pointer = struct { - base: Node, + base: Payload, data: struct { elem_type: Node, is_const: bool, @@ -576,7 +590,7 @@ pub const Payload = struct { }; pub const ArgRedecl = struct { - base: Node, + base: Payload, data: struct { actual: []const u8, mangled: []const u8, @@ -584,12 +598,12 @@ pub const Payload = struct { }; pub const Log2IntType = struct { - base: Node, + base: Payload, data: std.math.Log2Int(u64), }; pub const SimpleVarDecl = struct { - base: Node, + base: Payload, data: struct { name: []const u8, init: Node, @@ -597,7 +611,7 @@ pub const Payload = struct { }; pub const EnumRedecl = struct { - base: Node, + base: Payload, data: struct { enum_val_name: []const u8, field_name: []const u8, @@ -606,7 +620,7 @@ pub const Payload = struct { }; pub const ArrayFiller = struct { - base: Node, + base: Payload, data: struct { type: Node, filler: Node, @@ -615,7 +629,7 @@ pub const Payload = struct { }; pub const PubInlineFn = struct { - base: Node, + base: Payload, data: struct { name: []const u8, params: []Param, @@ -626,6 +640,6 @@ pub const Payload = struct { }; /// Converts the nodes into a Zig ast. -pub fn render(allocator: *Allocator, nodes: []const Node) !*ast.Tree { +pub fn render(allocator: *Allocator, nodes: []const Node) !std.zig.ast.Tree { @panic("TODO"); } diff --git a/src/type.zig b/src/type.zig index 8fcaba6fad..38fe6dd3e6 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1682,6 +1682,8 @@ pub const Type = extern union { .i32 => unreachable, .u64 => unreachable, .i64 => unreachable, + .u128 => unreachable, + .i128 => unreachable, .usize => unreachable, .isize => unreachable, .c_short => unreachable, @@ -2197,6 +2199,8 @@ pub const Type = extern union { .i32 => .{ .signedness = .signed, .bits = 32 }, .u64 => .{ .signedness = .unsigned, .bits = 64 }, .i64 => .{ .signedness = .signed, .bits = 64 }, + .u128 => .{ .signedness = .unsigned, .bits = 128 }, + .i128 => .{ .signedness = .signed, .bits = 128 }, .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() }, .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() }, .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) }, |
