From e072692e1ffb6012d3d75051996bfcbbbd80e093 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 23 May 2020 12:48:17 -0400 Subject: [PATCH] update translate-c to new AST API --- src-self-hosted/clang.zig | 13 +- src-self-hosted/translate_c.zig | 980 +++++++++++++++++--------------- 2 files changed, 527 insertions(+), 466 deletions(-) diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index b3d67aab25..72818d4ccc 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -63,7 +63,7 @@ pub const struct_ZigClangReturnStmt = @Type(.Opaque); pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque); pub const struct_ZigClangSourceManager = @Type(.Opaque); pub const struct_ZigClangSourceRange = @Type(.Opaque); -pub const struct_ZigClangStmt = @Type(.Opaque); +pub const ZigClangStmt = @Type(.Opaque); pub const struct_ZigClangStringLiteral = @Type(.Opaque); pub const struct_ZigClangStringRef = @Type(.Opaque); pub const struct_ZigClangSwitchStmt = @Type(.Opaque); @@ -842,9 +842,9 @@ pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [* pub extern fn ZigClangType_getAsArrayTypeUnsafe(self: *const ZigClangType) *const ZigClangArrayType; pub extern fn ZigClangType_getAsRecordType(self: *const ZigClangType) ?*const ZigClangRecordType; pub extern fn ZigClangType_getAsUnionType(self: *const ZigClangType) ?*const ZigClangRecordType; -pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; -pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass; -pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool; +pub extern fn ZigClangStmt_getBeginLoc(self: *const ZigClangStmt) struct_ZigClangSourceLocation; +pub extern fn ZigClangStmt_getStmtClass(self: ?*const ZigClangStmt) ZigClangStmtClass; +pub extern fn ZigClangStmt_classof_Expr(self: ?*const ZigClangStmt) bool; pub extern fn ZigClangExpr_getStmtClass(self: *const struct_ZigClangExpr) ZigClangStmtClass; pub extern fn ZigClangExpr_getType(self: *const struct_ZigClangExpr) struct_ZigClangQualType; pub extern fn ZigClangExpr_getBeginLoc(self: *const struct_ZigClangExpr) struct_ZigClangSourceLocation; @@ -873,7 +873,7 @@ pub extern fn ZigClangFunctionDecl_getLocation(self: *const ZigClangFunctionDecl pub extern fn ZigClangFunctionDecl_hasBody(self: *const ZigClangFunctionDecl) bool; pub extern fn ZigClangFunctionDecl_getStorageClass(self: *const ZigClangFunctionDecl) ZigClangStorageClass; pub extern fn ZigClangFunctionDecl_getParamDecl(self: *const ZigClangFunctionDecl, i: c_uint) *const struct_ZigClangParmVarDecl; -pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const struct_ZigClangStmt; +pub extern fn ZigClangFunctionDecl_getBody(self: *const ZigClangFunctionDecl) *const ZigClangStmt; pub extern fn ZigClangFunctionDecl_doesDeclarationForceExternallyVisibleDefinition(self: *const ZigClangFunctionDecl) bool; pub extern fn ZigClangFunctionDecl_isThisDeclarationADefinition(self: *const ZigClangFunctionDecl) bool; pub extern fn ZigClangFunctionDecl_doesThisDeclarationHaveABody(self: *const ZigClangFunctionDecl) bool; @@ -959,7 +959,6 @@ pub const ZigClangReturnStmt = struct_ZigClangReturnStmt; pub const ZigClangSkipFunctionBodiesScope = struct_ZigClangSkipFunctionBodiesScope; pub const ZigClangSourceManager = struct_ZigClangSourceManager; pub const ZigClangSourceRange = struct_ZigClangSourceRange; -pub const ZigClangStmt = struct_ZigClangStmt; pub const ZigClangStringLiteral = struct_ZigClangStringLiteral; pub const ZigClangStringRef = struct_ZigClangStringRef; pub const ZigClangSwitchStmt = struct_ZigClangSwitchStmt; @@ -1018,7 +1017,7 @@ pub extern fn ZigClangLoadFromCommandLine( pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind; pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8; -pub const ZigClangCompoundStmt_const_body_iterator = [*]const *struct_ZigClangStmt; +pub const ZigClangCompoundStmt_const_body_iterator = [*]const *ZigClangStmt; pub extern fn ZigClangCompoundStmt_body_begin(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; pub extern fn ZigClangCompoundStmt_body_end(self: *const ZigClangCompoundStmt) ZigClangCompoundStmt_const_body_iterator; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index fca959d536..17b6c1d9e0 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -54,44 +54,79 @@ const Scope = struct { Loop, }; + /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated. + /// When it is deinitialized, it produces an ast.Node.Switch which is allocated + /// into the main arena. const Switch = struct { base: Scope, - pending_block: *ast.Node.Block, - cases: *ast.Node.Switch.CaseList, + pending_block: *Block, + cases: []*ast.Node, + case_index: usize, has_default: bool = false, }; + /// Used for the scope of condition expressions, for example `if (cond)`. + /// The block is lazily initialised because it is only needed for rare + /// cases of comma operators being used. + const Condition = struct { + base: Scope, + block: ?Block = null, + + fn getBlockScope(self: *Condition, c: *Context) !*Block { + if (self.block) |*b| return b; + self.block = try Block.init(c, &self.base, "blk"); + return &self.block.?; + } + + fn deinit(self: *Condition) void { + if (self.block) |*b| b.deinit(); + } + }; + + /// Represents an in-progress ast.Node.Block. This struct is stack-allocated. + /// When it is deinitialized, it produces an ast.Node.Block which is allocated + /// into the main arena. const Block = struct { base: Scope, - block_node: *ast.Node.Block, - statements_it: *?*std.SinglyLinkedList(*ast.Node), + statements: std.ArrayList(*ast.Node), variables: AliasList, - label: ?[]const u8, + label: ?ast.TokenIndex, mangle_count: u32 = 0, + lbrace: ast.TokenIndex, - /// Don't forget to set rbrace token and block_node later - fn init(c: *Context, parent: *Scope, label: ?[]const u8) !*Block { - const block = try c.arena.create(Block); - block.* = .{ + fn init(c: *Context, parent: *Scope, label: ?[]const u8) !Block { + return Block{ .base = .{ .id = .Block, .parent = parent, }, - .block_node = undefined, - .statements_it = undefined, - .variables = AliasList.init(c.arena), - .label = label, + .statements = std.ArrayList(*ast.Node).init(c.gpa), + .variables = AliasList.init(c.gpa), + .label = if (self.label) |l| blk: { + const ll = try appendIdentifier(c, l); + _ = try appendToken(c, .Colon, ":"); + break :blk ll; + } else null, + .lbrace = try appendToken(c, .LBrace, "{"), }; - return block; } - fn pushStatement(self: *Block, c: *Context, stmt: *ast.Node) !void { - self.statements_it = c.llpush(*ast.Node, self.statements_it, stmt); + fn deinit(self: *Block) void { + self.statements.deinit(); + self.variables.deinit(); + self.* = undefined; } - fn setBlockNode(self: *Block, block: *ast.Node.Block) void { - self.block_node = block; - self.statements_it = &block.statements.first; + fn complete(self: *Block, c: *Context) !*ast.Node.Block { + const node = try ast.Node.Block.alloc(c.arena, self.statements.items.len); + node.* = .{ + .statements_len = self.statements.items.len, + .lbrace = self.lbrace, + .rbrace = try appendToken(c, .RBrace, "}"), + .label = self.label, + }; + mem.copy(*ast.Node, node.statements(), self.statements.items); + return node; } /// Given the desired name, return a name that does not shadow anything from outer scopes. @@ -102,12 +137,13 @@ const Scope = struct { scope.mangle_count += 1; proposed_name = try std.fmt.allocPrint(c.arena, "{}_{}", .{ name, scope.mangle_count }); } - try scope.variables.append(.{ .name = name, .alias = proposed_name }); + try scope.variables.push(.{ .name = name, .alias = proposed_name }); return proposed_name; } fn getAlias(scope: *Block, name: []const u8) []const u8 { - for (scope.variables.items) |p| { + var it = scope.variables.iterator(0); + while (it.next()) |p| { if (mem.eql(u8, p.name, name)) return p.alias; } @@ -115,7 +151,8 @@ const Scope = struct { } fn localContains(scope: *Block, name: []const u8) bool { - for (scope.variables.items) |p| { + var it = scope.variables.iterator(0); + while (it.next()) |p| { if (mem.eql(u8, p.name, name)) return true; } @@ -167,10 +204,7 @@ const Scope = struct { switch (scope.id) { .Root => unreachable, .Block => return @fieldParentPtr(Block, "base", scope), - .Condition => { - // comma operator used - return try Block.init(c, scope, "blk"); - }, + .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c), else => scope = scope.parent.?, } } @@ -219,7 +253,8 @@ const Scope = struct { pub const Context = struct { gpa: *mem.Allocator, arena: *mem.Allocator, - tokens: std.ArrayListUnmanaged(Token), + token_ids: std.ArrayListUnmanaged(Token.Id), + token_locs: std.ArrayListUnmanaged(Token.Loc), errors: std.ArrayListUnmanaged(ast.Error), source_buffer: *std.ArrayList(u8), err: Error, @@ -237,16 +272,6 @@ pub const Context = struct { /// up front in a pre-processing step. global_names: std.StringHashMap(void), - /// Helper type to append elements to a singly linked list. - const LinkedListPusher = struct { - c: *Context, - it: *?*std.SinglyLinkedList(*ast.Node).Node, - - fn push(self: *LinkedListPusher, element: *ast.Node) !void { - self.it = try self.c.llpush(*ast.Node, self.it, element); - } - }; - fn getMangle(c: *Context) u32 { c.mangle_count += 1; return c.mangle_count; @@ -267,6 +292,46 @@ pub const Context = struct { const column = ZigClangSourceManager_getSpellingColumnNumber(c.source_manager, spelling_loc); return std.fmt.allocPrint(c.arena, "{}:{}:{}", .{ filename, line, column }); } + + fn createCall(c: *Context, fn_expr: *ast.Node, params_len: ast.NodeIndex) !*ast.Node.Call { + _ = try appendToken(c, .LParen, "("); + const node = try ast.Node.Call.alloc(c.arena, params_len); + node.* = .{ + .lhs = fn_expr, + .params_len = params_len, + .async_token = null, + .rtoken = undefined, // set after appending args + }; + return node; + } + + fn createBuiltinCall(c: *Context, name: []const u8, params_len: ast.NodeIndex) !*ast.Node.BuiltinCall { + const builtin_token = try appendToken(c, .Builtin, name); + _ = try appendToken(c, .LParen, "("); + const node = try ast.Node.BuiltinCall.alloc(c.arena, params_len); + node.* = .{ + .builtin_token = builtin_token, + .params_len = params_len, + .rparen_token = undefined, // set after appending args + }; + return node; + } + + fn createBlock(c: *Context, label: ?[]const u8, statements_len: ast.NodeIndex) !*ast.Node.Block { + const label_node = if (label) |l| blk: { + const ll = try appendIdentifier(c, l); + _ = try appendToken(c, .Colon, ":"); + break :blk ll; + } else null; + const block_node = try ast.Node.Block.alloc(c.arena, statements_len); + block_node.* = .{ + .label = label_node, + .lbrace = try appendToken(c, .LBrace, "{"), + .statements_len = statements_len, + .rbrace = undefined, + }; + return block_node; + } }; pub fn translate( @@ -307,14 +372,16 @@ pub fn translate( .global_scope = try arena.allocator.create(Scope.Root), .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, .global_names = std.StringHashMap(void).init(gpa), - .tokens = .{}, + .token_ids = .{}, + .token_locs = .{}, .errors = .{}, .root_decls = .{}, }; context.global_scope.* = Scope.Root.init(&context); defer context.decl_table.deinit(); defer context.alias_list.deinit(); - defer context.tokens.deinit(gpa); + defer context.token_ids.deinit(gpa); + defer context.token_locs.deinit(gpa); defer context.errors.deinit(gpa); defer context.global_names.deinit(); defer context.root_decls.deinit(gpa); @@ -349,7 +416,8 @@ pub fn translate( tree.* = .{ .gpa = gpa, .source = try arena.allocator.dupe(u8, source_buffer.items), - .tokens = context.tokens.toOwnedSlice(gpa), + .token_ids = context.token_ids.toOwnedSlice(gpa), + .token_locs = context.token_locs.toOwnedSlice(gpa), .errors = context.errors.toOwnedSlice(gpa), .root_node = root_node, .arena = arena.state, @@ -508,10 +576,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { // actual function definition with body const body_stmt = ZigClangFunctionDecl_getBody(fn_decl); - const block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null); + var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null); + defer block_scope.deinit(); var scope = &block_scope.base; - const block_node = try transCreateNodeBlock(rp.c, null); - block_scope.setBlockNode(block_node); var param_id: c_uint = 0; for (proto_node.params()) |param, i| { @@ -541,7 +608,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { node.eq_token = try appendToken(c, .Equal, "="); node.init_node = try transCreateNodeIdentifier(c, arg_name); node.semicolon_token = try appendToken(c, .Semicolon, ";"); - block_scope.block_statements_it = try c.llpush(*ast.Node, block_scope.block_statements_it, &node.base); + try block_scope.statements.append(&node.base); param.name_token = try appendIdentifier(c, arg_name); _ = try appendToken(c, .Colon, ":"); } @@ -549,14 +616,14 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { param_id += 1; } - transCompoundStmtInline(rp, &block_scope.base, @ptrCast(*const ZigClangCompoundStmt, body_stmt), block_node) catch |err| switch (err) { + const casted_body = @ptrCast(*const ZigClangCompoundStmt, body_stmt); + transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) { error.OutOfMemory => |e| return e, error.UnsupportedTranslation, error.UnsupportedType, => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}), }; - block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); - proto_node.body_node = &block_node.base; + proto_node.body_node = try block_scope.complete(rp.c); return addTopLevelDecl(c, fn_name, &proto_node.base); } @@ -999,7 +1066,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No // At this point we can rely on the enum emitting successfully. const tld_node = try transCreateNodeVarDecl(c, true, true, enum_val_name); tld_node.eq_token = try appendToken(c, .Equal, "="); - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt"); + const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1); const enum_ident = try transCreateNodeIdentifier(c, name); const period_tok = try appendToken(c, .Period, "."); const field_ident = try transCreateNodeIdentifier(c, field_name); @@ -1010,7 +1077,7 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No .op = .Period, .rhs = field_ident, }; - try cast_node.params.push(&field_access_node.base); + cast_node.params()[0] = &field_access_node.base; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); tld_node.init_node = &cast_node.base; tld_node.semicolon_token = try appendToken(c, .Semicolon, ";"); @@ -1104,7 +1171,7 @@ fn transStmt( .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)), .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)), .NullStmtClass => { - const block = try transCreateNodeBlock(rp.c, null); + const block = try rp.c.createBlock(null, 0); block.rbrace = try appendToken(rp.c, .RBrace, "}"); return &block.base; }, @@ -1170,27 +1237,23 @@ fn transBinaryOperator( .Comma => { const block_scope = try scope.findBlockScope(rp.c); const expr = block_scope.base.parent == scope; - const lparen = if (expr) blk: { - const l = try appendToken(rp.c, .LParen, "("); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, block_scope.label)); - break :blk l; - } else undefined; + const lparen = if (expr) try appendToken(rp.c, .LParen, "(") else undefined; const lhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getLHS(stmt), .unused, .r_value); - try block_scope.statements.push(lhs); + try block_scope.statements.append(lhs); const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); if (expr) { _ = try appendToken(rp.c, .Semicolon, ";"); const break_node = try transCreateNodeBreak(rp.c, block_scope.label); break_node.rhs = rhs; - try block_scope.block_node.statements.push(&break_node.base); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + try block_scope.statements.append(&break_node.base); + const block_node = try block_scope.complete(rp.c); const rparen = try appendToken(rp.c, .RParen, ")"); const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); grouped_expr.* = .{ .lparen = lparen, - .expr = &block_scope.block_node.base, + .expr = &block_node.base, .rparen = rparen, }; return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base); @@ -1201,11 +1264,11 @@ fn transBinaryOperator( .Div => { if (cIsSignedInteger(qt)) { // signed integer division uses @divTrunc - const div_trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@divTrunc"); - try div_trunc_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); + const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2); + div_trunc_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); _ = try appendToken(rp.c, .Comma, ","); const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); - try div_trunc_node.params.push(rhs); + div_trunc_node.params()[1] = rhs; div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base); } @@ -1213,11 +1276,11 @@ fn transBinaryOperator( .Rem => { if (cIsSignedInteger(qt)) { // signed integer division uses @rem - const rem_node = try transCreateNodeBuiltinFnCall(rp.c, "@rem"); - try rem_node.params.push(try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value)); + const rem_node = try rp.c.createBuiltinCall("@rem", 2); + rem_node.params()[0] = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value); _ = try appendToken(rp.c, .Comma, ","); const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); - try rem_node.params.push(rhs); + rem_node.params()[1] = rhs; rem_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return maybeSuppressResult(rp, scope, result_used, &rem_node.base); } @@ -1321,15 +1384,15 @@ fn transBinaryOperator( const rhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value); const lhs = if (isBoolRes(lhs_node)) init: { - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); - try cast_node.params.push(lhs_node); + const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1); + cast_node.params()[0] = lhs_node; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); break :init &cast_node.base; } else lhs_node; const rhs = if (isBoolRes(rhs_node)) init: { - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); - try cast_node.params.push(rhs_node); + const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1); + cast_node.params()[0] = rhs_node; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); break :init &cast_node.base; } else rhs_node; @@ -1341,23 +1404,22 @@ fn transCompoundStmtInline( rp: RestorePoint, parent_scope: *Scope, stmt: *const ZigClangCompoundStmt, - block_node: *ast.Node.Block, + block: *Scope.Block, ) TransError!void { var it = ZigClangCompoundStmt_body_begin(stmt); const end_it = ZigClangCompoundStmt_body_end(stmt); while (it != end_it) : (it += 1) { const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value); - if (result != &block_node.base) - try block_node.statements.push(result); + try block.statements.append(result); } } fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node { - const block_scope = try Scope.Block.init(rp.c, scope, null); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, null)); - try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); - return &block_scope.block_node.base; + var block_scope = try Scope.Block.init(rp.c, scope, null); + defer block_scope.deinit(); + try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope); + const node = block_scope.complete(c); + return &node.base; } fn transCStyleCastExprClass( @@ -1411,14 +1473,14 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) else try transCreateNodeUndefinedLiteral(c); if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); - try builtin_node.params.push(init_node); + const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); + builtin_node.params()[0] = init_node; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); init_node = &builtin_node.base; } node.init_node = init_node; node.semicolon_token = try appendToken(c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&node.base); + try block_scope.statements.append(&node.base); }, .Typedef => { const typedef_decl = @ptrCast(*const ZigClangTypedefNameDecl, it[0]); @@ -1437,7 +1499,7 @@ fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangDeclStmt) }); } else { const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse return error.UnsupportedTranslation; - try block_scope.block_node.statements.push(&node.base); + try block_scope.statements.append(&node.base); } }, else => |kind| return revertAndWarn( @@ -1499,8 +1561,8 @@ fn transImplicitCastExpr( }, .PointerToBoolean => { // @ptrToInt(val) != 0 - const ptr_to_int = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); - try ptr_to_int.params.push(try transExpr(rp, scope, sub_expr, .used, .r_value)); + const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1); + ptr_to_int.params()[0] = try transExpr(rp, scope, sub_expr, .used, .r_value); ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")"); const op_token = try appendToken(rp.c, .BangEqual, "!="); @@ -1724,13 +1786,11 @@ fn transIntegerLiteral( // @as(T, x) const expr_base = @ptrCast(*const ZigClangExpr, expr); - const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const as_node = try rp.c.createBuiltinCall("@as", 2); const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); - try as_node.params.push(ty_node); + as_node.params()[0] = ty_node; _ = try appendToken(rp.c, .Comma, ","); - - const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); - try as_node.params.push(int_lit_node); + as_node.params()[1] = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&eval_result.Val)); as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return maybeSuppressResult(rp, scope, result_used, &as_node.base); @@ -1840,35 +1900,35 @@ fn transCCast( // 2. Bit-cast to correct signed-ness // @bitCast(dest_type, intermediate_value) - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast"); - try cast_node.params.push(try transQualType(rp, dst_type, loc)); + const cast_node = try rp.c.createBuiltinCall("@bitCast", 2); + cast_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); switch (cIntTypeCmp(dst_type, src_type)) { .lt => { // @truncate(SameSignSmallerInt, src_type) - const trunc_node = try transCreateNodeBuiltinFnCall(rp.c, "@truncate"); + const trunc_node = try rp.c.createBuiltinCall("@truncate", 2); const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); - try trunc_node.params.push(ty_node); + trunc_node.params()[0] = ty_node; _ = try appendToken(rp.c, .Comma, ","); - try trunc_node.params.push(expr); + trunc_node.params()[1] = expr; trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try cast_node.params.push(&trunc_node.base); + cast_node.params()[1] = &trunc_node.base; }, .gt => { // @as(SameSignBiggerInt, src_type) - const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const as_node = try rp.c.createBuiltinCall("@as", 2); const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, cIsSignedInteger(src_type)); - try as_node.params.push(ty_node); + as_node.params()[0] = ty_node; _ = try appendToken(rp.c, .Comma, ","); - try as_node.params.push(expr); + as_node.params()[1] = expr; as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try cast_node.params.push(&as_node.base); + cast_node.params()[1] = &as_node.base; }, .eq => { - try cast_node.params.push(expr); + cast_node.params()[1] = expr; }, } cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -1876,46 +1936,46 @@ fn transCCast( } if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) { // @intCast(dest_type, @ptrToInt(val)) - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); - try cast_node.params.push(try transQualType(rp, dst_type, loc)); + const cast_node = try rp.c.createBuiltinCall("@intCast", 2); + cast_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); - try builtin_node.params.push(expr); + const builtin_node = try rp.c.createBuiltinCall("@ptrToInt", 1); + builtin_node.params()[0] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try cast_node.params.push(&builtin_node.base); + cast_node.params()[1] = &builtin_node.base; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &cast_node.base; } if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) { // @intToPtr(dest_type, val) - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); - try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2); + builtin_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(expr); + builtin_node.params()[1] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } if (cIsFloating(src_type) and cIsFloating(dst_type)) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatCast"); - try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2); + builtin_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(expr); + builtin_node.params()[1] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } if (cIsFloating(src_type) and !cIsFloating(dst_type)) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@floatToInt"); - try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2); + builtin_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(expr); + builtin_node.params()[1] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } if (!cIsFloating(src_type) and cIsFloating(dst_type)) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToFloat"); - try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2); + builtin_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(expr); + builtin_node.params()[1] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } @@ -1923,54 +1983,54 @@ fn transCCast( !ZigClangType_isBooleanType(qualTypeCanon(dst_type))) { // @boolToInt returns either a comptime_int or a u1 - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); - try builtin_node.params.push(expr); + const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); + builtin_node.params()[0] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - const inner_cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); - try inner_cast_node.params.push(try transCreateNodeIdentifier(rp.c, "u1")); + const inner_cast_node = try rp.c.createBuiltinCall("@intCast", 2); + inner_cast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "u1"); _ = try appendToken(rp.c, .Comma, ","); - try inner_cast_node.params.push(&builtin_node.base); + inner_cast_node.params()[1] = &builtin_node.base; inner_cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); - try cast_node.params.push(try transQualType(rp, dst_type, loc)); + const cast_node = try rp.c.createBuiltinCall("@intCast", 2); + cast_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); if (cIsSignedInteger(dst_type)) { - const bitcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast"); - try bitcast_node.params.push(try transCreateNodeIdentifier(rp.c, "i1")); + const bitcast_node = try rp.c.createBuiltinCall("@bitCast", 2); + bitcast_node.params()[0] = try transCreateNodeIdentifier(rp.c, "i1"); _ = try appendToken(rp.c, .Comma, ","); - try bitcast_node.params.push(&inner_cast_node.base); + bitcast_node.params()[1] = &inner_cast_node.base; bitcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try cast_node.params.push(&bitcast_node.base); + cast_node.params()[1] = &bitcast_node.base; } else { - try cast_node.params.push(&inner_cast_node.base); + cast_node.params()[1] = &inner_cast_node.base; } cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &cast_node.base; } if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) == .Enum) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToEnum"); - try builtin_node.params.push(try transQualType(rp, dst_type, loc)); + const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2); + builtin_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(expr); + builtin_node.params()[1] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } if (ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(src_type)) == .Enum and ZigClangQualType_getTypeClass(ZigClangQualType_getCanonicalType(dst_type)) != .Enum) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@enumToInt"); - try builtin_node.params.push(expr); + const builtin_node = try rp.c.createBuiltinCall("@enumToInt", 1); + builtin_node.params()[0] = expr; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &builtin_node.base; } - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); - try cast_node.params.push(try transQualType(rp, dst_type, loc)); + const cast_node = try rp.c.createBuiltinCall("@as", 2); + cast_node.params()[0] = try transQualType(rp, dst_type, loc); _ = try appendToken(rp.c, .Comma, ","); - try cast_node.params.push(expr); + cast_node.params()[1] = expr; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &cast_node.base; } @@ -2077,12 +2137,13 @@ fn transInitListExprRecord( _ = try appendToken(c, .LBrace, "{"); - const node = try rp.c.arena.create(ast.Node.StructInitializer); + const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len); node.* = .{ .lhs = ty, .rtoken = try appendToken(rp.c, .RBrace, "}"), - .list = try rp.c.arena.dupe(*ast.Node, field_inits.items), + .list_len = field_inits.items.len, }; + mem.copy(*ast.Node, node.list(), field_inits.items); return &node.base; } @@ -2292,11 +2353,15 @@ fn transIfStmt( // if (c) t else e const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope{ - .parent = scope, - .id = .Condition, + var cond_scope = Scope.Condition{ + .base = .{ + .parent = scope, + .id = .Condition, + }, }; - if_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false); + defer cond_scope.deinit(); + const cond_expr = @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)); + if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); _ = try appendToken(rp.c, .RParen, ")"); if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .unused, .r_value); @@ -2316,11 +2381,15 @@ fn transWhileLoop( ) TransError!*ast.Node { const while_node = try transCreateNodeWhile(rp.c); - var cond_scope = Scope{ - .parent = scope, - .id = .Condition, + var cond_scope = Scope.Condition{ + .base = .{ + .parent = scope, + .id = .Condition, + }, }; - while_node.condition = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false); + defer cond_scope.deinit(); + const cond_expr = @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)); + while_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); _ = try appendToken(rp.c, .RParen, ")"); var loop_scope = Scope{ @@ -2349,12 +2418,15 @@ fn transDoWhileLoop( // if (!cond) break; const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope{ - .parent = scope, - .id = .Condition, + var cond_scope = Scope.Condition{ + .base = .{ + .parent = scope, + .id = .Condition, + }, }; + defer cond_scope.deinit(); const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!"); - prefix_op.rhs = try transBoolExpr(rp, &cond_scope, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); + prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, true); _ = try appendToken(rp.c, .RParen, ")"); if_node.condition = &prefix_op.base; if_node.body = &(try transCreateNodeBreak(rp.c, null)).base; @@ -2404,24 +2476,26 @@ fn transForLoop( .id = .Loop, }; - var block_scope: ?*Scope.Block = null; + var block_scope: ?Scope.Block = null; + defer if (block_scope) |*bs| bs.deinit(); + if (ZigClangForStmt_getInit(stmt)) |init| { block_scope = try Scope.Block.init(rp.c, scope, null); - const block = try transCreateNodeBlock(rp.c, null); - block_scope.?.setBlockNode(block); loop_scope.parent = &block_scope.?.base; const result = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value); - if (result != &block.base) - try block.statements.push(result); + try block_scope.statements.push(result); } - var cond_scope = Scope{ - .parent = scope, - .id = .Condition, + var cond_scope = Scope.Condition{ + .base = .{ + .parent = scope, + .id = .Condition, + }, }; + defer cond_scope.deinit(); const while_node = try transCreateNodeWhile(rp.c); while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond| - try transBoolExpr(rp, &cond_scope, cond, .used, .r_value, false) + try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false) else try transCreateNodeBoolLiteral(rp.c, true); _ = try appendToken(rp.c, .RParen, ")"); @@ -2429,62 +2503,90 @@ fn transForLoop( if (ZigClangForStmt_getInc(stmt)) |incr| { _ = try appendToken(rp.c, .Colon, ":"); _ = try appendToken(rp.c, .LParen, "("); - while_node.continue_expr = try transExpr(rp, &cond_scope, incr, .unused, .r_value); + while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value); _ = try appendToken(rp.c, .RParen, ")"); } while_node.body = try transStmt(rp, &loop_scope, ZigClangForStmt_getBody(stmt), .unused, .r_value); - if (block_scope != null) { - try block_scope.?.block_node.statements.push(&while_node.base); - block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); - return &block_scope.?.block_node.base; + if (block_scope) |*bs| { + try bs.statements.push(&while_node.base); + const node = bs.complete(rp.c); + return &node.base; } else { _ = try appendToken(rp.c, .Semicolon, ";"); return &while_node.base; } } +fn getSwitchCaseCount(stmt: *const ZigClangSwitchStmt) usize { + const stmt = ZigClangSwitchStmt_getBody(stmt); + const comp = ZigClangStmtExpr_getSubStmt(stmt); + return ZigClangCompoundStmt_body_end(comp) - ZigClangCompoundStmt_body_begin(comp); +} + fn transSwitch( rp: RestorePoint, scope: *Scope, stmt: *const ZigClangSwitchStmt, ) TransError!*ast.Node { - const switch_node = try transCreateNodeSwitch(rp.c); + const switch_tok = try appendToken(rp.c, .Keyword_switch, "switch"); + _ = try appendToken(rp.c, .LParen, "("); + + const cases_len = getSwitchCaseCount(ZigClangSwitchStmt_getBody(stmt)); + + var cond_scope = Scope.Condition{ + .base = .{ + .parent = scope, + .id = .Condition, + }, + }; + defer cond_scope.deinit(); + const switch_expr = try transExpr(rp, &cond_scope.base, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); + _ = try appendToken(rp.c, .RParen, ")"); + _ = try appendToken(rp.c, .LBrace, "{"); + // reserve +1 case in case there is no default case + const switch_node = try ast.Node.Switch.alloc(rp.c.arena, cases_len + 1); + switch_node.* = .{ + .switch_token = switch_tok, + .expr = switch_expr, + .cases_len = cases_len + 1, + .rbrace = try appendToken(rp.c, .RBrace, "}"), + }; + var switch_scope = Scope.Switch{ .base = .{ .id = .Switch, .parent = scope, }, - .cases = &switch_node.cases, + .cases = switch_node.cases(), + .case_index = 0, .pending_block = undefined, }; - var cond_scope = Scope{ - .parent = scope, - .id = .Condition, - }; - switch_node.expr = try transExpr(rp, &cond_scope, ZigClangSwitchStmt_getCond(stmt), .used, .r_value); - _ = try appendToken(rp.c, .RParen, ")"); - _ = try appendToken(rp.c, .LBrace, "{"); - switch_node.rbrace = try appendToken(rp.c, .RBrace, "}"); - - const block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); // tmp block that all statements will go before being picked up by a case or default - const block = try transCreateNodeBlock(rp.c, null); - block_scope.setBlockNode(block); + var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null); + defer block_scope.deinit(); - const switch_block = try transCreateNodeBlock(rp.c, null); - try switch_block.statements.push(&switch_node.base); - switch_scope.pending_block = switch_block; + // Note that we do not defer a deinit here; the switch_scope.pending_block field + // has its own memory management. This resource is freed inside `transCase` and + // then the final pending_block is freed at the bottom of this function with + // pending_block.deinit(). + switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); + try switch_scope.pending_block.statements.append(&switch_node.base); - const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); + _ = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value); _ = try appendToken(rp.c, .Semicolon, ";"); // take all pending statements - var it = last.cast(ast.Node.Block).?.statements.iterator(0); - while (it.next()) |n| { - try switch_scope.pending_block.statements.push(n.*); - } + try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); + // TODO delete the following commented out code + //const last_block_stmts = last.cast(ast.Node.Block).?.statements(); + //switch_scope.pending_block.statements.ensureCapacity( + // switch_scope.pending_block.statements.items.len + last_block_stmts.len, + //); + //for (last_block_stmts) |n| { + // switch_scope.pending_block.statements.appendAssumeCapacity(n); + //} switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch"); _ = try appendToken(rp.c, .Colon, ":"); @@ -2492,10 +2594,16 @@ fn transSwitch( const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch")).base; _ = try appendToken(rp.c, .Comma, ","); - try switch_node.cases.push(&else_prong.base); + switch_node.cases[switch_node.case_index] = &else_prong.base; + switch_node.case_index += 1; } - switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); - return &switch_scope.pending_block.base; + // We overallocated in case there was no default, so now we correct + // the number of cases in the AST node. + switch_node.cases_len = switch_scope.case_index; + + const result_node = try switch_scope.pending_block.complete(rp.c); + switch_scope.pending_block.deinit(); + return &result_node.base; } fn transCase( @@ -2527,22 +2635,21 @@ fn transCase( const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); switch_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; _ = try appendToken(rp.c, .Comma, ","); - try switch_scope.cases.push(&switch_prong.base); + switch_scope.cases[switch_scope.case_index] = &switch_prong.base; + switch_scope.case_index += 1; - const block = try transCreateNodeBlock(rp.c, null); switch_scope.pending_block.label = try appendIdentifier(rp.c, label); _ = try appendToken(rp.c, .Colon, ":"); - switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); - try block.statements.push(&switch_scope.pending_block.base); // take all pending statements - var it = block_scope.block_node.statements.iterator(0); - while (it.next()) |n| { - try switch_scope.pending_block.statements.push(n.*); - } - block_scope.block_node.statements.shrink(0); + try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); + block_scope.statements.shrink(0); - switch_scope.pending_block = block; + const pending_node = try switch_scope.pending_block.complete(rp.c); + switch_scope.pending_block.deinit(); + switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); + + try switch_scope.pending_block.statements.append(&pending_node.base); return transStmt(rp, scope, ZigClangCaseStmt_getSubStmt(stmt), .unused, .r_value); } @@ -2561,22 +2668,21 @@ fn transDefault( const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); else_prong.expr = &(try transCreateNodeBreak(rp.c, label)).base; _ = try appendToken(rp.c, .Comma, ","); - try switch_scope.cases.push(&else_prong.base); + switch_scope.cases[switch_scope.case_index] = &else_prong.base; + switch_scope.case_index += 1; - const block = try transCreateNodeBlock(rp.c, null); switch_scope.pending_block.label = try appendIdentifier(rp.c, label); _ = try appendToken(rp.c, .Colon, ":"); - switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); - try block.statements.push(&switch_scope.pending_block.base); // take all pending statements - var it = block_scope.block_node.statements.iterator(0); - while (it.next()) |n| { - try switch_scope.pending_block.statements.push(n.*); - } - block_scope.block_node.statements.shrink(0); + try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); + block_scope.statements.shrink(0); + + const pending_node = try switch_scope.pending_block.complete(rp.c); + switch_scope.pending_block.deinit(); + switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null); + try switch_scope.pending_block.statements.append(&pending_node.base); - switch_scope.pending_block = block; return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value); } @@ -2591,13 +2697,13 @@ fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const ZigClangExpr, // See comment in `transIntegerLiteral` for why this code is here. // @as(T, x) const expr_base = @ptrCast(*const ZigClangExpr, expr); - const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const as_node = try rp.c.createBuiltinCall("@as", 2); const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); - try as_node.params.push(ty_node); + as_node.params()[0] = ty_node; _ = try appendToken(rp.c, .Comma, ","); const int_lit_node = try transCreateNodeAPInt(rp.c, ZigClangAPValue_getInt(&result.Val)); - try as_node.params.push(int_lit_node); + as_node.params()[1] = int_lit_node; as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -2653,12 +2759,11 @@ fn transCharLiteral( // See comment in `transIntegerLiteral` for why this code is here. // @as(T, x) const expr_base = @ptrCast(*const ZigClangExpr, stmt); - const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as"); + const as_node = try rp.c.createBuiltinCall("@as", 2); const ty_node = try transQualType(rp, ZigClangExpr_getType(expr_base), ZigClangExpr_getBeginLoc(expr_base)); - try as_node.params.push(ty_node); + as_node.params()[0] = ty_node; _ = try appendToken(rp.c, .Comma, ","); - - try as_node.params.push(int_lit_node); + as_node.params()[1] = int_lit_node; as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return maybeSuppressResult(rp, scope, result_used, &as_node.base); @@ -2671,26 +2776,24 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr, } const lparen = try appendToken(rp.c, .LParen, "("); const block_scope = try Scope.Block.init(rp.c, scope, "blk"); - const block = try transCreateNodeBlock(rp.c, "blk"); - block_scope.setBlockNode(block); + defer block_scope.deinit(); var it = ZigClangCompoundStmt_body_begin(comp); const end_it = ZigClangCompoundStmt_body_end(comp); while (it != end_it - 1) : (it += 1) { const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); - if (result != &block.base) - try block.statements.push(result); + try block_scope.statements.append(result); } const break_node = try transCreateNodeBreak(rp.c, "blk"); break_node.rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value); _ = try appendToken(rp.c, .Semicolon, ";"); - try block.statements.push(&break_node.base); - block.rbrace = try appendToken(rp.c, .RBrace, "}"); + try block_scope.statements.append(&break_node.base); + const block_node = try block_scope.complete(rp.c); const rparen = try appendToken(rp.c, .RParen, ")"); const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); grouped_expr.* = .{ .lparen = lparen, - .expr = &block.base, + .expr = &block_node.base, .rparen = rparen, }; return maybeSuppressResult(rp, scope, used, &grouped_expr.base); @@ -2746,12 +2849,12 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangArrayS const is_signed = cIsSignedInteger(qt); if (is_longlong or is_signed) { - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); + const cast_node = try rp.c.createBuiltinCall("@intCast", 2); // 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(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false); - try cast_node.params.push(typeid_node); + cast_node.params()[0] = typeid_node; _ = try appendToken(rp.c, .Comma, ","); - try cast_node.params.push(try transExpr(rp, scope, subscr_expr, .used, .r_value)); + cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value); cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); node.rtoken = try appendToken(rp.c, .RBrace, "]"); node.op.ArrayAccess = &cast_node.base; @@ -2787,17 +2890,18 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCallExpr, break :blk try transCreateNodeUnwrapNull(rp.c, raw_fn_expr); } else raw_fn_expr; - const node = try transCreateNodeFnCall(rp.c, fn_expr); const num_args = ZigClangCallExpr_getNumArgs(stmt); + const node = try c.createCall(fn_expr, num_args); + const call_params = node.params(); + const args = ZigClangCallExpr_getArgs(stmt); var i: usize = 0; while (i < num_args) : (i += 1) { if (i != 0) { _ = try appendToken(rp.c, .Comma, ","); } - const arg = try transExpr(rp, scope, args[i], .used, .r_value); - try node.op.Call.params.push(arg); + call_params[i] = try transExpr(rp, scope, args[i], .used, .r_value); } node.rtoken = try appendToken(rp.c, .RParen, ")"); @@ -2856,8 +2960,8 @@ fn transUnaryExprOrTypeTraitExpr( ZigClangUnaryExprOrTypeTraitExpr_getBeginLoc(stmt), ); - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@sizeOf"); - try builtin_node.params.push(type_node); + const builtin_node = try rp.c.createBuiltinCall("@sizeOf", 1); + builtin_node.params()[0] = type_node; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); } @@ -2966,8 +3070,8 @@ fn transCreatePreCrement( // zig: _ref.* += 1; // zig: break :blk _ref.* // zig: }) - const block_scope = try Scope.Block.init(rp.c, scope, "blk"); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, block_scope.label)); + var block_scope = try Scope.Block.init(rp.c, scope, "blk"); + defer block_scope.deinit(); const ref = try block_scope.makeMangledName(rp.c, "ref"); const node = try transCreateNodeVarDecl(rp.c, false, true, ref); @@ -2976,7 +3080,7 @@ fn transCreatePreCrement( rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); node.init_node = &rhs_node.base; node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&node.base); + try block_scope.statements.append(&node.base); const lhs_node = try transCreateNodeIdentifier(rp.c, ref); const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); @@ -2985,18 +3089,18 @@ fn transCreatePreCrement( const one = try transCreateNodeInt(rp.c, 1); _ = try appendToken(rp.c, .Semicolon, ";"); const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); - try block_scope.block_node.statements.push(assign); + try block_scope.statements.append(assign); const break_node = try transCreateNodeBreak(rp.c, block_scope.label); break_node.rhs = ref_node; - try block_scope.block_node.statements.push(&break_node.base); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + try block_scope.statements.push(&break_node.base); + const block_node = try block_scope.complete(rp.c); // semicolon must immediately follow rbrace because it is the last token in a block _ = try appendToken(rp.c, .Semicolon, ";"); const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); grouped_expr.* = .{ .lparen = try appendToken(rp.c, .LParen, "("), - .expr = &block_scope.block_node.base, + .expr = &block_node.base, .rparen = try appendToken(rp.c, .RParen, ")"), }; return &grouped_expr.base; @@ -3032,8 +3136,8 @@ fn transCreatePostCrement( // zig: _ref.* += 1; // zig: break :blk _tmp // zig: }) - const block_scope = try Scope.Block.init(rp.c, scope, "blk"); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, block_scope.label)); + var block_scope = try Scope.Block.init(rp.c, scope, "blk"); + defer block_scope.deinit(); const ref = try block_scope.makeMangledName(rp.c, "ref"); const node = try transCreateNodeVarDecl(rp.c, false, true, ref); @@ -3042,7 +3146,7 @@ fn transCreatePostCrement( rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); node.init_node = &rhs_node.base; node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&node.base); + try block_scope.statements.push(&node.base); const lhs_node = try transCreateNodeIdentifier(rp.c, ref); const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); @@ -3053,23 +3157,23 @@ fn transCreatePostCrement( tmp_node.eq_token = try appendToken(rp.c, .Equal, "="); tmp_node.init_node = ref_node; tmp_node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&tmp_node.base); + try block_scope.statements.push(&tmp_node.base); const token = try appendToken(rp.c, op_tok_id, bytes); const one = try transCreateNodeInt(rp.c, 1); _ = try appendToken(rp.c, .Semicolon, ";"); const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false); - try block_scope.block_node.statements.push(assign); + try block_scope.statements.push(assign); const break_node = try transCreateNodeBreak(rp.c, block_scope.label); break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); - try block_scope.block_node.statements.push(&break_node.base); + try block_scope.statements.push(&break_node.base); _ = try appendToken(rp.c, .Semicolon, ";"); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + const block_node = try block_scope.complete(rp.c); const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); grouped_expr.* = .{ .lparen = try appendToken(rp.c, .LParen, "("), - .expr = &block_scope.block_node.base, + .expr = &block_node.base, .rparen = try appendToken(rp.c, .RParen, ")"), }; return &grouped_expr.base; @@ -3134,11 +3238,11 @@ fn transCreateCompoundAssign( const op_token = try appendToken(rp.c, .Equal, "="); const op_node = try rp.c.arena.create(ast.Node.InfixOp); const builtin = if (is_mod) "@rem" else "@divTrunc"; - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin); + const builtin_node = try rp.c.createBuiltinCall(builtin, 2); const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value); - try builtin_node.params.push(lhs_node); + builtin_node.params()[0] = lhs_node; _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); + builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); op_node.* = .{ .op_token = op_token, @@ -3158,11 +3262,11 @@ fn transCreateCompoundAssign( try transExpr(rp, scope, rhs, .used, .r_value); if (is_shift) { - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); + const cast_node = try rp.c.createBuiltinCall("@intCast", 2); const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); - try cast_node.params.push(rhs_type); + cast_node.params()[0] = rhs_type; _ = try appendToken(rp.c, .Comma, ","); - try cast_node.params.push(rhs_node); + cast_node.params()[1] = rhs_node; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); rhs_node = &cast_node.base; } @@ -3177,8 +3281,8 @@ fn transCreateCompoundAssign( // zig: _ref.* = _ref.* + rhs; // zig: break :blk _ref.* // zig: }) - const block_scope = try Scope.Block.init(rp.c, scope, "blk"); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, block_scope.label)); + var block_scope = try Scope.Block.init(rp.c, scope, "blk"); + defer block_scope.deinit(); const ref = try block_scope.makeMangledName(rp.c, "ref"); const node = try transCreateNodeVarDecl(rp.c, false, true, ref); @@ -3187,7 +3291,7 @@ fn transCreateCompoundAssign( addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value); node.init_node = &addr_node.base; node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&node.base); + try block_scope.statements.append(&node.base); const lhs_node = try transCreateNodeIdentifier(rp.c, ref); const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node); @@ -3197,10 +3301,10 @@ fn transCreateCompoundAssign( const op_token = try appendToken(rp.c, .Equal, "="); const op_node = try rp.c.arena.create(ast.Node.InfixOp); const builtin = if (is_mod) "@rem" else "@divTrunc"; - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, builtin); - try builtin_node.params.push(try transCreateNodePtrDeref(rp.c, lhs_node)); + const builtin_node = try rp.c.createBuiltinCall(builtin, 2); + builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node); _ = try appendToken(rp.c, .Comma, ","); - try builtin_node.params.push(try transExpr(rp, scope, rhs, .used, .r_value)); + builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value); builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); _ = try appendToken(rp.c, .Semicolon, ";"); op_node.* = .{ @@ -3210,17 +3314,17 @@ fn transCreateCompoundAssign( .rhs = &builtin_node.base, }; _ = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&op_node.base); + try block_scope.statements.append(&op_node.base); } else { const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes); var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); if (is_shift) { - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); + const cast_node = try rp.c.createBuiltinCall("@intCast", 2); const rhs_type = try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc); - try cast_node.params.push(rhs_type); + cast_node.params()[0] = rhs_type; _ = try appendToken(rp.c, .Comma, ","); - try cast_node.params.push(rhs_node); + cast_node.params()[1] = rhs_node; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); rhs_node = &cast_node.base; } @@ -3230,17 +3334,17 @@ fn transCreateCompoundAssign( const eq_token = try appendToken(rp.c, .Equal, "="); const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, eq_token, rhs_bin, .used, false); - try block_scope.block_node.statements.push(assign); + try block_scope.statements.append(assign); } const break_node = try transCreateNodeBreak(rp.c, block_scope.label); break_node.rhs = ref_node; - try block_scope.block_node.statements.push(&break_node.base); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + try block_scope.statements.append(&break_node.base); + const block_node = try block_scope.complete(rp.c); const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); grouped_expr.* = .{ .lparen = try appendToken(rp.c, .LParen, "("), - .expr = &block_scope.block_node.base, + .expr = &block_node.base, .rparen = try appendToken(rp.c, .RParen, ")"), }; return &grouped_expr.base; @@ -3264,43 +3368,43 @@ fn transCPtrCast( !ZigClangQualType_isVolatileQualified(child_type))) { // Casting away const or volatile requires us to use @intToPtr - const inttoptr_node = try transCreateNodeBuiltinFnCall(rp.c, "@intToPtr"); + const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2); const dst_type_node = try transType(rp, ty, loc); - try inttoptr_node.params.push(dst_type_node); + inttoptr_node.params()[0] = dst_type_node; _ = try appendToken(rp.c, .Comma, ","); - const ptrtoint_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrToInt"); - try ptrtoint_node.params.push(expr); + const ptrtoint_node = try rp.c.createBuiltinCall("@ptrToInt", 1); + ptrtoint_node.params()[0] = expr; ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try inttoptr_node.params.push(&ptrtoint_node.base); + inttoptr_node.params()[1] = &ptrtoint_node.base; inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")"); return &inttoptr_node.base; } else { // Implicit downcasting from higher to lower alignment values is forbidden, // use @alignCast to side-step this problem - const ptrcast_node = try transCreateNodeBuiltinFnCall(rp.c, "@ptrCast"); + const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2); const dst_type_node = try transType(rp, ty, loc); - try ptrcast_node.params.push(dst_type_node); + ptrcast_node.params()[0] = dst_type_node; _ = try appendToken(rp.c, .Comma, ","); if (ZigClangType_isVoidType(qualTypeCanon(child_type))) { // void has 1-byte alignment, so @alignCast is not needed - try ptrcast_node.params.push(expr); + ptrcast_node.params()[1] = expr; } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) { // For opaque types a ptrCast is enough - try ptrcast_node.params.push(expr); + ptrcast_node.params()[1] = expr; } else { - const aligncast_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignCast"); - const alignof_node = try transCreateNodeBuiltinFnCall(rp.c, "@alignOf"); + const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2); + const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1); const child_type_node = try transQualType(rp, child_type, loc); - try alignof_node.params.push(child_type_node); + alignof_node.params()[0] = child_type_node; alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try aligncast_node.params.push(&alignof_node.base); + aligncast_node.params()[0] = &alignof_node.base; _ = try appendToken(rp.c, .Comma, ","); - try aligncast_node.params.push(expr); + aligncast_node.params()[1] = expr; aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - try ptrcast_node.params.push(&aligncast_node.base); + ptrcast_node.params()[1] = &aligncast_node.base; } ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); @@ -3343,27 +3447,30 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const // }) const lparen = try appendToken(rp.c, .LParen, "("); - const block_scope = try Scope.Block.init(rp.c, scope, "blk"); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, block_scope.label)); + var block_scope = try Scope.Block.init(rp.c, scope, "blk"); + defer block_scope.deinit(); const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp"); const tmp_var = try transCreateNodeVarDecl(rp.c, false, true, mangled_name); tmp_var.eq_token = try appendToken(rp.c, .Equal, "="); tmp_var.init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value); tmp_var.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&tmp_var.base); + try block_scope.statements.append(&tmp_var.base); const break_node = try transCreateNodeBreak(rp.c, block_scope.label); const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope{ - .parent = &block_scope.base, - .id = .Condition, + var cond_scope = Scope.Condition{ + .base = .{ + .parent = &block_scope.base, + .id = .Condition, + }, }; + defer cond_scope.deinit(); const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name); const ty = ZigClangQualType_getTypePtr(getExprQualType(rp.c, cond_expr)); - const cond_node = try finishBoolExpr(rp, &block_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used); + const cond_node = try finishBoolExpr(rp, &cond_scope.base, ZigClangExpr_getBeginLoc(cond_expr), ty, tmp_var_node, used); if_node.condition = cond_node; _ = try appendToken(rp.c, .RParen, ")"); @@ -3374,13 +3481,13 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const break_node.rhs = &if_node.base; _ = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&break_node.base); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + try block_scope.statements.append(&break_node.base); + const block_node = block_scope.complete(rp.c); const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); grouped_expr.* = .{ .lparen = lparen, - .expr = &block_scope.block_node.base, + .expr = &block_node.base, .rparen = try appendToken(rp.c, .RParen, ")"), }; return maybeSuppressResult(rp, scope, used, &grouped_expr.base); @@ -3390,17 +3497,20 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla const grouped = scope.id == .Condition; const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined; const if_node = try transCreateNodeIf(rp.c); - var cond_scope = Scope{ - .parent = scope, - .id = .Condition, + var cond_scope = Scope.Condition{ + .base = .{ + .parent = scope, + .id = .Condition, + }, }; + defer cond_scope.deinit(); const casted_stmt = @ptrCast(*const ZigClangAbstractConditionalOperator, stmt); const cond_expr = ZigClangAbstractConditionalOperator_getCond(casted_stmt); const true_expr = ZigClangAbstractConditionalOperator_getTrueExpr(casted_stmt); const false_expr = ZigClangAbstractConditionalOperator_getFalseExpr(casted_stmt); - if_node.condition = try transBoolExpr(rp, &cond_scope, cond_expr, .used, .r_value, false); + if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false); _ = try appendToken(rp.c, .RParen, ")"); if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value); @@ -3571,19 +3681,19 @@ fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigC // Symbol "Log2Int" // Symbol (var from above) - const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import"); + const import_fn_call = try rp.c.createBuiltinCall("@import", 1); const std_token = try appendToken(rp.c, .StringLiteral, "\"std\""); const std_node = try rp.c.arena.create(ast.Node.StringLiteral); std_node.* = .{ .token = std_token, }; - try import_fn_call.params.push(&std_node.base); + import_fn_call.params()[0] = &std_node.base; import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")"); const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math"); const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int"); - const log2int_fn_call = try transCreateNodeFnCall(rp.c, outer_field_access); - try @fieldParentPtr(ast.Node.SuffixOp, "base", &log2int_fn_call.base).op.Call.params.push(zig_type_node); + const log2int_fn_call = try rp.c.createCall(outer_field_access, 1); + log2int_fn_call.params()[0] = zig_type_node; log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")"); return &log2int_fn_call.base; @@ -3757,8 +3867,8 @@ fn transCreateNodeAssign( const eq_token = try appendToken(rp.c, .Equal, "="); var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value); if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); - try builtin_node.params.push(rhs_node); + const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); + builtin_node.params()[0] = rhs_node; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); rhs_node = &builtin_node.base; } @@ -3774,22 +3884,23 @@ fn transCreateNodeAssign( // zig: lhs = _tmp; // zig: break :blk _tmp // zig: }) - const block_scope = try Scope.Block.init(rp.c, scope, "blk"); - block_scope.setBlockNode(try transCreateNodeBlock(rp.c, block_scope.label)); + var block_scope = try Scope.Block.init(rp.c, scope, "blk"); + defer block_scope.deinit(); + const tmp = try block_scope.makeMangledName(rp.c, "tmp"); const node = try transCreateNodeVarDecl(rp.c, false, true, tmp); node.eq_token = try appendToken(rp.c, .Equal, "="); var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value); if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) { - const builtin_node = try transCreateNodeBuiltinFnCall(rp.c, "@boolToInt"); - try builtin_node.params.push(rhs_node); + const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); + builtin_node.params()[0] = rhs_node; builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); rhs_node = &builtin_node.base; } node.init_node = rhs_node; node.semicolon_token = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&node.base); + try block_scope.statements.append(&node.base); const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value); const eq_token = try appendToken(rp.c, .Equal, "="); @@ -3797,44 +3908,16 @@ fn transCreateNodeAssign( _ = try appendToken(rp.c, .Semicolon, ";"); const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, eq_token, ident, .used, false); - try block_scope.block_node.statements.push(assign); + try block_scope.statements.append(assign); const break_node = try transCreateNodeBreak(rp.c, block_scope.label); break_node.rhs = try transCreateNodeIdentifier(rp.c, tmp); _ = try appendToken(rp.c, .Semicolon, ";"); - try block_scope.block_node.statements.push(&break_node.base); - block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}"); + try block_scope.statements.append(&break_node.base); + const block_node = try block_scope.complete(rp.c); // semicolon must immediately follow rbrace because it is the last token in a block _ = try appendToken(rp.c, .Semicolon, ";"); - return &block_scope.block_node.base; -} - -fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.BuiltinCall { - const builtin_token = try appendToken(c, .Builtin, name); - _ = try appendToken(c, .LParen, "("); - const node = try c.arena.create(ast.Node.BuiltinCall); - node.* = .{ - .builtin_token = builtin_token, - .params = ast.Node.BuiltinCall.ParamList{}, - .rparen_token = undefined, // set after appending args - }; - return node; -} - -fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp { - _ = try appendToken(c, .LParen, "("); - const node = try c.arena.create(ast.Node.SuffixOp); - node.* = .{ - .lhs = fn_expr, - .op = .{ - .Call = .{ - .params = ast.Node.SuffixOp.Op.Call.ParamList{}, - .async_token = null, - }, - }, - .rtoken = undefined, // set after appending args - }; - return node; + return &block_node.base; } fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node { @@ -4083,8 +4166,8 @@ fn transCreateNodeFloat(c: *Context, int: var) !*ast.Node { } fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { - const call_node = try transCreateNodeBuiltinFnCall(c, "@Type"); - try call_node.params.push(try transCreateNodeEnumLiteral(c, "Opaque")); + const call_node = try c.createBuiltinCall("@Type", 1); + call_node.params()[0] = try transCreateNodeEnumLiteral(c, "Opaque"); call_node.rparen_token = try appendToken(c, .RParen, ")"); return &call_node.base; } @@ -4139,26 +4222,33 @@ fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_a }; mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); - const block = try transCreateNodeBlock(c, null); - var block_statements_it = &block.statements.first; + const block_lbrace = try appendToken(c, .LBrace, "{"); const return_expr = try transCreateNodeReturnExpr(c); const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.init_node.?); - const call_expr = try transCreateNodeFnCall(c, unwrap_expr); - var call_params_it = &call_expr.op.Call.params.first; + + const call_expr = try c.createCall(unwrap_expr, fn_params.items.len); + const call_params = call_expr.params(); for (fn_params.items) |param, i| { if (i != 0) { _ = try appendToken(c, .Comma, ","); } - call_params_it = try c.llpush(*ast.Node, call_params_it, try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)),); + call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?)); } call_expr.rtoken = try appendToken(c, .RParen, ")"); + return_expr.rhs = &call_expr.base; _ = try appendToken(c, .Semicolon, ";"); - block.rbrace = try appendToken(c, .RBrace, "}"); - block_statements_it = try c.llpush(*ast.Node, block_statements_it, &return_expr.base); + const block = try ast.Node.Block.alloc(c.arena, 1); + block.* = .{ + .label = null, + .lbrace = block_lbrace, + .statements_len = 1, + .rbrace = try appendToken(c, .RBrace, "}"), + }; + block.statements()[0] = &return_expr.base; fn_proto.body_node = &block.base; return &fn_proto.base; } @@ -4216,22 +4306,6 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else { return node; } -fn transCreateNodeBlock(c: *Context, label: ?[]const u8) !*ast.Node.Block { - const label_node = if (label) |l| blk: { - const ll = try appendIdentifier(c, l); - _ = try appendToken(c, .Colon, ":"); - break :blk ll; - } else null; - const block_node = try c.arena.create(ast.Node.Block); - block_node.* = .{ - .label = label_node, - .lbrace = try appendToken(c, .LBrace, "{"), - .statements = ast.Node.Block.StatementList{}, - .rbrace = undefined, - }; - return block_node; -} - fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowExpression { const ltoken = try appendToken(c, .Keyword_break, "break"); const label_node = if (label) |l| blk: { @@ -4302,20 +4376,6 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node { return &node.base; } -fn transCreateNodeSwitch(c: *Context) !*ast.Node.Switch { - const switch_tok = try appendToken(c, .Keyword_switch, "switch"); - _ = try appendToken(c, .LParen, "("); - - const node = try c.arena.create(ast.Node.Switch); - node.* = .{ - .switch_token = switch_tok, - .expr = undefined, - .cases = ast.Node.Switch.CaseList{}, - .rbrace = undefined, - }; - return node; -} - fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase { const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>"); @@ -4356,12 +4416,12 @@ fn transCreateNodeShiftOp( const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value); const op_token = try appendToken(rp.c, op_tok_id, bytes); - const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@intCast"); + const cast_node = try rp.c.createBuiltinCall("@intCast", 2); const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location); - try cast_node.params.push(rhs_type); + cast_node.params()[0] = rhs_type; _ = try appendToken(rp.c, .Comma, ","); const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value); - try cast_node.params.push(rhs); + cast_node.params()[1] = rhs; cast_node.rparen_token = try appendToken(rp.c, .RParen, ")"); const node = try rp.c.arena.create(ast.Node.InfixOp); @@ -4832,14 +4892,13 @@ pub fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comp .token = msg_tok, }; - const call_node = try c.arena.create(ast.Node.BuiltinCall); + const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1); call_node.* = .{ .builtin_token = builtin_tok, - .params = ast.Node.BuiltinCall.ParamList{}, + .params_len = 1, .rparen_token = rparen_tok, }; - var call_params_it = &call_node.params.first; - call_params_it = try c.llpush(*ast.Node, call_params_it, &msg_node.base); + call_node.params()[0] = &msg_node.base; const var_decl_node = try c.arena.create(ast.Node.VarDecl); var_decl_node.* = .{ @@ -4868,23 +4927,20 @@ fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenInd fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: var) !ast.TokenIndex { assert(token_id != .Invalid); + + try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1); + try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1); + const start_index = c.source_buffer.items.len; - errdefer c.source_buffer.shrink(start_index); + try c.source_buffer.outStream().print(format ++ " ", args); - try c.source_buffer.outStream().print(format, args); - const end_index = c.source_buffer.items.len; - const token_index = c.tokens.items.len; - const new_token = try c.tokens.addOne(c.gpa); - errdefer c.tokens.shrink(c.gpa, token_index); - - new_token.* = .{ - .id = token_id, + c.token_ids.appendAssumeCapacity(token_id); + c.token_locs.appendAssumeCapacity(.{ .start = start_index, - .end = end_index, - }; - try c.source_buffer.append(' '); + .end = c.source_buffer.items.len - 1, // back up before the space + }); - return token_index; + return c.token_ids.items.len - 1; } // TODO hook up with codegen @@ -5072,7 +5128,8 @@ fn transMacroDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, n } fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, name: []const u8, source_loc: ZigClangSourceLocation) ParseError!void { - const block_scope = try Scope.Block.init(c, &c.global_scope.base, null); + var block_scope = try Scope.Block.init(c, &c.global_scope.base, null); + defer block_scope.deinit(); const scope = &block_scope.base; const pub_tok = try appendToken(c, .Keyword_pub, "pub"); @@ -5142,9 +5199,7 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, _ = try appendToken(c, .RParen, ")"); - const type_of = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); - type_of.rparen_token = try appendToken(c, .RParen, ")"); - var type_of_params = c.llpusher(&type_of.params); + const type_of = try c.createBuiltinCall("@TypeOf", 1); const fn_proto = try ast.Node.FnProto.alloc(c.arena, fn_params.items.len); fn_proto.* = .{ @@ -5164,9 +5219,6 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, }; mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items); - const block = try transCreateNodeBlock(c, null); - var block_statements = c.llpusher(&block.statements); - const return_expr = try transCreateNodeReturnExpr(c); const expr = try parseCExpr(c, it, source, source_loc, scope); const last = it.next().?; @@ -5186,12 +5238,13 @@ fn transMacroFnDefine(c: *Context, it: *CTokenList.Iterator, source: []const u8, const br = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", blk_last); break :blk br.rhs.?; }; - try type_of_params.push(type_of_arg); + type_of.params()[0] = type_of_arg; + type_of.rparen_token = try appendToken(c, .RParen, ")"); return_expr.rhs = expr; - block.rbrace = try appendToken(c, .RBrace, "}"); - try block_statements.push(&return_expr.base); - fn_proto.body_node = &block.base; + try block_scope.statements.append(&return_expr.base); + const block_node = try block_scope.complete(c); + fn_proto.body_node = &block_node.base; _ = try c.global_scope.macro_table.put(name, &fn_proto.base); } @@ -5223,8 +5276,8 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ }, .Comma => { _ = try appendToken(c, .Semicolon, ";"); - const block_scope = try Scope.Block.init(c, scope, "blk"); - block_scope.setBlockNode(try transCreateNodeBlock(c, block_scope.label)); + var block_scope = try Scope.Block.init(c, scope, "blk"); + defer block_scope.deinit(); var last = node; while (true) { @@ -5238,7 +5291,7 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ .op = .Assign, .rhs = last, }; - try block_scope.block_node.statements.push(&op_node.base); + try block_scope.statements.append(&op_node.base); last = try parseCPrefixOpExpr(c, it, source, source_loc, scope); _ = try appendToken(c, .Semicolon, ";"); @@ -5250,9 +5303,9 @@ fn parseCExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, source_ const break_node = try transCreateNodeBreak(c, block_scope.label); break_node.rhs = last; - try block_scope.block_node.statements.push(&break_node.base); - block_scope.block_node.rbrace = try appendToken(c, .RBrace, "}"); - return &block_scope.block_node.base; + try block_scope.statements.append(&break_node.base); + const block_node = try block_scope.complete(c); + return &block_node.base; }, else => { _ = it.prev(); @@ -5283,15 +5336,15 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl return transCreateNodeInt(c, lit_bytes); } - const cast_node = try transCreateNodeBuiltinFnCall(c, "@as"); - try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) { + const cast_node = try c.createBuiltinCall("@as", 2); + cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.IntegerLiteral) { .U => "c_uint", .L => "c_long", .LU => "c_ulong", .LL => "c_longlong", .LLU => "c_ulonglong", else => unreachable, - })); + }); lit_bytes = lit_bytes[0 .. lit_bytes.len - switch (tok.id.IntegerLiteral) { .U, .L => @as(u8, 1), .LU, .LL => 2, @@ -5299,7 +5352,7 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl else => unreachable, }]; _ = try appendToken(c, .Comma, ","); - try cast_node.params.push(try transCreateNodeInt(c, lit_bytes)); + cast_node.params()[1] = try transCreateNodeInt(c, lit_bytes); cast_node.rparen_token = try appendToken(c, .RParen, ")"); return &cast_node.base; } else if (tok.id == .FloatLiteral) { @@ -5308,14 +5361,14 @@ fn parseCNumLit(c: *Context, tok: *CToken, source: []const u8, source_loc: ZigCl if (tok.id.FloatLiteral == .None) { return transCreateNodeFloat(c, lit_bytes); } - const cast_node = try transCreateNodeBuiltinFnCall(c, "@as"); - try cast_node.params.push(try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) { + const cast_node = try c.createBuiltinCall("@as", 2); + cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (tok.id.FloatLiteral) { .F => "f32", .L => "c_longdouble", else => unreachable, - })); + }); _ = try appendToken(c, .Comma, ","); - try cast_node.params.push(try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1])); + cast_node.params()[1] = try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]); cast_node.rparen_token = try appendToken(c, .RParen, ")"); return &cast_node.base; } else unreachable; @@ -5585,8 +5638,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, //else // @as(dest, x) ) const if_node = try transCreateNodeIf(c); - const type_info_node = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); - try type_info_node.params.push(inner_node); + const type_info_node = try rp.c.createBuiltinCall("@typeInfo", 1); + type_info_node.params()[0] = inner_node; type_info_node.rparen_token = try appendToken(c, .LParen, ")"); const cmp_node = try c.arena.create(ast.Node.InfixOp); cmp_node.* = .{ @@ -5598,18 +5651,18 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, if_node.condition = &cmp_node.base; _ = try appendToken(c, .RParen, ")"); - const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr"); - try int_to_ptr.params.push(inner_node); - try int_to_ptr.params.push(node_to_cast); + const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2); + int_to_ptr.params()[0] = inner_node; + int_to_ptr.params()[1] = node_to_cast; int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); if_node.body = &int_to_ptr.base; const else_node = try transCreateNodeElse(c); if_node.@"else" = else_node; - const as_node = try transCreateNodeBuiltinFnCall(c, "@as"); - try as_node.params.push(inner_node); - try as_node.params.push(node_to_cast); + const as_node = try c.createBuiltinCall("@as", 2); + as_node.params()[0] = inner_node; + as_node.params()[1] = node_to_cast; as_node.rparen_token = try appendToken(c, .RParen, ")"); else_node.body = &as_node.base; @@ -5630,10 +5683,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, // @as(dest, x) ) const if_1 = try transCreateNodeIf(c); - const type_info_1 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); - const type_of_1 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); - try type_info_1.params.push(&type_of_1.base); - try type_of_1.params.push(node_to_cast); + const type_info_1 = try c.createBuiltinCall("@typeInfo", 1); + const type_of_1 = try c.createBuiltinCall("@TypeOf", 1); + type_info_1.params()[0] = &type_of_1.base; + type_of_1.params()[0] = node_to_cast; type_of_1.rparen_token = try appendToken(c, .RParen, ")"); type_info_1.rparen_token = try appendToken(c, .RParen, ")"); @@ -5657,20 +5710,20 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, .rhs = child_ident, }; - const align_of = try transCreateNodeBuiltinFnCall(c, "@alignOf"); - try align_of.params.push(&inner_node_child.base); + const align_of = try rp.c.createBuiltinCall("@alignOf", 1); + align_of.params()[0] = &inner_node_child.base; align_of.rparen_token = try appendToken(c, .RParen, ")"); // hack to get zig fmt to render a comma in builtin calls _ = try appendToken(c, .Comma, ","); - const align_cast = try transCreateNodeBuiltinFnCall(c, "@alignCast"); - try align_cast.params.push(&align_of.base); - try align_cast.params.push(node_to_cast); + const align_cast = try c.createBuiltinCall("@alignCast", 2); + align_cast.params()[0] = &align_of.base; + align_cast.params()[1] = node_to_cast; align_cast.rparen_token = try appendToken(c, .RParen, ")"); - const ptr_cast = try transCreateNodeBuiltinFnCall(c, "@ptrCast"); - try ptr_cast.params.push(inner_node); - try ptr_cast.params.push(&align_cast.base); + const ptr_cast = try c.createBuiltinCall("@ptrCast", 2); + ptr_cast.params()[0] = inner_node; + ptr_cast.params()[1] = &align_cast.base; ptr_cast.rparen_token = try appendToken(c, .RParen, ")"); if_1.body = &ptr_cast.base; @@ -5678,10 +5731,10 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, if_1.@"else" = else_1; const if_2 = try transCreateNodeIf(c); - const type_info_2 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); - const type_of_2 = try transCreateNodeBuiltinFnCall(c, "@TypeOf"); - try type_info_2.params.push(&type_of_2.base); - try type_of_2.params.push(node_to_cast); + const type_info_2 = try c.createBuiltinCall("@typeInfo", 1); + const type_of_2 = try c.createBuiltinCall("@TypeOf", 1); + type_info_2.params()[0] = &type_of_2.base; + type_of_2.params()[0] = node_to_cast; type_of_2.rparen_token = try appendToken(c, .RParen, ")"); type_info_2.rparen_token = try appendToken(c, .RParen, ")"); @@ -5700,8 +5753,8 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, .op = .BoolAnd, .rhs = undefined, }; - const type_info_3 = try transCreateNodeBuiltinFnCall(c, "@typeInfo"); - try type_info_3.params.push(inner_node); + const type_info_3 = try c.createBuiltinCall("@typeInfo", 1); + type_info_3.params()[0] = inner_node; type_info_3.rparen_token = try appendToken(c, .LParen, ")"); const cmp_3 = try c.arena.create(ast.Node.InfixOp); cmp_3.* = .{ @@ -5715,18 +5768,18 @@ fn parseCPrimaryExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, else_1.body = &if_2.base; _ = try appendToken(c, .RParen, ")"); - const int_to_ptr = try transCreateNodeBuiltinFnCall(c, "@intToPtr"); - try int_to_ptr.params.push(inner_node); - try int_to_ptr.params.push(node_to_cast); + const int_to_ptr = try c.createBuiltinCall("@intToPtr", 2); + int_to_ptr.params()[0] = inner_node; + int_to_ptr.params()[1] = node_to_cast; int_to_ptr.rparen_token = try appendToken(c, .RParen, ")"); if_2.body = &int_to_ptr.base; const else_2 = try transCreateNodeElse(c); if_2.@"else" = else_2; - const as = try transCreateNodeBuiltinFnCall(c, "@as"); - try as.params.push(inner_node); - try as.params.push(node_to_cast); + const as = try c.createBuiltinCall("@as", 2); + as.params()[0] = inner_node; + as.params()[1] = node_to_cast; as.rparen_token = try appendToken(c, .RParen, ")"); else_2.body = &as.base; @@ -5765,8 +5818,8 @@ fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node { return &group_node.base; } - const builtin_node = try transCreateNodeBuiltinFnCall(c, "@boolToInt"); - try builtin_node.params.push(node); + const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1); + builtin_node.params()[0] = node; builtin_node.rparen_token = try appendToken(c, .RParen, ")"); return &builtin_node.base; } @@ -5944,10 +5997,12 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, continue; }, .LParen => { - const call_node = try transCreateNodeFnCall(c, node); + _ = try appendToken(c, .LParen, "("); + var call_params = std.ArrayList(*ast.Node).init(c.gpa); + defer call_params.deinit(); while (true) { const arg = try parseCPrefixOpExpr(c, it, source, source_loc, scope); - try call_node.op.Call.params.push(arg); + try call_params.append(arg); const next = it.next().?; if (next.id == .Comma) _ = try appendToken(c, .Comma, ",") @@ -5965,7 +6020,14 @@ fn parseCSuffixOpExpr(c: *Context, it: *CTokenList.Iterator, source: []const u8, return error.ParseError; } } - call_node.rtoken = try appendToken(c, .RParen, ")"); + const call_node = try ast.Node.Call.alloc(c.arena, call_params.items.len); + call_node.* = .{ + .lhs = node, + .params_len = call_params.items.len, + .async_token = null, + .rtoken = try appendToken(c, .RParen, ")"), + }; + mem.copy(*ast.Node, call_node.params(), call_params.items); node = &call_node.base; continue; },