authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-19 13:03:29+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-02-19 13:03:29+02:00
logd672c20b8a8d93ba200160b3698c5edab531e091
tree18df7eef6458ece59d67d50bc2ef455f3320f7a0
parent914540ddb5867efe5c1823c281641897bc4cd22a
parent974a1c55255560318f1d99003d353374b94b63e1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7479 from ziglang/translate-c-ast

Make translate-c use intermediate AST

13 files changed, 4939 insertions(+), 4054 deletions(-)

CMakeLists.txt+1
......@@ -577,6 +577,7 @@ set(ZIG_STAGE2_SOURCES
577577 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"
578578 "${CMAKE_SOURCE_DIR}/src/zir.zig"
579579 "${CMAKE_SOURCE_DIR}/src/zir_sema.zig"
580 "${CMAKE_SOURCE_DIR}/src/translate_c/ast.zig"
580581)
581582
582583if(MSVC)
lib/std/zig/parser_test.zig+6-6
......@@ -3695,12 +3695,12 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
36953695 );
36963696}
36973697
3698//test "zig fmt: C var args" {
3699// try testCanonical(
3700// \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3701// \\
3702// );
3703//}
3698test "zig fmt: C var args" {
3699 try testCanonical(
3700 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3701 \\
3702 );
3703}
37043704
37053705//test "zig fmt: Only indent multiline string literals in function calls" {
37063706// try testCanonical(
lib/std/zig/render.zig+4-7
......@@ -556,14 +556,11 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
556556
557557 .builtin_call_two, .builtin_call_two_comma => {
558558 if (datas[node].lhs == 0) {
559 const params = [_]ast.Node.Index{};
560 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
559 return renderBuiltinCall(ais, tree, main_tokens[node], &.{}, space);
561560 } else if (datas[node].rhs == 0) {
562 const params = [_]ast.Node.Index{datas[node].lhs};
563 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
561 return renderBuiltinCall(ais, tree, main_tokens[node], &.{datas[node].lhs}, space);
564562 } else {
565 const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
566 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
563 return renderBuiltinCall(ais, tree, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space);
567564 }
568565 },
569566 .builtin_call, .builtin_call_comma => {
......@@ -1319,7 +1316,7 @@ fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.full.FnProto, space: S
13191316 .r_paren => break,
13201317 .comma => {
13211318 try renderToken(ais, tree, last_param_token, .space); // ,
1322 last_param_token += 1;
1319 continue;
13231320 },
13241321 else => {}, // Parameter type without a name.
13251322 }
src/Compilation.zig+1-1
......@@ -1334,7 +1334,7 @@ pub fn update(self: *Compilation) !void {
13341334 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
13351335 }
13361336
1337 const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_llvm;
1337 const use_stage1 = build_options.omit_stage2 or build_options.is_stage1 and self.bin_file.options.use_llvm;
13381338 if (!use_stage1) {
13391339 if (self.bin_file.options.module) |module| {
13401340 module.compile_log_text.shrinkAndFree(module.gpa, 0);
src/astgen.zig+32-38
......@@ -2935,8 +2935,11 @@ fn identifier(
29352935 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
29362936 }
29372937
2938 if (getSimplePrimitiveValue(ident_name)) |typed_value| {
2939 const result = try addZIRInstConst(mod, scope, src, typed_value);
2938 if (simple_types.get(ident_name)) |val_tag| {
2939 const result = try addZIRInstConst(mod, scope, src, TypedValue{
2940 .ty = Type.initTag(.type),
2941 .val = Value.initTag(val_tag),
2942 });
29402943 return rvalue(mod, scope, rl, result);
29412944 }
29422945
......@@ -3617,42 +3620,33 @@ fn callExpr(
36173620 return rvalue(mod, scope, rl, result);
36183621}
36193622
3620fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {
3621 const simple_types = std.ComptimeStringMap(Value.Tag, .{
3622 .{ "u8", .u8_type },
3623 .{ "i8", .i8_type },
3624 .{ "isize", .isize_type },
3625 .{ "usize", .usize_type },
3626 .{ "c_short", .c_short_type },
3627 .{ "c_ushort", .c_ushort_type },
3628 .{ "c_int", .c_int_type },
3629 .{ "c_uint", .c_uint_type },
3630 .{ "c_long", .c_long_type },
3631 .{ "c_ulong", .c_ulong_type },
3632 .{ "c_longlong", .c_longlong_type },
3633 .{ "c_ulonglong", .c_ulonglong_type },
3634 .{ "c_longdouble", .c_longdouble_type },
3635 .{ "f16", .f16_type },
3636 .{ "f32", .f32_type },
3637 .{ "f64", .f64_type },
3638 .{ "f128", .f128_type },
3639 .{ "c_void", .c_void_type },
3640 .{ "bool", .bool_type },
3641 .{ "void", .void_type },
3642 .{ "type", .type_type },
3643 .{ "anyerror", .anyerror_type },
3644 .{ "comptime_int", .comptime_int_type },
3645 .{ "comptime_float", .comptime_float_type },
3646 .{ "noreturn", .noreturn_type },
3647 });
3648 if (simple_types.get(name)) |tag| {
3649 return TypedValue{
3650 .ty = Type.initTag(.type),
3651 .val = Value.initTag(tag),
3652 };
3653 }
3654 return null;
3655}
3623pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
3624 .{ "u8", .u8_type },
3625 .{ "i8", .i8_type },
3626 .{ "isize", .isize_type },
3627 .{ "usize", .usize_type },
3628 .{ "c_short", .c_short_type },
3629 .{ "c_ushort", .c_ushort_type },
3630 .{ "c_int", .c_int_type },
3631 .{ "c_uint", .c_uint_type },
3632 .{ "c_long", .c_long_type },
3633 .{ "c_ulong", .c_ulong_type },
3634 .{ "c_longlong", .c_longlong_type },
3635 .{ "c_ulonglong", .c_ulonglong_type },
3636 .{ "c_longdouble", .c_longdouble_type },
3637 .{ "f16", .f16_type },
3638 .{ "f32", .f32_type },
3639 .{ "f64", .f64_type },
3640 .{ "f128", .f128_type },
3641 .{ "c_void", .c_void_type },
3642 .{ "bool", .bool_type },
3643 .{ "void", .void_type },
3644 .{ "type", .type_type },
3645 .{ "anyerror", .anyerror_type },
3646 .{ "comptime_int", .comptime_int_type },
3647 .{ "comptime_float", .comptime_float_type },
3648 .{ "noreturn", .noreturn_type },
3649});
36563650
36573651fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {
36583652 const tree = scope.tree();
src/clang.zig+7-4
......@@ -127,6 +127,9 @@ pub const APSInt = opaque {
127127
128128 pub const getNumWords = ZigClangAPSInt_getNumWords;
129129 extern fn ZigClangAPSInt_getNumWords(*const APSInt) c_uint;
130
131 pub const lessThanEqual = ZigClangAPSInt_lessThanEqual;
132 extern fn ZigClangAPSInt_lessThanEqual(*const APSInt, rhs: u64) bool;
130133};
131134
132135pub const ASTContext = opaque {
......@@ -270,12 +273,12 @@ pub const CompoundAssignOperator = opaque {
270273
271274pub const CompoundStmt = opaque {
272275 pub const body_begin = ZigClangCompoundStmt_body_begin;
273 extern fn ZigClangCompoundStmt_body_begin(*const CompoundStmt) const_body_iterator;
276 extern fn ZigClangCompoundStmt_body_begin(*const CompoundStmt) ConstBodyIterator;
274277
275278 pub const body_end = ZigClangCompoundStmt_body_end;
276 extern fn ZigClangCompoundStmt_body_end(*const CompoundStmt) const_body_iterator;
279 extern fn ZigClangCompoundStmt_body_end(*const CompoundStmt) ConstBodyIterator;
277280
278 pub const const_body_iterator = [*]const *Stmt;
281 pub const ConstBodyIterator = [*]const *Stmt;
279282};
280283
281284pub const ConditionalOperator = opaque {};
......@@ -407,7 +410,7 @@ pub const Expr = opaque {
407410 pub const getBeginLoc = ZigClangExpr_getBeginLoc;
408411 extern fn ZigClangExpr_getBeginLoc(*const Expr) SourceLocation;
409412
410 pub const EvaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
413 pub const evaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
411414 extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstExprUsage, *const ASTContext) bool;
412415};
413416
src/translate_c.zig+1786-3707
......@@ -3,23 +3,24 @@
33
44const std = @import("std");
55const assert = std.debug.assert;
6const ast = std.zig.ast;
7const Token = std.zig.Token;
86const clang = @import("clang.zig");
97const ctok = std.c.tokenizer;
108const CToken = std.c.Token;
119const mem = std.mem;
1210const math = std.math;
11const ast = @import("translate_c/ast.zig");
12const Node = ast.Node;
13const Tag = Node.Tag;
1314
1415const CallingConvention = std.builtin.CallingConvention;
1516
1617pub const ClangErrMsg = clang.Stage2ErrorMsg;
1718
18pub const Error = error{OutOfMemory};
19pub const Error = std.mem.Allocator.Error;
1920const TypeError = Error || error{UnsupportedType};
2021const TransError = TypeError || error{UnsupportedTranslation};
2122
22const SymbolTable = std.StringArrayHashMap(*ast.Node);
23const SymbolTable = std.StringArrayHashMap(Node);
2324const AliasList = std.ArrayList(struct {
2425 alias: []const u8,
2526 name: []const u8,
......@@ -30,23 +31,11 @@ const Scope = struct {
3031 parent: ?*Scope,
3132
3233 const Id = enum {
33 Switch,
34 Block,
35 Root,
36 Condition,
37 Loop,
38 };
39
40 /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated.
41 /// When it is deinitialized, it produces an ast.Node.Switch which is allocated
42 /// into the main arena.
43 const Switch = struct {
44 base: Scope,
45 pending_block: Block,
46 cases: []*ast.Node,
47 case_index: usize,
48 switch_label: ?[]const u8,
49 default_label: ?[]const u8,
34 block,
35 root,
36 condition,
37 loop,
38 do_loop,
5039 };
5140
5241 /// Used for the scope of condition expressions, for example `if (cond)`.
......@@ -67,16 +56,15 @@ const Scope = struct {
6756 }
6857 };
6958
70 /// Represents an in-progress ast.Node.Block. This struct is stack-allocated.
71 /// When it is deinitialized, it produces an ast.Node.Block which is allocated
59 /// Represents an in-progress Node.Block. This struct is stack-allocated.
60 /// When it is deinitialized, it produces an Node.Block which is allocated
7261 /// into the main arena.
7362 const Block = struct {
7463 base: Scope,
75 statements: std.ArrayList(*ast.Node),
64 statements: std.ArrayList(Node),
7665 variables: AliasList,
77 label: ?ast.TokenIndex,
7866 mangle_count: u32 = 0,
79 lbrace: ast.TokenIndex,
67 label: ?[]const u8 = null,
8068
8169 /// When the block corresponds to a function, keep track of the return type
8270 /// so that the return expression can be cast, if necessary
......@@ -85,17 +73,14 @@ const Scope = struct {
8573 fn init(c: *Context, parent: *Scope, labeled: bool) !Block {
8674 var blk = Block{
8775 .base = .{
88 .id = .Block,
76 .id = .block,
8977 .parent = parent,
9078 },
91 .statements = std.ArrayList(*ast.Node).init(c.gpa),
79 .statements = std.ArrayList(Node).init(c.gpa),
9280 .variables = AliasList.init(c.gpa),
93 .label = null,
94 .lbrace = try appendToken(c, .LBrace, "{"),
9581 };
9682 if (labeled) {
97 blk.label = try appendIdentifier(c, try blk.makeMangledName(c, "blk"));
98 _ = try appendToken(c, .Colon, ":");
83 blk.label = try blk.makeMangledName(c, "blk");
9984 }
10085 return blk;
10186 }
......@@ -106,31 +91,24 @@ const Scope = struct {
10691 self.* = undefined;
10792 }
10893
109 fn complete(self: *Block, c: *Context) !*ast.Node {
110 // We reserve 1 extra statement if the parent is a Loop. This is in case of
111 // do while, we want to put `if (cond) break;` at the end.
112 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
113 const rbrace = try appendToken(c, .RBrace, "}");
114 if (self.label) |label| {
115 const node = try ast.Node.LabeledBlock.alloc(c.arena, alloc_len);
116 node.* = .{
117 .statements_len = self.statements.items.len,
118 .lbrace = self.lbrace,
119 .rbrace = rbrace,
120 .label = label,
121 };
122 mem.copy(*ast.Node, node.statements(), self.statements.items);
123 return &node.base;
124 } else {
125 const node = try ast.Node.Block.alloc(c.arena, alloc_len);
126 node.* = .{
127 .statements_len = self.statements.items.len,
128 .lbrace = self.lbrace,
129 .rbrace = rbrace,
130 };
131 mem.copy(*ast.Node, node.statements(), self.statements.items);
132 return &node.base;
94 fn complete(self: *Block, c: *Context) !Node {
95 if (self.base.parent.?.id == .do_loop) {
96 // We reserve 1 extra statement if the parent is a do_loop. This is in case of
97 // do while, we want to put `if (cond) break;` at the end.
98 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .do_loop);
99 var stmts = try c.arena.alloc(Node, alloc_len);
100 stmts.len = self.statements.items.len;
101 mem.copy(Node, stmts, self.statements.items);
102 return Tag.block.create(c.arena, .{
103 .label = self.label,
104 .stmts = stmts,
105 });
133106 }
107 if (self.statements.items.len == 0) return Tag.empty_block.init();
108 return Tag.block.create(c.arena, .{
109 .label = self.label,
110 .stmts = try c.arena.dupe(Node, self.statements.items),
111 });
134112 }
135113
136114 /// Given the desired name, return a name that does not shadow anything from outer scopes.
......@@ -174,19 +152,27 @@ const Scope = struct {
174152 sym_table: SymbolTable,
175153 macro_table: SymbolTable,
176154 context: *Context,
155 nodes: std.ArrayList(Node),
177156
178157 fn init(c: *Context) Root {
179158 return .{
180159 .base = .{
181 .id = .Root,
160 .id = .root,
182161 .parent = null,
183162 },
184 .sym_table = SymbolTable.init(c.arena),
185 .macro_table = SymbolTable.init(c.arena),
163 .sym_table = SymbolTable.init(c.gpa),
164 .macro_table = SymbolTable.init(c.gpa),
186165 .context = c,
166 .nodes = std.ArrayList(Node).init(c.gpa),
187167 };
188168 }
189169
170 fn deinit(scope: *Root) void {
171 scope.sym_table.deinit();
172 scope.macro_table.deinit();
173 scope.nodes.deinit();
174 }
175
190176 /// Check if the global scope contains this name, without looking into the "future", e.g.
191177 /// ignore the preprocessed decl and macro names.
192178 fn containsNow(scope: *Root, name: []const u8) bool {
......@@ -205,20 +191,20 @@ const Scope = struct {
205191 var scope = inner;
206192 while (true) {
207193 switch (scope.id) {
208 .Root => unreachable,
209 .Block => return @fieldParentPtr(Block, "base", scope),
210 .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c),
194 .root => unreachable,
195 .block => return @fieldParentPtr(Block, "base", scope),
196 .condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c),
211197 else => scope = scope.parent.?,
212198 }
213199 }
214200 }
215201
216 fn findBlockReturnType(inner: *Scope, c: *Context) ?clang.QualType {
202 fn findBlockReturnType(inner: *Scope, c: *Context) clang.QualType {
217203 var scope = inner;
218204 while (true) {
219205 switch (scope.id) {
220 .Root => return null,
221 .Block => {
206 .root => unreachable,
207 .block => {
222208 const block = @fieldParentPtr(Block, "base", scope);
223209 if (block.return_type) |qt| return qt;
224210 scope = scope.parent.?;
......@@ -230,17 +216,17 @@ const Scope = struct {
230216
231217 fn getAlias(scope: *Scope, name: []const u8) []const u8 {
232218 return switch (scope.id) {
233 .Root => return name,
234 .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
235 .Switch, .Loop, .Condition => scope.parent.?.getAlias(name),
219 .root => return name,
220 .block => @fieldParentPtr(Block, "base", scope).getAlias(name),
221 .loop, .do_loop, .condition => scope.parent.?.getAlias(name),
236222 };
237223 }
238224
239225 fn contains(scope: *Scope, name: []const u8) bool {
240226 return switch (scope.id) {
241 .Root => @fieldParentPtr(Root, "base", scope).contains(name),
242 .Block => @fieldParentPtr(Block, "base", scope).contains(name),
243 .Switch, .Loop, .Condition => scope.parent.?.contains(name),
227 .root => @fieldParentPtr(Root, "base", scope).contains(name),
228 .block => @fieldParentPtr(Block, "base", scope).contains(name),
229 .loop, .do_loop, .condition => scope.parent.?.contains(name),
244230 };
245231 }
246232
......@@ -248,20 +234,26 @@ const Scope = struct {
248234 var scope = inner;
249235 while (true) {
250236 switch (scope.id) {
251 .Root => unreachable,
252 .Switch => return scope,
253 .Loop => return scope,
237 .root => unreachable,
238 .loop, .do_loop => return scope,
254239 else => scope = scope.parent.?,
255240 }
256241 }
257242 }
258243
259 fn getSwitch(inner: *Scope) *Scope.Switch {
244 /// Appends a node to the first block scope if inside a function, or to the root tree if not.
245 fn appendNode(inner: *Scope, node: Node) !void {
260246 var scope = inner;
261247 while (true) {
262248 switch (scope.id) {
263 .Root => unreachable,
264 .Switch => return @fieldParentPtr(Switch, "base", scope),
249 .root => {
250 const root = @fieldParentPtr(Root, "base", scope);
251 return root.nodes.append(node);
252 },
253 .block => {
254 const block = @fieldParentPtr(Block, "base", scope);
255 return block.statements.append(node);
256 },
265257 else => scope = scope.parent.?,
266258 }
267259 }
......@@ -271,18 +263,12 @@ const Scope = struct {
271263pub const Context = struct {
272264 gpa: *mem.Allocator,
273265 arena: *mem.Allocator,
274 token_ids: std.ArrayListUnmanaged(Token.Id) = .{},
275 token_locs: std.ArrayListUnmanaged(Token.Loc) = .{},
276 errors: std.ArrayListUnmanaged(ast.Error) = .{},
277 source_buffer: *std.ArrayList(u8),
278 err: Error,
279266 source_manager: *clang.SourceManager,
280267 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},
281268 alias_list: AliasList,
282269 global_scope: *Scope.Root,
283270 clang_context: *clang.ASTContext,
284271 mangle_count: u32 = 0,
285 root_decls: std.ArrayListUnmanaged(*ast.Node) = .{},
286272 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
287273
288274 /// This one is different than the root scope's name table. This contains
......@@ -311,90 +297,15 @@ pub const Context = struct {
311297 const column = c.source_manager.getSpellingColumnNumber(spelling_loc);
312298 return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });
313299 }
314
315 fn createCall(c: *Context, fn_expr: *ast.Node, params_len: ast.NodeIndex) !*ast.Node.Call {
316 _ = try appendToken(c, .LParen, "(");
317 const node = try ast.Node.Call.alloc(c.arena, params_len);
318 node.* = .{
319 .lhs = fn_expr,
320 .params_len = params_len,
321 .async_token = null,
322 .rtoken = undefined, // set after appending args
323 };
324 return node;
325 }
326
327 fn createBuiltinCall(c: *Context, name: []const u8, params_len: ast.NodeIndex) !*ast.Node.BuiltinCall {
328 const builtin_token = try appendToken(c, .Builtin, name);
329 _ = try appendToken(c, .LParen, "(");
330 const node = try ast.Node.BuiltinCall.alloc(c.arena, params_len);
331 node.* = .{
332 .builtin_token = builtin_token,
333 .params_len = params_len,
334 .rparen_token = undefined, // set after appending args
335 };
336 return node;
337 }
338
339 fn createBlock(c: *Context, statements_len: ast.NodeIndex) !*ast.Node.Block {
340 const block_node = try ast.Node.Block.alloc(c.arena, statements_len);
341 block_node.* = .{
342 .lbrace = try appendToken(c, .LBrace, "{"),
343 .statements_len = statements_len,
344 .rbrace = undefined,
345 };
346 return block_node;
347 }
348300};
349301
350fn addCBuiltinsNamespace(c: *Context) Error!void {
351 // pub usingnamespace @import("std").c.builtins;
352 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
353 const use_tok = try appendToken(c, .Keyword_usingnamespace, "usingnamespace");
354 const import_tok = try appendToken(c, .Builtin, "@import");
355 const lparen_tok = try appendToken(c, .LParen, "(");
356 const std_tok = try appendToken(c, .StringLiteral, "\"std\"");
357 const rparen_tok = try appendToken(c, .RParen, ")");
358
359 const std_node = try c.arena.create(ast.Node.OneToken);
360 std_node.* = .{
361 .base = .{ .tag = .StringLiteral },
362 .token = std_tok,
363 };
364
365 const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
366 call_node.* = .{
367 .builtin_token = import_tok,
368 .params_len = 1,
369 .rparen_token = rparen_tok,
370 };
371 call_node.params()[0] = &std_node.base;
372
373 var access_chain = &call_node.base;
374 access_chain = try transCreateNodeFieldAccess(c, access_chain, "c");
375 access_chain = try transCreateNodeFieldAccess(c, access_chain, "builtins");
376
377 const semi_tok = try appendToken(c, .Semicolon, ";");
378
379 const bytes = try c.gpa.alignedAlloc(u8, @alignOf(ast.Node.Use), @sizeOf(ast.Node.Use));
380 const using_node = @ptrCast(*ast.Node.Use, bytes.ptr);
381 using_node.* = .{
382 .doc_comments = null,
383 .visib_token = pub_tok,
384 .use_token = use_tok,
385 .expr = access_chain,
386 .semicolon_token = semi_tok,
387 };
388 try c.root_decls.append(c.gpa, &using_node.base);
389}
390
391302pub fn translate(
392303 gpa: *mem.Allocator,
393304 args_begin: [*]?[*]const u8,
394305 args_end: [*]?[*]const u8,
395306 errors: *[]ClangErrMsg,
396307 resources_path: [*:0]const u8,
397) !ast.Tree {
308) !std.zig.ast.Tree {
398309 const ast_unit = clang.LoadFromCommandLine(
399310 args_begin,
400311 args_end,
......@@ -407,28 +318,15 @@ pub fn translate(
407318 };
408319 defer ast_unit.delete();
409320
410 var source_buffer = std.ArrayList(u8).init(gpa);
411 defer source_buffer.deinit();
412
413321 // For memory that has the same lifetime as the Tree that we return
414322 // from this function.
415323 var arena = std.heap.ArenaAllocator.init(gpa);
416324 errdefer arena.deinit();
417325
418 if (true) {
419 var x = false;
420 if (x) {
421 return error.OutOfMemory;
422 }
423 @panic("TODO update translate-c");
424 }
425
426326 var context = Context{
427327 .gpa = gpa,
428328 .arena = &arena.allocator,
429 .source_buffer = &source_buffer,
430329 .source_manager = ast_unit.getSourceManager(),
431 .err = undefined,
432330 .alias_list = AliasList.init(gpa),
433331 .global_scope = try arena.allocator.create(Scope.Root),
434332 .clang_context = ast_unit.getASTContext(),
......@@ -437,20 +335,17 @@ pub fn translate(
437335 defer {
438336 context.decl_table.deinit(gpa);
439337 context.alias_list.deinit();
440 context.token_ids.deinit(gpa);
441 context.token_locs.deinit(gpa);
442 context.errors.deinit(gpa);
443338 context.global_names.deinit(gpa);
444 context.root_decls.deinit(gpa);
445339 context.opaque_demotes.deinit(gpa);
340 context.global_scope.deinit();
446341 }
447342
448 try addCBuiltinsNamespace(&context);
343 try context.global_scope.nodes.append(Tag.usingnamespace_builtins.init());
449344
450345 try prepopulateGlobalNameTable(ast_unit, &context);
451346
452347 if (!ast_unit.visitLocalTopLevelDecls(&context, declVisitorC)) {
453 return context.err;
348 return error.OutOfMemory;
454349 }
455350
456351 try transPreprocessorEntities(&context, ast_unit);
......@@ -458,38 +353,17 @@ pub fn translate(
458353 try addMacros(&context);
459354 for (context.alias_list.items) |alias| {
460355 if (!context.global_scope.sym_table.contains(alias.alias)) {
461 try createAlias(&context, alias);
462 }
463 }
464
465 const eof_token = try appendToken(&context, .Eof, "");
466 const root_node = try ast.Node.Root.create(&arena.allocator, context.root_decls.items.len, eof_token);
467 mem.copy(*ast.Node, root_node.decls(), context.root_decls.items);
468
469 if (false) {
470 std.debug.warn("debug source:\n{s}\n==EOF==\ntokens:\n", .{source_buffer.items});
471 for (context.token_ids.items) |token| {
472 std.debug.warn("{}\n", .{token});
356 const node = try Tag.alias.create(context.arena, .{ .actual = alias.alias, .mangled = alias.name });
357 try addTopLevelDecl(&context, alias.alias, node);
473358 }
474359 }
475360
476 const tree = try arena.allocator.create(ast.Tree);
477 tree.* = .{
478 .gpa = gpa,
479 .source = try arena.allocator.dupe(u8, source_buffer.items),
480 .token_ids = context.token_ids.toOwnedSlice(gpa),
481 .token_locs = context.token_locs.toOwnedSlice(gpa),
482 .errors = context.errors.toOwnedSlice(gpa),
483 .root_node = root_node,
484 .arena = arena.state,
485 .generated = true,
486 };
487 return tree;
361 return ast.render(gpa, context.global_scope.nodes.items);
488362}
489363
490364fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
491365 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
492 return c.err;
366 return error.OutOfMemory;
493367 }
494368
495369 // TODO if we see #undef, delete it from the table
......@@ -512,19 +386,13 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
512386
513387fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {
514388 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
515 declVisitorNamesOnly(c, decl) catch |err| {
516 c.err = err;
517 return false;
518 };
389 declVisitorNamesOnly(c, decl) catch return false;
519390 return true;
520391}
521392
522393fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {
523394 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
524 declVisitor(c, decl) catch |err| {
525 c.err = err;
526 return false;
527 };
395 declVisitor(c, decl) catch return false;
528396 return true;
529397}
530398
......@@ -541,13 +409,13 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
541409 return visitFnDecl(c, @ptrCast(*const clang.FunctionDecl, decl));
542410 },
543411 .Typedef => {
544 _ = try transTypeDef(c, @ptrCast(*const clang.TypedefNameDecl, decl), true);
412 try transTypeDef(c, &c.global_scope.base, @ptrCast(*const clang.TypedefNameDecl, decl));
545413 },
546414 .Enum => {
547 _ = try transEnumDecl(c, @ptrCast(*const clang.EnumDecl, decl));
415 try transEnumDecl(c, &c.global_scope.base, @ptrCast(*const clang.EnumDecl, decl));
548416 },
549417 .Record => {
550 _ = try transRecordDecl(c, @ptrCast(*const clang.RecordDecl, decl));
418 try transRecordDecl(c, &c.global_scope.base, @ptrCast(*const clang.RecordDecl, decl));
551419 },
552420 .Var => {
553421 return visitVarDecl(c, @ptrCast(*const clang.VarDecl, decl), null);
......@@ -557,7 +425,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
557425 },
558426 else => {
559427 const decl_name = try c.str(decl.getDeclKindName());
560 try emitWarning(c, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
428 try warn(c, &c.global_scope.base, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
561429 },
562430 }
563431}
......@@ -573,7 +441,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
573441 return visitFnDecl(c, def);
574442 }
575443
576 const rp = makeRestorePoint(c);
577444 const fn_decl_loc = fn_decl.getLocation();
578445 const has_body = fn_decl.hasBody();
579446 const storage_class = fn_decl.getStorageClass();
......@@ -617,9 +484,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
617484 decl_ctx.has_body = false;
618485 decl_ctx.storage_class = .Extern;
619486 decl_ctx.is_export = false;
620 try emitWarning(c, fn_decl_loc, "TODO unable to translate variadic function, demoted to declaration", .{});
487 try warn(c, &c.global_scope.base, fn_decl_loc, "TODO unable to translate variadic function, demoted to extern", .{});
621488 }
622 break :blk transFnProto(rp, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
489 break :blk transFnProto(c, fn_decl, fn_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
623490 error.UnsupportedType => {
624491 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
625492 },
......@@ -628,7 +495,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
628495 },
629496 .FunctionNoProto => blk: {
630497 const fn_no_proto_type = @ptrCast(*const clang.FunctionType, fn_type);
631 break :blk transFnNoProto(rp, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
498 break :blk transFnNoProto(c, fn_no_proto_type, fn_decl_loc, decl_ctx, true) catch |err| switch (err) {
632499 error.UnsupportedType => {
633500 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
634501 },
......@@ -639,124 +506,99 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
639506 };
640507
641508 if (!decl_ctx.has_body) {
642 const semi_tok = try appendToken(c, .Semicolon, ";");
643 return addTopLevelDecl(c, fn_name, &proto_node.base);
509 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
644510 }
645511
646512 // actual function definition with body
647513 const body_stmt = fn_decl.getBody();
648 var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false);
514 var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
649515 block_scope.return_type = return_qt;
650516 defer block_scope.deinit();
651517
652518 var scope = &block_scope.base;
653519
654520 var param_id: c_uint = 0;
655 for (proto_node.params()) |*param, i| {
656 const param_name = if (param.name_token) |name_tok|
657 tokenSlice(c, name_tok)
658 else
659 return failDecl(c, fn_decl_loc, fn_name, "function {s} parameter has no name", .{fn_name});
521 for (proto_node.data.params) |*param, i| {
522 const param_name = param.name orelse {
523 proto_node.data.is_extern = true;
524 proto_node.data.is_export = false;
525 try warn(c, &c.global_scope.base, fn_decl_loc, "function {s} parameter has no name, demoted to extern", .{fn_name});
526 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
527 };
660528
661529 const c_param = fn_decl.getParamDecl(param_id);
662530 const qual_type = c_param.getOriginalType();
663531 const is_const = qual_type.isConstQualified();
664532
665533 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
534 param.name = mangled_param_name;
666535
667536 if (!is_const) {
668537 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});
669538 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);
539 param.name = arg_name;
670540
671 const mut_tok = try appendToken(c, .Keyword_var, "var");
672 const name_tok = try appendIdentifier(c, mangled_param_name);
673 const eq_token = try appendToken(c, .Equal, "=");
674 const init_node = try transCreateNodeIdentifier(c, arg_name);
675 const semicolon_token = try appendToken(c, .Semicolon, ";");
676 const node = try ast.Node.VarDecl.create(c.arena, .{
677 .mut_token = mut_tok,
678 .name_token = name_tok,
679 .semicolon_token = semicolon_token,
680 }, .{
681 .eq_token = eq_token,
682 .init_node = init_node,
683 });
684 try block_scope.statements.append(&node.base);
685 param.name_token = try appendIdentifier(c, arg_name);
686 _ = try appendToken(c, .Colon, ":");
541 const redecl_node = try Tag.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
542 try block_scope.statements.append(redecl_node);
687543 }
688544
689545 param_id += 1;
690546 }
691547
692548 const casted_body = @ptrCast(*const clang.CompoundStmt, body_stmt);
693 transCompoundStmtInline(rp, &block_scope.base, casted_body, &block_scope) catch |err| switch (err) {
549 transCompoundStmtInline(c, casted_body, &block_scope) catch |err| switch (err) {
694550 error.OutOfMemory => |e| return e,
695551 error.UnsupportedTranslation,
696552 error.UnsupportedType,
697 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
553 => {
554 proto_node.data.is_extern = true;
555 proto_node.data.is_export = false;
556 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to translate function, demoted to extern", .{});
557 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
558 },
698559 };
699560 // add return statement if the function didn't have one
700561 blk: {
701 if (fn_ty.getNoReturnAttr()) break :blk;
702 if (isCVoid(return_qt)) break :blk;
703
704 if (block_scope.statements.items.len > 0) {
705 var last = block_scope.statements.items[block_scope.statements.items.len - 1];
706 while (true) {
707 switch (last.tag) {
708 .Block, .LabeledBlock => {
709 const stmts = last.blockStatements();
710 if (stmts.len == 0) break;
711
712 last = stmts[stmts.len - 1];
713 },
714 // no extra return needed
715 .Return => break :blk,
716 else => break,
717 }
718 }
562 const maybe_body = try block_scope.complete(c);
563 if (fn_ty.getNoReturnAttr() or isCVoid(return_qt) or maybe_body.isNoreturn(false)) {
564 proto_node.data.body = maybe_body;
565 break :blk;
719566 }
720567
721 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
722 .ltoken = try appendToken(rp.c, .Keyword_return, "return"),
723 .tag = .Return,
724 }, .{
725 .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
726 error.OutOfMemory => |e| return e,
727 error.UnsupportedTranslation,
728 error.UnsupportedType,
729 => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
568 const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
569 error.OutOfMemory => |e| return e,
570 error.UnsupportedTranslation,
571 error.UnsupportedType,
572 => {
573 proto_node.data.is_extern = true;
574 proto_node.data.is_export = false;
575 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to create a return value for function, demoted to extern", .{});
576 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
730577 },
731 });
732 _ = try appendToken(rp.c, .Semicolon, ";");
733 try block_scope.statements.append(&return_expr.base);
578 };
579 const ret = try Tag.@"return".create(c.arena, rhs);
580 try block_scope.statements.append(ret);
581 proto_node.data.body = try block_scope.complete(c);
734582 }
735583
736 const body_node = try block_scope.complete(rp.c);
737 proto_node.setBodyNode(body_node);
738 return addTopLevelDecl(c, fn_name, &proto_node.base);
584 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
739585}
740586
741fn transQualTypeMaybeInitialized(rp: RestorePoint, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!*ast.Node {
587fn transQualTypeMaybeInitialized(c: *Context, scope: *Scope, qt: clang.QualType, decl_init: ?*const clang.Expr, loc: clang.SourceLocation) TransError!Node {
742588 return if (decl_init) |init_expr|
743 transQualTypeInitialized(rp, qt, init_expr, loc)
589 transQualTypeInitialized(c, scope, qt, init_expr, loc)
744590 else
745 transQualType(rp, qt, loc);
591 transQualType(c, scope, qt, loc);
746592}
593
747594/// if mangled_name is not null, this var decl was declared in a block scope.
748595fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void {
749596 const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());
750597 if (c.global_scope.sym_table.contains(var_name))
751598 return; // Avoid processing this decl twice
752 const rp = makeRestorePoint(c);
753 const visib_tok = if (mangled_name) |_| null else try appendToken(c, .Keyword_pub, "pub");
754
755 const thread_local_token = if (var_decl.getTLSKind() == .None)
756 null
757 else
758 try appendToken(c, .Keyword_threadlocal, "threadlocal");
759599
600 const is_pub = mangled_name == null;
601 const is_threadlocal = var_decl.getTLSKind() != .None;
760602 const scope = &c.global_scope.base;
761603
762604 // TODO https://github.com/ziglang/zig/issues/3756
......@@ -775,211 +617,148 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
775617 // does the same as:
776618 // extern int foo;
777619 // int foo = 2;
778 const extern_tok = if (storage_class == .Extern and !has_init)
779 try appendToken(c, .Keyword_extern, "extern")
780 else if (storage_class != .Static)
781 try appendToken(c, .Keyword_export, "export")
782 else
783 null;
784
785 const mut_tok = if (is_const)
786 try appendToken(c, .Keyword_const, "const")
787 else
788 try appendToken(c, .Keyword_var, "var");
789
790 const name_tok = try appendIdentifier(c, checked_name);
620 var is_extern = storage_class == .Extern and !has_init;
621 var is_export = !is_extern and storage_class != .Static;
791622
792 _ = try appendToken(c, .Colon, ":");
793
794 const type_node = transQualTypeMaybeInitialized(rp, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
623 const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
795624 error.UnsupportedTranslation, error.UnsupportedType => {
796625 return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{});
797626 },
798627 error.OutOfMemory => |e| return e,
799628 };
800629
801 var eq_tok: ast.TokenIndex = undefined;
802 var init_node: ?*ast.Node = null;
630 var init_node: ?Node = null;
803631
804632 // If the initialization expression is not present, initialize with undefined.
805633 // If it is an integer literal, we can skip the @as since it will be redundant
806634 // with the variable type.
807 if (has_init) {
808 eq_tok = try appendToken(c, .Equal, "=");
635 if (has_init) trans_init: {
809636 if (decl_init) |expr| {
810637 const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)
811 transStringLiteralAsArray(rp, &c.global_scope.base, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(rp.c, type_node) catch 0)
638 transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(c, type_node) catch 0)
812639 else
813 transExprCoercing(rp, scope, expr, .used, .r_value);
640 transExprCoercing(c, scope, expr, .used);
814641 init_node = node_or_error catch |err| switch (err) {
815642 error.UnsupportedTranslation,
816643 error.UnsupportedType,
817644 => {
818 return failDecl(c, var_decl_loc, checked_name, "unable to translate initializer", .{});
645 is_extern = true;
646 is_export = false;
647 try warn(c, scope, var_decl_loc, "unable to translate variable initializer, demoted to extern", .{});
648 break :trans_init;
819649 },
820650 error.OutOfMemory => |e| return e,
821651 };
652 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node.?)) {
653 init_node = try Tag.bool_to_int.create(c.arena, init_node.?);
654 }
822655 } else {
823 init_node = try transCreateNodeUndefinedLiteral(c);
656 init_node = Tag.undefined_literal.init();
824657 }
825658 } else if (storage_class != .Extern) {
826 eq_tok = try appendToken(c, .Equal, "=");
827659 // The C language specification states that variables with static or threadlocal
828660 // storage without an initializer are initialized to a zero value.
829661
830662 // @import("std").mem.zeroes(T)
831 const import_fn_call = try c.createBuiltinCall("@import", 1);
832 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
833 import_fn_call.params()[0] = std_node;
834 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
835 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem");
836 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroes");
837
838 const zero_init_call = try c.createCall(outer_field_access, 1);
839 zero_init_call.params()[0] = type_node;
840 zero_init_call.rtoken = try appendToken(c, .RParen, ")");
841
842 init_node = &zero_init_call.base;
663 init_node = try Tag.std_mem_zeroes.create(c.arena, type_node);
843664 }
844665
845 const linksection_expr = blk: {
666 const linksection_string = blk: {
846667 var str_len: usize = undefined;
847668 if (var_decl.getSectionAttribute(&str_len)) |str_ptr| {
848 _ = try appendToken(rp.c, .Keyword_linksection, "linksection");
849 _ = try appendToken(rp.c, .LParen, "(");
850 const expr = try transCreateNodeStringLiteral(
851 rp.c,
852 try std.fmt.allocPrint(rp.c.arena, "\"{s}\"", .{str_ptr[0..str_len]}),
853 );
854 _ = try appendToken(rp.c, .RParen, ")");
855
856 break :blk expr;
669 break :blk str_ptr[0..str_len];
857670 }
858671 break :blk null;
859672 };
860673
861 const align_expr = blk: {
862 const alignment = var_decl.getAlignedAttribute(rp.c.clang_context);
674 const alignment = blk: {
675 const alignment = var_decl.getAlignedAttribute(c.clang_context);
863676 if (alignment != 0) {
864 _ = try appendToken(rp.c, .Keyword_align, "align");
865 _ = try appendToken(rp.c, .LParen, "(");
866677 // Clang reports the alignment in bits
867 const expr = try transCreateNodeInt(rp.c, alignment / 8);
868 _ = try appendToken(rp.c, .RParen, ")");
869
870 break :blk expr;
678 break :blk alignment / 8;
871679 }
872680 break :blk null;
873681 };
874682
875 const node = try ast.Node.VarDecl.create(c.arena, .{
876 .name_token = name_tok,
877 .mut_token = mut_tok,
878 .semicolon_token = try appendToken(c, .Semicolon, ";"),
879 }, .{
880 .visib_token = visib_tok,
881 .thread_local_token = thread_local_token,
882 .eq_token = eq_tok,
883 .extern_export_token = extern_tok,
884 .type_node = type_node,
885 .align_node = align_expr,
886 .section_node = linksection_expr,
887 .init_node = init_node,
683 const node = try Tag.var_decl.create(c.arena, .{
684 .is_pub = is_pub,
685 .is_const = is_const,
686 .is_extern = is_extern,
687 .is_export = is_export,
688 .is_threadlocal = is_threadlocal,
689 .linksection_string = linksection_string,
690 .alignment = alignment,
691 .name = checked_name,
692 .type = type_node,
693 .init = init_node,
888694 });
889 return addTopLevelDecl(c, checked_name, &node.base);
890}
891
892fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !*ast.Node {
893 _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name);
894 return transCreateNodeIdentifier(c, builtin_name);
895}
896
897fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {
898 const table = [_][2][]const u8{
899 .{ "uint8_t", "u8" },
900 .{ "int8_t", "i8" },
901 .{ "uint16_t", "u16" },
902 .{ "int16_t", "i16" },
903 .{ "uint32_t", "u32" },
904 .{ "int32_t", "i32" },
905 .{ "uint64_t", "u64" },
906 .{ "int64_t", "i64" },
907 .{ "intptr_t", "isize" },
908 .{ "uintptr_t", "usize" },
909 .{ "ssize_t", "isize" },
910 .{ "size_t", "usize" },
911 };
912
913 for (table) |entry| {
914 if (mem.eql(u8, checked_name, entry[0])) {
915 return entry[1];
916 }
917 }
918
919 return null;
920}
695 return addTopLevelDecl(c, checked_name, node);
696}
697
698const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{
699 .{ "uint8_t", "u8" },
700 .{ "int8_t", "i8" },
701 .{ "uint16_t", "u16" },
702 .{ "int16_t", "i16" },
703 .{ "uint32_t", "u32" },
704 .{ "int32_t", "i32" },
705 .{ "uint64_t", "u64" },
706 .{ "int64_t", "i64" },
707 .{ "intptr_t", "isize" },
708 .{ "uintptr_t", "usize" },
709 .{ "ssize_t", "isize" },
710 .{ "size_t", "usize" },
711});
921712
922fn transTypeDef(c: *Context, typedef_decl: *const clang.TypedefNameDecl, top_level_visit: bool) Error!?*ast.Node {
713fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: *const clang.TypedefNameDecl) Error!void {
923714 if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name|
924 return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
925 const rp = makeRestorePoint(c);
715 return; // Avoid processing this decl twice
716 const toplevel = scope.id == .root;
717 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
926718
927 const typedef_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
719 const bare_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
928720
929721 // TODO https://github.com/ziglang/zig/issues/3756
930722 // TODO https://github.com/ziglang/zig/issues/1802
931 const checked_name = if (isZigPrimitiveType(typedef_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ typedef_name, c.getMangle() }) else typedef_name;
932 if (checkForBuiltinTypedef(checked_name)) |builtin| {
933 return transTypeDefAsBuiltin(c, typedef_decl, builtin);
723 var name: []const u8 = if (isZigPrimitiveType(bare_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ bare_name, c.getMangle() }) else bare_name;
724 if (builtin_typedef_map.get(name)) |builtin| {
725 return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
934726 }
727 if (!toplevel) name = try bs.makeMangledName(c, name);
728 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
935729
936 if (!top_level_visit) {
937 return transCreateNodeIdentifier(c, checked_name);
938 }
939
940 _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), checked_name);
941 const node = (try transCreateNodeTypedef(rp, typedef_decl, true, checked_name)) orelse return null;
942 try addTopLevelDecl(c, checked_name, node);
943 return transCreateNodeIdentifier(c, checked_name);
944}
945
946fn transCreateNodeTypedef(
947 rp: RestorePoint,
948 typedef_decl: *const clang.TypedefNameDecl,
949 toplevel: bool,
950 checked_name: []const u8,
951) Error!?*ast.Node {
952 const visib_tok = if (toplevel) try appendToken(rp.c, .Keyword_pub, "pub") else null;
953 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
954 const name_tok = try appendIdentifier(rp.c, checked_name);
955 const eq_token = try appendToken(rp.c, .Equal, "=");
956730 const child_qt = typedef_decl.getUnderlyingType();
957731 const typedef_loc = typedef_decl.getLocation();
958 const init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
732 const init_node = transQualType(c, scope, child_qt, typedef_loc) catch |err| switch (err) {
959733 error.UnsupportedType => {
960 try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});
961 return null;
734 return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{});
962735 },
963736 error.OutOfMemory => |e| return e,
964737 };
965 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
966
967 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
968 .name_token = name_tok,
969 .mut_token = mut_tok,
970 .semicolon_token = semicolon_token,
971 }, .{
972 .visib_token = visib_tok,
973 .eq_token = eq_token,
974 .init_node = init_node,
975 });
976 return &node.base;
738
739 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
740 payload.* = .{
741 .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(toplevel)] },
742 .data = .{
743 .name = name,
744 .init = init_node,
745 },
746 };
747 const node = Node.initPayload(&payload.base);
748
749 if (toplevel) {
750 try addTopLevelDecl(c, name, node);
751 } else {
752 try scope.appendNode(node);
753 }
977754}
978755
979fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*ast.Node {
756fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void {
980757 if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name|
981 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
758 return; // Avoid processing this decl twice
982759 const record_loc = record_decl.getLocation();
760 const toplevel = scope.id == .root;
761 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
983762
984763 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
985764 var is_unnamed = false;
......@@ -991,46 +770,31 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as
991770 }
992771
993772 var container_kind_name: []const u8 = undefined;
994 var container_kind: std.zig.Token.Id = undefined;
773 var is_union = false;
995774 if (record_decl.isUnion()) {
996775 container_kind_name = "union";
997 container_kind = .Keyword_union;
776 is_union = true;
998777 } else if (record_decl.isStruct()) {
999778 container_kind_name = "struct";
1000 container_kind = .Keyword_struct;
1001779 } else {
1002 try emitWarning(c, record_loc, "record {s} is not a struct or union", .{bare_name});
1003 return null;
780 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), bare_name);
781 return failDecl(c, record_loc, bare_name, "record {s} is not a struct or union", .{bare_name});
1004782 }
1005783
1006 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
1007 _ = try c.decl_table.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
1008
1009 const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
1010 const mut_tok = try appendToken(c, .Keyword_const, "const");
1011 const name_tok = try appendIdentifier(c, name);
784 var name: []const u8 = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
785 if (!toplevel) name = try bs.makeMangledName(c, name);
786 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
1012787
1013 const eq_token = try appendToken(c, .Equal, "=");
1014
1015 var semicolon: ast.TokenIndex = undefined;
788 const is_pub = toplevel and !is_unnamed;
1016789 const init_node = blk: {
1017 const rp = makeRestorePoint(c);
1018790 const record_def = record_decl.getDefinition() orelse {
1019791 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1020 const opaque_type = try transCreateNodeOpaqueType(c);
1021 semicolon = try appendToken(c, .Semicolon, ";");
1022 break :blk opaque_type;
792 break :blk Tag.opaque_literal.init();
1023793 };
1024794
1025 const layout_tok = try if (record_decl.getPackedAttribute())
1026 appendToken(c, .Keyword_packed, "packed")
1027 else
1028 appendToken(c, .Keyword_extern, "extern");
1029 const container_tok = try appendToken(c, container_kind, container_kind_name);
1030 const lbrace_token = try appendToken(c, .LBrace, "{");
1031
1032 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
1033 defer fields_and_decls.deinit();
795 const is_packed = record_decl.getPackedAttribute();
796 var fields = std.ArrayList(ast.Payload.Record.Field).init(c.gpa);
797 defer fields.deinit();
1034798
1035799 var unnamed_field_count: u32 = 0;
1036800 var it = record_def.field_begin();
......@@ -1042,111 +806,88 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as
1042806
1043807 if (field_decl.isBitField()) {
1044808 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1045 const opaque_type = try transCreateNodeOpaqueType(c);
1046 semicolon = try appendToken(c, .Semicolon, ";");
1047 try emitWarning(c, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
1048 break :blk opaque_type;
809 try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
810 break :blk Tag.opaque_literal.init();
1049811 }
1050812
1051813 if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) {
1052814 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1053 const opaque_type = try transCreateNodeOpaqueType(c);
1054 semicolon = try appendToken(c, .Semicolon, ";");
1055 try emitWarning(c, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
1056 break :blk opaque_type;
815 try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
816 break :blk Tag.opaque_literal.init();
1057817 }
1058818
1059819 var is_anon = false;
1060 var raw_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
1061 if (field_decl.isAnonymousStructOrUnion() or raw_name.len == 0) {
820 var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
821 if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {
1062822 // Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields.
1063 raw_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{unnamed_field_count});
823 field_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{unnamed_field_count});
1064824 unnamed_field_count += 1;
1065825 is_anon = true;
1066826 }
1067 const field_name = try appendIdentifier(c, raw_name);
1068 _ = try appendToken(c, .Colon, ":");
1069 const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
827 const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) {
1070828 error.UnsupportedType => {
1071829 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1072 const opaque_type = try transCreateNodeOpaqueType(c);
1073 semicolon = try appendToken(c, .Semicolon, ";");
1074 try emitWarning(c, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, raw_name });
1075 break :blk opaque_type;
830 try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name });
831 break :blk Tag.opaque_literal.init();
1076832 },
1077833 else => |e| return e,
1078834 };
1079835
1080 const align_expr = blk_2: {
836 const alignment = blk_2: {
1081837 const alignment = field_decl.getAlignedAttribute(c.clang_context);
1082838 if (alignment != 0) {
1083 _ = try appendToken(c, .Keyword_align, "align");
1084 _ = try appendToken(c, .LParen, "(");
1085839 // Clang reports the alignment in bits
1086 const expr = try transCreateNodeInt(c, alignment / 8);
1087 _ = try appendToken(c, .RParen, ")");
1088
1089 break :blk_2 expr;
840 break :blk_2 alignment / 8;
1090841 }
1091842 break :blk_2 null;
1092843 };
1093844
1094 const field_node = try c.arena.create(ast.Node.ContainerField);
1095 field_node.* = .{
1096 .doc_comments = null,
1097 .comptime_token = null,
1098 .name_token = field_name,
1099 .type_expr = field_type,
1100 .value_expr = null,
1101 .align_expr = align_expr,
1102 };
1103
1104845 if (is_anon) {
1105 _ = try c.decl_table.put(
1106 c.gpa,
1107 @ptrToInt(field_decl.getCanonicalDecl()),
1108 raw_name,
1109 );
846 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name);
1110847 }
1111848
1112 try fields_and_decls.append(&field_node.base);
1113 _ = try appendToken(c, .Comma, ",");
849 try fields.append(.{
850 .name = field_name,
851 .type = field_type,
852 .alignment = alignment,
853 });
1114854 }
1115 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
1116 container_node.* = .{
1117 .layout_token = layout_tok,
1118 .kind_token = container_tok,
1119 .init_arg_expr = .None,
1120 .fields_and_decls_len = fields_and_decls.items.len,
1121 .lbrace_token = lbrace_token,
1122 .rbrace_token = try appendToken(c, .RBrace, "}"),
855
856 const record_payload = try c.arena.create(ast.Payload.Record);
857 record_payload.* = .{
858 .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] },
859 .data = .{
860 .is_packed = is_packed,
861 .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items),
862 },
1123863 };
1124 mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);
1125 semicolon = try appendToken(c, .Semicolon, ";");
1126 break :blk &container_node.base;
864 break :blk Node.initPayload(&record_payload.base);
1127865 };
1128866
1129 const node = try ast.Node.VarDecl.create(c.arena, .{
1130 .name_token = name_tok,
1131 .mut_token = mut_tok,
1132 .semicolon_token = semicolon,
1133 }, .{
1134 .visib_token = visib_tok,
1135 .eq_token = eq_token,
1136 .init_node = init_node,
1137 });
867 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
868 payload.* = .{
869 .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
870 .data = .{
871 .name = name,
872 .init = init_node,
873 },
874 };
1138875
1139 try addTopLevelDecl(c, name, &node.base);
1140 if (!is_unnamed)
1141 try c.alias_list.append(.{ .alias = bare_name, .name = name });
1142 return transCreateNodeIdentifier(c, name);
876 if (toplevel) {
877 try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
878 if (!is_unnamed)
879 try c.alias_list.append(.{ .alias = bare_name, .name = name });
880 } else {
881 try scope.appendNode(Node.initPayload(&payload.base));
882 }
1143883}
1144884
1145fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node {
885fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) Error!void {
1146886 if (c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |name|
1147 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice
1148 const rp = makeRestorePoint(c);
887 return; // Avoid processing this decl twice
1149888 const enum_loc = enum_decl.getLocation();
889 const toplevel = scope.id == .root;
890 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
1150891
1151892 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
1152893 var is_unnamed = false;
......@@ -1155,13 +896,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1155896 is_unnamed = true;
1156897 }
1157898
1158 const name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
1159 _ = try c.decl_table.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
899 var name: []const u8 = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
900 if (!toplevel) _ = try bs.makeMangledName(c, name);
901 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
1160902
1161 const visib_tok = if (!is_unnamed) try appendToken(c, .Keyword_pub, "pub") else null;
1162 const mut_tok = try appendToken(c, .Keyword_const, "const");
1163 const name_tok = try appendIdentifier(c, name);
1164 const eq_token = try appendToken(c, .Equal, "=");
903 const is_pub = toplevel and !is_unnamed;
904 var redecls = std.ArrayList(Tag.enum_redecl.Data()).init(c.gpa);
905 defer redecls.deinit();
1165906
1166907 const init_node = if (enum_decl.getDefinition()) |enum_def| blk: {
1167908 var pure_enum = true;
......@@ -1175,11 +916,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1175916 }
1176917 }
1177918
1178 const extern_tok = try appendToken(c, .Keyword_extern, "extern");
1179 const container_tok = try appendToken(c, .Keyword_enum, "enum");
1180
1181 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
1182 defer fields_and_decls.deinit();
919 var fields = std.ArrayList(ast.Payload.Enum.Field).init(c.gpa);
920 defer fields.deinit();
1183921
1184922 const int_type = enum_decl.getIntegerType();
1185923 // The underlying type may be null in case of forward-declared enum
......@@ -1187,30 +925,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1187925 // default to the usual integer type used for all the enums.
1188926
1189927 // default to c_int since msvc and gcc default to different types
1190 _ = try appendToken(c, .LParen, "(");
1191 const init_arg_expr = ast.Node.ContainerDecl.InitArg{
1192 .Type = if (int_type.ptr != null and
1193 !isCBuiltinType(int_type, .UInt) and
1194 !isCBuiltinType(int_type, .Int))
1195 transQualType(rp, int_type, enum_loc) catch |err| switch (err) {
1196 error.UnsupportedType => {
1197 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
1198 return null;
1199 },
1200 else => |e| return e,
1201 }
1202 else
1203 try transCreateNodeIdentifier(c, "c_int"),
1204 };
1205 _ = try appendToken(c, .RParen, ")");
1206
1207 const lbrace_token = try appendToken(c, .LBrace, "{");
928 const init_arg_expr = if (int_type.ptr != null and
929 !isCBuiltinType(int_type, .UInt) and
930 !isCBuiltinType(int_type, .Int))
931 transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) {
932 error.UnsupportedType => {
933 return failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
934 },
935 else => |e| return e,
936 }
937 else
938 try Tag.type.create(c.arena, "c_int");
1208939
1209940 it = enum_def.enumerator_begin();
1210941 end_it = enum_def.enumerator_end();
1211942 while (it.neq(end_it)) : (it = it.next()) {
1212943 const enum_const = it.deref();
1213
1214944 const enum_val_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());
1215945
1216946 const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name))
......@@ -1218,123 +948,62 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1218948 else
1219949 enum_val_name;
1220950
1221 const field_name_tok = try appendIdentifier(c, field_name);
1222
1223 const int_node = if (!pure_enum) blk_2: {
1224 _ = try appendToken(c, .Colon, "=");
1225 break :blk_2 try transCreateNodeAPInt(c, enum_const.getInitVal());
1226 } else
951 const int_node = if (!pure_enum)
952 try transCreateNodeAPInt(c, enum_const.getInitVal())
953 else
1227954 null;
1228955
1229 const field_node = try c.arena.create(ast.Node.ContainerField);
1230 field_node.* = .{
1231 .doc_comments = null,
1232 .comptime_token = null,
1233 .name_token = field_name_tok,
1234 .type_expr = null,
1235 .value_expr = int_node,
1236 .align_expr = null,
1237 };
1238
1239 try fields_and_decls.append(&field_node.base);
1240 _ = try appendToken(c, .Comma, ",");
956 try fields.append(.{
957 .name = field_name,
958 .value = int_node,
959 });
1241960
1242961 // In C each enum value is in the global namespace. So we put them there too.
1243962 // At this point we can rely on the enum emitting successfully.
1244 const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");
1245 const tld_mut_tok = try appendToken(c, .Keyword_const, "const");
1246 const tld_name_tok = try appendIdentifier(c, enum_val_name);
1247 const tld_eq_token = try appendToken(c, .Equal, "=");
1248 const cast_node = try rp.c.createBuiltinCall("@enumToInt", 1);
1249 const enum_ident = try transCreateNodeIdentifier(c, name);
1250 const period_tok = try appendToken(c, .Period, ".");
1251 const field_ident = try transCreateNodeIdentifier(c, field_name);
1252 const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp);
1253 field_access_node.* = .{
1254 .base = .{ .tag = .Period },
1255 .op_token = period_tok,
1256 .lhs = enum_ident,
1257 .rhs = field_ident,
1258 };
1259 cast_node.params()[0] = &field_access_node.base;
1260 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1261 const tld_init_node = &cast_node.base;
1262 const tld_semicolon_token = try appendToken(c, .Semicolon, ";");
1263 const tld_node = try ast.Node.VarDecl.create(c.arena, .{
1264 .name_token = tld_name_tok,
1265 .mut_token = tld_mut_tok,
1266 .semicolon_token = tld_semicolon_token,
1267 }, .{
1268 .visib_token = tld_visib_tok,
1269 .eq_token = tld_eq_token,
1270 .init_node = tld_init_node,
963 try redecls.append(.{
964 .enum_val_name = enum_val_name,
965 .field_name = field_name,
966 .enum_name = name,
1271967 });
1272 try addTopLevelDecl(c, field_name, &tld_node.base);
1273968 }
1274 // make non exhaustive
1275 const field_node = try c.arena.create(ast.Node.ContainerField);
1276 field_node.* = .{
1277 .doc_comments = null,
1278 .comptime_token = null,
1279 .name_token = try appendIdentifier(c, "_"),
1280 .type_expr = null,
1281 .value_expr = null,
1282 .align_expr = null,
1283 };
1284969
1285 try fields_and_decls.append(&field_node.base);
1286 _ = try appendToken(c, .Comma, ",");
1287 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);
1288 container_node.* = .{
1289 .layout_token = extern_tok,
1290 .kind_token = container_tok,
1291 .init_arg_expr = init_arg_expr,
1292 .fields_and_decls_len = fields_and_decls.items.len,
1293 .lbrace_token = lbrace_token,
1294 .rbrace_token = try appendToken(c, .RBrace, "}"),
1295 };
1296 mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);
1297 break :blk &container_node.base;
970 break :blk try Tag.@"enum".create(c.arena, .{
971 .int_type = init_arg_expr,
972 .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items),
973 });
1298974 } else blk: {
1299975 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
1300 break :blk try transCreateNodeOpaqueType(c);
976 break :blk Tag.opaque_literal.init();
1301977 };
1302978
1303 const semicolon_token = try appendToken(c, .Semicolon, ";");
1304 const node = try ast.Node.VarDecl.create(c.arena, .{
1305 .name_token = name_tok,
1306 .mut_token = mut_tok,
1307 .semicolon_token = semicolon_token,
1308 }, .{
1309 .visib_token = visib_tok,
1310 .eq_token = eq_token,
1311 .init_node = init_node,
1312 });
979 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
980 payload.* = .{
981 .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
982 .data = .{
983 .name = name,
984 .init = init_node,
985 },
986 };
1313987
1314 try addTopLevelDecl(c, name, &node.base);
1315 if (!is_unnamed)
1316 try c.alias_list.append(.{ .alias = bare_name, .name = name });
1317 return transCreateNodeIdentifier(c, name);
1318}
1319
1320fn createAlias(c: *Context, alias: anytype) !void {
1321 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
1322 const mut_tok = try appendToken(c, .Keyword_const, "const");
1323 const name_tok = try appendIdentifier(c, alias.alias);
1324 const eq_token = try appendToken(c, .Equal, "=");
1325 const init_node = try transCreateNodeIdentifier(c, alias.name);
1326 const semicolon_token = try appendToken(c, .Semicolon, ";");
1327
1328 const node = try ast.Node.VarDecl.create(c.arena, .{
1329 .name_token = name_tok,
1330 .mut_token = mut_tok,
1331 .semicolon_token = semicolon_token,
1332 }, .{
1333 .visib_token = visib_tok,
1334 .eq_token = eq_token,
1335 .init_node = init_node,
1336 });
1337 return addTopLevelDecl(c, alias.alias, &node.base);
988 if (toplevel) {
989 try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
990 if (!is_unnamed)
991 try c.alias_list.append(.{ .alias = bare_name, .name = name });
992 } else {
993 try scope.appendNode(Node.initPayload(&payload.base));
994 }
995
996 for (redecls.items) |redecl| {
997 if (toplevel) {
998 try addTopLevelDecl(c, redecl.field_name, try Tag.pub_enum_redecl.create(c.arena, redecl));
999 } else {
1000 try scope.appendNode(try Tag.enum_redecl.create(c.arena, .{
1001 .enum_val_name = try bs.makeMangledName(c, redecl.enum_val_name),
1002 .field_name = redecl.field_name,
1003 .enum_name = redecl.enum_name,
1004 }));
1005 }
1006 }
13381007}
13391008
13401009const ResultUsed = enum {
......@@ -1342,317 +1011,252 @@ const ResultUsed = enum {
13421011 unused,
13431012};
13441013
1345const LRValue = enum {
1346 l_value,
1347 r_value,
1348};
1349
13501014fn transStmt(
1351 rp: RestorePoint,
1015 c: *Context,
13521016 scope: *Scope,
13531017 stmt: *const clang.Stmt,
13541018 result_used: ResultUsed,
1355 lrvalue: LRValue,
1356) TransError!*ast.Node {
1019) TransError!Node {
13571020 const sc = stmt.getStmtClass();
13581021 switch (sc) {
1359 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used),
1360 .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const clang.CompoundStmt, stmt)),
1361 .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue),
1362 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const clang.DeclStmt, stmt)),
1363 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue),
1364 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used),
1365 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as),
1366 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const clang.ReturnStmt, stmt)),
1367 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),
1022 .BinaryOperatorClass => return transBinaryOperator(c, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used),
1023 .CompoundStmtClass => return transCompoundStmt(c, scope, @ptrCast(*const clang.CompoundStmt, stmt)),
1024 .CStyleCastExprClass => return transCStyleCastExprClass(c, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used),
1025 .DeclStmtClass => return transDeclStmt(c, scope, @ptrCast(*const clang.DeclStmt, stmt)),
1026 .DeclRefExprClass => return transDeclRefExpr(c, scope, @ptrCast(*const clang.DeclRefExpr, stmt)),
1027 .ImplicitCastExprClass => return transImplicitCastExpr(c, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used),
1028 .IntegerLiteralClass => return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as),
1029 .ReturnStmtClass => return transReturnStmt(c, scope, @ptrCast(*const clang.ReturnStmt, stmt)),
1030 .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),
13681031 .ParenExprClass => {
1369 const expr = try transExpr(rp, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue);
1370 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1371 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1372 node.* = .{
1373 .lparen = try appendToken(rp.c, .LParen, "("),
1374 .expr = expr,
1375 .rparen = try appendToken(rp.c, .RParen, ")"),
1376 };
1377 return maybeSuppressResult(rp, scope, result_used, &node.base);
1378 },
1379 .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),
1380 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1381 .IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const clang.IfStmt, stmt)),
1382 .WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const clang.WhileStmt, stmt)),
1383 .DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const clang.DoStmt, stmt)),
1032 const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used);
1033 return maybeSuppressResult(c, scope, result_used, expr);
1034 },
1035 .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),
1036 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1037 .IfStmtClass => return transIfStmt(c, scope, @ptrCast(*const clang.IfStmt, stmt)),
1038 .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)),
1039 .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)),
13841040 .NullStmtClass => {
1385 const block = try rp.c.createBlock(0);
1386 block.rbrace = try appendToken(rp.c, .RBrace, "}");
1387 return &block.base;
1388 },
1389 .ContinueStmtClass => return try transCreateNodeContinue(rp.c),
1390 .BreakStmtClass => return transBreak(rp, scope),
1391 .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const clang.ForStmt, stmt)),
1392 .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
1041 return Tag.empty_block.init();
1042 },
1043 .ContinueStmtClass => return Tag.@"continue".init(),
1044 .BreakStmtClass => return Tag.@"break".init(),
1045 .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)),
1046 .FloatingLiteralClass => return transFloatingLiteral(c, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
13931047 .ConditionalOperatorClass => {
1394 return transConditionalOperator(rp, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used);
1048 return transConditionalOperator(c, scope, @ptrCast(*const clang.ConditionalOperator, stmt), result_used);
13951049 },
13961050 .BinaryConditionalOperatorClass => {
1397 return transBinaryConditionalOperator(rp, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used);
1398 },
1399 .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const clang.SwitchStmt, stmt)),
1400 .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const clang.CaseStmt, stmt)),
1401 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const clang.DefaultStmt, stmt)),
1402 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1403 .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used),
1404 .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as),
1405 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used),
1406 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used),
1407 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used),
1408 .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const clang.CallExpr, stmt), result_used),
1409 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used),
1410 .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used),
1411 .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used),
1051 return transBinaryConditionalOperator(c, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used);
1052 },
1053 .SwitchStmtClass => return transSwitch(c, scope, @ptrCast(*const clang.SwitchStmt, stmt)),
1054 .CaseStmtClass, .DefaultStmtClass => {
1055 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO complex switch", .{});
1056 },
1057 .ConstantExprClass => return transConstantExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1058 .PredefinedExprClass => return transPredefinedExpr(c, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used),
1059 .CharacterLiteralClass => return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as),
1060 .StmtExprClass => return transStmtExpr(c, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used),
1061 .MemberExprClass => return transMemberExpr(c, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used),
1062 .ArraySubscriptExprClass => return transArrayAccess(c, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used),
1063 .CallExprClass => return transCallExpr(c, scope, @ptrCast(*const clang.CallExpr, stmt), result_used),
1064 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(c, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used),
1065 .UnaryOperatorClass => return transUnaryOperator(c, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used),
1066 .CompoundAssignOperatorClass => return transCompoundAssignOperator(c, scope, @ptrCast(*const clang.CompoundAssignOperator, stmt), result_used),
14121067 .OpaqueValueExprClass => {
14131068 const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;
1414 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);
1415 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);
1416 const node = try rp.c.arena.create(ast.Node.GroupedExpression);
1417 node.* = .{
1418 .lparen = try appendToken(rp.c, .LParen, "("),
1419 .expr = expr,
1420 .rparen = try appendToken(rp.c, .RParen, ")"),
1421 };
1422 return maybeSuppressResult(rp, scope, result_used, &node.base);
1069 const expr = try transExpr(c, scope, source_expr, .used);
1070 return maybeSuppressResult(c, scope, result_used, expr);
14231071 },
14241072 else => {
1425 return revertAndWarn(
1426 rp,
1427 error.UnsupportedTranslation,
1428 stmt.getBeginLoc(),
1429 "TODO implement translation of stmt class {s}",
1430 .{@tagName(sc)},
1431 );
1073 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
14321074 },
14331075 }
14341076}
14351077
14361078fn transBinaryOperator(
1437 rp: RestorePoint,
1079 c: *Context,
14381080 scope: *Scope,
14391081 stmt: *const clang.BinaryOperator,
14401082 result_used: ResultUsed,
1441) TransError!*ast.Node {
1083) TransError!Node {
14421084 const op = stmt.getOpcode();
14431085 const qt = stmt.getType();
1444 var op_token: ast.TokenIndex = undefined;
1445 var op_id: ast.Node.Tag = undefined;
14461086 switch (op) {
1447 .Assign => return try transCreateNodeAssign(rp, scope, result_used, stmt.getLHS(), stmt.getRHS()),
1087 .Assign => return try transCreateNodeAssign(c, scope, result_used, stmt.getLHS(), stmt.getRHS()),
14481088 .Comma => {
1449 var block_scope = try Scope.Block.init(rp.c, scope, true);
1450 const lparen = try appendToken(rp.c, .LParen, "(");
1089 var block_scope = try Scope.Block.init(c, scope, true);
1090 defer block_scope.deinit();
14511091
1452 const lhs = try transExpr(rp, &block_scope.base, stmt.getLHS(), .unused, .r_value);
1092 const lhs = try transExpr(c, &block_scope.base, stmt.getLHS(), .unused);
14531093 try block_scope.statements.append(lhs);
14541094
1455 const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value);
1456 _ = try appendToken(rp.c, .Semicolon, ";");
1457 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs);
1458 try block_scope.statements.append(&break_node.base);
1459 const block_node = try block_scope.complete(rp.c);
1460 const rparen = try appendToken(rp.c, .RParen, ")");
1461 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
1462 grouped_expr.* = .{
1463 .lparen = lparen,
1464 .expr = block_node,
1465 .rparen = rparen,
1466 };
1467 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
1095 const rhs = try transExpr(c, &block_scope.base, stmt.getRHS(), .used);
1096 const break_node = try Tag.break_val.create(c.arena, .{
1097 .label = block_scope.label,
1098 .val = rhs,
1099 });
1100 try block_scope.statements.append(break_node);
1101 const block_node = try block_scope.complete(c);
1102 return maybeSuppressResult(c, scope, result_used, block_node);
14681103 },
14691104 .Div => {
14701105 if (cIsSignedInteger(qt)) {
14711106 // signed integer division uses @divTrunc
1472 const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2);
1473 div_trunc_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);
1474 _ = try appendToken(rp.c, .Comma, ",");
1475 const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);
1476 div_trunc_node.params()[1] = rhs;
1477 div_trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1478 return maybeSuppressResult(rp, scope, result_used, &div_trunc_node.base);
1107 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);
1108 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);
1109 const div_trunc = try Tag.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
1110 return maybeSuppressResult(c, scope, result_used, div_trunc);
14791111 }
14801112 },
14811113 .Rem => {
14821114 if (cIsSignedInteger(qt)) {
14831115 // signed integer division uses @rem
1484 const rem_node = try rp.c.createBuiltinCall("@rem", 2);
1485 rem_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);
1486 _ = try appendToken(rp.c, .Comma, ",");
1487 const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);
1488 rem_node.params()[1] = rhs;
1489 rem_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1490 return maybeSuppressResult(rp, scope, result_used, &rem_node.base);
1116 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);
1117 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);
1118 const rem = try Tag.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
1119 return maybeSuppressResult(c, scope, result_used, rem);
14911120 }
14921121 },
14931122 .Shl => {
1494 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
1495 return maybeSuppressResult(rp, scope, result_used, node);
1123 return transCreateNodeShiftOp(c, scope, stmt, .shl, result_used);
14961124 },
14971125 .Shr => {
1498 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
1499 return maybeSuppressResult(rp, scope, result_used, node);
1126 return transCreateNodeShiftOp(c, scope, stmt, .shr, result_used);
15001127 },
15011128 .LAnd => {
1502 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true);
1503 return maybeSuppressResult(rp, scope, result_used, node);
1129 return transCreateNodeBoolInfixOp(c, scope, stmt, .@"and", result_used);
15041130 },
15051131 .LOr => {
1506 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true);
1507 return maybeSuppressResult(rp, scope, result_used, node);
1132 return transCreateNodeBoolInfixOp(c, scope, stmt, .@"or", result_used);
15081133 },
15091134 else => {},
15101135 }
1511 const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);
1136 var op_id: Tag = undefined;
15121137 switch (op) {
15131138 .Add => {
15141139 if (cIsUnsignedInteger(qt)) {
1515 op_token = try appendToken(rp.c, .PlusPercent, "+%");
1516 op_id = .AddWrap;
1140 op_id = .add_wrap;
15171141 } else {
1518 op_token = try appendToken(rp.c, .Plus, "+");
1519 op_id = .Add;
1142 op_id = .add;
15201143 }
15211144 },
15221145 .Sub => {
15231146 if (cIsUnsignedInteger(qt)) {
1524 op_token = try appendToken(rp.c, .MinusPercent, "-%");
1525 op_id = .SubWrap;
1147 op_id = .sub_wrap;
15261148 } else {
1527 op_token = try appendToken(rp.c, .Minus, "-");
1528 op_id = .Sub;
1149 op_id = .sub;
15291150 }
15301151 },
15311152 .Mul => {
15321153 if (cIsUnsignedInteger(qt)) {
1533 op_token = try appendToken(rp.c, .AsteriskPercent, "*%");
1534 op_id = .MulWrap;
1154 op_id = .mul_wrap;
15351155 } else {
1536 op_token = try appendToken(rp.c, .Asterisk, "*");
1537 op_id = .Mul;
1156 op_id = .mul;
15381157 }
15391158 },
15401159 .Div => {
15411160 // unsigned/float division uses the operator
1542 op_id = .Div;
1543 op_token = try appendToken(rp.c, .Slash, "/");
1161 op_id = .div;
15441162 },
15451163 .Rem => {
15461164 // unsigned/float division uses the operator
1547 op_id = .Mod;
1548 op_token = try appendToken(rp.c, .Percent, "%");
1165 op_id = .mod;
15491166 },
15501167 .LT => {
1551 op_id = .LessThan;
1552 op_token = try appendToken(rp.c, .AngleBracketLeft, "<");
1168 op_id = .less_than;
15531169 },
15541170 .GT => {
1555 op_id = .GreaterThan;
1556 op_token = try appendToken(rp.c, .AngleBracketRight, ">");
1171 op_id = .greater_than;
15571172 },
15581173 .LE => {
1559 op_id = .LessOrEqual;
1560 op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<=");
1174 op_id = .less_than_equal;
15611175 },
15621176 .GE => {
1563 op_id = .GreaterOrEqual;
1564 op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">=");
1177 op_id = .greater_than_equal;
15651178 },
15661179 .EQ => {
1567 op_id = .EqualEqual;
1568 op_token = try appendToken(rp.c, .EqualEqual, "==");
1180 op_id = .equal;
15691181 },
15701182 .NE => {
1571 op_id = .BangEqual;
1572 op_token = try appendToken(rp.c, .BangEqual, "!=");
1183 op_id = .not_equal;
15731184 },
15741185 .And => {
1575 op_id = .BitAnd;
1576 op_token = try appendToken(rp.c, .Ampersand, "&");
1186 op_id = .bit_and;
15771187 },
15781188 .Xor => {
1579 op_id = .BitXor;
1580 op_token = try appendToken(rp.c, .Caret, "^");
1189 op_id = .bit_xor;
15811190 },
15821191 .Or => {
1583 op_id = .BitOr;
1584 op_token = try appendToken(rp.c, .Pipe, "|");
1192 op_id = .bit_or;
15851193 },
15861194 else => unreachable,
15871195 }
15881196
1589 const rhs_node = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);
1197 const lhs_uncasted = try transExpr(c, scope, stmt.getLHS(), .used);
1198 const rhs_uncasted = try transExpr(c, scope, stmt.getRHS(), .used);
15901199
1591 const lhs = if (isBoolRes(lhs_node)) init: {
1592 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1593 cast_node.params()[0] = lhs_node;
1594 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1595 break :init &cast_node.base;
1596 } else lhs_node;
1200 const lhs = if (isBoolRes(lhs_uncasted))
1201 try Tag.bool_to_int.create(c.arena, lhs_uncasted)
1202 else
1203 lhs_uncasted;
15971204
1598 const rhs = if (isBoolRes(rhs_node)) init: {
1599 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1600 cast_node.params()[0] = rhs_node;
1601 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1602 break :init &cast_node.base;
1603 } else rhs_node;
1205 const rhs = if (isBoolRes(rhs_uncasted))
1206 try Tag.bool_to_int.create(c.arena, rhs_uncasted)
1207 else
1208 rhs_uncasted;
16041209
1605 return transCreateNodeInfixOp(rp, scope, lhs, op_id, op_token, rhs, result_used, true);
1210 return transCreateNodeInfixOp(c, scope, op_id, lhs, rhs, result_used);
16061211}
16071212
16081213fn transCompoundStmtInline(
1609 rp: RestorePoint,
1610 parent_scope: *Scope,
1214 c: *Context,
16111215 stmt: *const clang.CompoundStmt,
16121216 block: *Scope.Block,
16131217) TransError!void {
16141218 var it = stmt.body_begin();
16151219 const end_it = stmt.body_end();
16161220 while (it != end_it) : (it += 1) {
1617 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);
1618 try block.statements.append(result);
1221 const result = try transStmt(c, &block.base, it[0], .unused);
1222 switch (result.tag()) {
1223 .declaration, .empty_block => {},
1224 else => try block.statements.append(result),
1225 }
16191226 }
16201227}
16211228
1622fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!*ast.Node {
1623 var block_scope = try Scope.Block.init(rp.c, scope, false);
1229fn transCompoundStmt(c: *Context, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!Node {
1230 var block_scope = try Scope.Block.init(c, scope, false);
16241231 defer block_scope.deinit();
1625 try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
1626 return try block_scope.complete(rp.c);
1232 try transCompoundStmtInline(c, stmt, &block_scope);
1233 return try block_scope.complete(c);
16271234}
16281235
16291236fn transCStyleCastExprClass(
1630 rp: RestorePoint,
1237 c: *Context,
16311238 scope: *Scope,
16321239 stmt: *const clang.CStyleCastExpr,
16331240 result_used: ResultUsed,
1634 lrvalue: LRValue,
1635) TransError!*ast.Node {
1241) TransError!Node {
16361242 const sub_expr = stmt.getSubExpr();
16371243 const cast_node = (try transCCast(
1638 rp,
1244 c,
16391245 scope,
16401246 stmt.getBeginLoc(),
16411247 stmt.getType(),
16421248 sub_expr.getType(),
1643 try transExpr(rp, scope, sub_expr, .used, lrvalue),
1249 try transExpr(c, scope, sub_expr, .used),
16441250 ));
1645 return maybeSuppressResult(rp, scope, result_used, cast_node);
1251 return maybeSuppressResult(c, scope, result_used, cast_node);
16461252}
16471253
16481254fn transDeclStmtOne(
1649 rp: RestorePoint,
1255 c: *Context,
16501256 scope: *Scope,
16511257 decl: *const clang.Decl,
16521258 block_scope: *Scope.Block,
1653) TransError!*ast.Node {
1654 const c = rp.c;
1655
1259) TransError!void {
16561260 switch (decl.getKind()) {
16571261 .Var => {
16581262 const var_decl = @ptrCast(*const clang.VarDecl, decl);
......@@ -1666,62 +1270,51 @@ fn transDeclStmtOne(
16661270 .Extern, .Static => {
16671271 // This is actually a global variable, put it in the global scope and reference it.
16681272 // `_ = mangled_name;`
1669 try visitVarDecl(rp.c, var_decl, mangled_name);
1670 return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name));
1273 return visitVarDecl(c, var_decl, mangled_name);
16711274 },
16721275 else => {},
16731276 }
16741277
1675 const mut_tok = if (qual_type.isConstQualified())
1676 try appendToken(c, .Keyword_const, "const")
1677 else
1678 try appendToken(c, .Keyword_var, "var");
1679 const name_tok = try appendIdentifier(c, mangled_name);
1278 const is_const = qual_type.isConstQualified();
16801279
1681 _ = try appendToken(c, .Colon, ":");
16821280 const loc = decl.getLocation();
1683 const type_node = try transQualTypeMaybeInitialized(rp, qual_type, decl_init, loc);
1281 const type_node = try transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, loc);
16841282
1685 const eq_token = try appendToken(c, .Equal, "=");
16861283 var init_node = if (decl_init) |expr|
16871284 if (expr.getStmtClass() == .StringLiteralClass)
1688 try transStringLiteralAsArray(rp, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(rp.c, type_node))
1285 try transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(c, type_node))
16891286 else
1690 try transExprCoercing(rp, scope, expr, .used, .r_value)
1287 try transExprCoercing(c, scope, expr, .used)
16911288 else
1692 try transCreateNodeUndefinedLiteral(c);
1289 Tag.undefined_literal.init();
16931290 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
1694 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1695 builtin_node.params()[0] = init_node;
1696 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1697 init_node = &builtin_node.base;
1291 init_node = try Tag.bool_to_int.create(c.arena, init_node);
16981292 }
1699 const semicolon_token = try appendToken(c, .Semicolon, ";");
1700 const node = try ast.Node.VarDecl.create(c.arena, .{
1701 .name_token = name_tok,
1702 .mut_token = mut_tok,
1703 .semicolon_token = semicolon_token,
1704 }, .{
1705 .eq_token = eq_token,
1706 .type_node = type_node,
1707 .init_node = init_node,
1293 const node = try Tag.var_decl.create(c.arena, .{
1294 .is_pub = false,
1295 .is_const = is_const,
1296 .is_extern = false,
1297 .is_export = false,
1298 .is_threadlocal = false,
1299 .linksection_string = null,
1300 .alignment = null,
1301 .name = mangled_name,
1302 .type = type_node,
1303 .init = init_node,
17081304 });
1709 return &node.base;
1305 try block_scope.statements.append(node);
17101306 },
17111307 .Typedef => {
1712 const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl);
1713 const name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
1714
1715 const underlying_qual = typedef_decl.getUnderlyingType();
1716 const underlying_type = underlying_qual.getTypePtr();
1717
1718 const mangled_name = try block_scope.makeMangledName(c, name);
1719 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
1720 return error.UnsupportedTranslation;
1721 return node;
1308 try transTypeDef(c, scope, @ptrCast(*const clang.TypedefNameDecl, decl));
1309 },
1310 .Record => {
1311 try transRecordDecl(c, scope, @ptrCast(*const clang.RecordDecl, decl));
1312 },
1313 .Enum => {
1314 try transEnumDecl(c, scope, @ptrCast(*const clang.EnumDecl, decl));
17221315 },
1723 else => |kind| return revertAndWarn(
1724 rp,
1316 else => |kind| return fail(
1317 c,
17251318 error.UnsupportedTranslation,
17261319 decl.getLocation(),
17271320 "TODO implement translation of DeclStmt kind {s}",
......@@ -1730,96 +1323,86 @@ fn transDeclStmtOne(
17301323 }
17311324}
17321325
1733fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.DeclStmt) TransError!*ast.Node {
1734 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
1326fn transDeclStmt(c: *Context, scope: *Scope, stmt: *const clang.DeclStmt) TransError!Node {
1327 const block_scope = try scope.findBlockScope(c);
17351328
17361329 var it = stmt.decl_begin();
17371330 const end_it = stmt.decl_end();
1738 assert(it != end_it);
1739 while (true) : (it += 1) {
1740 const node = try transDeclStmtOne(rp, scope, it[0], block_scope);
1741
1742 if (it + 1 == end_it) {
1743 return node;
1744 } else {
1745 try block_scope.statements.append(node);
1746 }
1331 while (it != end_it) : (it += 1) {
1332 try transDeclStmtOne(c, scope, it[0], block_scope);
17471333 }
1748 unreachable;
1334 return Tag.declaration.init();
17491335}
17501336
17511337fn transDeclRefExpr(
1752 rp: RestorePoint,
1338 c: *Context,
17531339 scope: *Scope,
17541340 expr: *const clang.DeclRefExpr,
1755 lrvalue: LRValue,
1756) TransError!*ast.Node {
1341) TransError!Node {
17571342 const value_decl = expr.getDecl();
1758 const name = try rp.c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin());
1343 const name = try c.str(@ptrCast(*const clang.NamedDecl, value_decl).getName_bytes_begin());
17591344 const mangled_name = scope.getAlias(name);
1760 return transCreateNodeIdentifier(rp.c, mangled_name);
1345 return Tag.identifier.create(c.arena, mangled_name);
17611346}
17621347
17631348fn transImplicitCastExpr(
1764 rp: RestorePoint,
1349 c: *Context,
17651350 scope: *Scope,
17661351 expr: *const clang.ImplicitCastExpr,
17671352 result_used: ResultUsed,
1768) TransError!*ast.Node {
1769 const c = rp.c;
1353) TransError!Node {
17701354 const sub_expr = expr.getSubExpr();
17711355 const dest_type = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
17721356 const src_type = getExprQualType(c, sub_expr);
17731357 switch (expr.getCastKind()) {
17741358 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {
1775 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
1776 return try transCCast(rp, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);
1359 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1360 const casted = try transCCast(c, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);
1361 return maybeSuppressResult(c, scope, result_used, casted);
17771362 },
17781363 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {
1779 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
1780 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
1364 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1365 return maybeSuppressResult(c, scope, result_used, sub_expr_node);
17811366 },
17821367 .ArrayToPointerDecay => {
17831368 if (exprIsNarrowStringLiteral(sub_expr)) {
1784 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
1785 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);
1369 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1370 return maybeSuppressResult(c, scope, result_used, sub_expr_node);
17861371 }
17871372
1788 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
1789 prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);
1790
1791 return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
1373 const addr = try Tag.address_of.create(c.arena, try transExpr(c, scope, sub_expr, .used));
1374 return maybeSuppressResult(c, scope, result_used, addr);
17921375 },
17931376 .NullToPointer => {
1794 return try transCreateNodeNullLiteral(rp.c);
1377 return Tag.null_literal.init();
17951378 },
17961379 .PointerToBoolean => {
17971380 // @ptrToInt(val) != 0
1798 const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1);
1799 ptr_to_int.params()[0] = try transExpr(rp, scope, sub_expr, .used, .r_value);
1800 ptr_to_int.rparen_token = try appendToken(rp.c, .RParen, ")");
1381 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used));
18011382
1802 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1803 const rhs_node = try transCreateNodeInt(rp.c, 0);
1804 return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false);
1383 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
1384 return maybeSuppressResult(c, scope, result_used, ne);
18051385 },
18061386 .IntegralToBoolean => {
1807 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);
1387 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
18081388
18091389 // The expression is already a boolean one, return it as-is
18101390 if (isBoolRes(sub_expr_node))
1811 return sub_expr_node;
1391 return maybeSuppressResult(c, scope, result_used, sub_expr_node);
18121392
18131393 // val != 0
1814 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1815 const rhs_node = try transCreateNodeInt(rp.c, 0);
1816 return transCreateNodeInfixOp(rp, scope, sub_expr_node, .BangEqual, op_token, rhs_node, result_used, false);
1394 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Tag.zero_literal.init() });
1395 return maybeSuppressResult(c, scope, result_used, ne);
18171396 },
18181397 .BuiltinFnToFnPtr => {
1819 return transExpr(rp, scope, sub_expr, .used, .r_value);
1398 return transExpr(c, scope, sub_expr, result_used);
18201399 },
1821 else => |kind| return revertAndWarn(
1822 rp,
1400 .ToVoid => {
1401 // Should only appear in the rhs and lhs of a ConditionalOperator
1402 return transExpr(c, scope, sub_expr, .unused);
1403 },
1404 else => |kind| return fail(
1405 c,
18231406 error.UnsupportedTranslation,
18241407 @ptrCast(*const clang.Stmt, expr).getBeginLoc(),
18251408 "TODO implement translation of CastKind {s}",
......@@ -1829,52 +1412,28 @@ fn transImplicitCastExpr(
18291412}
18301413
18311414fn transBoolExpr(
1832 rp: RestorePoint,
1415 c: *Context,
18331416 scope: *Scope,
18341417 expr: *const clang.Expr,
18351418 used: ResultUsed,
1836 lrvalue: LRValue,
1837 grouped: bool,
1838) TransError!*ast.Node {
1419) TransError!Node {
18391420 if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) {
18401421 var is_zero: bool = undefined;
1841 if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, rp.c.clang_context))) {
1842 return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
1422 if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) {
1423 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
18431424 }
1844 return try transCreateNodeBoolLiteral(rp.c, !is_zero);
1425 return Node{ .tag_if_small_enough = @enumToInt(([2]Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)]) };
18451426 }
18461427
1847 const lparen = if (grouped)
1848 try appendToken(rp.c, .LParen, "(")
1849 else
1850 undefined;
1851 var res = try transExpr(rp, scope, expr, used, lrvalue);
1852
1428 var res = try transExpr(c, scope, expr, used);
18531429 if (isBoolRes(res)) {
1854 if (!grouped and res.tag == .GroupedExpression) {
1855 const group = @fieldParentPtr(ast.Node.GroupedExpression, "base", res);
1856 res = group.expr;
1857 // get zig fmt to work properly
1858 tokenSlice(rp.c, group.lparen)[0] = ')';
1859 }
1860 return res;
1430 return maybeSuppressResult(c, scope, used, res);
18611431 }
18621432
1863 const ty = getExprQualType(rp.c, expr).getTypePtr();
1864 const node = try finishBoolExpr(rp, scope, expr.getBeginLoc(), ty, res, used);
1433 const ty = getExprQualType(c, expr).getTypePtr();
1434 const node = try finishBoolExpr(c, scope, expr.getBeginLoc(), ty, res, used);
18651435
1866 if (grouped) {
1867 const rparen = try appendToken(rp.c, .RParen, ")");
1868 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
1869 grouped_expr.* = .{
1870 .lparen = lparen,
1871 .expr = node,
1872 .rparen = rparen,
1873 };
1874 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
1875 } else {
1876 return maybeSuppressResult(rp, scope, used, node);
1877 }
1436 return maybeSuppressResult(c, scope, used, node);
18781437}
18791438
18801439fn exprIsBooleanType(expr: *const clang.Expr) bool {
......@@ -1900,34 +1459,32 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool {
19001459 }
19011460}
19021461
1903fn isBoolRes(res: *ast.Node) bool {
1904 switch (res.tag) {
1905 .BoolOr,
1906 .BoolAnd,
1907 .EqualEqual,
1908 .BangEqual,
1909 .LessThan,
1910 .GreaterThan,
1911 .LessOrEqual,
1912 .GreaterOrEqual,
1913 .BoolNot,
1914 .BoolLiteral,
1462fn isBoolRes(res: Node) bool {
1463 switch (res.tag()) {
1464 .@"or",
1465 .@"and",
1466 .equal,
1467 .not_equal,
1468 .less_than,
1469 .less_than_equal,
1470 .greater_than,
1471 .greater_than_equal,
1472 .not,
1473 .false_literal,
1474 .true_literal,
19151475 => return true,
1916
1917 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
1918
19191476 else => return false,
19201477 }
19211478}
19221479
19231480fn finishBoolExpr(
1924 rp: RestorePoint,
1481 c: *Context,
19251482 scope: *Scope,
19261483 loc: clang.SourceLocation,
19271484 ty: *const clang.Type,
1928 node: *ast.Node,
1485 node: Node,
19291486 used: ResultUsed,
1930) TransError!*ast.Node {
1487) TransError!Node {
19311488 switch (ty.getTypeClass()) {
19321489 .Builtin => {
19331490 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
......@@ -1959,42 +1516,38 @@ fn finishBoolExpr(
19591516 .WChar_S,
19601517 .Float16,
19611518 => {
1962 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1963 const rhs_node = try transCreateNodeInt(rp.c, 0);
1964 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1519 // node != 0
1520 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
19651521 },
19661522 .NullPtr => {
1967 const op_token = try appendToken(rp.c, .EqualEqual, "==");
1968 const rhs_node = try transCreateNodeNullLiteral(rp.c);
1969 return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false);
1523 // node == null
1524 return Tag.equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
19701525 },
19711526 else => {},
19721527 }
19731528 },
19741529 .Pointer => {
1975 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1976 const rhs_node = try transCreateNodeNullLiteral(rp.c);
1977 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1530 // node != null
1531 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
19781532 },
19791533 .Typedef => {
19801534 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
19811535 const typedef_decl = typedef_ty.getDecl();
19821536 const underlying_type = typedef_decl.getUnderlyingType();
1983 return finishBoolExpr(rp, scope, loc, underlying_type.getTypePtr(), node, used);
1537 return finishBoolExpr(c, scope, loc, underlying_type.getTypePtr(), node, used);
19841538 },
19851539 .Enum => {
1986 const op_token = try appendToken(rp.c, .BangEqual, "!=");
1987 const rhs_node = try transCreateNodeInt(rp.c, 0);
1988 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1540 // node != 0
1541 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
19891542 },
19901543 .Elaborated => {
19911544 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
19921545 const named_type = elaborated_ty.getNamedType();
1993 return finishBoolExpr(rp, scope, loc, named_type.getTypePtr(), node, used);
1546 return finishBoolExpr(c, scope, loc, named_type.getTypePtr(), node, used);
19941547 },
19951548 else => {},
19961549 }
1997 return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});
1550 return fail(c, error.UnsupportedType, loc, "unsupported bool expression type", .{});
19981551}
19991552
20001553const SuppressCast = enum {
......@@ -2002,21 +1555,21 @@ const SuppressCast = enum {
20021555 no_as,
20031556};
20041557fn transIntegerLiteral(
2005 rp: RestorePoint,
1558 c: *Context,
20061559 scope: *Scope,
20071560 expr: *const clang.IntegerLiteral,
20081561 result_used: ResultUsed,
20091562 suppress_as: SuppressCast,
2010) TransError!*ast.Node {
1563) TransError!Node {
20111564 var eval_result: clang.ExprEvalResult = undefined;
2012 if (!expr.EvaluateAsInt(&eval_result, rp.c.clang_context)) {
1565 if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) {
20131566 const loc = expr.getBeginLoc();
2014 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
1567 return fail(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
20151568 }
20161569
20171570 if (suppress_as == .no_as) {
2018 const int_lit_node = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());
2019 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
1571 const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt());
1572 return maybeSuppressResult(c, scope, result_used, int_lit_node);
20201573 }
20211574
20221575 // Integer literals in C have types, and this can matter for several reasons.
......@@ -2031,115 +1584,61 @@ fn transIntegerLiteral(
20311584
20321585 // @as(T, x)
20331586 const expr_base = @ptrCast(*const clang.Expr, expr);
2034 const as_node = try rp.c.createBuiltinCall("@as", 2);
2035 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());
2036 as_node.params()[0] = ty_node;
2037 _ = try appendToken(rp.c, .Comma, ",");
2038 as_node.params()[1] = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());
2039
2040 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2041 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
2042}
2043
2044/// In C if a function has return type `int` and the return value is a boolean
2045/// expression, there is no implicit cast. So the translated Zig will need to
2046/// call @boolToInt
2047fn zigShouldCastBooleanReturnToInt(node: ?*ast.Node, qt: ?clang.QualType) bool {
2048 if (node == null or qt == null) return false;
2049 return isBoolRes(node.?) and cIsNativeInt(qt.?);
1587 const ty_node = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc());
1588 const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());
1589 const as = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });
1590 return maybeSuppressResult(c, scope, result_used, as);
20501591}
20511592
20521593fn transReturnStmt(
2053 rp: RestorePoint,
1594 c: *Context,
20541595 scope: *Scope,
20551596 expr: *const clang.ReturnStmt,
2056) TransError!*ast.Node {
2057 const return_kw = try appendToken(rp.c, .Keyword_return, "return");
2058 var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr|
2059 try transExprCoercing(rp, scope, val_expr, .used, .r_value)
2060 else
2061 null;
2062 const return_qt = scope.findBlockReturnType(rp.c);
2063 if (zigShouldCastBooleanReturnToInt(rhs, return_qt)) {
2064 const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);
2065 bool_to_int_node.params()[0] = rhs.?;
2066 bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2067
2068 rhs = &bool_to_int_node.base;
2069 }
2070 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
2071 .ltoken = return_kw,
2072 .tag = .Return,
2073 }, .{
2074 .rhs = rhs,
2075 });
2076 _ = try appendToken(rp.c, .Semicolon, ";");
2077 return &return_expr.base;
1597) TransError!Node {
1598 const val_expr = expr.getRetValue() orelse
1599 return Tag.return_void.init();
1600
1601 var rhs = try transExprCoercing(c, scope, val_expr, .used);
1602 const return_qt = scope.findBlockReturnType(c);
1603 if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) {
1604 rhs = try Tag.bool_to_int.create(c.arena, rhs);
1605 }
1606 return Tag.@"return".create(c.arena, rhs);
20781607}
20791608
20801609fn transStringLiteral(
2081 rp: RestorePoint,
1610 c: *Context,
20821611 scope: *Scope,
20831612 stmt: *const clang.StringLiteral,
20841613 result_used: ResultUsed,
2085) TransError!*ast.Node {
1614) TransError!Node {
20861615 const kind = stmt.getKind();
20871616 switch (kind) {
20881617 .Ascii, .UTF8 => {
20891618 var len: usize = undefined;
20901619 const bytes_ptr = stmt.getString_bytes_begin_size(&len);
2091 const str = bytes_ptr[0..len];
20921620
2093 const token = try appendTokenFmt(rp.c, .StringLiteral, "\"{}\"", .{std.zig.fmtEscapes(str)});
2094 const node = try rp.c.arena.create(ast.Node.OneToken);
2095 node.* = .{
2096 .base = .{ .tag = .StringLiteral },
2097 .token = token,
2098 };
2099 return maybeSuppressResult(rp, scope, result_used, &node.base);
1621 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
1622 const node = try Tag.string_literal.create(c.arena, str);
1623 return maybeSuppressResult(c, scope, result_used, node);
21001624 },
21011625 .UTF16, .UTF32, .Wide => {
2102 const node = try transWideStringLiteral(rp, scope, stmt);
2103 return maybeSuppressResult(rp, scope, result_used, node);
1626 const str_type = @tagName(stmt.getKind());
1627 const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() });
1628 const lit_array = try transStringLiteralAsArray(c, scope, stmt, stmt.getLength() + 1);
1629
1630 const decl = try Tag.var_simple.create(c.arena, .{ .name = name, .init = lit_array });
1631 try scope.appendNode(decl);
1632 const node = try Tag.identifier.create(c.arena, name);
1633 return maybeSuppressResult(c, scope, result_used, node);
21041634 },
21051635 }
21061636}
21071637
2108/// Translates a wide string literal as a global "anonymous" array of the relevant-sized
2109/// integer type + null terminator, and returns an identifier node for it
2110fn transWideStringLiteral(rp: RestorePoint, scope: *Scope, stmt: *const clang.StringLiteral) TransError!*ast.Node {
2111 const str_type = @tagName(stmt.getKind());
2112 const mangle = rp.c.getMangle();
2113 const name = try std.fmt.allocPrint(rp.c.arena, "zig.{s}_string_{d}", .{ str_type, mangle });
2114
2115 const const_tok = try appendToken(rp.c, .Keyword_const, "const");
2116 const name_tok = try appendIdentifier(rp.c, name);
2117 const eq_tok = try appendToken(rp.c, .Equal, "=");
2118 var semi_tok: ast.TokenIndex = undefined;
2119
2120 const lit_array = try transStringLiteralAsArray(rp, scope, stmt, stmt.getLength() + 1);
2121
2122 semi_tok = try appendToken(rp.c, .Semicolon, ";");
2123 const var_decl_node = try ast.Node.VarDecl.create(rp.c.arena, .{
2124 .name_token = name_tok,
2125 .mut_token = const_tok,
2126 .semicolon_token = semi_tok,
2127 }, .{
2128 .visib_token = null,
2129 .eq_token = eq_tok,
2130 .init_node = lit_array,
2131 });
2132 try addTopLevelDecl(rp.c, name, &var_decl_node.base);
2133 return transCreateNodeIdentifier(rp.c, name);
2134}
2135
21361638/// Parse the size of an array back out from an ast Node.
2137fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {
2138 if (node.castTag(.ArrayType)) |array| {
2139 if (array.len_expr.castTag(.IntegerLiteral)) |int_lit| {
2140 const tok = tokenSlice(c, int_lit.token);
2141 return std.fmt.parseUnsigned(usize, tok, 10) catch error.UnsupportedTranslation;
2142 }
1639fn zigArraySize(c: *Context, node: Node) TransError!usize {
1640 if (node.castTag(.array_type)) |array| {
1641 return array.data.len;
21431642 }
21441643 return error.UnsupportedTranslation;
21451644}
......@@ -2150,11 +1649,11 @@ fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {
21501649/// than the array, truncate the string. If the array is larger than the
21511650/// string literal, pad the array with 0's
21521651fn transStringLiteralAsArray(
2153 rp: RestorePoint,
1652 c: *Context,
21541653 scope: *Scope,
21551654 stmt: *const clang.StringLiteral,
21561655 array_size: usize,
2157) TransError!*ast.Node {
1656) TransError!Node {
21581657 if (array_size == 0) return error.UnsupportedType;
21591658
21601659 const str_length = stmt.getLength();
......@@ -2163,40 +1662,25 @@ fn transStringLiteralAsArray(
21631662 const ty = expr_base.getType().getTypePtr();
21641663 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
21651664
2166 const ty_node = try rp.c.arena.create(ast.Node.ArrayType);
2167 const op_token = try appendToken(rp.c, .LBracket, "[");
2168 const len_expr = try transCreateNodeInt(rp.c, array_size);
2169 _ = try appendToken(rp.c, .RBracket, "]");
2170
2171 ty_node.* = .{
2172 .op_token = op_token,
2173 .rhs = try transQualType(rp, const_arr_ty.getElementType(), expr_base.getBeginLoc()),
2174 .len_expr = len_expr,
2175 };
2176 _ = try appendToken(rp.c, .LBrace, "{");
2177 var init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, array_size);
2178 init_node.* = .{
2179 .lhs = &ty_node.base,
2180 .rtoken = undefined,
2181 .list_len = array_size,
2182 };
2183 const init_list = init_node.list();
1665 const elem_type = try transQualType(c, scope, const_arr_ty.getElementType(), expr_base.getBeginLoc());
1666 const arr_type = try Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_type });
1667 const init_list = try c.arena.alloc(Node, array_size);
21841668
21851669 var i: c_uint = 0;
21861670 const kind = stmt.getKind();
21871671 const narrow = kind == .Ascii or kind == .UTF8;
21881672 while (i < str_length and i < array_size) : (i += 1) {
21891673 const code_unit = stmt.getCodeUnit(i);
2190 init_list[i] = try transCreateCharLitNode(rp.c, narrow, code_unit);
2191 _ = try appendToken(rp.c, .Comma, ",");
1674 init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);
21921675 }
21931676 while (i < array_size) : (i += 1) {
2194 init_list[i] = try transCreateNodeInt(rp.c, 0);
2195 _ = try appendToken(rp.c, .Comma, ",");
1677 init_list[i] = try transCreateNodeNumber(c, 0, .int);
21961678 }
2197 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
21981679
2199 return &init_node.base;
1680 return Tag.array_init.create(c.arena, .{
1681 .cond = arr_type,
1682 .cases = init_list,
1683 });
22001684}
22011685
22021686fn cIsEnum(qt: clang.QualType) bool {
......@@ -2215,217 +1699,180 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
22151699}
22161700
22171701fn transCCast(
2218 rp: RestorePoint,
1702 c: *Context,
22191703 scope: *Scope,
22201704 loc: clang.SourceLocation,
22211705 dst_type: clang.QualType,
22221706 src_type: clang.QualType,
2223 expr: *ast.Node,
2224) !*ast.Node {
1707 expr: Node,
1708) !Node {
22251709 if (qualTypeCanon(dst_type).isVoidType()) return expr;
22261710 if (dst_type.eq(src_type)) return expr;
22271711 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
2228 return transCPtrCast(rp, loc, dst_type, src_type, expr);
1712 return transCPtrCast(c, scope, loc, dst_type, src_type, expr);
1713
1714 const dst_node = try transQualType(c, scope, dst_type, loc);
22291715 if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
22301716 // 1. If src_type is an enum, determine the underlying signed int type
22311717 // 2. Extend or truncate without changing signed-ness.
22321718 // 3. Bit-cast to correct signed-ness
22331719 const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type);
22341720 const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type);
2235 var src_int_expr = if (cIsInteger(src_type)) expr else try transEnumToInt(rp.c, expr);
2236
2237 // @bitCast(dest_type, intermediate_value)
2238 const cast_node = try rp.c.createBuiltinCall("@bitCast", 2);
2239 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
2240 _ = try appendToken(rp.c, .Comma, ",");
1721 var src_int_expr = if (cIsInteger(src_type)) expr else try Tag.enum_to_int.create(c.arena, expr);
22411722
22421723 if (isBoolRes(src_int_expr)) {
2243 const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);
2244 bool_to_int_node.params()[0] = src_int_expr;
2245 bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2246 src_int_expr = &bool_to_int_node.base;
1724 src_int_expr = try Tag.bool_to_int.create(c.arena, src_int_expr);
22471725 }
22481726
22491727 switch (cIntTypeCmp(dst_type, src_int_type)) {
22501728 .lt => {
22511729 // @truncate(SameSignSmallerInt, src_int_expr)
2252 const trunc_node = try rp.c.createBuiltinCall("@truncate", 2);
2253 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, src_type_is_signed);
2254 trunc_node.params()[0] = ty_node;
2255 _ = try appendToken(rp.c, .Comma, ",");
2256 trunc_node.params()[1] = src_int_expr;
2257 trunc_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2258
2259 cast_node.params()[1] = &trunc_node.base;
1730 const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
1731 src_int_expr = try Tag.truncate.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr });
22601732 },
22611733 .gt => {
22621734 // @as(SameSignBiggerInt, src_int_expr)
2263 const as_node = try rp.c.createBuiltinCall("@as", 2);
2264 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, src_type_is_signed);
2265 as_node.params()[0] = ty_node;
2266 _ = try appendToken(rp.c, .Comma, ",");
2267 as_node.params()[1] = src_int_expr;
2268 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2269
2270 cast_node.params()[1] = &as_node.base;
1735 const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
1736 src_int_expr = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr });
22711737 },
22721738 .eq => {
2273 cast_node.params()[1] = src_int_expr;
1739 // src_int_expr = src_int_expr
22741740 },
22751741 }
2276 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2277 return &cast_node.base;
1742 // @bitCast(dest_type, intermediate_value)
1743 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });
22781744 }
22791745 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
22801746 // @intCast(dest_type, @ptrToInt(val))
2281 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2282 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
2283 _ = try appendToken(rp.c, .Comma, ",");
2284 const builtin_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
2285 builtin_node.params()[0] = expr;
2286 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2287 cast_node.params()[1] = &builtin_node.base;
2288 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2289 return &cast_node.base;
1747 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
1748 return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
22901749 }
22911750 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
22921751 // @intToPtr(dest_type, val)
2293 const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2);
2294 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
2295 _ = try appendToken(rp.c, .Comma, ",");
2296 builtin_node.params()[1] = expr;
2297 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2298 return &builtin_node.base;
1752 return Tag.int_to_ptr.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
22991753 }
23001754 if (cIsFloating(src_type) and cIsFloating(dst_type)) {
2301 const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2);
2302 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
2303 _ = try appendToken(rp.c, .Comma, ",");
2304 builtin_node.params()[1] = expr;
2305 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2306 return &builtin_node.base;
1755 // @floatCast(dest_type, val)
1756 return Tag.float_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
23071757 }
23081758 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {
2309 const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2);
2310 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
2311 _ = try appendToken(rp.c, .Comma, ",");
2312 builtin_node.params()[1] = expr;
2313 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2314 return &builtin_node.base;
1759 // @floatToInt(dest_type, val)
1760 return Tag.float_to_int.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
23151761 }
23161762 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {
2317 const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2);
2318 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
2319 _ = try appendToken(rp.c, .Comma, ",");
2320 builtin_node.params()[1] = expr;
2321 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2322 return &builtin_node.base;
1763 // @intToFloat(dest_type, val)
1764 return Tag.int_to_float.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
23231765 }
23241766 if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {
23251767 // @boolToInt returns either a comptime_int or a u1
23261768 // TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast
23271769 // instead of @as
2328 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
2329 builtin_node.params()[0] = expr;
2330 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2331
2332 const as_node = try rp.c.createBuiltinCall("@as", 2);
2333 as_node.params()[0] = try transQualType(rp, dst_type, loc);
2334 _ = try appendToken(rp.c, .Comma, ",");
2335 as_node.params()[1] = &builtin_node.base;
2336 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2337
2338 return &as_node.base;
1770 const bool_to_int = try Tag.bool_to_int.create(c.arena, expr);
1771 return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
23391772 }
23401773 if (cIsEnum(dst_type)) {
2341 const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);
2342 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);
2343 _ = try appendToken(rp.c, .Comma, ",");
2344 builtin_node.params()[1] = expr;
2345 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2346 return &builtin_node.base;
1774 // @intToEnum(dest_type, val)
1775 return Tag.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
23471776 }
23481777 if (cIsEnum(src_type) and !cIsEnum(dst_type)) {
2349 return transEnumToInt(rp.c, expr);
1778 // @enumToInt(val)
1779 return Tag.enum_to_int.create(c.arena, expr);
23501780 }
2351 const cast_node = try rp.c.createBuiltinCall("@as", 2);
2352 cast_node.params()[0] = try transQualType(rp, dst_type, loc);
2353 _ = try appendToken(rp.c, .Comma, ",");
2354 cast_node.params()[1] = expr;
2355 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
2356 return &cast_node.base;
2357}
2358
2359fn transEnumToInt(c: *Context, enum_expr: *ast.Node) TypeError!*ast.Node {
2360 const builtin_node = try c.createBuiltinCall("@enumToInt", 1);
2361 builtin_node.params()[0] = enum_expr;
2362 builtin_node.rparen_token = try appendToken(c, .RParen, ")");
2363 return &builtin_node.base;
1781 // @as(dest_type, val)
1782 return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
23641783}
23651784
2366fn transExpr(
2367 rp: RestorePoint,
2368 scope: *Scope,
2369 expr: *const clang.Expr,
2370 used: ResultUsed,
2371 lrvalue: LRValue,
2372) TransError!*ast.Node {
2373 return transStmt(rp, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue);
1785fn transExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
1786 return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used);
23741787}
23751788
23761789/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
23771790/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
2378fn transExprCoercing(
2379 rp: RestorePoint,
2380 scope: *Scope,
2381 expr: *const clang.Expr,
2382 used: ResultUsed,
2383 lrvalue: LRValue,
2384) TransError!*ast.Node {
1791fn transExprCoercing(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
23851792 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
23861793 .IntegerLiteralClass => {
2387 return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as);
1794 return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as);
23881795 },
23891796 .CharacterLiteralClass => {
2390 return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, expr), .used, .no_as);
1797 return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, expr), .used, .no_as);
23911798 },
23921799 .UnaryOperatorClass => {
23931800 const un_expr = @ptrCast(*const clang.UnaryOperator, expr);
23941801 if (un_expr.getOpcode() == .Extension) {
2395 return transExprCoercing(rp, scope, un_expr.getSubExpr(), used, lrvalue);
1802 return transExprCoercing(c, scope, un_expr.getSubExpr(), used);
1803 }
1804 },
1805 .ImplicitCastExprClass => {
1806 const cast_expr = @ptrCast(*const clang.ImplicitCastExpr, expr);
1807 const sub_expr = cast_expr.getSubExpr();
1808 switch (@ptrCast(*const clang.Stmt, sub_expr).getStmtClass()) {
1809 .IntegerLiteralClass, .CharacterLiteralClass => switch (cast_expr.getCastKind()) {
1810 .IntegralToFloating => return transExprCoercing(c, scope, sub_expr, used),
1811 .IntegralCast => {
1812 const dest_type = getExprQualType(c, expr);
1813 if (literalFitsInType(c, sub_expr, dest_type))
1814 return transExprCoercing(c, scope, sub_expr, used);
1815 },
1816 else => {},
1817 },
1818 else => {},
23961819 }
23971820 },
23981821 else => {},
23991822 }
2400 return transExpr(rp, scope, expr, .used, .r_value);
1823 return transExpr(c, scope, expr, .used);
24011824}
24021825
2403fn transInitListExprRecord(
2404 rp: RestorePoint,
2405 scope: *Scope,
2406 loc: clang.SourceLocation,
2407 expr: *const clang.InitListExpr,
2408 ty: *const clang.Type,
2409 used: ResultUsed,
2410) TransError!*ast.Node {
2411 var is_union_type = false;
2412 // Unions and Structs are both represented as RecordDecl
2413 const record_ty = ty.getAsRecordType() orelse
2414 blk: {
2415 is_union_type = true;
1826fn literalFitsInType(c: *Context, expr: *const clang.Expr, qt: clang.QualType) bool {
1827 var width = qualTypeIntBitWidth(c, qt) catch 8;
1828 if (width == 0) width = 8; // Byte is the smallest type.
1829 const is_signed = cIsSignedInteger(qt);
1830 const width_max_int = (@as(u64, 1) << math.lossyCast(u6, width - @boolToInt(is_signed))) - 1;
1831
1832 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
1833 .CharacterLiteralClass => {
1834 const char_lit = @ptrCast(*const clang.CharacterLiteral, expr);
1835 const val = char_lit.getValue();
1836 // If the val is less than the max int then it fits.
1837 return val <= width_max_int;
1838 },
1839 .IntegerLiteralClass => {
1840 const int_lit = @ptrCast(*const clang.IntegerLiteral, expr);
1841 var eval_result: clang.ExprEvalResult = undefined;
1842 if (!int_lit.EvaluateAsInt(&eval_result, c.clang_context)) {
1843 return false;
1844 }
1845
1846 const int = eval_result.Val.getInt();
1847 return int.lessThanEqual(width_max_int);
1848 },
1849 else => unreachable,
1850 }
1851}
1852
1853fn transInitListExprRecord(
1854 c: *Context,
1855 scope: *Scope,
1856 loc: clang.SourceLocation,
1857 expr: *const clang.InitListExpr,
1858 ty: *const clang.Type,
1859) TransError!Node {
1860 var is_union_type = false;
1861 // Unions and Structs are both represented as RecordDecl
1862 const record_ty = ty.getAsRecordType() orelse
1863 blk: {
1864 is_union_type = true;
24161865 break :blk ty.getAsUnionType();
24171866 } orelse unreachable;
24181867 const record_decl = record_ty.getDecl();
24191868 const record_def = record_decl.getDefinition() orelse
24201869 unreachable;
24211870
2422 const ty_node = try transType(rp, ty, loc);
1871 const ty_node = try transType(c, scope, ty, loc);
24231872 const init_count = expr.getNumInits();
2424 var field_inits = std.ArrayList(*ast.Node).init(rp.c.gpa);
1873 var field_inits = std.ArrayList(ast.Payload.ContainerInit.Initializer).init(c.gpa);
24251874 defer field_inits.deinit();
24261875
2427 _ = try appendToken(rp.c, .LBrace, "{");
2428
24291876 var init_i: c_uint = 0;
24301877 var it = record_def.field_begin();
24311878 const end_it = record_def.field_end();
......@@ -2443,78 +1890,34 @@ fn transInitListExprRecord(
24431890
24441891 // Generate the field assignment expression:
24451892 // .field_name = expr
2446 const period_tok = try appendToken(rp.c, .Period, ".");
2447
2448 var raw_name = try rp.c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
1893 var raw_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
24491894 if (field_decl.isAnonymousStructOrUnion()) {
2450 const name = rp.c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
2451 raw_name = try mem.dupe(rp.c.arena, u8, name);
1895 const name = c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
1896 raw_name = try mem.dupe(c.arena, u8, name);
24521897 }
2453 const field_name_tok = try appendIdentifier(rp.c, raw_name);
24541898
2455 _ = try appendToken(rp.c, .Equal, "=");
2456
2457 const field_init_node = try rp.c.arena.create(ast.Node.FieldInitializer);
2458 field_init_node.* = .{
2459 .period_token = period_tok,
2460 .name_token = field_name_tok,
2461 .expr = try transExpr(rp, scope, elem_expr, .used, .r_value),
2462 };
2463
2464 try field_inits.append(&field_init_node.base);
2465 _ = try appendToken(rp.c, .Comma, ",");
1899 try field_inits.append(.{
1900 .name = raw_name,
1901 .value = try transExpr(c, scope, elem_expr, .used),
1902 });
24661903 }
24671904
2468 const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len);
2469 node.* = .{
1905 return Tag.container_init.create(c.arena, .{
24701906 .lhs = ty_node,
2471 .rtoken = try appendToken(rp.c, .RBrace, "}"),
2472 .list_len = field_inits.items.len,
2473 };
2474 mem.copy(*ast.Node, node.list(), field_inits.items);
2475 return &node.base;
2476}
2477
2478fn transCreateNodeArrayType(
2479 rp: RestorePoint,
2480 source_loc: clang.SourceLocation,
2481 ty: *const clang.Type,
2482 len: anytype,
2483) !*ast.Node {
2484 const node = try rp.c.arena.create(ast.Node.ArrayType);
2485 const op_token = try appendToken(rp.c, .LBracket, "[");
2486 const len_expr = try transCreateNodeInt(rp.c, len);
2487 _ = try appendToken(rp.c, .RBracket, "]");
2488 node.* = .{
2489 .op_token = op_token,
2490 .rhs = try transType(rp, ty, source_loc),
2491 .len_expr = len_expr,
2492 };
2493 return &node.base;
2494}
2495
2496fn transCreateEmptyArray(rp: RestorePoint, loc: clang.SourceLocation, ty: *const clang.Type) TransError!*ast.Node {
2497 const ty_node = try transCreateNodeArrayType(rp, loc, ty, 0);
2498 _ = try appendToken(rp.c, .LBrace, "{");
2499 const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 0);
2500 filler_init_node.* = .{
2501 .lhs = ty_node,
2502 .rtoken = try appendToken(rp.c, .RBrace, "}"),
2503 .list_len = 0,
2504 };
2505 return &filler_init_node.base;
1907 .inits = try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items),
1908 });
25061909}
25071910
25081911fn transInitListExprArray(
2509 rp: RestorePoint,
1912 c: *Context,
25101913 scope: *Scope,
25111914 loc: clang.SourceLocation,
25121915 expr: *const clang.InitListExpr,
25131916 ty: *const clang.Type,
2514 used: ResultUsed,
2515) TransError!*ast.Node {
1917) TransError!Node {
25161918 const arr_type = ty.getAsArrayTypeUnsafe();
25171919 const child_qt = arr_type.getElementType();
1920 const child_type = try transQualType(c, scope, child_qt, loc);
25181921 const init_count = expr.getNumInits();
25191922 assert(@ptrCast(*const clang.Type, arr_type).isConstantArrayType());
25201923 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, arr_type);
......@@ -2523,125 +1926,83 @@ fn transInitListExprArray(
25231926 const leftover_count = all_count - init_count;
25241927
25251928 if (all_count == 0) {
2526 return transCreateEmptyArray(rp, loc, child_qt.getTypePtr());
1929 return Tag.empty_array.create(c.arena, child_type);
25271930 }
25281931
2529 var init_node: *ast.Node.ArrayInitializer = undefined;
2530 var cat_tok: ast.TokenIndex = undefined;
2531 if (init_count != 0) {
2532 const ty_node = try transCreateNodeArrayType(
2533 rp,
2534 loc,
2535 child_qt.getTypePtr(),
2536 init_count,
2537 );
2538 _ = try appendToken(rp.c, .LBrace, "{");
2539 init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, init_count);
2540 init_node.* = .{
2541 .lhs = ty_node,
2542 .rtoken = undefined,
2543 .list_len = init_count,
2544 };
2545 const init_list = init_node.list();
1932 const init_node = if (init_count != 0) blk: {
1933 const init_list = try c.arena.alloc(Node, init_count);
25461934
2547 var i: c_uint = 0;
2548 while (i < init_count) : (i += 1) {
2549 const elem_expr = expr.getInit(i);
2550 init_list[i] = try transExpr(rp, scope, elem_expr, .used, .r_value);
2551 _ = try appendToken(rp.c, .Comma, ",");
1935 for (init_list) |*init, i| {
1936 const elem_expr = expr.getInit(@intCast(c_uint, i));
1937 init.* = try transExprCoercing(c, scope, elem_expr, .used);
25521938 }
2553 init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
1939 const init_node = try Tag.array_init.create(c.arena, .{
1940 .cond = try Tag.array_type.create(c.arena, .{ .len = init_count, .elem_type = child_type }),
1941 .cases = init_list,
1942 });
25541943 if (leftover_count == 0) {
2555 return &init_node.base;
1944 return init_node;
25561945 }
2557 cat_tok = try appendToken(rp.c, .PlusPlus, "++");
2558 }
1946 break :blk init_node;
1947 } else null;
25591948
2560 const ty_node = try transCreateNodeArrayType(rp, loc, child_qt.getTypePtr(), 1);
2561 _ = try appendToken(rp.c, .LBrace, "{");
2562 const filler_init_node = try ast.Node.ArrayInitializer.alloc(rp.c.arena, 1);
2563 filler_init_node.* = .{
2564 .lhs = ty_node,
2565 .rtoken = undefined,
2566 .list_len = 1,
2567 };
25681949 const filler_val_expr = expr.getArrayFiller();
2569 filler_init_node.list()[0] = try transExpr(rp, scope, filler_val_expr, .used, .r_value);
2570 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");
2571
2572 const rhs_node = if (leftover_count == 1)
2573 &filler_init_node.base
2574 else blk: {
2575 const mul_tok = try appendToken(rp.c, .AsteriskAsterisk, "**");
2576 const mul_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
2577 mul_node.* = .{
2578 .base = .{ .tag = .ArrayMult },
2579 .op_token = mul_tok,
2580 .lhs = &filler_init_node.base,
2581 .rhs = try transCreateNodeInt(rp.c, leftover_count),
2582 };
2583 break :blk &mul_node.base;
2584 };
1950 const filler_node = try Tag.array_filler.create(c.arena, .{
1951 .type = child_type,
1952 .filler = try transExprCoercing(c, scope, filler_val_expr, .used),
1953 .count = leftover_count,
1954 });
25851955
2586 if (init_count == 0) {
2587 return rhs_node;
1956 if (init_node) |some| {
1957 return Tag.array_cat.create(c.arena, .{ .lhs = some, .rhs = filler_node });
1958 } else {
1959 return filler_node;
25881960 }
2589
2590 const cat_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
2591 cat_node.* = .{
2592 .base = .{ .tag = .ArrayCat },
2593 .op_token = cat_tok,
2594 .lhs = &init_node.base,
2595 .rhs = rhs_node,
2596 };
2597 return &cat_node.base;
25981961}
25991962
26001963fn transInitListExpr(
2601 rp: RestorePoint,
1964 c: *Context,
26021965 scope: *Scope,
26031966 expr: *const clang.InitListExpr,
26041967 used: ResultUsed,
2605) TransError!*ast.Node {
2606 const qt = getExprQualType(rp.c, @ptrCast(*const clang.Expr, expr));
1968) TransError!Node {
1969 const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
26071970 var qual_type = qt.getTypePtr();
26081971 const source_loc = @ptrCast(*const clang.Expr, expr).getBeginLoc();
26091972
26101973 if (qual_type.isRecordType()) {
2611 return transInitListExprRecord(
2612 rp,
1974 return maybeSuppressResult(c, scope, used, try transInitListExprRecord(
1975 c,
26131976 scope,
26141977 source_loc,
26151978 expr,
26161979 qual_type,
2617 used,
2618 );
1980 ));
26191981 } else if (qual_type.isArrayType()) {
2620 return transInitListExprArray(
2621 rp,
1982 return maybeSuppressResult(c, scope, used, try transInitListExprArray(
1983 c,
26221984 scope,
26231985 source_loc,
26241986 expr,
26251987 qual_type,
2626 used,
2627 );
1988 ));
26281989 } else {
2629 const type_name = rp.c.str(qual_type.getTypeClassName());
2630 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
1990 const type_name = c.str(qual_type.getTypeClassName());
1991 return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
26311992 }
26321993}
26331994
26341995fn transZeroInitExpr(
2635 rp: RestorePoint,
1996 c: *Context,
26361997 scope: *Scope,
26371998 source_loc: clang.SourceLocation,
26381999 ty: *const clang.Type,
2639) TransError!*ast.Node {
2000) TransError!Node {
26402001 switch (ty.getTypeClass()) {
26412002 .Builtin => {
26422003 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
26432004 switch (builtin_ty.getKind()) {
2644 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),
2005 .Bool => return Tag.false_literal.init(),
26452006 .Char_U,
26462007 .UChar,
26472008 .Char_S,
......@@ -2662,126 +2023,112 @@ fn transZeroInitExpr(
26622023 .Float128,
26632024 .Float16,
26642025 .LongDouble,
2665 => return transCreateNodeInt(rp.c, 0),
2666 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2026 => return Tag.zero_literal.init(),
2027 else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
26672028 }
26682029 },
2669 .Pointer => return transCreateNodeNullLiteral(rp.c),
2030 .Pointer => return Tag.null_literal.init(),
26702031 .Typedef => {
26712032 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
26722033 const typedef_decl = typedef_ty.getDecl();
26732034 return transZeroInitExpr(
2674 rp,
2035 c,
26752036 scope,
26762037 source_loc,
26772038 typedef_decl.getUnderlyingType().getTypePtr(),
26782039 );
26792040 },
2680 else => {},
2041 else => return Tag.std_mem_zeroes.create(c.arena, try transType(c, scope, ty, source_loc)),
26812042 }
2682
2683 return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
26842043}
26852044
26862045fn transImplicitValueInitExpr(
2687 rp: RestorePoint,
2046 c: *Context,
26882047 scope: *Scope,
26892048 expr: *const clang.Expr,
26902049 used: ResultUsed,
2691) TransError!*ast.Node {
2050) TransError!Node {
26922051 const source_loc = expr.getBeginLoc();
2693 const qt = getExprQualType(rp.c, expr);
2052 const qt = getExprQualType(c, expr);
26942053 const ty = qt.getTypePtr();
2695 return transZeroInitExpr(rp, scope, source_loc, ty);
2054 return transZeroInitExpr(c, scope, source_loc, ty);
26962055}
26972056
26982057fn transIfStmt(
2699 rp: RestorePoint,
2058 c: *Context,
27002059 scope: *Scope,
27012060 stmt: *const clang.IfStmt,
2702) TransError!*ast.Node {
2061) TransError!Node {
27032062 // if (c) t
27042063 // if (c) t else e
2705 const if_node = try transCreateNodeIf(rp.c);
2706
27072064 var cond_scope = Scope.Condition{
27082065 .base = .{
27092066 .parent = scope,
2710 .id = .Condition,
2067 .id = .condition,
27112068 },
27122069 };
27132070 defer cond_scope.deinit();
27142071 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
2715 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
2716 _ = try appendToken(rp.c, .RParen, ")");
2072 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
27172073
2718 if_node.body = try transStmt(rp, scope, stmt.getThen(), .unused, .r_value);
2719
2720 if (stmt.getElse()) |expr| {
2721 if_node.@"else" = try transCreateNodeElse(rp.c);
2722 if_node.@"else".?.body = try transStmt(rp, scope, expr, .unused, .r_value);
2723 }
2724 _ = try appendToken(rp.c, .Semicolon, ";");
2725 return &if_node.base;
2074 const then_body = try transStmt(c, scope, stmt.getThen(), .unused);
2075 const else_body = if (stmt.getElse()) |expr|
2076 try transStmt(c, scope, expr, .unused)
2077 else
2078 null;
2079 return Tag.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body });
27262080}
27272081
27282082fn transWhileLoop(
2729 rp: RestorePoint,
2083 c: *Context,
27302084 scope: *Scope,
27312085 stmt: *const clang.WhileStmt,
2732) TransError!*ast.Node {
2733 const while_node = try transCreateNodeWhile(rp.c);
2734
2086) TransError!Node {
27352087 var cond_scope = Scope.Condition{
27362088 .base = .{
27372089 .parent = scope,
2738 .id = .Condition,
2090 .id = .condition,
27392091 },
27402092 };
27412093 defer cond_scope.deinit();
27422094 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
2743 while_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
2744 _ = try appendToken(rp.c, .RParen, ")");
2095 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
27452096
27462097 var loop_scope = Scope{
27472098 .parent = scope,
2748 .id = .Loop,
2099 .id = .loop,
27492100 };
2750 while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
2751 _ = try appendToken(rp.c, .Semicolon, ";");
2752 return &while_node.base;
2101 const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2102 return Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null });
27532103}
27542104
27552105fn transDoWhileLoop(
2756 rp: RestorePoint,
2106 c: *Context,
27572107 scope: *Scope,
27582108 stmt: *const clang.DoStmt,
2759) TransError!*ast.Node {
2760 const while_node = try transCreateNodeWhile(rp.c);
2761
2762 while_node.condition = try transCreateNodeBoolLiteral(rp.c, true);
2763 _ = try appendToken(rp.c, .RParen, ")");
2764 var new = false;
2109) TransError!Node {
27652110 var loop_scope = Scope{
27662111 .parent = scope,
2767 .id = .Loop,
2112 .id = .do_loop,
27682113 };
27692114
27702115 // if (!cond) break;
2771 const if_node = try transCreateNodeIf(rp.c);
27722116 var cond_scope = Scope.Condition{
27732117 .base = .{
27742118 .parent = scope,
2775 .id = .Condition,
2119 .id = .condition,
27762120 },
27772121 };
27782122 defer cond_scope.deinit();
2779 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
2780 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value, true);
2781 _ = try appendToken(rp.c, .RParen, ")");
2782 if_node.condition = &prefix_op.base;
2783 if_node.body = &(try transCreateNodeBreak(rp.c, null, null)).base;
2784 _ = try appendToken(rp.c, .Semicolon, ";");
2123 const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used);
2124 const if_not_break = switch (cond.tag()) {
2125 .false_literal => return transStmt(c, scope, stmt.getBody(), .unused),
2126 .true_literal => {
2127 const body_node = try transStmt(c, scope, stmt.getBody(), .unused);
2128 return Tag.while_true.create(c.arena, body_node);
2129 },
2130 else => try Tag.if_not_break.create(c.arena, cond),
2131 };
27852132
27862133 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
27872134 // there's already a block in C, so we'll append our condition to it.
......@@ -2794,8 +2141,11 @@ fn transDoWhileLoop(
27942141 // zig: b;
27952142 // zig: if (!cond) break;
27962143 // zig: }
2797 const node = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
2798 break :blk node.castTag(.Block).?;
2144 const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2145 const block = node.castTag(.block).?;
2146 block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete.
2147 block.data.stmts[block.data.stmts.len - 1] = if_not_break;
2148 break :blk node;
27992149 } else blk: {
28002150 // the C statement is without a block, so we need to create a block to contain it.
28012151 // c: do
......@@ -2805,387 +2155,355 @@ fn transDoWhileLoop(
28052155 // zig: a;
28062156 // zig: if (!cond) break;
28072157 // zig: }
2808 new = true;
2809 const block = try rp.c.createBlock(2);
2810 block.statements_len = 1; // over-allocated so we can add another below
2811 block.statements()[0] = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
2812 break :blk block;
2158 const statements = try c.arena.alloc(Node, 2);
2159 statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2160 statements[1] = if_not_break;
2161 break :blk try Tag.block.create(c.arena, .{ .label = null, .stmts = statements });
28132162 };
2814
2815 // In both cases above, we reserved 1 extra statement.
2816 body_node.statements_len += 1;
2817 body_node.statements()[body_node.statements_len - 1] = &if_node.base;
2818 if (new)
2819 body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
2820 while_node.body = &body_node.base;
2821 return &while_node.base;
2163 return Tag.while_true.create(c.arena, body_node);
28222164}
28232165
28242166fn transForLoop(
2825 rp: RestorePoint,
2167 c: *Context,
28262168 scope: *Scope,
28272169 stmt: *const clang.ForStmt,
2828) TransError!*ast.Node {
2170) TransError!Node {
28292171 var loop_scope = Scope{
28302172 .parent = scope,
2831 .id = .Loop,
2173 .id = .loop,
28322174 };
28332175
28342176 var block_scope: ?Scope.Block = null;
28352177 defer if (block_scope) |*bs| bs.deinit();
28362178
28372179 if (stmt.getInit()) |init| {
2838 block_scope = try Scope.Block.init(rp.c, scope, false);
2180 block_scope = try Scope.Block.init(c, scope, false);
28392181 loop_scope.parent = &block_scope.?.base;
2840 const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);
2841 try block_scope.?.statements.append(init_node);
2182 const init_node = try transStmt(c, &block_scope.?.base, init, .unused);
2183 if (init_node.tag() != .declaration) try block_scope.?.statements.append(init_node);
28422184 }
28432185 var cond_scope = Scope.Condition{
28442186 .base = .{
28452187 .parent = &loop_scope,
2846 .id = .Condition,
2188 .id = .condition,
28472189 },
28482190 };
28492191 defer cond_scope.deinit();
28502192
2851 const while_node = try transCreateNodeWhile(rp.c);
2852 while_node.condition = if (stmt.getCond()) |cond|
2853 try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
2193 const cond = if (stmt.getCond()) |cond|
2194 try transBoolExpr(c, &cond_scope.base, cond, .used)
28542195 else
2855 try transCreateNodeBoolLiteral(rp.c, true);
2856 _ = try appendToken(rp.c, .RParen, ")");
2196 Tag.true_literal.init();
28572197
2858 if (stmt.getInc()) |incr| {
2859 _ = try appendToken(rp.c, .Colon, ":");
2860 _ = try appendToken(rp.c, .LParen, "(");
2861 while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value);
2862 _ = try appendToken(rp.c, .RParen, ")");
2863 }
2198 const cont_expr = if (stmt.getInc()) |incr|
2199 try transExpr(c, &cond_scope.base, incr, .unused)
2200 else
2201 null;
28642202
2865 while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
2203 const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2204 const while_node = try Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr });
28662205 if (block_scope) |*bs| {
2867 try bs.statements.append(&while_node.base);
2868 return try bs.complete(rp.c);
2206 try bs.statements.append(while_node);
2207 return try bs.complete(c);
28692208 } else {
2870 _ = try appendToken(rp.c, .Semicolon, ";");
2871 return &while_node.base;
2209 return while_node;
28722210 }
28732211}
28742212
2875fn getSwitchCaseCount(stmt: *const clang.SwitchStmt) usize {
2876 const body = stmt.getBody();
2877 assert(body.getStmtClass() == .CompoundStmtClass);
2878 const comp = @ptrCast(*const clang.CompoundStmt, body);
2879 // TODO https://github.com/ziglang/zig/issues/1738
2880 // return comp.body_end() - comp.body_begin();
2881 const start_addr = @ptrToInt(comp.body_begin());
2882 const end_addr = @ptrToInt(comp.body_end());
2883 return (end_addr - start_addr) / @sizeOf(*clang.Stmt);
2884}
2885
28862213fn transSwitch(
2887 rp: RestorePoint,
2214 c: *Context,
28882215 scope: *Scope,
28892216 stmt: *const clang.SwitchStmt,
2890) TransError!*ast.Node {
2891 const switch_tok = try appendToken(rp.c, .Keyword_switch, "switch");
2892 _ = try appendToken(rp.c, .LParen, "(");
2893
2894 const cases_len = getSwitchCaseCount(stmt);
2895
2217) TransError!Node {
28962218 var cond_scope = Scope.Condition{
28972219 .base = .{
28982220 .parent = scope,
2899 .id = .Condition,
2221 .id = .condition,
29002222 },
29012223 };
29022224 defer cond_scope.deinit();
2903 const switch_expr = try transExpr(rp, &cond_scope.base, stmt.getCond(), .used, .r_value);
2904 _ = try appendToken(rp.c, .RParen, ")");
2905 _ = try appendToken(rp.c, .LBrace, "{");
2906 // reserve +1 case in case there is no default case
2907 const switch_node = try ast.Node.Switch.alloc(rp.c.arena, cases_len + 1);
2908 switch_node.* = .{
2909 .switch_token = switch_tok,
2910 .expr = switch_expr,
2911 .cases_len = cases_len + 1,
2912 .rbrace = try appendToken(rp.c, .RBrace, "}"),
2913 };
2225 const switch_expr = try transExpr(c, &cond_scope.base, stmt.getCond(), .used);
29142226
2915 var switch_scope = Scope.Switch{
2916 .base = .{
2917 .id = .Switch,
2918 .parent = scope,
2919 },
2920 .cases = switch_node.cases(),
2921 .case_index = 0,
2922 .pending_block = undefined,
2923 .default_label = null,
2924 .switch_label = null,
2925 };
2227 var cases = std.ArrayList(Node).init(c.gpa);
2228 defer cases.deinit();
2229 var has_default = false;
29262230
2927 // tmp block that all statements will go before being picked up by a case or default
2928 var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, false);
2929 defer block_scope.deinit();
2231 const body = stmt.getBody();
2232 assert(body.getStmtClass() == .CompoundStmtClass);
2233 const compound_stmt = @ptrCast(*const clang.CompoundStmt, body);
2234 var it = compound_stmt.body_begin();
2235 const end_it = compound_stmt.body_end();
2236 // Iterate over switch body and collect all cases.
2237 // Fallthrough is handled by duplicating statements.
2238 while (it != end_it) : (it += 1) {
2239 switch (it[0].getStmtClass()) {
2240 .CaseStmtClass => {
2241 var items = std.ArrayList(Node).init(c.gpa);
2242 defer items.deinit();
2243 const sub = try transCaseStmt(c, scope, it[0], &items);
2244 const res = try transSwitchProngStmt(c, scope, sub, it, end_it);
2245
2246 if (items.items.len == 0) {
2247 has_default = true;
2248 const switch_else = try Tag.switch_else.create(c.arena, res);
2249 try cases.append(switch_else);
2250 } else {
2251 const switch_prong = try Tag.switch_prong.create(c.arena, .{
2252 .cases = try c.arena.dupe(Node, items.items),
2253 .cond = res,
2254 });
2255 try cases.append(switch_prong);
2256 }
2257 },
2258 .DefaultStmtClass => {
2259 has_default = true;
2260 const default_stmt = @ptrCast(*const clang.DefaultStmt, it[0]);
2261
2262 var sub = default_stmt.getSubStmt();
2263 while (true) switch (sub.getStmtClass()) {
2264 .CaseStmtClass => sub = @ptrCast(*const clang.CaseStmt, sub).getSubStmt(),
2265 .DefaultStmtClass => sub = @ptrCast(*const clang.DefaultStmt, sub).getSubStmt(),
2266 else => break,
2267 };
29302268
2931 // Note that we do not defer a deinit here; the switch_scope.pending_block field
2932 // has its own memory management. This resource is freed inside `transCase` and
2933 // then the final pending_block is freed at the bottom of this function with
2934 // pending_block.deinit().
2935 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
2936 try switch_scope.pending_block.statements.append(&switch_node.base);
2937
2938 const last = try transStmt(rp, &block_scope.base, stmt.getBody(), .unused, .r_value);
2939 _ = try appendToken(rp.c, .Semicolon, ";");
2940
2941 // take all pending statements
2942 const last_block_stmts = last.cast(ast.Node.Block).?.statements();
2943 try switch_scope.pending_block.statements.ensureCapacity(
2944 switch_scope.pending_block.statements.items.len + last_block_stmts.len,
2945 );
2946 for (last_block_stmts) |n| {
2947 switch_scope.pending_block.statements.appendAssumeCapacity(n);
2948 }
2949
2950 if (switch_scope.default_label == null) {
2951 switch_scope.switch_label = try block_scope.makeMangledName(rp.c, "switch");
2952 }
2953 if (switch_scope.switch_label) |l| {
2954 switch_scope.pending_block.label = try appendIdentifier(rp.c, l);
2955 _ = try appendToken(rp.c, .Colon, ":");
2956 }
2957 if (switch_scope.default_label == null) {
2958 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2959 else_prong.expr = blk: {
2960 var br = try CtrlFlow.init(rp.c, .Break, switch_scope.switch_label.?);
2961 break :blk &(try br.finish(null)).base;
2962 };
2963 _ = try appendToken(rp.c, .Comma, ",");
2269 const res = try transSwitchProngStmt(c, scope, sub, it, end_it);
29642270
2965 if (switch_scope.case_index >= switch_scope.cases.len)
2966 return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});
2967 switch_scope.cases[switch_scope.case_index] = &else_prong.base;
2968 switch_scope.case_index += 1;
2271 const switch_else = try Tag.switch_else.create(c.arena, res);
2272 try cases.append(switch_else);
2273 },
2274 else => {}, // collected in transSwitchProngStmt
2275 }
29692276 }
2970 // We overallocated in case there was no default, so now we correct
2971 // the number of cases in the AST node.
2972 switch_node.cases_len = switch_scope.case_index;
29732277
2974 const result_node = try switch_scope.pending_block.complete(rp.c);
2975 switch_scope.pending_block.deinit();
2976 return result_node;
2977}
2978
2979fn transCase(
2980 rp: RestorePoint,
2981 scope: *Scope,
2982 stmt: *const clang.CaseStmt,
2983) TransError!*ast.Node {
2984 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
2985 const switch_scope = scope.getSwitch();
2986 const label = try block_scope.makeMangledName(rp.c, "case");
2987 _ = try appendToken(rp.c, .Semicolon, ";");
2988
2989 const expr = if (stmt.getRHS()) |rhs| blk: {
2990 const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .r_value);
2991 const ellips = try appendToken(rp.c, .Ellipsis3, "...");
2992 const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2993
2994 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
2995 node.* = .{
2996 .base = .{ .tag = .Range },
2997 .op_token = ellips,
2998 .lhs = lhs_node,
2999 .rhs = rhs_node,
3000 };
3001 break :blk &node.base;
3002 } else
3003 try transExpr(rp, scope, stmt.getLHS(), .used, .r_value);
3004
3005 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
3006 switch_prong.expr = blk: {
3007 var br = try CtrlFlow.init(rp.c, .Break, label);
3008 break :blk &(try br.finish(null)).base;
3009 };
3010 _ = try appendToken(rp.c, .Comma, ",");
2278 if (!has_default) {
2279 const else_prong = try Tag.switch_else.create(c.arena, Tag.@"break".init());
2280 try cases.append(else_prong);
2281 }
30112282
3012 if (switch_scope.case_index >= switch_scope.cases.len)
3013 return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});
3014 switch_scope.cases[switch_scope.case_index] = &switch_prong.base;
3015 switch_scope.case_index += 1;
2283 return Tag.@"switch".create(c.arena, .{
2284 .cond = switch_expr,
2285 .cases = try c.arena.dupe(Node, cases.items),
2286 });
2287}
30162288
3017 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
3018 _ = try appendToken(rp.c, .Colon, ":");
2289/// Collects all items for this case, returns the first statement after the labels.
2290/// If items ends up empty, the prong should be translated as an else.
2291fn transCaseStmt(c: *Context, scope: *Scope, stmt: *const clang.Stmt, items: *std.ArrayList(Node)) TransError!*const clang.Stmt {
2292 var sub = stmt;
2293 var seen_default = false;
2294 while (true) {
2295 switch (sub.getStmtClass()) {
2296 .DefaultStmtClass => {
2297 seen_default = true;
2298 items.items.len = 0;
2299 const default_stmt = @ptrCast(*const clang.DefaultStmt, sub);
2300 sub = default_stmt.getSubStmt();
2301 },
2302 .CaseStmtClass => {
2303 const case_stmt = @ptrCast(*const clang.CaseStmt, sub);
30192304
3020 // take all pending statements
3021 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
3022 block_scope.statements.shrinkAndFree(0);
2305 if (seen_default) {
2306 items.items.len = 0;
2307 sub = case_stmt.getSubStmt();
2308 continue;
2309 }
30232310
3024 const pending_node = try switch_scope.pending_block.complete(rp.c);
3025 switch_scope.pending_block.deinit();
3026 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
2311 const expr = if (case_stmt.getRHS()) |rhs| blk: {
2312 const lhs_node = try transExprCoercing(c, scope, case_stmt.getLHS(), .used);
2313 const rhs_node = try transExprCoercing(c, scope, rhs, .used);
30272314
3028 try switch_scope.pending_block.statements.append(pending_node);
2315 break :blk try Tag.ellipsis3.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
2316 } else
2317 try transExprCoercing(c, scope, case_stmt.getLHS(), .used);
30292318
3030 return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value);
2319 try items.append(expr);
2320 sub = case_stmt.getSubStmt();
2321 },
2322 else => return sub,
2323 }
2324 }
30312325}
30322326
3033fn transDefault(
3034 rp: RestorePoint,
2327/// Collects all statements seen by this case into a block.
2328/// Avoids creating a block if the first statement is a break or return.
2329fn transSwitchProngStmt(
2330 c: *Context,
30352331 scope: *Scope,
3036 stmt: *const clang.DefaultStmt,
3037) TransError!*ast.Node {
3038 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
3039 const switch_scope = scope.getSwitch();
3040 switch_scope.default_label = try block_scope.makeMangledName(rp.c, "default");
3041 _ = try appendToken(rp.c, .Semicolon, ";");
3042
3043 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
3044 else_prong.expr = blk: {
3045 var br = try CtrlFlow.init(rp.c, .Break, switch_scope.default_label.?);
3046 break :blk &(try br.finish(null)).base;
3047 };
3048 _ = try appendToken(rp.c, .Comma, ",");
3049
3050 if (switch_scope.case_index >= switch_scope.cases.len)
3051 return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});
3052 switch_scope.cases[switch_scope.case_index] = &else_prong.base;
3053 switch_scope.case_index += 1;
3054
3055 switch_scope.pending_block.label = try appendIdentifier(rp.c, switch_scope.default_label.?);
3056 _ = try appendToken(rp.c, .Colon, ":");
3057
3058 // take all pending statements
3059 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
3060 block_scope.statements.shrinkAndFree(0);
2332 stmt: *const clang.Stmt,
2333 parent_it: clang.CompoundStmt.ConstBodyIterator,
2334 parent_end_it: clang.CompoundStmt.ConstBodyIterator,
2335) TransError!Node {
2336 switch (stmt.getStmtClass()) {
2337 .BreakStmtClass => return Tag.empty_block.init(),
2338 .ReturnStmtClass => return transStmt(c, scope, stmt, .unused),
2339 .CaseStmtClass, .DefaultStmtClass => unreachable,
2340 else => {
2341 var block_scope = try Scope.Block.init(c, scope, false);
2342 defer block_scope.deinit();
30612343
3062 const pending_node = try switch_scope.pending_block.complete(rp.c);
3063 switch_scope.pending_block.deinit();
3064 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
3065 try switch_scope.pending_block.statements.append(pending_node);
2344 // we do not need to translate `stmt` since it is the first stmt of `parent_it`
2345 try transSwitchProngStmtInline(c, &block_scope, parent_it, parent_end_it);
2346 return try block_scope.complete(c);
2347 },
2348 }
2349}
30662350
3067 return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value);
2351/// Collects all statements seen by this case into a block.
2352fn transSwitchProngStmtInline(
2353 c: *Context,
2354 block: *Scope.Block,
2355 start_it: clang.CompoundStmt.ConstBodyIterator,
2356 end_it: clang.CompoundStmt.ConstBodyIterator,
2357) TransError!void {
2358 var it = start_it;
2359 while (it != end_it) : (it += 1) {
2360 switch (it[0].getStmtClass()) {
2361 .ReturnStmtClass => {
2362 const result = try transStmt(c, &block.base, it[0], .unused);
2363 try block.statements.append(result);
2364 return;
2365 },
2366 .BreakStmtClass => return,
2367 .CaseStmtClass => {
2368 var sub = @ptrCast(*const clang.CaseStmt, it[0]).getSubStmt();
2369 while (true) switch (sub.getStmtClass()) {
2370 .CaseStmtClass => sub = @ptrCast(*const clang.CaseStmt, sub).getSubStmt(),
2371 .DefaultStmtClass => sub = @ptrCast(*const clang.DefaultStmt, sub).getSubStmt(),
2372 else => break,
2373 };
2374 const result = try transStmt(c, &block.base, sub, .unused);
2375 assert(result.tag() != .declaration);
2376 try block.statements.append(result);
2377 },
2378 .DefaultStmtClass => {
2379 var sub = @ptrCast(*const clang.DefaultStmt, it[0]).getSubStmt();
2380 while (true) switch (sub.getStmtClass()) {
2381 .CaseStmtClass => sub = @ptrCast(*const clang.CaseStmt, sub).getSubStmt(),
2382 .DefaultStmtClass => sub = @ptrCast(*const clang.DefaultStmt, sub).getSubStmt(),
2383 else => break,
2384 };
2385 const result = try transStmt(c, &block.base, sub, .unused);
2386 assert(result.tag() != .declaration);
2387 try block.statements.append(result);
2388 },
2389 .CompoundStmtClass => {
2390 const compound_stmt = @ptrCast(*const clang.CompoundStmt, it[0]);
2391 var child_block = try Scope.Block.init(c, &block.base, false);
2392 defer child_block.deinit();
2393
2394 try transCompoundStmtInline(c, compound_stmt, &child_block);
2395 const result = try child_block.complete(c);
2396 try block.statements.append(result);
2397 if (result.isNoreturn(true)) {
2398 return;
2399 }
2400 },
2401 else => {
2402 const result = try transStmt(c, &block.base, it[0], .unused);
2403 switch (result.tag()) {
2404 .declaration, .empty_block => {},
2405 else => try block.statements.append(result),
2406 }
2407 },
2408 }
2409 }
2410 return;
30682411}
30692412
3070fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!*ast.Node {
2413fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
30712414 var result: clang.ExprEvalResult = undefined;
3072 if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, rp.c.clang_context))
3073 return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{});
2415 if (!expr.evaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context))
2416 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{});
30742417
3075 var val_node: ?*ast.Node = null;
30762418 switch (result.Val.getKind()) {
30772419 .Int => {
30782420 // See comment in `transIntegerLiteral` for why this code is here.
30792421 // @as(T, x)
30802422 const expr_base = @ptrCast(*const clang.Expr, expr);
3081 const as_node = try rp.c.createBuiltinCall("@as", 2);
3082 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());
3083 as_node.params()[0] = ty_node;
3084 _ = try appendToken(rp.c, .Comma, ",");
3085
3086 const int_lit_node = try transCreateNodeAPInt(rp.c, result.Val.getInt());
3087 as_node.params()[1] = int_lit_node;
3088
3089 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3090
3091 return maybeSuppressResult(rp, scope, used, &as_node.base);
2423 const as_node = try Tag.as.create(c.arena, .{
2424 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
2425 .rhs = try transCreateNodeAPInt(c, result.Val.getInt()),
2426 });
2427 return maybeSuppressResult(c, scope, used, as_node);
30922428 },
30932429 else => {
3094 return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind", .{});
2430 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind", .{});
30952431 },
30962432 }
30972433}
30982434
3099fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!*ast.Node {
3100 return transStringLiteral(rp, scope, expr.getFunctionName(), used);
2435fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!Node {
2436 return transStringLiteral(c, scope, expr.getFunctionName(), used);
31012437}
31022438
3103fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!*ast.Node {
3104 const node = try c.arena.create(ast.Node.OneToken);
3105 node.* = .{
3106 .base = .{ .tag = .CharLiteral },
3107 .token = undefined,
3108 };
3109 if (narrow) {
3110 const val_array = [_]u8{@intCast(u8, val)};
3111 node.token = try appendTokenFmt(c, .CharLiteral, "'{}'", .{std.zig.fmtEscapes(&val_array)});
3112 } else {
3113 node.token = try appendTokenFmt(c, .CharLiteral, "'\\u{{{x}}}'", .{val});
3114 }
3115 return &node.base;
2439fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node {
2440 return Tag.char_literal.create(c.arena, if (narrow)
2441 try std.fmt.allocPrint(c.arena, "'{s}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})})
2442 else
2443 try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val}));
31162444}
31172445
31182446fn transCharLiteral(
3119 rp: RestorePoint,
2447 c: *Context,
31202448 scope: *Scope,
31212449 stmt: *const clang.CharacterLiteral,
31222450 result_used: ResultUsed,
31232451 suppress_as: SuppressCast,
3124) TransError!*ast.Node {
2452) TransError!Node {
31252453 const kind = stmt.getKind();
31262454 const val = stmt.getValue();
31272455 const narrow = kind == .Ascii or kind == .UTF8;
31282456 // C has a somewhat obscure feature called multi-character character constant
31292457 // e.g. 'abcd'
31302458 const int_lit_node = if (kind == .Ascii and val > 255)
3131 try transCreateNodeInt(rp.c, val)
2459 try transCreateNodeNumber(c, val, .int)
31322460 else
3133 try transCreateCharLitNode(rp.c, narrow, val);
2461 try transCreateCharLitNode(c, narrow, val);
31342462
31352463 if (suppress_as == .no_as) {
3136 return maybeSuppressResult(rp, scope, result_used, int_lit_node);
2464 return maybeSuppressResult(c, scope, result_used, int_lit_node);
31372465 }
31382466 // See comment in `transIntegerLiteral` for why this code is here.
31392467 // @as(T, x)
31402468 const expr_base = @ptrCast(*const clang.Expr, stmt);
3141 const as_node = try rp.c.createBuiltinCall("@as", 2);
3142 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());
3143 as_node.params()[0] = ty_node;
3144 _ = try appendToken(rp.c, .Comma, ",");
3145 as_node.params()[1] = int_lit_node;
3146
3147 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3148 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
2469 const as_node = try Tag.as.create(c.arena, .{
2470 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
2471 .rhs = int_lit_node,
2472 });
2473 return maybeSuppressResult(c, scope, result_used, as_node);
31492474}
31502475
3151fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!*ast.Node {
2476fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!Node {
31522477 const comp = stmt.getSubStmt();
31532478 if (used == .unused) {
3154 return transCompoundStmt(rp, scope, comp);
2479 return transCompoundStmt(c, scope, comp);
31552480 }
3156 const lparen = try appendToken(rp.c, .LParen, "(");
3157 var block_scope = try Scope.Block.init(rp.c, scope, true);
2481 var block_scope = try Scope.Block.init(c, scope, true);
31582482 defer block_scope.deinit();
31592483
31602484 var it = comp.body_begin();
31612485 const end_it = comp.body_end();
31622486 while (it != end_it - 1) : (it += 1) {
3163 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
3164 try block_scope.statements.append(result);
2487 const result = try transStmt(c, &block_scope.base, it[0], .unused);
2488 switch (result.tag()) {
2489 .declaration, .empty_block => {},
2490 else => try block_scope.statements.append(result),
2491 }
31652492 }
3166 const break_node = blk: {
3167 var tmp = try CtrlFlow.init(rp.c, .Break, "blk");
3168 const rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);
3169 break :blk try tmp.finish(rhs);
3170 };
3171 _ = try appendToken(rp.c, .Semicolon, ";");
3172 try block_scope.statements.append(&break_node.base);
3173 const block_node = try block_scope.complete(rp.c);
3174 const rparen = try appendToken(rp.c, .RParen, ")");
3175 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3176 grouped_expr.* = .{
3177 .lparen = lparen,
3178 .expr = block_node,
3179 .rparen = rparen,
3180 };
3181 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
2493 const break_node = try Tag.break_val.create(c.arena, .{
2494 .label = block_scope.label,
2495 .val = try transStmt(c, &block_scope.base, it[0], .used),
2496 });
2497 try block_scope.statements.append(break_node);
2498 const res = try block_scope.complete(c);
2499 return maybeSuppressResult(c, scope, used, res);
31822500}
31832501
3184fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node {
3185 var container_node = try transExpr(rp, scope, stmt.getBase(), .used, .r_value);
2502fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {
2503 var container_node = try transExpr(c, scope, stmt.getBase(), .used);
31862504
31872505 if (stmt.isArrow()) {
3188 container_node = try transCreateNodePtrDeref(rp.c, container_node);
2506 container_node = try Tag.deref.create(c.arena, container_node);
31892507 }
31902508
31912509 const member_decl = stmt.getMemberDecl();
......@@ -3196,19 +2514,18 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExp
31962514 if (decl_kind == .Field) {
31972515 const field_decl = @ptrCast(*const clang.FieldDecl, member_decl);
31982516 if (field_decl.isAnonymousStructOrUnion()) {
3199 const name = rp.c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
3200 break :blk try mem.dupe(rp.c.arena, u8, name);
2517 const name = c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
2518 break :blk try mem.dupe(c.arena, u8, name);
32012519 }
32022520 }
32032521 const decl = @ptrCast(*const clang.NamedDecl, member_decl);
3204 break :blk try rp.c.str(decl.getName_bytes_begin());
2522 break :blk try c.str(decl.getName_bytes_begin());
32052523 };
3206
3207 const node = try transCreateNodeFieldAccess(rp.c, container_node, name);
3208 return maybeSuppressResult(rp, scope, result_used, node);
2524 const node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .field_name = name });
2525 return maybeSuppressResult(c, scope, result_used, node);
32092526}
32102527
3211fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const clang.ArraySubscriptExpr, result_used: ResultUsed) TransError!*ast.Node {
2528fn transArrayAccess(c: *Context, scope: *Scope, stmt: *const clang.ArraySubscriptExpr, result_used: ResultUsed) TransError!Node {
32122529 var base_stmt = stmt.getBase();
32132530
32142531 // Unwrap the base statement if it's an array decayed to a bare pointer type
......@@ -3221,30 +2538,26 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const clang.ArraySub
32212538 }
32222539 }
32232540
3224 const container_node = try transExpr(rp, scope, base_stmt, .used, .r_value);
3225 const node = try transCreateNodeArrayAccess(rp.c, container_node);
2541 const container_node = try transExpr(c, scope, base_stmt, .used);
32262542
32272543 // cast if the index is long long or signed
32282544 const subscr_expr = stmt.getIdx();
3229 const qt = getExprQualType(rp.c, subscr_expr);
2545 const qt = getExprQualType(c, subscr_expr);
32302546 const is_longlong = cIsLongLongInteger(qt);
32312547 const is_signed = cIsSignedInteger(qt);
32322548
3233 if (is_longlong or is_signed) {
3234 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2549 const rhs = if (is_longlong or is_signed) blk: {
32352550 // check if long long first so that signed long long doesn't just become unsigned long long
3236 var typeid_node = if (is_longlong) try transCreateNodeIdentifier(rp.c, "usize") else try transQualTypeIntWidthOf(rp.c, qt, false);
3237 cast_node.params()[0] = typeid_node;
3238 _ = try appendToken(rp.c, .Comma, ",");
3239 cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);
3240 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3241 node.rtoken = try appendToken(rp.c, .RBrace, "]");
3242 node.index_expr = &cast_node.base;
3243 } else {
3244 node.index_expr = try transExpr(rp, scope, subscr_expr, .used, .r_value);
3245 node.rtoken = try appendToken(rp.c, .RBrace, "]");
3246 }
3247 return maybeSuppressResult(rp, scope, result_used, &node.base);
2551 var typeid_node = if (is_longlong) try Tag.identifier.create(c.arena, "usize") else try transQualTypeIntWidthOf(c, qt, false);
2552 break :blk try Tag.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used) });
2553 } else
2554 try transExpr(c, scope, subscr_expr, .used);
2555
2556 const node = try Tag.array_access.create(c.arena, .{
2557 .lhs = container_node,
2558 .rhs = rhs,
2559 });
2560 return maybeSuppressResult(c, scope, result_used, node);
32482561}
32492562
32502563/// Check if an expression is ultimately a reference to a function declaration
......@@ -3279,29 +2592,25 @@ fn cIsFunctionDeclRef(expr: *const clang.Expr) bool {
32792592 }
32802593}
32812594
3282fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!*ast.Node {
2595fn transCallExpr(c: *Context, scope: *Scope, stmt: *const clang.CallExpr, result_used: ResultUsed) TransError!Node {
32832596 const callee = stmt.getCallee();
3284 var raw_fn_expr = try transExpr(rp, scope, callee, .used, .r_value);
2597 var raw_fn_expr = try transExpr(c, scope, callee, .used);
32852598
32862599 var is_ptr = false;
32872600 const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr);
32882601
32892602 const fn_expr = if (is_ptr and fn_ty != null and !cIsFunctionDeclRef(callee))
3290 try transCreateNodeUnwrapNull(rp.c, raw_fn_expr)
2603 try Tag.unwrap.create(c.arena, raw_fn_expr)
32912604 else
32922605 raw_fn_expr;
32932606
32942607 const num_args = stmt.getNumArgs();
3295 const node = try rp.c.createCall(fn_expr, num_args);
3296 const call_params = node.params();
2608 const args = try c.arena.alloc(Node, num_args);
32972609
3298 const args = stmt.getArgs();
2610 const c_args = stmt.getArgs();
32992611 var i: usize = 0;
33002612 while (i < num_args) : (i += 1) {
3301 if (i != 0) {
3302 _ = try appendToken(rp.c, .Comma, ",");
3303 }
3304 var call_param = try transExpr(rp, scope, args[i], .used, .r_value);
2613 var arg = try transExpr(c, scope, c_args[i], .used);
33052614
33062615 // In C the result type of a boolean expression is int. If this result is passed as
33072616 // an argument to a function whose parameter is also int, there is no cast. Therefore
......@@ -3312,31 +2621,26 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, r
33122621 const param_count = fn_proto.getNumParams();
33132622 if (i < param_count) {
33142623 const param_qt = fn_proto.getParamType(@intCast(c_uint, i));
3315 if (isBoolRes(call_param) and cIsNativeInt(param_qt)) {
3316 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
3317 builtin_node.params()[0] = call_param;
3318 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3319 call_param = &builtin_node.base;
2624 if (isBoolRes(arg) and cIsNativeInt(param_qt)) {
2625 arg = try Tag.bool_to_int.create(c.arena, arg);
33202626 }
33212627 }
33222628 },
33232629 else => {},
33242630 }
33252631 }
3326 call_params[i] = call_param;
2632 args[i] = arg;
33272633 }
3328 node.rtoken = try appendToken(rp.c, .RParen, ")");
3329
2634 const node = try Tag.call.create(c.arena, .{ .lhs = fn_expr, .args = args });
33302635 if (fn_ty) |ty| {
33312636 const canon = ty.getReturnType().getCanonicalType();
33322637 const ret_ty = canon.getTypePtr();
33332638 if (ret_ty.isVoidType()) {
3334 _ = try appendToken(rp.c, .Semicolon, ";");
3335 return &node.base;
2639 return node;
33362640 }
33372641 }
33382642
3339 return maybeSuppressResult(rp, scope, result_used, &node.base);
2643 return maybeSuppressResult(c, scope, result_used, node);
33402644}
33412645
33422646const ClangFunctionType = union(enum) {
......@@ -3371,38 +2675,29 @@ fn qualTypeGetFnProto(qt: clang.QualType, is_ptr: *bool) ?ClangFunctionType {
33712675}
33722676
33732677fn transUnaryExprOrTypeTraitExpr(
3374 rp: RestorePoint,
2678 c: *Context,
33752679 scope: *Scope,
33762680 stmt: *const clang.UnaryExprOrTypeTraitExpr,
33772681 result_used: ResultUsed,
3378) TransError!*ast.Node {
2682) TransError!Node {
33792683 const loc = stmt.getBeginLoc();
3380 const type_node = try transQualType(
3381 rp,
3382 stmt.getTypeOfArgument(),
3383 loc,
3384 );
2684 const type_node = try transQualType(c, scope, stmt.getTypeOfArgument(), loc);
33852685
33862686 const kind = stmt.getKind();
3387 const kind_str = switch (kind) {
3388 .SizeOf => "@sizeOf",
3389 .AlignOf => "@alignOf",
2687 switch (kind) {
2688 .SizeOf => return Tag.sizeof.create(c.arena, type_node),
2689 .AlignOf => return Tag.alignof.create(c.arena, type_node),
33902690 .PreferredAlignOf,
33912691 .VecStep,
33922692 .OpenMPRequiredSimdAlign,
3393 => return revertAndWarn(
3394 rp,
2693 => return fail(
2694 c,
33952695 error.UnsupportedTranslation,
33962696 loc,
33972697 "Unsupported type trait kind {}",
33982698 .{kind},
33992699 ),
3400 };
3401
3402 const builtin_node = try rp.c.createBuiltinCall(kind_str, 1);
3403 builtin_node.params()[0] = type_node;
3404 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3405 return maybeSuppressResult(rp, scope, result_used, &builtin_node.base);
2700 }
34062701}
34072702
34082703fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
......@@ -3415,95 +2710,79 @@ fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
34152710 }
34162711}
34172712
3418fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!*ast.Node {
2713fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!Node {
34192714 const op_expr = stmt.getSubExpr();
34202715 switch (stmt.getOpcode()) {
34212716 .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3422 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
2717 return transCreatePostCrement(c, scope, stmt, .add_wrap_assign, used)
34232718 else
3424 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
2719 return transCreatePostCrement(c, scope, stmt, .add_assign, used),
34252720 .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3426 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
2721 return transCreatePostCrement(c, scope, stmt, .sub_wrap_assign, used)
34272722 else
3428 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
2723 return transCreatePostCrement(c, scope, stmt, .sub_assign, used),
34292724 .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3430 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
2725 return transCreatePreCrement(c, scope, stmt, .add_wrap_assign, used)
34312726 else
3432 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
2727 return transCreatePreCrement(c, scope, stmt, .add_assign, used),
34332728 .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3434 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
2729 return transCreatePreCrement(c, scope, stmt, .sub_wrap_assign, used)
34352730 else
3436 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
2731 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
34372732 .AddrOf => {
34382733 if (cIsFunctionDeclRef(op_expr)) {
3439 return transExpr(rp, scope, op_expr, used, .r_value);
2734 return transExpr(c, scope, op_expr, used);
34402735 }
3441 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3442 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
3443 return &op_node.base;
2736 return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
34442737 },
34452738 .Deref => {
3446 const value_node = try transExpr(rp, scope, op_expr, used, .r_value);
2739 const node = try transExpr(c, scope, op_expr, used);
34472740 var is_ptr = false;
34482741 const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);
34492742 if (fn_ty != null and is_ptr)
3450 return value_node;
3451 const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);
3452 return transCreateNodePtrDeref(rp.c, unwrapped);
2743 return node;
2744 const unwrapped = try Tag.unwrap.create(c.arena, node);
2745 return Tag.deref.create(c.arena, unwrapped);
34532746 },
3454 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),
2747 .Plus => return transExpr(c, scope, op_expr, used),
34552748 .Minus => {
34562749 if (!qualTypeHasWrappingOverflow(op_expr.getType())) {
3457 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-");
3458 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3459 return &op_node.base;
2750 return Tag.negate.create(c.arena, try transExpr(c, scope, op_expr, .used));
34602751 } else if (cIsUnsignedInteger(op_expr.getType())) {
3461 // we gotta emit 0 -% x
3462 const zero = try transCreateNodeInt(rp.c, 0);
3463 const token = try appendToken(rp.c, .MinusPercent, "-%");
3464 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
3465 return transCreateNodeInfixOp(rp, scope, zero, .SubWrap, token, expr, used, true);
2752 // use -% x for unsigned integers
2753 return Tag.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used));
34662754 } else
3467 return revertAndWarn(rp, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{});
2755 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{});
34682756 },
34692757 .Not => {
3470 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");
3471 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3472 return &op_node.base;
2758 return Tag.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used));
34732759 },
34742760 .LNot => {
3475 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
3476 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
3477 return &op_node.base;
2761 return Tag.not.create(c.arena, try transBoolExpr(c, scope, op_expr, .used));
34782762 },
34792763 .Extension => {
3480 return transExpr(rp, scope, stmt.getSubExpr(), used, .l_value);
2764 return transExpr(c, scope, stmt.getSubExpr(), used);
34812765 },
3482 else => return revertAndWarn(rp, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}),
2766 else => return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}),
34832767 }
34842768}
34852769
34862770fn transCreatePreCrement(
3487 rp: RestorePoint,
2771 c: *Context,
34882772 scope: *Scope,
34892773 stmt: *const clang.UnaryOperator,
3490 op: ast.Node.Tag,
3491 op_tok_id: std.zig.Token.Id,
3492 bytes: []const u8,
2774 op: Tag,
34932775 used: ResultUsed,
3494) TransError!*ast.Node {
2776) TransError!Node {
34952777 const op_expr = stmt.getSubExpr();
34962778
34972779 if (used == .unused) {
34982780 // common case
34992781 // c: ++expr
35002782 // zig: expr += 1
3501 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
3502 const token = try appendToken(rp.c, op_tok_id, bytes);
3503 const one = try transCreateNodeInt(rp.c, 1);
3504 if (scope.id != .Condition)
3505 _ = try appendToken(rp.c, .Semicolon, ";");
3506 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
2783 const lhs = try transExpr(c, scope, op_expr, .used);
2784 const rhs = Tag.one_literal.init();
2785 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);
35072786 }
35082787 // worst case
35092788 // c: ++expr
......@@ -3512,71 +2791,44 @@ fn transCreatePreCrement(
35122791 // zig: _ref.* += 1;
35132792 // zig: break :blk _ref.*
35142793 // zig: })
3515 var block_scope = try Scope.Block.init(rp.c, scope, true);
2794 var block_scope = try Scope.Block.init(c, scope, true);
35162795 defer block_scope.deinit();
3517 const ref = try block_scope.makeMangledName(rp.c, "ref");
3518
3519 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3520 const name_tok = try appendIdentifier(rp.c, ref);
3521 const eq_token = try appendToken(rp.c, .Equal, "=");
3522 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3523 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3524 const init_node = &rhs_node.base;
3525 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3526 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3527 .name_token = name_tok,
3528 .mut_token = mut_tok,
3529 .semicolon_token = semicolon_token,
3530 }, .{
3531 .eq_token = eq_token,
3532 .init_node = init_node,
3533 });
3534 try block_scope.statements.append(&node.base);
3535
3536 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
3537 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
3538 _ = try appendToken(rp.c, .Semicolon, ";");
3539 const token = try appendToken(rp.c, op_tok_id, bytes);
3540 const one = try transCreateNodeInt(rp.c, 1);
3541 _ = try appendToken(rp.c, .Semicolon, ";");
3542 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
3543 try block_scope.statements.append(assign);
2796 const ref = try block_scope.makeMangledName(c, "ref");
35442797
3545 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);
3546 try block_scope.statements.append(&break_node.base);
3547 const block_node = try block_scope.complete(rp.c);
3548 // semicolon must immediately follow rbrace because it is the last token in a block
3549 _ = try appendToken(rp.c, .Semicolon, ";");
3550 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3551 grouped_expr.* = .{
3552 .lparen = try appendToken(rp.c, .LParen, "("),
3553 .expr = block_node,
3554 .rparen = try appendToken(rp.c, .RParen, ")"),
3555 };
3556 return &grouped_expr.base;
2798 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
2799 const addr_of = try Tag.address_of.create(c.arena, expr);
2800 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
2801 try block_scope.statements.append(ref_decl);
2802
2803 const lhs_node = try Tag.identifier.create(c.arena, ref);
2804 const ref_node = try Tag.deref.create(c.arena, lhs_node);
2805 const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);
2806 try block_scope.statements.append(node);
2807
2808 const break_node = try Tag.break_val.create(c.arena, .{
2809 .label = block_scope.label,
2810 .val = ref_node,
2811 });
2812 try block_scope.statements.append(break_node);
2813 return block_scope.complete(c);
35572814}
35582815
35592816fn transCreatePostCrement(
3560 rp: RestorePoint,
2817 c: *Context,
35612818 scope: *Scope,
35622819 stmt: *const clang.UnaryOperator,
3563 op: ast.Node.Tag,
3564 op_tok_id: std.zig.Token.Id,
3565 bytes: []const u8,
2820 op: Tag,
35662821 used: ResultUsed,
3567) TransError!*ast.Node {
2822) TransError!Node {
35682823 const op_expr = stmt.getSubExpr();
35692824
35702825 if (used == .unused) {
35712826 // common case
3572 // c: ++expr
2827 // c: expr++
35732828 // zig: expr += 1
3574 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
3575 const token = try appendToken(rp.c, op_tok_id, bytes);
3576 const one = try transCreateNodeInt(rp.c, 1);
3577 if (scope.id != .Condition)
3578 _ = try appendToken(rp.c, .Semicolon, ";");
3579 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
2829 const lhs = try transExpr(c, scope, op_expr, .used);
2830 const rhs = Tag.one_literal.init();
2831 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);
35802832 }
35812833 // worst case
35822834 // c: expr++
......@@ -3586,93 +2838,56 @@ fn transCreatePostCrement(
35862838 // zig: _ref.* += 1;
35872839 // zig: break :blk _tmp
35882840 // zig: })
3589 var block_scope = try Scope.Block.init(rp.c, scope, true);
2841 var block_scope = try Scope.Block.init(c, scope, true);
35902842 defer block_scope.deinit();
3591 const ref = try block_scope.makeMangledName(rp.c, "ref");
3592
3593 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3594 const name_tok = try appendIdentifier(rp.c, ref);
3595 const eq_token = try appendToken(rp.c, .Equal, "=");
3596 const rhs_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3597 rhs_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3598 const init_node = &rhs_node.base;
3599 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3600 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3601 .name_token = name_tok,
3602 .mut_token = mut_tok,
3603 .semicolon_token = semicolon_token,
3604 }, .{
3605 .eq_token = eq_token,
3606 .init_node = init_node,
3607 });
3608 try block_scope.statements.append(&node.base);
3609
3610 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
3611 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
3612 _ = try appendToken(rp.c, .Semicolon, ";");
3613
3614 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
3615 const tmp_mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3616 const tmp_name_tok = try appendIdentifier(rp.c, tmp);
3617 const tmp_eq_token = try appendToken(rp.c, .Equal, "=");
3618 const tmp_init_node = ref_node;
3619 const tmp_semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3620 const tmp_node = try ast.Node.VarDecl.create(rp.c.arena, .{
3621 .name_token = tmp_name_tok,
3622 .mut_token = tmp_mut_tok,
3623 .semicolon_token = semicolon_token,
3624 }, .{
3625 .eq_token = tmp_eq_token,
3626 .init_node = tmp_init_node,
3627 });
3628 try block_scope.statements.append(&tmp_node.base);
2843 const ref = try block_scope.makeMangledName(c, "ref");
36292844
3630 const token = try appendToken(rp.c, op_tok_id, bytes);
3631 const one = try transCreateNodeInt(rp.c, 1);
3632 _ = try appendToken(rp.c, .Semicolon, ";");
3633 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
3634 try block_scope.statements.append(assign);
2845 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
2846 const addr_of = try Tag.address_of.create(c.arena, expr);
2847 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
2848 try block_scope.statements.append(ref_decl);
36352849
3636 const break_node = blk: {
3637 var tmp_ctrl_flow = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
3638 const rhs = try transCreateNodeIdentifier(rp.c, tmp);
3639 break :blk try tmp_ctrl_flow.finish(rhs);
3640 };
3641 try block_scope.statements.append(&break_node.base);
3642 _ = try appendToken(rp.c, .Semicolon, ";");
3643 const block_node = try block_scope.complete(rp.c);
3644 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3645 grouped_expr.* = .{
3646 .lparen = try appendToken(rp.c, .LParen, "("),
3647 .expr = block_node,
3648 .rparen = try appendToken(rp.c, .RParen, ")"),
3649 };
3650 return &grouped_expr.base;
2850 const lhs_node = try Tag.identifier.create(c.arena, ref);
2851 const ref_node = try Tag.deref.create(c.arena, lhs_node);
2852
2853 const tmp = try block_scope.makeMangledName(c, "tmp");
2854 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });
2855 try block_scope.statements.append(tmp_decl);
2856
2857 const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);
2858 try block_scope.statements.append(node);
2859
2860 const break_node = try Tag.break_val.create(c.arena, .{
2861 .label = block_scope.label,
2862 .val = try Tag.identifier.create(c.arena, tmp),
2863 });
2864 try block_scope.statements.append(break_node);
2865 return block_scope.complete(c);
36512866}
36522867
3653fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!*ast.Node {
2868fn transCompoundAssignOperator(c: *Context, scope: *Scope, stmt: *const clang.CompoundAssignOperator, used: ResultUsed) TransError!Node {
36542869 switch (stmt.getOpcode()) {
36552870 .MulAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))
3656 return transCreateCompoundAssign(rp, scope, stmt, .AssignMulWrap, .AsteriskPercentEqual, "*%=", .MulWrap, .AsteriskPercent, "*%", used)
2871 return transCreateCompoundAssign(c, scope, stmt, .mul_wrap_assign, used)
36572872 else
3658 return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),
2873 return transCreateCompoundAssign(c, scope, stmt, .mul_assign, used),
36592874 .AddAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))
3660 return transCreateCompoundAssign(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", .AddWrap, .PlusPercent, "+%", used)
2875 return transCreateCompoundAssign(c, scope, stmt, .add_wrap_assign, used)
36612876 else
3662 return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),
2877 return transCreateCompoundAssign(c, scope, stmt, .add_assign, used),
36632878 .SubAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))
3664 return transCreateCompoundAssign(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", .SubWrap, .MinusPercent, "-%", used)
2879 return transCreateCompoundAssign(c, scope, stmt, .sub_wrap_assign, used)
36652880 else
3666 return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),
3667 .DivAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignDiv, .SlashEqual, "/=", .Div, .Slash, "/", used),
3668 .RemAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignMod, .PercentEqual, "%=", .Mod, .Percent, "%", used),
3669 .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used),
3670 .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used),
3671 .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used),
3672 .XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used),
3673 .OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used),
3674 else => return revertAndWarn(
3675 rp,
2881 return transCreateCompoundAssign(c, scope, stmt, .sub_assign, used),
2882 .DivAssign => return transCreateCompoundAssign(c, scope, stmt, .div_assign, used),
2883 .RemAssign => return transCreateCompoundAssign(c, scope, stmt, .mod_assign, used),
2884 .ShlAssign => return transCreateCompoundAssign(c, scope, stmt, .shl_assign, used),
2885 .ShrAssign => return transCreateCompoundAssign(c, scope, stmt, .shr_assign, used),
2886 .AndAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_and_assign, used),
2887 .XorAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_xor_assign, used),
2888 .OrAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_or_assign, used),
2889 else => return fail(
2890 c,
36762891 error.UnsupportedTranslation,
36772892 stmt.getBeginLoc(),
36782893 "unsupported C translation {}",
......@@ -3682,25 +2897,20 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const cla
36822897}
36832898
36842899fn transCreateCompoundAssign(
3685 rp: RestorePoint,
2900 c: *Context,
36862901 scope: *Scope,
36872902 stmt: *const clang.CompoundAssignOperator,
3688 assign_op: ast.Node.Tag,
3689 assign_tok_id: std.zig.Token.Id,
3690 assign_bytes: []const u8,
3691 bin_op: ast.Node.Tag,
3692 bin_tok_id: std.zig.Token.Id,
3693 bin_bytes: []const u8,
2903 op: Tag,
36942904 used: ResultUsed,
3695) TransError!*ast.Node {
3696 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;
3697 const is_div = bin_op == .Div;
3698 const is_mod = bin_op == .Mod;
2905) TransError!Node {
2906 const is_shift = op == .shl_assign or op == .shr_assign;
2907 const is_div = op == .div_assign;
2908 const is_mod = op == .mod_assign;
36992909 const lhs = stmt.getLHS();
37002910 const rhs = stmt.getRHS();
37012911 const loc = stmt.getBeginLoc();
3702 const lhs_qt = getExprQualType(rp.c, lhs);
3703 const rhs_qt = getExprQualType(rp.c, rhs);
2912 const lhs_qt = getExprQualType(c, lhs);
2913 const rhs_qt = getExprQualType(c, rhs);
37042914 const is_signed = cIsSignedInteger(lhs_qt);
37052915 const requires_int_cast = blk: {
37062916 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);
......@@ -3712,146 +2922,100 @@ fn transCreateCompoundAssign(
37122922 // c: lhs += rhs
37132923 // zig: lhs += rhs
37142924 if ((is_mod or is_div) and is_signed) {
3715 const op_token = try appendToken(rp.c, .Equal, "=");
3716 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
3717 const builtin = if (is_mod) "@rem" else "@divTrunc";
3718 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3719 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
3720 builtin_node.params()[0] = lhs_node;
3721 _ = try appendToken(rp.c, .Comma, ",");
3722 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);
3723 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3724 op_node.* = .{
3725 .base = .{ .tag = .Assign },
3726 .op_token = op_token,
3727 .lhs = lhs_node,
3728 .rhs = &builtin_node.base,
3729 };
3730 _ = try appendToken(rp.c, .Semicolon, ";");
3731 return &op_node.base;
2925 const lhs_node = try transExpr(c, scope, lhs, .used);
2926 const rhs_node = try transExpr(c, scope, rhs, .used);
2927 const builtin = if (is_mod)
2928 try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })
2929 else
2930 try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
2931
2932 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);
37322933 }
37332934
3734 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
3735 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
2935 const lhs_node = try transExpr(c, scope, lhs, .used);
37362936 var rhs_node = if (is_shift or requires_int_cast)
3737 try transExprCoercing(rp, scope, rhs, .used, .r_value)
2937 try transExprCoercing(c, scope, rhs, .used)
37382938 else
3739 try transExpr(rp, scope, rhs, .used, .r_value);
2939 try transExpr(c, scope, rhs, .used);
37402940
37412941 if (is_shift or requires_int_cast) {
3742 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2942 // @intCast(rhs)
37432943 const cast_to_type = if (is_shift)
3744 try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc)
2944 try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc)
37452945 else
3746 try transQualType(rp, getExprQualType(rp.c, lhs), loc);
3747 cast_node.params()[0] = cast_to_type;
3748 _ = try appendToken(rp.c, .Comma, ",");
3749 cast_node.params()[1] = rhs_node;
3750 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3751 rhs_node = &cast_node.base;
2946 try transQualType(c, scope, getExprQualType(c, lhs), loc);
2947
2948 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
37522949 }
3753 if (scope.id != .Condition)
3754 _ = try appendToken(rp.c, .Semicolon, ";");
3755 return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false);
2950
2951 return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used);
37562952 }
37572953 // worst case
37582954 // c: lhs += rhs
37592955 // zig: (blk: {
37602956 // zig: const _ref = &lhs;
3761 // zig: _ref.* = _ref.* + rhs;
2957 // zig: _ref.* += rhs;
37622958 // zig: break :blk _ref.*
37632959 // zig: })
3764 var block_scope = try Scope.Block.init(rp.c, scope, true);
2960 var block_scope = try Scope.Block.init(c, scope, true);
37652961 defer block_scope.deinit();
3766 const ref = try block_scope.makeMangledName(rp.c, "ref");
3767
3768 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3769 const name_tok = try appendIdentifier(rp.c, ref);
3770 const eq_token = try appendToken(rp.c, .Equal, "=");
3771 const addr_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");
3772 addr_node.rhs = try transExpr(rp, scope, lhs, .used, .l_value);
3773 const init_node = &addr_node.base;
3774 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3775 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
3776 .name_token = name_tok,
3777 .mut_token = mut_tok,
3778 .semicolon_token = semicolon_token,
3779 }, .{
3780 .eq_token = eq_token,
3781 .init_node = init_node,
3782 });
3783 try block_scope.statements.append(&node.base);
2962 const ref = try block_scope.makeMangledName(c, "ref");
37842963
3785 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);
3786 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);
3787 _ = try appendToken(rp.c, .Semicolon, ";");
2964 const expr = try transExpr(c, &block_scope.base, lhs, .used);
2965 const addr_of = try Tag.address_of.create(c.arena, expr);
2966 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
2967 try block_scope.statements.append(ref_decl);
2968
2969 const lhs_node = try Tag.identifier.create(c.arena, ref);
2970 const ref_node = try Tag.deref.create(c.arena, lhs_node);
37882971
37892972 if ((is_mod or is_div) and is_signed) {
3790 const op_token = try appendToken(rp.c, .Equal, "=");
3791 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
3792 const builtin = if (is_mod) "@rem" else "@divTrunc";
3793 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);
3794 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);
3795 _ = try appendToken(rp.c, .Comma, ",");
3796 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);
3797 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3798 _ = try appendToken(rp.c, .Semicolon, ";");
3799 op_node.* = .{
3800 .base = .{ .tag = .Assign },
3801 .op_token = op_token,
3802 .lhs = ref_node,
3803 .rhs = &builtin_node.base,
3804 };
3805 _ = try appendToken(rp.c, .Semicolon, ";");
3806 try block_scope.statements.append(&op_node.base);
2973 const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
2974 const builtin = if (is_mod)
2975 try Tag.rem.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node })
2976 else
2977 try Tag.div_trunc.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node });
2978
2979 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used);
2980 try block_scope.statements.append(assign);
38072981 } else {
3808 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);
3809 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
2982 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
38102983
38112984 if (is_shift or requires_int_cast) {
3812 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
2985 // @intCast(rhs)
38132986 const cast_to_type = if (is_shift)
3814 try qualTypeToLog2IntRef(rp, getExprQualType(rp.c, rhs), loc)
2987 try qualTypeToLog2IntRef(c, scope, getExprQualType(c, rhs), loc)
38152988 else
3816 try transQualType(rp, getExprQualType(rp.c, lhs), loc);
3817 cast_node.params()[0] = cast_to_type;
3818 _ = try appendToken(rp.c, .Comma, ",");
3819 cast_node.params()[1] = rhs_node;
3820 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3821 rhs_node = &cast_node.base;
3822 }
2989 try transQualType(c, scope, getExprQualType(c, lhs), loc);
38232990
3824 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);
3825 _ = try appendToken(rp.c, .Semicolon, ";");
2991 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
2992 }
38262993
3827 const ass_eq_token = try appendToken(rp.c, .Equal, "=");
3828 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
2994 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);
38292995 try block_scope.statements.append(assign);
38302996 }
38312997
3832 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);
3833 try block_scope.statements.append(&break_node.base);
3834 const block_node = try block_scope.complete(rp.c);
3835 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3836 grouped_expr.* = .{
3837 .lparen = try appendToken(rp.c, .LParen, "("),
3838 .expr = block_node,
3839 .rparen = try appendToken(rp.c, .RParen, ")"),
3840 };
3841 return &grouped_expr.base;
2998 const break_node = try Tag.break_val.create(c.arena, .{
2999 .label = block_scope.label,
3000 .val = ref_node,
3001 });
3002 try block_scope.statements.append(break_node);
3003 return block_scope.complete(c);
38423004}
38433005
38443006fn transCPtrCast(
3845 rp: RestorePoint,
3007 c: *Context,
3008 scope: *Scope,
38463009 loc: clang.SourceLocation,
38473010 dst_type: clang.QualType,
38483011 src_type: clang.QualType,
3849 expr: *ast.Node,
3850) !*ast.Node {
3012 expr: Node,
3013) !Node {
38513014 const ty = dst_type.getTypePtr();
38523015 const child_type = ty.getPointeeType();
38533016 const src_ty = src_type.getTypePtr();
38543017 const src_child_type = src_ty.getPointeeType();
3018 const dst_type_node = try transType(c, scope, ty, loc);
38553019
38563020 if ((src_child_type.isConstQualified() and
38573021 !child_type.isConstQualified()) or
......@@ -3859,80 +3023,47 @@ fn transCPtrCast(
38593023 !child_type.isVolatileQualified()))
38603024 {
38613025 // Casting away const or volatile requires us to use @intToPtr
3862 const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2);
3863 const dst_type_node = try transType(rp, ty, loc);
3864 inttoptr_node.params()[0] = dst_type_node;
3865 _ = try appendToken(rp.c, .Comma, ",");
3866
3867 const ptrtoint_node = try rp.c.createBuiltinCall("@ptrToInt", 1);
3868 ptrtoint_node.params()[0] = expr;
3869 ptrtoint_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3870
3871 inttoptr_node.params()[1] = &ptrtoint_node.base;
3872 inttoptr_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3873 return &inttoptr_node.base;
3026 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
3027 const int_to_ptr = try Tag.int_to_ptr.create(c.arena, .{ .lhs = dst_type_node, .rhs = ptr_to_int });
3028 return int_to_ptr;
38743029 } else {
38753030 // Implicit downcasting from higher to lower alignment values is forbidden,
38763031 // use @alignCast to side-step this problem
3877 const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2);
3878 const dst_type_node = try transType(rp, ty, loc);
3879 ptrcast_node.params()[0] = dst_type_node;
3880 _ = try appendToken(rp.c, .Comma, ",");
3881
3882 if (qualTypeCanon(child_type).isVoidType()) {
3032 const rhs = if (qualTypeCanon(child_type).isVoidType())
38833033 // void has 1-byte alignment, so @alignCast is not needed
3884 ptrcast_node.params()[1] = expr;
3885 } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {
3034 expr
3035 else if (typeIsOpaque(c, qualTypeCanon(child_type), loc))
38863036 // For opaque types a ptrCast is enough
3887 ptrcast_node.params()[1] = expr;
3888 } else {
3889 const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2);
3890 const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1);
3891 const child_type_node = try transQualType(rp, child_type, loc);
3892 alignof_node.params()[0] = child_type_node;
3893 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3894 aligncast_node.params()[0] = &alignof_node.base;
3895 _ = try appendToken(rp.c, .Comma, ",");
3896 aligncast_node.params()[1] = expr;
3897 aligncast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3898 ptrcast_node.params()[1] = &aligncast_node.base;
3899 }
3900 ptrcast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3901
3902 return &ptrcast_node.base;
3037 expr
3038 else blk: {
3039 const child_type_node = try transQualType(c, scope, child_type, loc);
3040 const alignof = try Tag.alignof.create(c.arena, child_type_node);
3041 const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });
3042 break :blk align_cast;
3043 };
3044 return Tag.ptr_cast.create(c.arena, .{ .lhs = dst_type_node, .rhs = rhs });
39033045 }
39043046}
39053047
3906fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
3907 const break_scope = scope.getBreakableScope();
3908 const label_text: ?[]const u8 = if (break_scope.id == .Switch) blk: {
3909 const swtch = @fieldParentPtr(Scope.Switch, "base", break_scope);
3910 const block_scope = try scope.findBlockScope(rp.c);
3911 swtch.switch_label = try block_scope.makeMangledName(rp.c, "switch");
3912 break :blk swtch.switch_label;
3913 } else
3914 null;
3915
3916 var cf = try CtrlFlow.init(rp.c, .Break, label_text);
3917 const br = try cf.finish(null);
3918 _ = try appendToken(rp.c, .Semicolon, ";");
3919 return &br.base;
3920}
3921
3922fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!*ast.Node {
3048fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node {
39233049 // TODO use something more accurate
3924 const dbl = stmt.getValueAsApproximateDouble();
3925 const node = try rp.c.arena.create(ast.Node.OneToken);
3926 node.* = .{
3927 .base = .{ .tag = .FloatLiteral },
3928 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),
3929 };
3930 return maybeSuppressResult(rp, scope, used, &node.base);
3050 var dbl = stmt.getValueAsApproximateDouble();
3051 const is_negative = dbl < 0;
3052 if (is_negative) dbl = -dbl;
3053 const str = try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
3054 var node = if (dbl == std.math.floor(dbl))
3055 try Tag.integer_literal.create(c.arena, str)
3056 else
3057 try Tag.float_literal.create(c.arena, str);
3058 if (is_negative) node = try Tag.negate.create(c.arena, node);
3059 return maybeSuppressResult(c, scope, used, node);
39313060}
39323061
3933fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!*ast.Node {
3062fn transBinaryConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.BinaryConditionalOperator, used: ResultUsed) TransError!Node {
39343063 // GNU extension of the ternary operator where the middle expression is
39353064 // omitted, the conditition itself is returned if it evaluates to true
3065 const qt = @ptrCast(*const clang.Expr, stmt).getType();
3066 const res_is_bool = qualTypeIsBoolean(qt);
39363067 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);
39373068 const cond_expr = casted_stmt.getCond();
39383069 const true_expr = casted_stmt.getTrueExpr();
......@@ -3943,184 +3074,149 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
39433074 // const _cond_temp = (cond_expr);
39443075 // break :blk if (_cond_temp) _cond_temp else (false_expr);
39453076 // })
3946 const lparen = try appendToken(rp.c, .LParen, "(");
3947
3948 var block_scope = try Scope.Block.init(rp.c, scope, true);
3077 var block_scope = try Scope.Block.init(c, scope, true);
39493078 defer block_scope.deinit();
39503079
3951 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
3952 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
3953 const name_tok = try appendIdentifier(rp.c, mangled_name);
3954 const eq_token = try appendToken(rp.c, .Equal, "=");
3955 const init_node = try transExpr(rp, &block_scope.base, cond_expr, .used, .r_value);
3956 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
3957 const tmp_var = try ast.Node.VarDecl.create(rp.c.arena, .{
3958 .name_token = name_tok,
3959 .mut_token = mut_tok,
3960 .semicolon_token = semicolon_token,
3961 }, .{
3962 .eq_token = eq_token,
3963 .init_node = init_node,
3964 });
3965 try block_scope.statements.append(&tmp_var.base);
3966
3967 var break_node_tmp = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);
3080 const mangled_name = try block_scope.makeMangledName(c, "cond_temp");
3081 const init_node = try transExpr(c, &block_scope.base, cond_expr, .used);
3082 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node });
3083 try block_scope.statements.append(ref_decl);
39683084
3969 const if_node = try transCreateNodeIf(rp.c);
39703085 var cond_scope = Scope.Condition{
39713086 .base = .{
39723087 .parent = &block_scope.base,
3973 .id = .Condition,
3088 .id = .condition,
39743089 },
39753090 };
39763091 defer cond_scope.deinit();
3977 const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name);
3978
3979 const ty = getExprQualType(rp.c, cond_expr).getTypePtr();
3980 const cond_node = try finishBoolExpr(rp, &cond_scope.base, cond_expr.getBeginLoc(), ty, tmp_var_node, used);
3981 if_node.condition = cond_node;
3982 _ = try appendToken(rp.c, .RParen, ")");
3983
3984 if_node.body = try transCreateNodeIdentifier(rp.c, mangled_name);
3985 if_node.@"else" = try transCreateNodeElse(rp.c);
3986 if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value);
3987 _ = try appendToken(rp.c, .Semicolon, ";");
3988
3989 const break_node = try break_node_tmp.finish(&if_node.base);
3990 _ = try appendToken(rp.c, .Semicolon, ";");
3991 try block_scope.statements.append(&break_node.base);
3992 const block_node = try block_scope.complete(rp.c);
3993
3994 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
3995 grouped_expr.* = .{
3996 .lparen = lparen,
3997 .expr = block_node,
3998 .rparen = try appendToken(rp.c, .RParen, ")"),
3999 };
4000 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
3092
3093 const cond_ident = try Tag.identifier.create(c.arena, mangled_name);
3094 const ty = getExprQualType(c, cond_expr).getTypePtr();
3095 const cond_node = try finishBoolExpr(c, &cond_scope.base, cond_expr.getBeginLoc(), ty, cond_ident, .used);
3096 var then_body = cond_ident;
3097 if (!res_is_bool and isBoolRes(init_node)) {
3098 then_body = try Tag.bool_to_int.create(c.arena, then_body);
3099 }
3100
3101 var else_body = try transExpr(c, &block_scope.base, false_expr, .used);
3102 if (!res_is_bool and isBoolRes(else_body)) {
3103 else_body = try Tag.bool_to_int.create(c.arena, else_body);
3104 }
3105 const if_node = try Tag.@"if".create(c.arena, .{
3106 .cond = cond_node,
3107 .then = then_body,
3108 .@"else" = else_body,
3109 });
3110 const break_node = try Tag.break_val.create(c.arena, .{
3111 .label = block_scope.label,
3112 .val = if_node,
3113 });
3114 try block_scope.statements.append(break_node);
3115 const res = try block_scope.complete(c);
3116 return maybeSuppressResult(c, scope, used, res);
40013117}
40023118
4003fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!*ast.Node {
4004 const grouped = scope.id == .Condition;
4005 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
4006 const if_node = try transCreateNodeIf(rp.c);
3119fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!Node {
40073120 var cond_scope = Scope.Condition{
40083121 .base = .{
40093122 .parent = scope,
4010 .id = .Condition,
3123 .id = .condition,
40113124 },
40123125 };
40133126 defer cond_scope.deinit();
40143127
3128 const qt = @ptrCast(*const clang.Expr, stmt).getType();
3129 const res_is_bool = qualTypeIsBoolean(qt);
40153130 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);
40163131 const cond_expr = casted_stmt.getCond();
40173132 const true_expr = casted_stmt.getTrueExpr();
40183133 const false_expr = casted_stmt.getFalseExpr();
40193134
4020 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
4021 _ = try appendToken(rp.c, .RParen, ")");
3135 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
40223136
4023 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);
4024
4025 if_node.@"else" = try transCreateNodeElse(rp.c);
4026 if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);
3137 var then_body = try transExpr(c, scope, true_expr, used);
3138 if (!res_is_bool and isBoolRes(then_body)) {
3139 then_body = try Tag.bool_to_int.create(c.arena, then_body);
3140 }
40273141
4028 if (grouped) {
4029 const rparen = try appendToken(rp.c, .RParen, ")");
4030 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
4031 grouped_expr.* = .{
4032 .lparen = lparen,
4033 .expr = &if_node.base,
4034 .rparen = rparen,
4035 };
4036 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
4037 } else {
4038 return maybeSuppressResult(rp, scope, used, &if_node.base);
3142 var else_body = try transExpr(c, scope, false_expr, used);
3143 if (!res_is_bool and isBoolRes(else_body)) {
3144 else_body = try Tag.bool_to_int.create(c.arena, else_body);
40393145 }
3146
3147 const if_node = try Tag.@"if".create(c.arena, .{
3148 .cond = cond,
3149 .then = then_body,
3150 .@"else" = else_body,
3151 });
3152 // Clang inserts ImplicitCast(ToVoid)'s to both rhs and lhs so we don't need to supress the result here.
3153 return if_node;
40403154}
40413155
40423156fn maybeSuppressResult(
4043 rp: RestorePoint,
3157 c: *Context,
40443158 scope: *Scope,
40453159 used: ResultUsed,
4046 result: *ast.Node,
4047) TransError!*ast.Node {
3160 result: Node,
3161) TransError!Node {
40483162 if (used == .used) return result;
4049 if (scope.id != .Condition) {
4050 // NOTE: This is backwards, but the semicolon must immediately follow the node.
4051 _ = try appendToken(rp.c, .Semicolon, ";");
4052 } else { // TODO is there a way to avoid this hack?
4053 // this parenthesis must come immediately following the node
4054 _ = try appendToken(rp.c, .RParen, ")");
4055 // these need to come before _
4056 _ = try appendToken(rp.c, .Colon, ":");
4057 _ = try appendToken(rp.c, .LParen, "(");
4058 }
4059 const lhs = try transCreateNodeIdentifier(rp.c, "_");
4060 const op_token = try appendToken(rp.c, .Equal, "=");
4061 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4062 op_node.* = .{
4063 .base = .{ .tag = .Assign },
4064 .op_token = op_token,
4065 .lhs = lhs,
4066 .rhs = result,
4067 };
4068 return &op_node.base;
3163 return Tag.discard.create(c.arena, result);
40693164}
40703165
4071fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {
4072 try c.root_decls.append(c.gpa, decl_node);
3166fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
40733167 _ = try c.global_scope.sym_table.put(name, decl_node);
3168 try c.global_scope.nodes.append(decl_node);
40743169}
40753170
40763171/// Translate a qual type for a variable with an initializer. The initializer
40773172/// only matters for incomplete arrays, since the size of the array is determined
40783173/// by the size of the initializer
40793174fn transQualTypeInitialized(
4080 rp: RestorePoint,
3175 c: *Context,
3176 scope: *Scope,
40813177 qt: clang.QualType,
40823178 decl_init: *const clang.Expr,
40833179 source_loc: clang.SourceLocation,
4084) TypeError!*ast.Node {
3180) TypeError!Node {
40853181 const ty = qt.getTypePtr();
40863182 if (ty.getTypeClass() == .IncompleteArray) {
40873183 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
4088 const elem_ty = incomplete_array_ty.getElementType().getTypePtr();
3184 const elem_ty = try transType(c, scope, incomplete_array_ty.getElementType().getTypePtr(), source_loc);
40893185
40903186 switch (decl_init.getStmtClass()) {
40913187 .StringLiteralClass => {
40923188 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);
40933189 const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator
40943190 const array_size = @intCast(usize, string_lit_size);
4095 return transCreateNodeArrayType(rp, source_loc, elem_ty, array_size);
3191 return Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
40963192 },
40973193 .InitListExprClass => {
40983194 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);
40993195 const size = init_expr.getNumInits();
4100 return transCreateNodeArrayType(rp, source_loc, elem_ty, size);
3196 return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_ty });
41013197 },
41023198 else => {},
41033199 }
41043200 }
4105 return transQualType(rp, qt, source_loc);
3201 return transQualType(c, scope, qt, source_loc);
41063202}
41073203
4108fn transQualType(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!*ast.Node {
4109 return transType(rp, qt.getTypePtr(), source_loc);
3204fn transQualType(c: *Context, scope: *Scope, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {
3205 return transType(c, scope, qt.getTypePtr(), source_loc);
41103206}
41113207
41123208/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
41133209/// Asserts the type is an integer.
4114fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) TypeError!*ast.Node {
3210fn transQualTypeIntWidthOf(c: *Context, ty: clang.QualType, is_signed: bool) TypeError!Node {
41153211 return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);
41163212}
41173213
41183214/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.
41193215/// Asserts the type is an integer.
4120fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!*ast.Node {
3216fn transTypeIntWidthOf(c: *Context, ty: *const clang.Type, is_signed: bool) TypeError!Node {
41213217 assert(ty.getTypeClass() == .Builtin);
41223218 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
4123 return transCreateNodeIdentifier(c, switch (builtin_ty.getKind()) {
3219 return Tag.type.create(c.arena, switch (builtin_ty.getKind()) {
41243220 .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",
41253221 .UShort, .Short => if (is_signed) "c_short" else "c_ushort",
41263222 .UInt, .Int => if (is_signed) "c_int" else "c_uint",
......@@ -4149,7 +3245,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool {
41493245 return qualTypeCanon(qt).isBooleanType();
41503246}
41513247
4152fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 {
3248fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType) !u32 {
41533249 const ty = qt.getTypePtr();
41543250
41553251 switch (ty.getTypeClass()) {
......@@ -4173,7 +3269,7 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S
41733269 .Typedef => {
41743270 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
41753271 const typedef_decl = typedef_ty.getDecl();
4176 const type_name = try rp.c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
3272 const type_name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());
41773273
41783274 if (mem.eql(u8, type_name, "uint8_t") or mem.eql(u8, type_name, "int8_t")) {
41793275 return 8;
......@@ -4189,55 +3285,19 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S
41893285 },
41903286 else => return 0,
41913287 }
4192
4193 unreachable;
41943288}
41953289
4196fn qualTypeToLog2IntRef(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !*ast.Node {
4197 const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);
3290fn qualTypeToLog2IntRef(c: *Context, scope: *Scope, qt: clang.QualType, source_loc: clang.SourceLocation) !Node {
3291 const int_bit_width = try qualTypeIntBitWidth(c, qt);
41983292
41993293 if (int_bit_width != 0) {
42003294 // we can perform the log2 now.
42013295 const cast_bit_width = math.log2_int(u64, int_bit_width);
4202 const node = try rp.c.arena.create(ast.Node.OneToken);
4203 node.* = .{
4204 .base = .{ .tag = .IntegerLiteral },
4205 .token = try appendTokenFmt(rp.c, .Identifier, "u{d}", .{cast_bit_width}),
4206 };
4207 return &node.base;
4208 }
4209
4210 const zig_type_node = try transQualType(rp, qt, source_loc);
4211
4212 // @import("std").math.Log2Int(c_long);
4213 //
4214 // FnCall
4215 // FieldAccess
4216 // FieldAccess
4217 // FnCall (.builtin = true)
4218 // Symbol "import"
4219 // StringLiteral "std"
4220 // Symbol "math"
4221 // Symbol "Log2Int"
4222 // Symbol <zig_type_node> (var from above)
4223
4224 const import_fn_call = try rp.c.createBuiltinCall("@import", 1);
4225 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
4226 const std_node = try rp.c.arena.create(ast.Node.OneToken);
4227 std_node.* = .{
4228 .base = .{ .tag = .StringLiteral },
4229 .token = std_token,
4230 };
4231 import_fn_call.params()[0] = &std_node.base;
4232 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
4233
4234 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
4235 const outer_field_access = try transCreateNodeFieldAccess(rp.c, inner_field_access, "Log2Int");
4236 const log2int_fn_call = try rp.c.createCall(outer_field_access, 1);
4237 log2int_fn_call.params()[0] = zig_type_node;
4238 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
3296 return Tag.log2_int_type.create(c.arena, cast_bit_width);
3297 }
42393298
4240 return &log2int_fn_call.base;
3299 const zig_type = try transQualType(c, scope, qt, source_loc);
3300 return Tag.std_math_Log2Int.create(c.arena, zig_type);
42413301}
42423302
42433303fn qualTypeChildIsFnProto(qt: clang.QualType) bool {
......@@ -4401,28 +3461,22 @@ fn cIsLongLongInteger(qt: clang.QualType) bool {
44013461 };
44023462}
44033463fn transCreateNodeAssign(
4404 rp: RestorePoint,
3464 c: *Context,
44053465 scope: *Scope,
44063466 result_used: ResultUsed,
44073467 lhs: *const clang.Expr,
44083468 rhs: *const clang.Expr,
4409) !*ast.Node {
3469) !Node {
44103470 // common case
44113471 // c: lhs = rhs
44123472 // zig: lhs = rhs
44133473 if (result_used == .unused) {
4414 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
4415 const eq_token = try appendToken(rp.c, .Equal, "=");
4416 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
3474 const lhs_node = try transExpr(c, scope, lhs, .used);
3475 var rhs_node = try transExprCoercing(c, scope, rhs, .used);
44173476 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
4418 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
4419 builtin_node.params()[0] = rhs_node;
4420 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
4421 rhs_node = &builtin_node.base;
3477 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);
44223478 }
4423 if (scope.id != .Condition)
4424 _ = try appendToken(rp.c, .Semicolon, ";");
4425 return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false);
3479 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, rhs_node, .used);
44263480 }
44273481
44283482 // worst case
......@@ -4432,176 +3486,62 @@ fn transCreateNodeAssign(
44323486 // zig: lhs = _tmp;
44333487 // zig: break :blk _tmp
44343488 // zig: })
4435 var block_scope = try Scope.Block.init(rp.c, scope, true);
3489 var block_scope = try Scope.Block.init(c, scope, true);
44363490 defer block_scope.deinit();
44373491
4438 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
4439 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");
4440 const name_tok = try appendIdentifier(rp.c, tmp);
4441 const eq_token = try appendToken(rp.c, .Equal, "=");
4442 var rhs_node = try transExpr(rp, &block_scope.base, rhs, .used, .r_value);
4443 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
4444 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);
4445 builtin_node.params()[0] = rhs_node;
4446 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
4447 rhs_node = &builtin_node.base;
4448 }
4449 const init_node = rhs_node;
4450 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");
4451 const node = try ast.Node.VarDecl.create(rp.c.arena, .{
4452 .name_token = name_tok,
4453 .mut_token = mut_tok,
4454 .semicolon_token = semicolon_token,
4455 }, .{
4456 .eq_token = eq_token,
4457 .init_node = init_node,
4458 });
4459 try block_scope.statements.append(&node.base);
4460
4461 const lhs_node = try transExpr(rp, &block_scope.base, lhs, .used, .l_value);
4462 const lhs_eq_token = try appendToken(rp.c, .Equal, "=");
4463 const ident = try transCreateNodeIdentifier(rp.c, tmp);
4464 _ = try appendToken(rp.c, .Semicolon, ";");
4465
4466 const assign = try transCreateNodeInfixOp(rp, &block_scope.base, lhs_node, .Assign, lhs_eq_token, ident, .used, false);
4467 try block_scope.statements.append(assign);
4468
4469 const break_node = blk: {
4470 var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, tokenSlice(rp.c, block_scope.label.?));
4471 const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp);
4472 break :blk try tmp_ctrl_flow.finish(rhs_expr);
4473 };
4474 _ = try appendToken(rp.c, .Semicolon, ";");
4475 try block_scope.statements.append(&break_node.base);
4476 const block_node = try block_scope.complete(rp.c);
4477 // semicolon must immediately follow rbrace because it is the last token in a block
4478 _ = try appendToken(rp.c, .Semicolon, ";");
4479 return block_node;
4480}
4481
4482fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node {
4483 const field_access_node = try c.arena.create(ast.Node.SimpleInfixOp);
4484 field_access_node.* = .{
4485 .base = .{ .tag = .Period },
4486 .op_token = try appendToken(c, .Period, "."),
4487 .lhs = container,
4488 .rhs = try transCreateNodeIdentifier(c, field_name),
4489 };
4490 return &field_access_node.base;
4491}
3492 const tmp = try block_scope.makeMangledName(c, "tmp");
3493 const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
3494 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node });
3495 try block_scope.statements.append(tmp_decl);
44923496
4493fn transCreateNodeSimplePrefixOp(
4494 c: *Context,
4495 comptime tag: ast.Node.Tag,
4496 op_tok_id: std.zig.Token.Id,
4497 bytes: []const u8,
4498) !*ast.Node.SimplePrefixOp {
4499 const node = try c.arena.create(ast.Node.SimplePrefixOp);
4500 node.* = .{
4501 .base = .{ .tag = tag },
4502 .op_token = try appendToken(c, op_tok_id, bytes),
4503 .rhs = undefined, // translate and set afterward
4504 };
4505 return node;
3497 const lhs_node = try transExpr(c, &block_scope.base, lhs, .used);
3498 const tmp_ident = try Tag.identifier.create(c.arena, tmp);
3499 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs_node, tmp_ident, .used);
3500 try block_scope.statements.append(assign);
3501
3502 const break_node = try Tag.break_val.create(c.arena, .{
3503 .label = block_scope.label,
3504 .val = tmp_ident,
3505 });
3506 try block_scope.statements.append(break_node);
3507 return block_scope.complete(c);
45063508}
45073509
45083510fn transCreateNodeInfixOp(
4509 rp: RestorePoint,
3511 c: *Context,
45103512 scope: *Scope,
4511 lhs_node: *ast.Node,
4512 op: ast.Node.Tag,
4513 op_token: ast.TokenIndex,
4514 rhs_node: *ast.Node,
3513 op: Tag,
3514 lhs: Node,
3515 rhs: Node,
45153516 used: ResultUsed,
4516 grouped: bool,
4517) !*ast.Node {
4518 var lparen = if (grouped)
4519 try appendToken(rp.c, .LParen, "(")
4520 else
4521 null;
4522 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4523 node.* = .{
3517) !Node {
3518 const payload = try c.arena.create(ast.Payload.BinOp);
3519 payload.* = .{
45243520 .base = .{ .tag = op },
4525 .op_token = op_token,
4526 .lhs = lhs_node,
4527 .rhs = rhs_node,
4528 };
4529 if (!grouped) return maybeSuppressResult(rp, scope, used, &node.base);
4530 const rparen = try appendToken(rp.c, .RParen, ")");
4531 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
4532 grouped_expr.* = .{
4533 .lparen = lparen.?,
4534 .expr = &node.base,
4535 .rparen = rparen,
3521 .data = .{
3522 .lhs = lhs,
3523 .rhs = rhs,
3524 },
45363525 };
4537 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
3526 return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));
45383527}
45393528
45403529fn transCreateNodeBoolInfixOp(
4541 rp: RestorePoint,
3530 c: *Context,
45423531 scope: *Scope,
45433532 stmt: *const clang.BinaryOperator,
4544 op: ast.Node.Tag,
3533 op: Tag,
45453534 used: ResultUsed,
4546 grouped: bool,
4547) !*ast.Node {
4548 std.debug.assert(op == .BoolAnd or op == .BoolOr);
4549
4550 const lhs_hode = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value, true);
4551 const op_token = if (op == .BoolAnd)
4552 try appendToken(rp.c, .Keyword_and, "and")
4553 else
4554 try appendToken(rp.c, .Keyword_or, "or");
4555 const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value, true);
3535) !Node {
3536 std.debug.assert(op == .@"and" or op == .@"or");
45563537
4557 return transCreateNodeInfixOp(
4558 rp,
4559 scope,
4560 lhs_hode,
4561 op,
4562 op_token,
4563 rhs,
4564 used,
4565 grouped,
4566 );
4567}
3538 const lhs = try transBoolExpr(c, scope, stmt.getLHS(), .used);
3539 const rhs = try transBoolExpr(c, scope, stmt.getRHS(), .used);
45683540
4569fn transCreateNodePtrType(
4570 c: *Context,
4571 is_const: bool,
4572 is_volatile: bool,
4573 op_tok_id: std.zig.Token.Id,
4574) !*ast.Node.PtrType {
4575 const node = try c.arena.create(ast.Node.PtrType);
4576 const op_token = switch (op_tok_id) {
4577 .LBracket => blk: {
4578 const lbracket = try appendToken(c, .LBracket, "[");
4579 _ = try appendToken(c, .Asterisk, "*");
4580 _ = try appendToken(c, .RBracket, "]");
4581 break :blk lbracket;
4582 },
4583 .Identifier => blk: {
4584 const lbracket = try appendToken(c, .LBracket, "["); // Rendering checks if this token + 2 == .Identifier, so needs to return this token
4585 _ = try appendToken(c, .Asterisk, "*");
4586 _ = try appendIdentifier(c, "c");
4587 _ = try appendToken(c, .RBracket, "]");
4588 break :blk lbracket;
4589 },
4590 .Asterisk => try appendToken(c, .Asterisk, "*"),
4591 else => unreachable,
4592 };
4593 node.* = .{
4594 .op_token = op_token,
4595 .ptr_info = .{
4596 .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
4597 .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
4598 },
4599 .rhs = undefined, // translate and set afterward
4600 };
4601 return node;
3541 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, used);
46023542}
46033543
4604fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {
3544fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
46053545 const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) {
46063546 error.Overflow => return error.OutOfMemory,
46073547 };
......@@ -4637,418 +3577,96 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {
46373577 else => @compileError("unimplemented"),
46383578 }
46393579
4640 const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative };
3580 const big: math.big.int.Const = .{ .limbs = limbs, .positive = true };
46413581 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
46423582 error.OutOfMemory => return error.OutOfMemory,
46433583 };
4644 defer c.arena.free(str);
4645 const token = try appendToken(c, .IntegerLiteral, str);
4646 const node = try c.arena.create(ast.Node.OneToken);
4647 node.* = .{
4648 .base = .{ .tag = .IntegerLiteral },
4649 .token = token,
4650 };
4651 return &node.base;
4652}
4653
4654fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
4655 const token = try appendToken(c, .Keyword_undefined, "undefined");
4656 const node = try c.arena.create(ast.Node.OneToken);
4657 node.* = .{
4658 .base = .{ .tag = .UndefinedLiteral },
4659 .token = token,
4660 };
4661 return &node.base;
4662}
4663
4664fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
4665 const token = try appendToken(c, .Keyword_null, "null");
4666 const node = try c.arena.create(ast.Node.OneToken);
4667 node.* = .{
4668 .base = .{ .tag = .NullLiteral },
4669 .token = token,
4670 };
4671 return &node.base;
3584 const res = try Tag.integer_literal.create(c.arena, str);
3585 if (is_negative) return Tag.negate.create(c.arena, res);
3586 return res;
46723587}
46733588
4674fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
4675 const token = if (value)
4676 try appendToken(c, .Keyword_true, "true")
3589fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node {
3590 const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}";
3591 const str = try std.fmt.allocPrint(c.arena, fmt_s, .{num});
3592 if (num_kind == .float)
3593 return Tag.float_literal.create(c.arena, str)
46773594 else
4678 try appendToken(c, .Keyword_false, "false");
4679 const node = try c.arena.create(ast.Node.OneToken);
4680 node.* = .{
4681 .base = .{ .tag = .BoolLiteral },
4682 .token = token,
4683 };
4684 return &node.base;
4685}
4686
4687fn transCreateNodeInt(c: *Context, int: anytype) !*ast.Node {
4688 const fmt_s = if (comptime std.meta.trait.isIntegerNumber(@TypeOf(int))) "{d}" else "{s}";
4689 const token = try appendTokenFmt(c, .IntegerLiteral, fmt_s, .{int});
4690 const node = try c.arena.create(ast.Node.OneToken);
4691 node.* = .{
4692 .base = .{ .tag = .IntegerLiteral },
4693 .token = token,
4694 };
4695 return &node.base;
3595 return Tag.integer_literal.create(c.arena, str);
46963596}
46973597
4698fn transCreateNodeFloat(c: *Context, str: []const u8) !*ast.Node {
4699 const token = try appendTokenFmt(c, .FloatLiteral, "{s}", .{str});
4700 const node = try c.arena.create(ast.Node.OneToken);
4701 node.* = .{
4702 .base = .{ .tag = .FloatLiteral },
4703 .token = token,
4704 };
4705 return &node.base;
4706}
4707
4708fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
4709 const container_tok = try appendToken(c, .Keyword_opaque, "opaque");
4710 const lbrace_token = try appendToken(c, .LBrace, "{");
4711 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, 0);
4712 container_node.* = .{
4713 .kind_token = container_tok,
4714 .layout_token = null,
4715 .lbrace_token = lbrace_token,
4716 .rbrace_token = try appendToken(c, .RBrace, "}"),
4717 .fields_and_decls_len = 0,
4718 .init_arg_expr = .None,
4719 };
4720 return &container_node.base;
4721}
4722
4723fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {
3598fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: Node, proto_alias: *ast.Payload.Func) !Node {
47243599 const scope = &c.global_scope.base;
47253600
4726 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
4727 const fn_tok = try appendToken(c, .Keyword_fn, "fn");
4728 const name_tok = try appendIdentifier(c, name);
4729 _ = try appendToken(c, .LParen, "(");
4730
4731 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
3601 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
47323602 defer fn_params.deinit();
47333603
4734 for (proto_alias.params()) |param, i| {
4735 if (i != 0) {
4736 _ = try appendToken(c, .Comma, ",");
4737 }
4738 const param_name_tok = param.name_token orelse
4739 try appendTokenFmt(c, .Identifier, "arg_{d}", .{c.getMangle()});
4740
4741 _ = try appendToken(c, .Colon, ":");
3604 for (proto_alias.data.params) |param, i| {
3605 const param_name = param.name orelse
3606 try std.fmt.allocPrint(c.arena, "arg_{d}", .{c.getMangle()});
47423607
4743 (try fn_params.addOne()).* = .{
4744 .doc_comments = null,
4745 .comptime_token = null,
4746 .noalias_token = param.noalias_token,
4747 .name_token = param_name_tok,
4748 .param_type = param.param_type,
4749 };
3608 try fn_params.append(.{
3609 .name = param_name,
3610 .type = param.type,
3611 .is_noalias = param.is_noalias,
3612 });
47503613 }
47513614
4752 _ = try appendToken(c, .RParen, ")");
4753
4754 _ = try appendToken(c, .Keyword_callconv, "callconv");
4755 _ = try appendToken(c, .LParen, "(");
4756 const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline");
4757 _ = try appendToken(c, .RParen, ")");
4758
4759 const block_lbrace = try appendToken(c, .LBrace, "{");
4760
4761 const return_kw = try appendToken(c, .Keyword_return, "return");
4762 const unwrap_expr = try transCreateNodeUnwrapNull(c, ref.cast(ast.Node.VarDecl).?.getInitNode().?);
4763
4764 const call_expr = try c.createCall(unwrap_expr, fn_params.items.len);
4765 const call_params = call_expr.params();
3615 const init = if (ref.castTag(.var_decl)) |v|
3616 v.data.init.?
3617 else if (ref.castTag(.var_simple) orelse ref.castTag(.pub_var_simple)) |v|
3618 v.data.init
3619 else
3620 unreachable;
47663621
3622 const unwrap_expr = try Tag.unwrap.create(c.arena, init);
3623 const args = try c.arena.alloc(Node, fn_params.items.len);
47673624 for (fn_params.items) |param, i| {
4768 if (i != 0) {
4769 _ = try appendToken(c, .Comma, ",");
4770 }
4771 call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?));
3625 args[i] = try Tag.identifier.create(c.arena, param.name.?);
47723626 }
4773 call_expr.rtoken = try appendToken(c, .RParen, ")");
4774
4775 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
4776 .ltoken = return_kw,
4777 .tag = .Return,
4778 }, .{
4779 .rhs = &call_expr.base,
3627 const call_expr = try Tag.call.create(c.arena, .{
3628 .lhs = unwrap_expr,
3629 .args = args,
47803630 });
4781 _ = try appendToken(c, .Semicolon, ";");
4782
4783 const block = try ast.Node.Block.alloc(c.arena, 1);
4784 block.* = .{
4785 .lbrace = block_lbrace,
4786 .statements_len = 1,
4787 .rbrace = try appendToken(c, .RBrace, "}"),
4788 };
4789 block.statements()[0] = &return_expr.base;
4790
4791 const fn_proto = try ast.Node.FnProto.create(c.arena, .{
4792 .params_len = fn_params.items.len,
4793 .fn_token = fn_tok,
4794 .return_type = proto_alias.return_type,
4795 }, .{
4796 .visib_token = pub_tok,
4797 .name_token = name_tok,
4798 .body_node = &block.base,
4799 .callconv_expr = callconv_expr,
3631 const return_expr = try Tag.@"return".create(c.arena, call_expr);
3632 const block = try Tag.block_single.create(c.arena, return_expr);
3633
3634 return Tag.pub_inline_fn.create(c.arena, .{
3635 .name = name,
3636 .params = try c.arena.dupe(ast.Payload.Param, fn_params.items),
3637 .return_type = proto_alias.data.return_type,
3638 .body = block,
48003639 });
4801 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4802 return &fn_proto.base;
4803}
4804
4805fn transCreateNodeUnwrapNull(c: *Context, wrapped: *ast.Node) !*ast.Node {
4806 _ = try appendToken(c, .Period, ".");
4807 const qm = try appendToken(c, .QuestionMark, "?");
4808 const node = try c.arena.create(ast.Node.SimpleSuffixOp);
4809 node.* = .{
4810 .base = .{ .tag = .UnwrapOptional },
4811 .lhs = wrapped,
4812 .rtoken = qm,
4813 };
4814 return &node.base;
4815}
4816
4817fn transCreateNodeEnumLiteral(c: *Context, name: []const u8) !*ast.Node {
4818 const node = try c.arena.create(ast.Node.EnumLiteral);
4819 node.* = .{
4820 .dot = try appendToken(c, .Period, "."),
4821 .name = try appendIdentifier(c, name),
4822 };
4823 return &node.base;
4824}
4825
4826fn transCreateNodeStringLiteral(c: *Context, str: []const u8) !*ast.Node {
4827 const node = try c.arena.create(ast.Node.OneToken);
4828 node.* = .{
4829 .base = .{ .tag = .StringLiteral },
4830 .token = try appendToken(c, .StringLiteral, str),
4831 };
4832 return &node.base;
4833}
4834
4835fn transCreateNodeIf(c: *Context) !*ast.Node.If {
4836 const if_tok = try appendToken(c, .Keyword_if, "if");
4837 _ = try appendToken(c, .LParen, "(");
4838 const node = try c.arena.create(ast.Node.If);
4839 node.* = .{
4840 .if_token = if_tok,
4841 .condition = undefined,
4842 .payload = null,
4843 .body = undefined,
4844 .@"else" = null,
4845 };
4846 return node;
4847}
4848
4849fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
4850 const node = try c.arena.create(ast.Node.Else);
4851 node.* = .{
4852 .else_token = try appendToken(c, .Keyword_else, "else"),
4853 .payload = null,
4854 .body = undefined,
4855 };
4856 return node;
4857}
4858
4859fn transCreateNodeBreak(
4860 c: *Context,
4861 label: ?ast.TokenIndex,
4862 rhs: ?*ast.Node,
4863) !*ast.Node.ControlFlowExpression {
4864 var ctrl_flow = try CtrlFlow.init(c, .Break, if (label) |l| tokenSlice(c, l) else null);
4865 return ctrl_flow.finish(rhs);
4866}
4867
4868const CtrlFlow = struct {
4869 c: *Context,
4870 ltoken: ast.TokenIndex,
4871 label_token: ?ast.TokenIndex,
4872 tag: ast.Node.Tag,
4873
4874 /// Does everything except the RHS.
4875 fn init(c: *Context, tag: ast.Node.Tag, label: ?[]const u8) !CtrlFlow {
4876 const kw: Token.Id = switch (tag) {
4877 .Break => .Keyword_break,
4878 .Continue => .Keyword_continue,
4879 .Return => .Keyword_return,
4880 else => unreachable,
4881 };
4882 const kw_text = switch (tag) {
4883 .Break => "break",
4884 .Continue => "continue",
4885 .Return => "return",
4886 else => unreachable,
4887 };
4888 const ltoken = try appendToken(c, kw, kw_text);
4889 const label_token = if (label) |l| blk: {
4890 _ = try appendToken(c, .Colon, ":");
4891 break :blk try appendIdentifier(c, l);
4892 } else null;
4893 return CtrlFlow{
4894 .c = c,
4895 .ltoken = ltoken,
4896 .label_token = label_token,
4897 .tag = tag,
4898 };
4899 }
4900
4901 fn initToken(c: *Context, tag: ast.Node.Tag, label: ?ast.TokenIndex) !CtrlFlow {
4902 const other_token = label orelse return init(c, tag, null);
4903 const loc = c.token_locs.items[other_token];
4904 const label_name = c.source_buffer.items[loc.start..loc.end];
4905 return init(c, tag, label_name);
4906 }
4907
4908 fn finish(self: *CtrlFlow, rhs: ?*ast.Node) !*ast.Node.ControlFlowExpression {
4909 return ast.Node.ControlFlowExpression.create(self.c.arena, .{
4910 .ltoken = self.ltoken,
4911 .tag = self.tag,
4912 }, .{
4913 .label = self.label_token,
4914 .rhs = rhs,
4915 });
4916 }
4917};
4918
4919fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
4920 const while_tok = try appendToken(c, .Keyword_while, "while");
4921 _ = try appendToken(c, .LParen, "(");
4922
4923 const node = try c.arena.create(ast.Node.While);
4924 node.* = .{
4925 .label = null,
4926 .inline_token = null,
4927 .while_token = while_tok,
4928 .condition = undefined,
4929 .payload = null,
4930 .continue_expr = null,
4931 .body = undefined,
4932 .@"else" = null,
4933 };
4934 return node;
4935}
4936
4937fn transCreateNodeContinue(c: *Context) !*ast.Node {
4938 const ltoken = try appendToken(c, .Keyword_continue, "continue");
4939 const node = try ast.Node.ControlFlowExpression.create(c.arena, .{
4940 .ltoken = ltoken,
4941 .tag = .Continue,
4942 }, .{});
4943 _ = try appendToken(c, .Semicolon, ";");
4944 return &node.base;
4945}
4946
4947fn transCreateNodeSwitchCase(c: *Context, lhs: *ast.Node) !*ast.Node.SwitchCase {
4948 const arrow_tok = try appendToken(c, .EqualAngleBracketRight, "=>");
4949
4950 const node = try ast.Node.SwitchCase.alloc(c.arena, 1);
4951 node.* = .{
4952 .items_len = 1,
4953 .arrow_token = arrow_tok,
4954 .payload = null,
4955 .expr = undefined,
4956 };
4957 node.items()[0] = lhs;
4958 return node;
4959}
4960
4961fn transCreateNodeSwitchElse(c: *Context) !*ast.Node {
4962 const node = try c.arena.create(ast.Node.SwitchElse);
4963 node.* = .{
4964 .token = try appendToken(c, .Keyword_else, "else"),
4965 };
4966 return &node.base;
49673640}
49683641
49693642fn transCreateNodeShiftOp(
4970 rp: RestorePoint,
3643 c: *Context,
49713644 scope: *Scope,
49723645 stmt: *const clang.BinaryOperator,
4973 op: ast.Node.Tag,
4974 op_tok_id: std.zig.Token.Id,
4975 bytes: []const u8,
4976) !*ast.Node {
4977 std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight);
3646 op: Tag,
3647 used: ResultUsed,
3648) !Node {
3649 std.debug.assert(op == .shl or op == .shr);
49783650
49793651 const lhs_expr = stmt.getLHS();
49803652 const rhs_expr = stmt.getRHS();
49813653 const rhs_location = rhs_expr.getBeginLoc();
49823654 // lhs >> @as(u5, rh)
49833655
4984 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);
4985 const op_token = try appendToken(rp.c, op_tok_id, bytes);
4986
4987 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
4988 const rhs_type = try qualTypeToLog2IntRef(rp, stmt.getType(), rhs_location);
4989 cast_node.params()[0] = rhs_type;
4990 _ = try appendToken(rp.c, .Comma, ",");
4991 const rhs = try transExprCoercing(rp, scope, rhs_expr, .used, .r_value);
4992 cast_node.params()[1] = rhs;
4993 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
4994
4995 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4996 node.* = .{
4997 .base = .{ .tag = op },
4998 .op_token = op_token,
4999 .lhs = lhs,
5000 .rhs = &cast_node.base,
5001 };
5002
5003 return &node.base;
5004}
5005
5006fn transCreateNodePtrDeref(c: *Context, lhs: *ast.Node) !*ast.Node {
5007 const node = try c.arena.create(ast.Node.SimpleSuffixOp);
5008 node.* = .{
5009 .base = .{ .tag = .Deref },
5010 .lhs = lhs,
5011 .rtoken = try appendToken(c, .PeriodAsterisk, ".*"),
5012 };
5013 return &node.base;
5014}
5015
5016fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAccess {
5017 _ = try appendToken(c, .LBrace, "[");
5018 const node = try c.arena.create(ast.Node.ArrayAccess);
5019 node.* = .{
5020 .lhs = lhs,
5021 .index_expr = undefined,
5022 .rtoken = undefined,
5023 };
5024 return node;
5025}
5026
5027const RestorePoint = struct {
5028 c: *Context,
5029 token_index: ast.TokenIndex,
5030 src_buf_index: usize,
3656 const lhs = try transExpr(c, scope, lhs_expr, .used);
50313657
5032 fn activate(self: RestorePoint) void {
5033 self.c.token_ids.shrinkAndFree(self.c.gpa, self.token_index);
5034 self.c.token_locs.shrinkAndFree(self.c.gpa, self.token_index);
5035 self.c.source_buffer.shrinkAndFree(self.src_buf_index);
5036 }
5037};
3658 const rhs_type = try qualTypeToLog2IntRef(c, scope, stmt.getType(), rhs_location);
3659 const rhs = try transExprCoercing(c, scope, rhs_expr, .used);
3660 const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs });
50383661
5039fn makeRestorePoint(c: *Context) RestorePoint {
5040 return RestorePoint{
5041 .c = c,
5042 .token_index = c.token_ids.items.len,
5043 .src_buf_index = c.source_buffer.items.len,
5044 };
3662 return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used);
50453663}
50463664
5047fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!*ast.Node {
3665fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node {
50483666 switch (ty.getTypeClass()) {
50493667 .Builtin => {
50503668 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
5051 return transCreateNodeIdentifier(rp.c, switch (builtin_ty.getKind()) {
3669 return Tag.type.create(c.arena, switch (builtin_ty.getKind()) {
50523670 .Void => "c_void",
50533671 .Bool => "bool",
50543672 .Char_U, .UChar, .Char_S, .Char8 => "u8",
......@@ -5068,112 +3686,100 @@ fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLo
50683686 .Float128 => "f128",
50693687 .Float16 => "f16",
50703688 .LongDouble => "c_longdouble",
5071 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
3689 else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
50723690 });
50733691 },
50743692 .FunctionProto => {
50753693 const fn_proto_ty = @ptrCast(*const clang.FunctionProtoType, ty);
5076 const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);
5077 return &fn_proto.base;
3694 const fn_proto = try transFnProto(c, null, fn_proto_ty, source_loc, null, false);
3695 return Node.initPayload(&fn_proto.base);
50783696 },
50793697 .FunctionNoProto => {
50803698 const fn_no_proto_ty = @ptrCast(*const clang.FunctionType, ty);
5081 const fn_proto = try transFnNoProto(rp, fn_no_proto_ty, source_loc, null, false);
5082 return &fn_proto.base;
3699 const fn_proto = try transFnNoProto(c, fn_no_proto_ty, source_loc, null, false);
3700 return Node.initPayload(&fn_proto.base);
50833701 },
50843702 .Paren => {
50853703 const paren_ty = @ptrCast(*const clang.ParenType, ty);
5086 return transQualType(rp, paren_ty.getInnerType(), source_loc);
3704 return transQualType(c, scope, paren_ty.getInnerType(), source_loc);
50873705 },
50883706 .Pointer => {
50893707 const child_qt = ty.getPointeeType();
50903708 if (qualTypeChildIsFnProto(child_qt)) {
5091 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
5092 optional_node.rhs = try transQualType(rp, child_qt, source_loc);
5093 return &optional_node.base;
3709 return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc));
50943710 }
5095 if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) {
5096 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");
5097 const pointer_node = try transCreateNodePtrType(
5098 rp.c,
5099 child_qt.isConstQualified(),
5100 child_qt.isVolatileQualified(),
5101 .Asterisk,
5102 );
5103 optional_node.rhs = &pointer_node.base;
5104 pointer_node.rhs = try transQualType(rp, child_qt, source_loc);
5105 return &optional_node.base;
3711 const is_const = child_qt.isConstQualified();
3712 const is_volatile = child_qt.isVolatileQualified();
3713 const elem_type = try transQualType(c, scope, child_qt, source_loc);
3714 if (typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(c, child_qt)) {
3715 const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
3716 return Tag.optional_type.create(c.arena, ptr);
51063717 }
5107 const pointer_node = try transCreateNodePtrType(
5108 rp.c,
5109 child_qt.isConstQualified(),
5110 child_qt.isVolatileQualified(),
5111 .Identifier,
5112 );
5113 pointer_node.rhs = try transQualType(rp, child_qt, source_loc);
5114 return &pointer_node.base;
3718
3719 return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
51153720 },
51163721 .ConstantArray => {
51173722 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
51183723
51193724 const size_ap_int = const_arr_ty.getSize();
51203725 const size = size_ap_int.getLimitedValue(math.maxInt(usize));
5121 const elem_ty = const_arr_ty.getElementType().getTypePtr();
5122 return try transCreateNodeArrayType(rp, source_loc, elem_ty, size);
3726 const elem_type = try transType(c, scope, const_arr_ty.getElementType().getTypePtr(), source_loc);
3727
3728 return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type });
51233729 },
51243730 .IncompleteArray => {
51253731 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
51263732
51273733 const child_qt = incomplete_array_ty.getElementType();
5128 var node = try transCreateNodePtrType(
5129 rp.c,
5130 child_qt.isConstQualified(),
5131 child_qt.isVolatileQualified(),
5132 .Identifier,
5133 );
5134 node.rhs = try transQualType(rp, child_qt, source_loc);
5135 return &node.base;
3734 const is_const = child_qt.isConstQualified();
3735 const is_volatile = child_qt.isVolatileQualified();
3736 const elem_type = try transQualType(c, scope, child_qt, source_loc);
3737
3738 return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
51363739 },
51373740 .Typedef => {
51383741 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
51393742
51403743 const typedef_decl = typedef_ty.getDecl();
5141 return (try transTypeDef(rp.c, typedef_decl, false)) orelse
5142 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});
3744 try transTypeDef(c, scope, typedef_decl);
3745 const name = c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl())).?;
3746 return Tag.identifier.create(c.arena, name);
51433747 },
51443748 .Record => {
51453749 const record_ty = @ptrCast(*const clang.RecordType, ty);
51463750
51473751 const record_decl = record_ty.getDecl();
5148 return (try transRecordDecl(rp.c, record_decl)) orelse
5149 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});
3752 try transRecordDecl(c, scope, record_decl);
3753 const name = c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl())).?;
3754 return Tag.identifier.create(c.arena, name);
51503755 },
51513756 .Enum => {
51523757 const enum_ty = @ptrCast(*const clang.EnumType, ty);
51533758
51543759 const enum_decl = enum_ty.getDecl();
5155 return (try transEnumDecl(rp.c, enum_decl)) orelse
5156 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
3760 try transEnumDecl(c, scope, enum_decl);
3761 const name = c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl())).?;
3762 return Tag.identifier.create(c.arena, name);
51573763 },
51583764 .Elaborated => {
51593765 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
5160 return transQualType(rp, elaborated_ty.getNamedType(), source_loc);
3766 return transQualType(c, scope, elaborated_ty.getNamedType(), source_loc);
51613767 },
51623768 .Decayed => {
51633769 const decayed_ty = @ptrCast(*const clang.DecayedType, ty);
5164 return transQualType(rp, decayed_ty.getDecayedType(), source_loc);
3770 return transQualType(c, scope, decayed_ty.getDecayedType(), source_loc);
51653771 },
51663772 .Attributed => {
51673773 const attributed_ty = @ptrCast(*const clang.AttributedType, ty);
5168 return transQualType(rp, attributed_ty.getEquivalentType(), source_loc);
3774 return transQualType(c, scope, attributed_ty.getEquivalentType(), source_loc);
51693775 },
51703776 .MacroQualified => {
51713777 const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty);
5172 return transQualType(rp, macroqualified_ty.getModifiedType(), source_loc);
3778 return transQualType(c, scope, macroqualified_ty.getModifiedType(), source_loc);
51733779 },
51743780 else => {
5175 const type_name = rp.c.str(ty.getTypeClassName());
5176 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
3781 const type_name = c.str(ty.getTypeClassName());
3782 return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
51773783 },
51783784 }
51793785}
......@@ -5239,7 +3845,7 @@ const FnDeclContext = struct {
52393845};
52403846
52413847fn transCC(
5242 rp: RestorePoint,
3848 c: *Context,
52433849 fn_ty: *const clang.FunctionType,
52443850 source_loc: clang.SourceLocation,
52453851) !CallingConvention {
......@@ -5252,8 +3858,8 @@ fn transCC(
52523858 .X86ThisCall => return CallingConvention.Thiscall,
52533859 .AAPCS => return CallingConvention.AAPCS,
52543860 .AAPCS_VFP => return CallingConvention.AAPCSVFP,
5255 else => return revertAndWarn(
5256 rp,
3861 else => return fail(
3862 c,
52573863 error.UnsupportedType,
52583864 source_loc,
52593865 "unsupported calling convention: {s}",
......@@ -5263,33 +3869,33 @@ fn transCC(
52633869}
52643870
52653871fn transFnProto(
5266 rp: RestorePoint,
3872 c: *Context,
52673873 fn_decl: ?*const clang.FunctionDecl,
52683874 fn_proto_ty: *const clang.FunctionProtoType,
52693875 source_loc: clang.SourceLocation,
52703876 fn_decl_context: ?FnDeclContext,
52713877 is_pub: bool,
5272) !*ast.Node.FnProto {
3878) !*ast.Payload.Func {
52733879 const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty);
5274 const cc = try transCC(rp, fn_ty, source_loc);
3880 const cc = try transCC(c, fn_ty, source_loc);
52753881 const is_var_args = fn_proto_ty.isVariadic();
5276 return finishTransFnProto(rp, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
3882 return finishTransFnProto(c, fn_decl, fn_proto_ty, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
52773883}
52783884
52793885fn transFnNoProto(
5280 rp: RestorePoint,
3886 c: *Context,
52813887 fn_ty: *const clang.FunctionType,
52823888 source_loc: clang.SourceLocation,
52833889 fn_decl_context: ?FnDeclContext,
52843890 is_pub: bool,
5285) !*ast.Node.FnProto {
5286 const cc = try transCC(rp, fn_ty, source_loc);
3891) !*ast.Payload.Func {
3892 const cc = try transCC(c, fn_ty, source_loc);
52873893 const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true;
5288 return finishTransFnProto(rp, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
3894 return finishTransFnProto(c, null, null, fn_ty, source_loc, fn_decl_context, is_var_args, cc, is_pub);
52893895}
52903896
52913897fn finishTransFnProto(
5292 rp: RestorePoint,
3898 c: *Context,
52933899 fn_decl: ?*const clang.FunctionDecl,
52943900 fn_proto_ty: ?*const clang.FunctionProtoType,
52953901 fn_ty: *const clang.FunctionType,
......@@ -5298,128 +3904,78 @@ fn finishTransFnProto(
52983904 is_var_args: bool,
52993905 cc: CallingConvention,
53003906 is_pub: bool,
5301) !*ast.Node.FnProto {
3907) !*ast.Payload.Func {
53023908 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
53033909 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
3910 const scope = &c.global_scope.base;
53043911
53053912 // TODO check for always_inline attribute
53063913 // TODO check for align attribute
53073914
5308 // pub extern fn name(...) T
5309 const pub_tok = if (is_pub) try appendToken(rp.c, .Keyword_pub, "pub") else null;
5310 const extern_export_inline_tok = if (is_export)
5311 try appendToken(rp.c, .Keyword_export, "export")
5312 else if (is_extern)
5313 try appendToken(rp.c, .Keyword_extern, "extern")
5314 else
5315 null;
5316 const fn_tok = try appendToken(rp.c, .Keyword_fn, "fn");
5317 const name_tok = if (fn_decl_context) |ctx| try appendIdentifier(rp.c, ctx.fn_name) else null;
5318 const lparen_tok = try appendToken(rp.c, .LParen, "(");
5319
5320 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(rp.c.gpa);
3915 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
53213916 defer fn_params.deinit();
53223917 const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;
5323 try fn_params.ensureCapacity(param_count + 1); // +1 for possible var args node
3918 try fn_params.ensureCapacity(param_count);
53243919
53253920 var i: usize = 0;
53263921 while (i < param_count) : (i += 1) {
53273922 const param_qt = fn_proto_ty.?.getParamType(@intCast(c_uint, i));
3923 const is_noalias = param_qt.isRestrictQualified();
53283924
5329 const noalias_tok = if (param_qt.isRestrictQualified()) try appendToken(rp.c, .Keyword_noalias, "noalias") else null;
5330
5331 const param_name_tok: ?ast.TokenIndex = blk: {
5332 if (fn_decl) |decl| {
5333 const param = decl.getParamDecl(@intCast(c_uint, i));
5334 const param_name: []const u8 = try rp.c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());
5335 if (param_name.len < 1)
5336 break :blk null;
5337
5338 const result = try appendIdentifier(rp.c, param_name);
5339 _ = try appendToken(rp.c, .Colon, ":");
5340 break :blk result;
5341 }
5342 break :blk null;
5343 };
3925 const param_name: ?[]const u8 =
3926 if (fn_decl) |decl|
3927 blk: {
3928 const param = decl.getParamDecl(@intCast(c_uint, i));
3929 const param_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());
3930 if (param_name.len < 1)
3931 break :blk null;
53443932
5345 const type_node = try transQualType(rp, param_qt, source_loc);
3933 break :blk param_name;
3934 } else null;
3935 const type_node = try transQualType(c, scope, param_qt, source_loc);
53463936
53473937 fn_params.addOneAssumeCapacity().* = .{
5348 .doc_comments = null,
5349 .comptime_token = null,
5350 .noalias_token = noalias_tok,
5351 .name_token = param_name_tok,
5352 .param_type = .{ .type_expr = type_node },
3938 .is_noalias = is_noalias,
3939 .name = param_name,
3940 .type = type_node,
53533941 };
5354
5355 if (i + 1 < param_count) {
5356 _ = try appendToken(rp.c, .Comma, ",");
5357 }
53583942 }
53593943
5360 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {
5361 if (param_count > 0) {
5362 _ = try appendToken(rp.c, .Comma, ",");
5363 }
5364 break :blk try appendToken(rp.c, .Ellipsis3, "...");
5365 } else null;
5366
5367 const rparen_tok = try appendToken(rp.c, .RParen, ")");
5368
5369 const linksection_expr = blk: {
3944 const linksection_string = blk: {
53703945 if (fn_decl) |decl| {
53713946 var str_len: usize = undefined;
53723947 if (decl.getSectionAttribute(&str_len)) |str_ptr| {
5373 _ = try appendToken(rp.c, .Keyword_linksection, "linksection");
5374 _ = try appendToken(rp.c, .LParen, "(");
5375 const expr = try transCreateNodeStringLiteral(
5376 rp.c,
5377 try std.fmt.allocPrint(rp.c.arena, "\"{s}\"", .{str_ptr[0..str_len]}),
5378 );
5379 _ = try appendToken(rp.c, .RParen, ")");
5380
5381 break :blk expr;
3948 break :blk str_ptr[0..str_len];
53823949 }
53833950 }
53843951 break :blk null;
53853952 };
53863953
5387 const align_expr = blk: {
3954 const alignment = blk: {
53883955 if (fn_decl) |decl| {
5389 const alignment = decl.getAlignedAttribute(rp.c.clang_context);
3956 const alignment = decl.getAlignedAttribute(c.clang_context);
53903957 if (alignment != 0) {
5391 _ = try appendToken(rp.c, .Keyword_align, "align");
5392 _ = try appendToken(rp.c, .LParen, "(");
53933958 // Clang reports the alignment in bits
5394 const expr = try transCreateNodeInt(rp.c, alignment / 8);
5395 _ = try appendToken(rp.c, .RParen, ")");
5396
5397 break :blk expr;
3959 break :blk alignment / 8;
53983960 }
53993961 }
54003962 break :blk null;
54013963 };
54023964
5403 const callconv_expr = if ((is_export or is_extern) and cc == .C) null else blk: {
5404 _ = try appendToken(rp.c, .Keyword_callconv, "callconv");
5405 _ = try appendToken(rp.c, .LParen, "(");
5406 const expr = try transCreateNodeEnumLiteral(rp.c, @tagName(cc));
5407 _ = try appendToken(rp.c, .RParen, ")");
5408 break :blk expr;
5409 };
3965 const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc;
54103966
54113967 const return_type_node = blk: {
54123968 if (fn_ty.getNoReturnAttr()) {
5413 break :blk try transCreateNodeIdentifier(rp.c, "noreturn");
3969 break :blk Tag.noreturn_type.init();
54143970 } else {
54153971 const return_qt = fn_ty.getReturnType();
54163972 if (isCVoid(return_qt)) {
54173973 // convert primitive c_void to actual void (only for return type)
5418 break :blk try transCreateNodeIdentifier(rp.c, "void");
3974 break :blk Tag.void_type.init();
54193975 } else {
5420 break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
3976 break :blk transQualType(c, scope, return_qt, source_loc) catch |err| switch (err) {
54213977 error.UnsupportedType => {
5422 try emitWarning(rp.c, source_loc, "unsupported function proto return type", .{});
3978 try warn(c, scope, source_loc, "unsupported function proto return type", .{});
54233979 return err;
54243980 },
54253981 error.OutOfMemory => |e| return e,
......@@ -5427,116 +3983,57 @@ fn finishTransFnProto(
54273983 }
54283984 }
54293985 };
3986 const name: ?[]const u8 = if (fn_decl_context) |ctx| ctx.fn_name else null;
3987 const payload = try c.arena.create(ast.Payload.Func);
3988 payload.* = .{
3989 .base = .{ .tag = .func },
3990 .data = .{
3991 .is_pub = is_pub,
3992 .is_extern = is_extern,
3993 .is_export = is_export,
3994 .is_var_args = is_var_args,
3995 .name = name,
3996 .linksection_string = linksection_string,
3997 .explicit_callconv = explicit_callconv,
3998 .params = try c.arena.dupe(ast.Payload.Param, fn_params.items),
3999 .return_type = return_type_node,
4000 .body = null,
4001 .alignment = alignment,
4002 },
4003 };
4004 return payload;
4005}
54304006
5431 // We need to reserve an undefined (but non-null) body node to set later.
5432 var body_node: ?*ast.Node = null;
5433 if (fn_decl_context) |ctx| {
5434 if (ctx.has_body) {
5435 // TODO: we should be able to use undefined here but
5436 // it causes a bug. This is undefined without zig language
5437 // being aware of it.
5438 body_node = @intToPtr(*ast.Node, 0x08);
5439 }
5440 }
5441
5442 const fn_proto = try ast.Node.FnProto.create(rp.c.arena, .{
5443 .params_len = fn_params.items.len,
5444 .return_type = .{ .Explicit = return_type_node },
5445 .fn_token = fn_tok,
5446 }, .{
5447 .visib_token = pub_tok,
5448 .name_token = name_tok,
5449 .extern_export_inline_token = extern_export_inline_tok,
5450 .align_expr = align_expr,
5451 .section_expr = linksection_expr,
5452 .callconv_expr = callconv_expr,
5453 .body_node = body_node,
5454 .var_args_token = var_args_token,
5455 });
5456 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
5457 return fn_proto;
4007fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void {
4008 const args_prefix = .{c.locStr(loc)};
4009 const value = try std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, args_prefix ++ args);
4010 try scope.appendNode(try Tag.warning.create(c.arena, value));
54584011}
54594012
5460fn revertAndWarn(
5461 rp: RestorePoint,
4013fn fail(
4014 c: *Context,
54624015 err: anytype,
54634016 source_loc: clang.SourceLocation,
54644017 comptime format: []const u8,
54654018 args: anytype,
54664019) (@TypeOf(err) || error{OutOfMemory}) {
5467 rp.activate();
5468 try emitWarning(rp.c, source_loc, format, args);
4020 try warn(c, &c.global_scope.base, source_loc, format, args);
54694021 return err;
54704022}
54714023
5472fn emitWarning(c: *Context, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void {
5473 const args_prefix = .{c.locStr(loc)};
5474 _ = try appendTokenFmt(c, .LineComment, "// {s}: warning: " ++ format, args_prefix ++ args);
5475}
5476
5477pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) !void {
4024pub fn failDecl(c: *Context, loc: clang.SourceLocation, name: []const u8, comptime format: []const u8, args: anytype) Error!void {
4025 // location
54784026 // pub const name = @compileError(msg);
5479 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
5480 const const_tok = try appendToken(c, .Keyword_const, "const");
5481 const name_tok = try appendIdentifier(c, name);
5482 const eq_tok = try appendToken(c, .Equal, "=");
5483 const builtin_tok = try appendToken(c, .Builtin, "@compileError");
5484 const lparen_tok = try appendToken(c, .LParen, "(");
5485 const msg_tok = try appendTokenFmt(c, .StringLiteral, "\"" ++ format ++ "\"", args);
5486 const rparen_tok = try appendToken(c, .RParen, ")");
5487 const semi_tok = try appendToken(c, .Semicolon, ";");
5488 _ = try appendTokenFmt(c, .LineComment, "// {s}", .{c.locStr(loc)});
5489
5490 const msg_node = try c.arena.create(ast.Node.OneToken);
5491 msg_node.* = .{
5492 .base = .{ .tag = .StringLiteral },
5493 .token = msg_tok,
5494 };
5495
5496 const call_node = try ast.Node.BuiltinCall.alloc(c.arena, 1);
5497 call_node.* = .{
5498 .builtin_token = builtin_tok,
5499 .params_len = 1,
5500 .rparen_token = rparen_tok,
5501 };
5502 call_node.params()[0] = &msg_node.base;
5503
5504 const var_decl_node = try ast.Node.VarDecl.create(c.arena, .{
5505 .name_token = name_tok,
5506 .mut_token = const_tok,
5507 .semicolon_token = semi_tok,
5508 }, .{
5509 .visib_token = pub_tok,
5510 .eq_token = eq_tok,
5511 .init_node = &call_node.base,
5512 });
5513 try addTopLevelDecl(c, name, &var_decl_node.base);
5514}
5515
5516fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex {
5517 std.debug.assert(token_id != .Identifier); // use appendIdentifier
5518 return appendTokenFmt(c, token_id, "{s}", .{bytes});
4027 const fail_msg = try std.fmt.allocPrint(c.arena, format, args);
4028 try addTopLevelDecl(c, name, try Tag.fail_decl.create(c.arena, .{ .actual = name, .mangled = fail_msg }));
4029 const location_comment = try std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)});
4030 try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment));
55194031}
55204032
5521fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: anytype) !ast.TokenIndex {
5522 assert(token_id != .Invalid);
5523
5524 try c.token_ids.ensureCapacity(c.gpa, c.token_ids.items.len + 1);
5525 try c.token_locs.ensureCapacity(c.gpa, c.token_locs.items.len + 1);
5526
5527 const start_index = c.source_buffer.items.len;
5528 try c.source_buffer.writer().print(format ++ " ", args);
5529
5530 c.token_ids.appendAssumeCapacity(token_id);
5531 c.token_locs.appendAssumeCapacity(.{
5532 .start = start_index,
5533 .end = c.source_buffer.items.len - 1, // back up before the space
5534 });
5535
5536 return c.token_ids.items.len - 1;
4033pub fn freeErrors(errors: []ClangErrMsg) void {
4034 errors.ptr.delete(errors.len);
55374035}
55384036
5539// TODO hook up with codegen
55404037fn isZigPrimitiveType(name: []const u8) bool {
55414038 if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
55424039 for (name[1..]) |c| {
......@@ -5547,56 +4044,7 @@ fn isZigPrimitiveType(name: []const u8) bool {
55474044 }
55484045 return true;
55494046 }
5550 // void is invalid in c so it doesn't need to be checked.
5551 return mem.eql(u8, name, "comptime_float") or
5552 mem.eql(u8, name, "comptime_int") or
5553 mem.eql(u8, name, "bool") or
5554 mem.eql(u8, name, "isize") or
5555 mem.eql(u8, name, "usize") or
5556 mem.eql(u8, name, "f16") or
5557 mem.eql(u8, name, "f32") or
5558 mem.eql(u8, name, "f64") or
5559 mem.eql(u8, name, "f128") or
5560 mem.eql(u8, name, "c_longdouble") or
5561 mem.eql(u8, name, "noreturn") or
5562 mem.eql(u8, name, "type") or
5563 mem.eql(u8, name, "anyerror") or
5564 mem.eql(u8, name, "c_short") or
5565 mem.eql(u8, name, "c_ushort") or
5566 mem.eql(u8, name, "c_int") or
5567 mem.eql(u8, name, "c_uint") or
5568 mem.eql(u8, name, "c_long") or
5569 mem.eql(u8, name, "c_ulong") or
5570 mem.eql(u8, name, "c_longlong") or
5571 mem.eql(u8, name, "c_ulonglong");
5572}
5573
5574fn appendIdentifier(c: *Context, name: []const u8) !ast.TokenIndex {
5575 return appendTokenFmt(c, .Identifier, "{}", .{std.zig.fmtId(name)});
5576}
5577
5578fn transCreateNodeIdentifier(c: *Context, name: []const u8) !*ast.Node {
5579 const token_index = try appendIdentifier(c, name);
5580 const identifier = try c.arena.create(ast.Node.OneToken);
5581 identifier.* = .{
5582 .base = .{ .tag = .Identifier },
5583 .token = token_index,
5584 };
5585 return &identifier.base;
5586}
5587
5588fn transCreateNodeIdentifierUnchecked(c: *Context, name: []const u8) !*ast.Node {
5589 const token_index = try appendTokenFmt(c, .Identifier, "{s}", .{name});
5590 const identifier = try c.arena.create(ast.Node.OneToken);
5591 identifier.* = .{
5592 .base = .{ .tag = .Identifier },
5593 .token = token_index,
5594 };
5595 return &identifier.base;
5596}
5597
5598pub fn freeErrors(errors: []ClangErrMsg) void {
5599 errors.ptr.delete(errors.len);
4047 return @import("astgen.zig").simple_types.has(name);
56004048}
56014049
56024050const MacroCtx = struct {
......@@ -5717,27 +4165,13 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
57174165fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
57184166 const scope = &c.global_scope.base;
57194167
5720 const visib_tok = try appendToken(c, .Keyword_pub, "pub");
5721 const mut_tok = try appendToken(c, .Keyword_const, "const");
5722 const name_tok = try appendIdentifier(c, m.name);
5723 const eq_token = try appendToken(c, .Equal, "=");
5724
57254168 const init_node = try parseCExpr(c, m, scope);
57264169 const last = m.next().?;
57274170 if (last != .Eof and last != .Nl)
57284171 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
57294172
5730 const semicolon_token = try appendToken(c, .Semicolon, ";");
5731 const node = try ast.Node.VarDecl.create(c.arena, .{
5732 .name_token = name_tok,
5733 .mut_token = mut_tok,
5734 .semicolon_token = semicolon_token,
5735 }, .{
5736 .visib_token = visib_tok,
5737 .eq_token = eq_token,
5738 .init_node = init_node,
5739 });
5740 _ = try c.global_scope.macro_table.put(m.name, &node.base);
4173 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
4174 _ = try c.global_scope.macro_table.put(m.name, var_decl);
57414175}
57424176
57434177fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
......@@ -5745,16 +4179,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
57454179 defer block_scope.deinit();
57464180 const scope = &block_scope.base;
57474181
5748 const pub_tok = try appendToken(c, .Keyword_pub, "pub");
5749 const fn_tok = try appendToken(c, .Keyword_fn, "fn");
5750 const name_tok = try appendIdentifier(c, m.name);
5751 _ = try appendToken(c, .LParen, "(");
5752
57534182 if (m.next().? != .LParen) {
57544183 return m.fail(c, "unable to translate C expr: expected '('", .{});
57554184 }
57564185
5757 var fn_params = std.ArrayList(ast.Node.FnProto.ParamDecl).init(c.gpa);
4186 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
57584187 defer fn_params.deinit();
57594188
57604189 while (true) {
......@@ -5762,120 +4191,82 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
57624191 _ = m.next();
57634192
57644193 const mangled_name = try block_scope.makeMangledName(c, m.slice());
5765 const param_name_tok = try appendIdentifier(c, mangled_name);
5766 _ = try appendToken(c, .Colon, ":");
5767
5768 const any_type = try c.arena.create(ast.Node.OneToken);
5769 any_type.* = .{
5770 .base = .{ .tag = .AnyType },
5771 .token = try appendToken(c, .Keyword_anytype, "anytype"),
5772 };
5773
5774 (try fn_params.addOne()).* = .{
5775 .doc_comments = null,
5776 .comptime_token = null,
5777 .noalias_token = null,
5778 .name_token = param_name_tok,
5779 .param_type = .{ .any_type = &any_type.base },
5780 };
4194 try fn_params.append(.{
4195 .is_noalias = false,
4196 .name = mangled_name,
4197 .type = Tag.@"anytype".init(),
4198 });
57814199
57824200 if (m.peek().? != .Comma) break;
57834201 _ = m.next();
5784 _ = try appendToken(c, .Comma, ",");
57854202 }
57864203
57874204 if (m.next().? != .RParen) {
57884205 return m.fail(c, "unable to translate C expr: expected ')'", .{});
57894206 }
57904207
5791 _ = try appendToken(c, .RParen, ")");
5792
5793 _ = try appendToken(c, .Keyword_callconv, "callconv");
5794 _ = try appendToken(c, .LParen, "(");
5795 const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline");
5796 _ = try appendToken(c, .RParen, ")");
5797
5798 const type_of = try c.createBuiltinCall("@TypeOf", 1);
5799
5800 const return_kw = try appendToken(c, .Keyword_return, "return");
58014208 const expr = try parseCExpr(c, m, scope);
58024209 const last = m.next().?;
58034210 if (last != .Eof and last != .Nl)
58044211 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
5805 _ = try appendToken(c, .Semicolon, ";");
5806 const type_of_arg = if (!expr.tag.isBlock()) expr else blk: {
5807 const stmts = expr.blockStatements();
4212
4213 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
4214 const stmts = some.data.stmts;
58084215 const blk_last = stmts[stmts.len - 1];
5809 const br = blk_last.cast(ast.Node.ControlFlowExpression).?;
5810 break :blk br.getRHS().?;
5811 };
5812 type_of.params()[0] = type_of_arg;
5813 type_of.rparen_token = try appendToken(c, .RParen, ")");
5814 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{
5815 .ltoken = return_kw,
5816 .tag = .Return,
5817 }, .{
5818 .rhs = expr,
5819 });
4216 const br = blk_last.castTag(.break_val).?;
4217 break :blk br.data.val;
4218 } else expr;
4219 const return_type = if (typeof_arg.castTag(.std_meta_cast)) |some|
4220 some.data.lhs
4221 else
4222 try Tag.typeof.create(c.arena, typeof_arg);
58204223
5821 try block_scope.statements.append(&return_expr.base);
5822 const block_node = try block_scope.complete(c);
5823 const fn_proto = try ast.Node.FnProto.create(c.arena, .{
5824 .fn_token = fn_tok,
5825 .params_len = fn_params.items.len,
5826 .return_type = .{ .Explicit = &type_of.base },
5827 }, .{
5828 .visib_token = pub_tok,
5829 .name_token = name_tok,
5830 .body_node = block_node,
5831 .callconv_expr = callconv_expr,
5832 });
5833 mem.copy(ast.Node.FnProto.ParamDecl, fn_proto.params(), fn_params.items);
4224 const return_expr = try Tag.@"return".create(c.arena, expr);
4225 try block_scope.statements.append(return_expr);
58344226
5835 _ = try c.global_scope.macro_table.put(m.name, &fn_proto.base);
4227 const fn_decl = try Tag.pub_inline_fn.create(c.arena, .{
4228 .name = m.name,
4229 .params = try c.arena.dupe(ast.Payload.Param, fn_params.items),
4230 .return_type = return_type,
4231 .body = try block_scope.complete(c),
4232 });
4233 _ = try c.global_scope.macro_table.put(m.name, fn_decl);
58364234}
58374235
58384236const ParseError = Error || error{ParseError};
58394237
5840fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4238fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
58414239 // TODO parseCAssignExpr here
58424240 const node = try parseCCondExpr(c, m, scope);
58434241 if (m.next().? != .Comma) {
58444242 m.i -= 1;
58454243 return node;
58464244 }
5847 _ = try appendToken(c, .Semicolon, ";");
58484245 var block_scope = try Scope.Block.init(c, scope, true);
58494246 defer block_scope.deinit();
58504247
58514248 var last = node;
58524249 while (true) {
58534250 // suppress result
5854 const lhs = try transCreateNodeIdentifier(c, "_");
5855 const op_token = try appendToken(c, .Equal, "=");
5856 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
5857 op_node.* = .{
5858 .base = .{ .tag = .Assign },
5859 .op_token = op_token,
5860 .lhs = lhs,
5861 .rhs = last,
5862 };
5863 try block_scope.statements.append(&op_node.base);
4251 const ignore = try Tag.discard.create(c.arena, last);
4252 try block_scope.statements.append(ignore);
58644253
58654254 last = try parseCCondExpr(c, m, scope);
5866 _ = try appendToken(c, .Semicolon, ";");
58674255 if (m.next().? != .Comma) {
58684256 m.i -= 1;
58694257 break;
58704258 }
58714259 }
58724260
5873 const break_node = try transCreateNodeBreak(c, block_scope.label, last);
5874 try block_scope.statements.append(&break_node.base);
4261 const break_node = try Tag.break_val.create(c.arena, .{
4262 .label = block_scope.label,
4263 .val = last,
4264 });
4265 try block_scope.statements.append(break_node);
58754266 return try block_scope.complete(c);
58764267}
58774268
5878fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
4269fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
58794270 var lit_bytes = m.slice();
58804271
58814272 switch (m.list[m.i].id) {
......@@ -5895,11 +4286,10 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
58954286 }
58964287
58974288 if (suffix == .none) {
5898 return transCreateNodeInt(c, lit_bytes);
4289 return transCreateNodeNumber(c, lit_bytes, .int);
58994290 }
59004291
5901 const cast_node = try c.createBuiltinCall("@as", 2);
5902 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (suffix) {
4292 const type_node = try Tag.type.create(c.arena, switch (suffix) {
59034293 .u => "c_uint",
59044294 .l => "c_long",
59054295 .lu => "c_ulong",
......@@ -5913,27 +4303,22 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
59134303 .llu => 3,
59144304 else => unreachable,
59154305 }];
5916 _ = try appendToken(c, .Comma, ",");
5917 cast_node.params()[1] = try transCreateNodeInt(c, lit_bytes);
5918 cast_node.rparen_token = try appendToken(c, .RParen, ")");
5919 return &cast_node.base;
4306 const rhs = try transCreateNodeNumber(c, lit_bytes, .int);
4307 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
59204308 },
59214309 .FloatLiteral => |suffix| {
59224310 if (lit_bytes[0] == '.')
59234311 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});
59244312 if (suffix == .none) {
5925 return transCreateNodeFloat(c, lit_bytes);
4313 return transCreateNodeNumber(c, lit_bytes, .float);
59264314 }
5927 const cast_node = try c.createBuiltinCall("@as", 2);
5928 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (suffix) {
4315 const type_node = try Tag.type.create(c.arena, switch (suffix) {
59294316 .f => "f32",
59304317 .l => "c_longdouble",
59314318 else => unreachable,
59324319 });
5933 _ = try appendToken(c, .Comma, ",");
5934 cast_node.params()[1] = try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]);
5935 cast_node.rparen_token = try appendToken(c, .RParen, ")");
5936 return &cast_node.base;
4320 const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1], .float);
4321 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
59374322 },
59384323 else => unreachable,
59394324 }
......@@ -6099,79 +4484,62 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
60994484 return bytes[0..i];
61004485}
61014486
6102fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4487fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
61034488 const tok = m.next().?;
61044489 const slice = m.slice();
61054490 switch (tok) {
61064491 .CharLiteral => {
61074492 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
6108 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, m));
6109 const node = try c.arena.create(ast.Node.OneToken);
6110 node.* = .{
6111 .base = .{ .tag = .CharLiteral },
6112 .token = token,
6113 };
6114 return &node.base;
4493 return Tag.char_literal.create(c.arena, try zigifyEscapeSequences(c, m));
61154494 } else {
6116 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{slice[1 .. slice.len - 1]});
6117 const node = try c.arena.create(ast.Node.OneToken);
6118 node.* = .{
6119 .base = .{ .tag = .IntegerLiteral },
6120 .token = token,
6121 };
6122 return &node.base;
4495 const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});
4496 return Tag.integer_literal.create(c.arena, str);
61234497 }
61244498 },
61254499 .StringLiteral => {
6126 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, m));
6127 const node = try c.arena.create(ast.Node.OneToken);
6128 node.* = .{
6129 .base = .{ .tag = .StringLiteral },
6130 .token = token,
6131 };
6132 return &node.base;
4500 return Tag.string_literal.create(c.arena, try zigifyEscapeSequences(c, m));
61334501 },
61344502 .IntegerLiteral, .FloatLiteral => {
61354503 return parseCNumLit(c, m);
61364504 },
61374505 // eventually this will be replaced by std.c.parse which will handle these correctly
6138 .Keyword_void => return transCreateNodeIdentifierUnchecked(c, "c_void"),
6139 .Keyword_bool => return transCreateNodeIdentifierUnchecked(c, "bool"),
6140 .Keyword_double => return transCreateNodeIdentifierUnchecked(c, "f64"),
6141 .Keyword_long => return transCreateNodeIdentifierUnchecked(c, "c_long"),
6142 .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"),
6143 .Keyword_float => return transCreateNodeIdentifierUnchecked(c, "f32"),
6144 .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"),
6145 .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "u8"),
4506 .Keyword_void => return Tag.type.create(c.arena, "c_void"),
4507 .Keyword_bool => return Tag.type.create(c.arena, "bool"),
4508 .Keyword_double => return Tag.type.create(c.arena, "f64"),
4509 .Keyword_long => return Tag.type.create(c.arena, "c_long"),
4510 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
4511 .Keyword_float => return Tag.type.create(c.arena, "f32"),
4512 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
4513 .Keyword_char => return Tag.type.create(c.arena, "u8"),
61464514 .Keyword_unsigned => if (m.next()) |t| switch (t) {
6147 .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "u8"),
6148 .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_ushort"),
6149 .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_uint"),
4515 .Keyword_char => return Tag.type.create(c.arena, "u8"),
4516 .Keyword_short => return Tag.type.create(c.arena, "c_ushort"),
4517 .Keyword_int => return Tag.type.create(c.arena, "c_uint"),
61504518 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
61514519 _ = m.next();
6152 return transCreateNodeIdentifierUnchecked(c, "c_ulonglong");
6153 } else return transCreateNodeIdentifierUnchecked(c, "c_ulong"),
4520 return Tag.type.create(c.arena, "c_ulonglong");
4521 } else return Tag.type.create(c.arena, "c_ulong"),
61544522 else => {
61554523 m.i -= 1;
6156 return transCreateNodeIdentifierUnchecked(c, "c_uint");
4524 return Tag.type.create(c.arena, "c_uint");
61574525 },
61584526 } else {
6159 return transCreateNodeIdentifierUnchecked(c, "c_uint");
4527 return Tag.type.create(c.arena, "c_uint");
61604528 },
61614529 .Keyword_signed => if (m.next()) |t| switch (t) {
6162 .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "i8"),
6163 .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"),
6164 .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"),
4530 .Keyword_char => return Tag.type.create(c.arena, "i8"),
4531 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
4532 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
61654533 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
61664534 _ = m.next();
6167 return transCreateNodeIdentifierUnchecked(c, "c_longlong");
6168 } else return transCreateNodeIdentifierUnchecked(c, "c_long"),
4535 return Tag.type.create(c.arena, "c_longlong");
4536 } else return Tag.type.create(c.arena, "c_long"),
61694537 else => {
61704538 m.i -= 1;
6171 return transCreateNodeIdentifierUnchecked(c, "c_int");
4539 return Tag.type.create(c.arena, "c_int");
61724540 },
61734541 } else {
6174 return transCreateNodeIdentifierUnchecked(c, "c_int");
4542 return Tag.type.create(c.arena, "c_int");
61754543 },
61764544 .Keyword_enum, .Keyword_struct, .Keyword_union => {
61774545 // struct Foo will be declared as struct_Foo by transRecordDecl
......@@ -6181,17 +4549,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
61814549 return error.ParseError;
61824550 }
61834551
6184 const ident_token = try appendTokenFmt(c, .Identifier, "{s}_{s}", .{ slice, m.slice() });
6185 const identifier = try c.arena.create(ast.Node.OneToken);
6186 identifier.* = .{
6187 .base = .{ .tag = .Identifier },
6188 .token = ident_token,
6189 };
6190 return &identifier.base;
4552 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
4553 return Tag.identifier.create(c.arena, name);
61914554 },
61924555 .Identifier => {
61934556 const mangled_name = scope.getAlias(slice);
6194 return transCreateNodeIdentifier(c, checkForBuiltinTypedef(mangled_name) orelse mangled_name);
4557 return Tag.identifier.create(c.arena, builtin_typedef_map.get(mangled_name) orelse mangled_name);
61954558 },
61964559 .LParen => {
61974560 const inner_node = try parseCExpr(c, m, scope);
......@@ -6221,10 +4584,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
62214584 },
62224585 else => return inner_node,
62234586 }
6224
6225 // hack to get zig fmt to render a comma in builtin calls
6226 _ = try appendToken(c, .Comma, ",");
6227
62284587 const node_to_cast = try parseCExpr(c, m, scope);
62294588
62304589 if (saw_l_paren and m.next().? != .RParen) {
......@@ -6232,28 +4591,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
62324591 return error.ParseError;
62334592 }
62344593
6235 const lparen = try appendToken(c, .LParen, "(");
6236
6237 //(@import("std").meta.cast(dest, x))
6238 const import_fn_call = try c.createBuiltinCall("@import", 1);
6239 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
6240 import_fn_call.params()[0] = std_node;
6241 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
6242 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
6243 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "cast");
6244
6245 const cast_fn_call = try c.createCall(outer_field_access, 2);
6246 cast_fn_call.params()[0] = inner_node;
6247 cast_fn_call.params()[1] = node_to_cast;
6248 cast_fn_call.rtoken = try appendToken(c, .RParen, ")");
6249
6250 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6251 group_node.* = .{
6252 .lparen = lparen,
6253 .expr = &cast_fn_call.base,
6254 .rparen = try appendToken(c, .RParen, ")"),
6255 };
6256 return &group_node.base;
4594 return Tag.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast });
62574595 },
62584596 else => {
62594597 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});
......@@ -6262,447 +4600,256 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
62624600 }
62634601}
62644602
6265fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4603fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
62664604 var node = try parseCPrimaryExprInner(c, m, scope);
62674605 // In C the preprocessor would handle concatting strings while expanding macros.
62684606 // This should do approximately the same by concatting any strings and identifiers
62694607 // after a primary expression.
62704608 while (true) {
6271 var op_token: ast.TokenIndex = undefined;
6272 var op_id: ast.Node.Tag = undefined;
62734609 switch (m.peek().?) {
62744610 .StringLiteral, .Identifier => {},
62754611 else => break,
62764612 }
6277 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6278 op_node.* = .{
6279 .base = .{ .tag = .ArrayCat },
6280 .op_token = try appendToken(c, .PlusPlus, "++"),
6281 .lhs = node,
6282 .rhs = try parseCPrimaryExprInner(c, m, scope),
6283 };
6284 node = &op_node.base;
4613 node = try Tag.array_cat.create(c.arena, .{ .lhs = node, .rhs = try parseCPrimaryExprInner(c, m, scope) });
62854614 }
62864615 return node;
62874616}
62884617
6289fn nodeIsInfixOp(tag: ast.Node.Tag) bool {
6290 return switch (tag) {
6291 .Add,
6292 .AddWrap,
6293 .ArrayCat,
6294 .ArrayMult,
6295 .Assign,
6296 .AssignBitAnd,
6297 .AssignBitOr,
6298 .AssignBitShiftLeft,
6299 .AssignBitShiftRight,
6300 .AssignBitXor,
6301 .AssignDiv,
6302 .AssignSub,
6303 .AssignSubWrap,
6304 .AssignMod,
6305 .AssignAdd,
6306 .AssignAddWrap,
6307 .AssignMul,
6308 .AssignMulWrap,
6309 .BangEqual,
6310 .BitAnd,
6311 .BitOr,
6312 .BitShiftLeft,
6313 .BitShiftRight,
6314 .BitXor,
6315 .BoolAnd,
6316 .BoolOr,
6317 .Div,
6318 .EqualEqual,
6319 .ErrorUnion,
6320 .GreaterOrEqual,
6321 .GreaterThan,
6322 .LessOrEqual,
6323 .LessThan,
6324 .MergeErrorSets,
6325 .Mod,
6326 .Mul,
6327 .MulWrap,
6328 .Period,
6329 .Range,
6330 .Sub,
6331 .SubWrap,
6332 .UnwrapOptional,
6333 .Catch,
6334 => true,
6335
6336 else => false,
6337 };
6338}
6339
6340fn macroBoolToInt(c: *Context, node: *ast.Node) !*ast.Node {
4618fn macroBoolToInt(c: *Context, node: Node) !Node {
63414619 if (!isBoolRes(node)) {
6342 if (!nodeIsInfixOp(node.tag)) return node;
6343
6344 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6345 group_node.* = .{
6346 .lparen = try appendToken(c, .LParen, "("),
6347 .expr = node,
6348 .rparen = try appendToken(c, .RParen, ")"),
6349 };
6350 return &group_node.base;
4620 return node;
63514621 }
63524622
6353 const builtin_node = try c.createBuiltinCall("@boolToInt", 1);
6354 builtin_node.params()[0] = node;
6355 builtin_node.rparen_token = try appendToken(c, .RParen, ")");
6356 return &builtin_node.base;
4623 return Tag.bool_to_int.create(c.arena, node);
63574624}
63584625
6359fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {
4626fn macroIntToBool(c: *Context, node: Node) !Node {
63604627 if (isBoolRes(node)) {
6361 if (!nodeIsInfixOp(node.tag)) return node;
6362
6363 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6364 group_node.* = .{
6365 .lparen = try appendToken(c, .LParen, "("),
6366 .expr = node,
6367 .rparen = try appendToken(c, .RParen, ")"),
6368 };
6369 return &group_node.base;
4628 return node;
63704629 }
63714630
6372 const op_token = try appendToken(c, .BangEqual, "!=");
6373 const zero = try transCreateNodeInt(c, 0);
6374 const res = try c.arena.create(ast.Node.SimpleInfixOp);
6375 res.* = .{
6376 .base = .{ .tag = .BangEqual },
6377 .op_token = op_token,
6378 .lhs = node,
6379 .rhs = zero,
6380 };
6381 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6382 group_node.* = .{
6383 .lparen = try appendToken(c, .LParen, "("),
6384 .expr = &res.base,
6385 .rparen = try appendToken(c, .RParen, ")"),
6386 };
6387 return &group_node.base;
6388}
6389
6390fn macroGroup(c: *Context, node: *ast.Node) !*ast.Node {
6391 if (!nodeIsInfixOp(node.tag)) return node;
6392
6393 const group_node = try c.arena.create(ast.Node.GroupedExpression);
6394 group_node.* = .{
6395 .lparen = try appendToken(c, .LParen, "("),
6396 .expr = node,
6397 .rparen = try appendToken(c, .RParen, ")"),
6398 };
6399 return &group_node.base;
4631 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
64004632}
64014633
6402fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4634fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
64034635 const node = try parseCOrExpr(c, m, scope);
64044636 if (m.peek().? != .QuestionMark) {
64054637 return node;
64064638 }
64074639 _ = m.next();
64084640
6409 // must come immediately after expr
6410 _ = try appendToken(c, .RParen, ")");
6411 const if_node = try transCreateNodeIf(c);
6412 if_node.condition = node;
6413 if_node.body = try parseCOrExpr(c, m, scope);
4641 const then_body = try parseCOrExpr(c, m, scope);
64144642 if (m.next().? != .Colon) {
64154643 try m.fail(c, "unable to translate C expr: expected ':'", .{});
64164644 return error.ParseError;
64174645 }
6418 if_node.@"else" = try transCreateNodeElse(c);
6419 if_node.@"else".?.body = try parseCCondExpr(c, m, scope);
6420 return &if_node.base;
4646 const else_body = try parseCCondExpr(c, m, scope);
4647 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
64214648}
64224649
6423fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4650fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
64244651 var node = try parseCAndExpr(c, m, scope);
64254652 while (m.next().? == .PipePipe) {
6426 const lhs_node = try macroIntToBool(c, node);
6427 const op_token = try appendToken(c, .Keyword_or, "or");
6428 const rhs_node = try parseCAndExpr(c, m, scope);
6429 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6430 op_node.* = .{
6431 .base = .{ .tag = .BoolOr },
6432 .op_token = op_token,
6433 .lhs = lhs_node,
6434 .rhs = try macroIntToBool(c, rhs_node),
6435 };
6436 node = &op_node.base;
4653 const lhs = try macroIntToBool(c, node);
4654 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
4655 node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
64374656 }
64384657 m.i -= 1;
64394658 return node;
64404659}
64414660
6442fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4661fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
64434662 var node = try parseCBitOrExpr(c, m, scope);
64444663 while (m.next().? == .AmpersandAmpersand) {
6445 const lhs_node = try macroIntToBool(c, node);
6446 const op_token = try appendToken(c, .Keyword_and, "and");
6447 const rhs_node = try parseCBitOrExpr(c, m, scope);
6448 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6449 op_node.* = .{
6450 .base = .{ .tag = .BoolAnd },
6451 .op_token = op_token,
6452 .lhs = lhs_node,
6453 .rhs = try macroIntToBool(c, rhs_node),
6454 };
6455 node = &op_node.base;
4664 const lhs = try macroIntToBool(c, node);
4665 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
4666 node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
64564667 }
64574668 m.i -= 1;
64584669 return node;
64594670}
64604671
6461fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4672fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
64624673 var node = try parseCBitXorExpr(c, m, scope);
64634674 while (m.next().? == .Pipe) {
6464 const lhs_node = try macroBoolToInt(c, node);
6465 const op_token = try appendToken(c, .Pipe, "|");
6466 const rhs_node = try parseCBitXorExpr(c, m, scope);
6467 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6468 op_node.* = .{
6469 .base = .{ .tag = .BitOr },
6470 .op_token = op_token,
6471 .lhs = lhs_node,
6472 .rhs = try macroBoolToInt(c, rhs_node),
6473 };
6474 node = &op_node.base;
4675 const lhs = try macroBoolToInt(c, node);
4676 const rhs = try macroBoolToInt(c, try parseCBitXorExpr(c, m, scope));
4677 node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
64754678 }
64764679 m.i -= 1;
64774680 return node;
64784681}
64794682
6480fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4683fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
64814684 var node = try parseCBitAndExpr(c, m, scope);
64824685 while (m.next().? == .Caret) {
6483 const lhs_node = try macroBoolToInt(c, node);
6484 const op_token = try appendToken(c, .Caret, "^");
6485 const rhs_node = try parseCBitAndExpr(c, m, scope);
6486 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6487 op_node.* = .{
6488 .base = .{ .tag = .BitXor },
6489 .op_token = op_token,
6490 .lhs = lhs_node,
6491 .rhs = try macroBoolToInt(c, rhs_node),
6492 };
6493 node = &op_node.base;
4686 const lhs = try macroBoolToInt(c, node);
4687 const rhs = try macroBoolToInt(c, try parseCBitAndExpr(c, m, scope));
4688 node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
64944689 }
64954690 m.i -= 1;
64964691 return node;
64974692}
64984693
6499fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4694fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
65004695 var node = try parseCEqExpr(c, m, scope);
65014696 while (m.next().? == .Ampersand) {
6502 const lhs_node = try macroBoolToInt(c, node);
6503 const op_token = try appendToken(c, .Ampersand, "&");
6504 const rhs_node = try parseCEqExpr(c, m, scope);
6505 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6506 op_node.* = .{
6507 .base = .{ .tag = .BitAnd },
6508 .op_token = op_token,
6509 .lhs = lhs_node,
6510 .rhs = try macroBoolToInt(c, rhs_node),
6511 };
6512 node = &op_node.base;
4697 const lhs = try macroBoolToInt(c, node);
4698 const rhs = try macroBoolToInt(c, try parseCEqExpr(c, m, scope));
4699 node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65134700 }
65144701 m.i -= 1;
65154702 return node;
65164703}
65174704
6518fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4705fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
65194706 var node = try parseCRelExpr(c, m, scope);
65204707 while (true) {
6521 var op_token: ast.TokenIndex = undefined;
6522 var op_id: ast.Node.Tag = undefined;
65234708 switch (m.peek().?) {
65244709 .BangEqual => {
6525 op_token = try appendToken(c, .BangEqual, "!=");
6526 op_id = .BangEqual;
4710 _ = m.next();
4711 const lhs = try macroBoolToInt(c, node);
4712 const rhs = try macroBoolToInt(c, try parseCRelExpr(c, m, scope));
4713 node = try Tag.not_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65274714 },
65284715 .EqualEqual => {
6529 op_token = try appendToken(c, .EqualEqual, "==");
6530 op_id = .EqualEqual;
4716 _ = m.next();
4717 const lhs = try macroBoolToInt(c, node);
4718 const rhs = try macroBoolToInt(c, try parseCRelExpr(c, m, scope));
4719 node = try Tag.equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65314720 },
65324721 else => return node,
65334722 }
6534 _ = m.next();
6535 const lhs_node = try macroBoolToInt(c, node);
6536 const rhs_node = try parseCRelExpr(c, m, scope);
6537 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6538 op_node.* = .{
6539 .base = .{ .tag = op_id },
6540 .op_token = op_token,
6541 .lhs = lhs_node,
6542 .rhs = try macroBoolToInt(c, rhs_node),
6543 };
6544 node = &op_node.base;
65454723 }
65464724}
65474725
6548fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4726fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
65494727 var node = try parseCShiftExpr(c, m, scope);
65504728 while (true) {
6551 var op_token: ast.TokenIndex = undefined;
6552 var op_id: ast.Node.Tag = undefined;
65534729 switch (m.peek().?) {
65544730 .AngleBracketRight => {
6555 op_token = try appendToken(c, .AngleBracketRight, ">");
6556 op_id = .GreaterThan;
4731 _ = m.next();
4732 const lhs = try macroBoolToInt(c, node);
4733 const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
4734 node = try Tag.greater_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65574735 },
65584736 .AngleBracketRightEqual => {
6559 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");
6560 op_id = .GreaterOrEqual;
4737 _ = m.next();
4738 const lhs = try macroBoolToInt(c, node);
4739 const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
4740 node = try Tag.greater_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65614741 },
65624742 .AngleBracketLeft => {
6563 op_token = try appendToken(c, .AngleBracketLeft, "<");
6564 op_id = .LessThan;
4743 _ = m.next();
4744 const lhs = try macroBoolToInt(c, node);
4745 const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
4746 node = try Tag.less_than.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65654747 },
65664748 .AngleBracketLeftEqual => {
6567 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");
6568 op_id = .LessOrEqual;
4749 _ = m.next();
4750 const lhs = try macroBoolToInt(c, node);
4751 const rhs = try macroBoolToInt(c, try parseCShiftExpr(c, m, scope));
4752 node = try Tag.less_than_equal.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65694753 },
65704754 else => return node,
65714755 }
6572 _ = m.next();
6573 const lhs_node = try macroBoolToInt(c, node);
6574 const rhs_node = try parseCShiftExpr(c, m, scope);
6575 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6576 op_node.* = .{
6577 .base = .{ .tag = op_id },
6578 .op_token = op_token,
6579 .lhs = lhs_node,
6580 .rhs = try macroBoolToInt(c, rhs_node),
6581 };
6582 node = &op_node.base;
65834756 }
65844757}
65854758
6586fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4759fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
65874760 var node = try parseCAddSubExpr(c, m, scope);
65884761 while (true) {
6589 var op_token: ast.TokenIndex = undefined;
6590 var op_id: ast.Node.Tag = undefined;
65914762 switch (m.peek().?) {
65924763 .AngleBracketAngleBracketLeft => {
6593 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");
6594 op_id = .BitShiftLeft;
4764 _ = m.next();
4765 const lhs = try macroBoolToInt(c, node);
4766 const rhs = try macroBoolToInt(c, try parseCAddSubExpr(c, m, scope));
4767 node = try Tag.shl.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65954768 },
65964769 .AngleBracketAngleBracketRight => {
6597 op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");
6598 op_id = .BitShiftRight;
4770 _ = m.next();
4771 const lhs = try macroBoolToInt(c, node);
4772 const rhs = try macroBoolToInt(c, try parseCAddSubExpr(c, m, scope));
4773 node = try Tag.shr.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
65994774 },
66004775 else => return node,
66014776 }
6602 _ = m.next();
6603 const lhs_node = try macroBoolToInt(c, node);
6604 const rhs_node = try parseCAddSubExpr(c, m, scope);
6605 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6606 op_node.* = .{
6607 .base = .{ .tag = op_id },
6608 .op_token = op_token,
6609 .lhs = lhs_node,
6610 .rhs = try macroBoolToInt(c, rhs_node),
6611 };
6612 node = &op_node.base;
66134777 }
66144778}
66154779
6616fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4780fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
66174781 var node = try parseCMulExpr(c, m, scope);
66184782 while (true) {
6619 var op_token: ast.TokenIndex = undefined;
6620 var op_id: ast.Node.Tag = undefined;
66214783 switch (m.peek().?) {
66224784 .Plus => {
6623 op_token = try appendToken(c, .Plus, "+");
6624 op_id = .Add;
4785 _ = m.next();
4786 const lhs = try macroBoolToInt(c, node);
4787 const rhs = try macroBoolToInt(c, try parseCMulExpr(c, m, scope));
4788 node = try Tag.add.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
66254789 },
66264790 .Minus => {
6627 op_token = try appendToken(c, .Minus, "-");
6628 op_id = .Sub;
4791 _ = m.next();
4792 const lhs = try macroBoolToInt(c, node);
4793 const rhs = try macroBoolToInt(c, try parseCMulExpr(c, m, scope));
4794 node = try Tag.sub.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
66294795 },
66304796 else => return node,
66314797 }
6632 _ = m.next();
6633 const lhs_node = try macroBoolToInt(c, node);
6634 const rhs_node = try parseCMulExpr(c, m, scope);
6635 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6636 op_node.* = .{
6637 .base = .{ .tag = op_id },
6638 .op_token = op_token,
6639 .lhs = lhs_node,
6640 .rhs = try macroBoolToInt(c, rhs_node),
6641 };
6642 node = &op_node.base;
66434798 }
66444799}
66454800
6646fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4801fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
66474802 var node = try parseCUnaryExpr(c, m, scope);
66484803 while (true) {
6649 var op_token: ast.TokenIndex = undefined;
6650 var op_id: ast.Node.Tag = undefined;
66514804 switch (m.next().?) {
66524805 .Asterisk => {
6653 if (m.peek().? == .RParen) {
4806 const next = m.peek().?;
4807 if (next == .RParen or next == .Nl or next == .Eof) {
66544808 // type *)
66554809
6656 // hack to get zig fmt to render a comma in builtin calls
6657 _ = try appendToken(c, .Comma, ",");
6658
66594810 // last token of `node`
66604811 const prev_id = m.list[m.i - 1].id;
66614812
66624813 if (prev_id == .Keyword_void) {
6663 const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);
6664 ptr.rhs = node;
6665 const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?");
6666 optional_node.rhs = &ptr.base;
6667 return &optional_node.base;
4814 const ptr = try Tag.single_pointer.create(c.arena, .{
4815 .is_const = false,
4816 .is_volatile = false,
4817 .elem_type = node,
4818 });
4819 return Tag.optional_type.create(c.arena, ptr);
66684820 } else {
6669 const ptr = try transCreateNodePtrType(c, false, false, Token.Id.Identifier);
6670 ptr.rhs = node;
6671 return &ptr.base;
4821 return Tag.c_pointer.create(c.arena, .{
4822 .is_const = false,
4823 .is_volatile = false,
4824 .elem_type = node,
4825 });
66724826 }
66734827 } else {
66744828 // expr * expr
6675 op_token = try appendToken(c, .Asterisk, "*");
6676 op_id = .BitShiftLeft;
4829 const lhs = try macroBoolToInt(c, node);
4830 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4831 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
66774832 }
66784833 },
66794834 .Slash => {
6680 op_id = .Div;
6681 op_token = try appendToken(c, .Slash, "/");
4835 const lhs = try macroBoolToInt(c, node);
4836 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4837 node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
66824838 },
66834839 .Percent => {
6684 op_id = .Mod;
6685 op_token = try appendToken(c, .Percent, "%");
4840 const lhs = try macroBoolToInt(c, node);
4841 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4842 node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
66864843 },
66874844 else => {
66884845 m.i -= 1;
66894846 return node;
66904847 },
66914848 }
6692 const lhs_node = try macroBoolToInt(c, node);
6693 const rhs_node = try parseCUnaryExpr(c, m, scope);
6694 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);
6695 op_node.* = .{
6696 .base = .{ .tag = op_id },
6697 .op_token = op_token,
6698 .lhs = lhs_node,
6699 .rhs = try macroBoolToInt(c, rhs_node),
6700 };
6701 node = &op_node.base;
67024849 }
67034850}
67044851
6705fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4852fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
67064853 var node = try parseCPrimaryExpr(c, m, scope);
67074854 while (true) {
67084855 switch (m.next().?) {
......@@ -6712,38 +4859,33 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
67124859 return error.ParseError;
67134860 }
67144861
6715 node = try transCreateNodeFieldAccess(c, node, m.slice());
6716 continue;
4862 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
67174863 },
67184864 .Arrow => {
67194865 if (m.next().? != .Identifier) {
67204866 try m.fail(c, "unable to translate C expr: expected identifier", .{});
67214867 return error.ParseError;
67224868 }
6723 const deref = try transCreateNodePtrDeref(c, node);
6724 node = try transCreateNodeFieldAccess(c, deref, m.slice());
6725 continue;
4869
4870 const deref = try Tag.deref.create(c.arena, node);
4871 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
67264872 },
67274873 .LBracket => {
6728 const arr_node = try transCreateNodeArrayAccess(c, node);
6729 arr_node.index_expr = try parseCExpr(c, m, scope);
6730 arr_node.rtoken = try appendToken(c, .RBracket, "]");
6731 node = &arr_node.base;
4874 const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
4875 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
67324876 if (m.next().? != .RBracket) {
67334877 try m.fail(c, "unable to translate C expr: expected ']'", .{});
67344878 return error.ParseError;
67354879 }
6736 continue;
67374880 },
67384881 .LParen => {
6739 _ = try appendToken(c, .LParen, "(");
6740 var call_params = std.ArrayList(*ast.Node).init(c.gpa);
6741 defer call_params.deinit();
4882 var args = std.ArrayList(Node).init(c.gpa);
4883 defer args.deinit();
67424884 while (true) {
67434885 const arg = try parseCCondExpr(c, m, scope);
6744 try call_params.append(arg);
4886 try args.append(arg);
67454887 switch (m.next().?) {
6746 .Comma => _ = try appendToken(c, .Comma, ","),
4888 .Comma => {},
67474889 .RParen => break,
67484890 else => {
67494891 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});
......@@ -6751,32 +4893,17 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
67514893 },
67524894 }
67534895 }
6754 const call_node = try ast.Node.Call.alloc(c.arena, call_params.items.len);
6755 call_node.* = .{
6756 .lhs = node,
6757 .params_len = call_params.items.len,
6758 .async_token = null,
6759 .rtoken = try appendToken(c, .RParen, ")"),
6760 };
6761 mem.copy(*ast.Node, call_node.params(), call_params.items);
6762 node = &call_node.base;
6763 continue;
4896 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
67644897 },
67654898 .LBrace => {
6766 // must come immediately after `node`
6767 _ = try appendToken(c, .Comma, ",");
6768
6769 const dot = try appendToken(c, .Period, ".");
6770 _ = try appendToken(c, .LBrace, "{");
6771
6772 var init_vals = std.ArrayList(*ast.Node).init(c.gpa);
4899 var init_vals = std.ArrayList(Node).init(c.gpa);
67734900 defer init_vals.deinit();
67744901
67754902 while (true) {
67764903 const val = try parseCCondExpr(c, m, scope);
67774904 try init_vals.append(val);
67784905 switch (m.next().?) {
6779 .Comma => _ = try appendToken(c, .Comma, ","),
4906 .Comma => {},
67804907 .RBrace => break,
67814908 else => {
67824909 try m.fail(c, "unable to translate C expr: expected ',' or '}}'", .{});
......@@ -6784,29 +4911,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
67844911 },
67854912 }
67864913 }
6787 const tuple_node = try ast.Node.StructInitializerDot.alloc(c.arena, init_vals.items.len);
6788 tuple_node.* = .{
6789 .dot = dot,
6790 .list_len = init_vals.items.len,
6791 .rtoken = try appendToken(c, .RBrace, "}"),
6792 };
6793 mem.copy(*ast.Node, tuple_node.list(), init_vals.items);
6794
6795 //(@import("std").mem.zeroInit(T, .{x}))
6796 const import_fn_call = try c.createBuiltinCall("@import", 1);
6797 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
6798 import_fn_call.params()[0] = std_node;
6799 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
6800 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "mem");
6801 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "zeroInit");
6802
6803 const zero_init_call = try c.createCall(outer_field_access, 2);
6804 zero_init_call.params()[0] = node;
6805 zero_init_call.params()[1] = &tuple_node.base;
6806 zero_init_call.rtoken = try appendToken(c, .RParen, ")");
6807
6808 node = &zero_init_call.base;
6809 continue;
4914 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
4915 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = tuple_node });
68104916 },
68114917 .PlusPlus, .MinusMinus => {
68124918 try m.fail(c, "TODO postfix inc/dec expr", .{});
......@@ -6820,35 +4926,31 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
68204926 }
68214927}
68224928
6823fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
4929fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
68244930 switch (m.next().?) {
68254931 .Bang => {
6826 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");
6827 node.rhs = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
6828 return &node.base;
4932 const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
4933 return Tag.not.create(c.arena, operand);
68294934 },
68304935 .Minus => {
6831 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");
6832 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
6833 return &node.base;
4936 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4937 return Tag.negate.create(c.arena, operand);
68344938 },
68354939 .Plus => return try parseCUnaryExpr(c, m, scope),
68364940 .Tilde => {
6837 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");
6838 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
6839 return &node.base;
4941 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4942 return Tag.bit_not.create(c.arena, operand);
68404943 },
68414944 .Asterisk => {
6842 const node = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
6843 return try transCreateNodePtrDeref(c, node);
4945 const operand = try parseCUnaryExpr(c, m, scope);
4946 return Tag.deref.create(c.arena, operand);
68444947 },
68454948 .Ampersand => {
6846 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");
6847 node.rhs = try macroGroup(c, try parseCUnaryExpr(c, m, scope));
6848 return &node.base;
4949 const operand = try parseCUnaryExpr(c, m, scope);
4950 return Tag.address_of.create(c.arena, operand);
68494951 },
68504952 .Keyword_sizeof => {
6851 const inner = if (m.peek().? == .LParen) blk: {
4953 const operand = if (m.peek().? == .LParen) blk: {
68524954 _ = m.next();
68534955 // C grammar says this should be 'type-name' but we have to
68544956 // use parseCMulExpr to correctly handle pointer types.
......@@ -6860,18 +4962,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
68604962 break :blk inner;
68614963 } else try parseCUnaryExpr(c, m, scope);
68624964
6863 //(@import("std").meta.sizeof(dest, x))
6864 const import_fn_call = try c.createBuiltinCall("@import", 1);
6865 const std_node = try transCreateNodeStringLiteral(c, "\"std\"");
6866 import_fn_call.params()[0] = std_node;
6867 import_fn_call.rparen_token = try appendToken(c, .RParen, ")");
6868 const inner_field_access = try transCreateNodeFieldAccess(c, &import_fn_call.base, "meta");
6869 const outer_field_access = try transCreateNodeFieldAccess(c, inner_field_access, "sizeof");
6870
6871 const sizeof_call = try c.createCall(outer_field_access, 1);
6872 sizeof_call.params()[0] = inner;
6873 sizeof_call.rtoken = try appendToken(c, .RParen, ")");
6874 return &sizeof_call.base;
4965 return Tag.std_meta_sizeof.create(c.arena, operand);
68754966 },
68764967 .Keyword_alignof => {
68774968 // TODO this won't work if using <stdalign.h>'s
......@@ -6882,16 +4973,13 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
68824973 }
68834974 // C grammar says this should be 'type-name' but we have to
68844975 // use parseCMulExpr to correctly handle pointer types.
6885 const inner = try parseCMulExpr(c, m, scope);
4976 const operand = try parseCMulExpr(c, m, scope);
68864977 if (m.next().? != .RParen) {
68874978 try m.fail(c, "unable to translate C expr: expected ')'", .{});
68884979 return error.ParseError;
68894980 }
68904981
6891 const builtin_call = try c.createBuiltinCall("@alignOf", 1);
6892 builtin_call.params()[0] = inner;
6893 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
6894 return &builtin_call.base;
4982 return Tag.alignof.create(c.arena, operand);
68954983 },
68964984 .PlusPlus, .MinusMinus => {
68974985 try m.fail(c, "TODO unary inc/dec expr", .{});
......@@ -6904,51 +4992,40 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
69044992 }
69054993}
69064994
6907fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {
6908 const tok = c.token_locs.items[token];
6909 const slice = c.source_buffer.items[tok.start..tok.end];
6910 return if (mem.startsWith(u8, slice, "@\""))
6911 slice[2 .. slice.len - 1]
6912 else
6913 slice;
6914}
6915
6916fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6917 switch (node.tag) {
6918 .ContainerDecl,
6919 .AddressOf,
6920 .Await,
6921 .BitNot,
6922 .BoolNot,
6923 .OptionalType,
6924 .Negation,
6925 .NegationWrap,
6926 .Resume,
6927 .Try,
6928 .ArrayType,
6929 .ArrayTypeSentinel,
6930 .PtrType,
6931 .SliceType,
4995fn getContainer(c: *Context, node: Node) ?Node {
4996 switch (node.tag()) {
4997 .@"union",
4998 .@"struct",
4999 .@"enum",
5000 .address_of,
5001 .bit_not,
5002 .not,
5003 .optional_type,
5004 .negate,
5005 .negate_wrap,
5006 .array_type,
5007 .c_pointer,
5008 .single_pointer,
69325009 => return node,
69335010
6934 .Identifier => {
6935 const ident = node.castTag(.Identifier).?;
6936 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6937 if (value.cast(ast.Node.VarDecl)) |var_decl|
6938 return getContainer(c, var_decl.getInitNode().?);
5011 .identifier => {
5012 const ident = node.castTag(.identifier).?;
5013 if (c.global_scope.sym_table.get(ident.data)) |value| {
5014 if (value.castTag(.var_decl)) |var_decl|
5015 return getContainer(c, var_decl.data.init.?);
5016 if (value.castTag(.var_simple) orelse value.castTag(.pub_var_simple)) |var_decl|
5017 return getContainer(c, var_decl.data.init);
69395018 }
69405019 },
69415020
6942 .Period => {
6943 const infix = node.castTag(.Period).?;
5021 .field_access => {
5022 const field_access = node.castTag(.field_access).?;
69445023
6945 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6946 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6947 for (container.fieldsAndDecls()) |field_ref| {
6948 const field = field_ref.cast(ast.Node.ContainerField).?;
6949 const ident = infix.rhs.castTag(.Identifier).?;
6950 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6951 return getContainer(c, field.type_expr.?);
5024 if (getContainerTypeOf(c, field_access.data.lhs)) |ty_node| {
5025 if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
5026 for (container.data.fields) |field| {
5027 if (mem.eql(u8, field.name, field_access.data.field_name)) {
5028 return getContainer(c, field.type);
69525029 }
69535030 }
69545031 }
......@@ -6960,22 +5037,19 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
69605037 return null;
69615038}
69625039
6963fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6964 if (ref.castTag(.Identifier)) |ident| {
6965 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {
6966 if (value.cast(ast.Node.VarDecl)) |var_decl| {
6967 if (var_decl.getTypeNode()) |ty|
6968 return getContainer(c, ty);
5040fn getContainerTypeOf(c: *Context, ref: Node) ?Node {
5041 if (ref.castTag(.identifier)) |ident| {
5042 if (c.global_scope.sym_table.get(ident.data)) |value| {
5043 if (value.castTag(.var_decl)) |var_decl| {
5044 return getContainer(c, var_decl.data.type);
69695045 }
69705046 }
6971 } else if (ref.castTag(.Period)) |infix| {
6972 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {
6973 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {
6974 for (container.fieldsAndDecls()) |field_ref| {
6975 const field = field_ref.cast(ast.Node.ContainerField).?;
6976 const ident = infix.rhs.castTag(.Identifier).?;
6977 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6978 return getContainer(c, field.type_expr.?);
5047 } else if (ref.castTag(.field_access)) |field_access| {
5048 if (getContainerTypeOf(c, field_access.data.lhs)) |ty_node| {
5049 if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
5050 for (container.data.fields) |field| {
5051 if (mem.eql(u8, field.name, field_access.data.field_name)) {
5052 return getContainer(c, field.type);
69795053 }
69805054 }
69815055 } else
......@@ -6985,11 +5059,16 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
69855059 return null;
69865060}
69875061
6988fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {
6989 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getInitNode().? else return null;
5062fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {
5063 const init = if (ref.castTag(.var_decl)) |v|
5064 v.data.init orelse return null
5065 else if (ref.castTag(.var_simple) orelse ref.castTag(.pub_var_simple)) |v|
5066 v.data.init
5067 else
5068 return null;
69905069 if (getContainerTypeOf(c, init)) |ty_node| {
6991 if (ty_node.castTag(.OptionalType)) |prefix| {
6992 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {
5070 if (ty_node.castTag(.optional_type)) |prefix| {
5071 if (prefix.data.castTag(.func)) |fn_proto| {
69935072 return fn_proto;
69945073 }
69955074 }
src/translate_c/ast.zig created+2531
......@@ -0,0 +1,2531 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6const std = @import("std");
7const Type = @import("../type.zig").Type;
8const Allocator = std.mem.Allocator;
9
10pub const Node = extern union {
11 /// If the tag value is less than Tag.no_payload_count, then no pointer
12 /// dereference is needed.
13 tag_if_small_enough: usize,
14 ptr_otherwise: *Payload,
15
16 pub const Tag = enum {
17 /// Declarations add themselves to the correct scopes and should not be emitted as this tag.
18 declaration,
19 null_literal,
20 undefined_literal,
21 /// opaque {}
22 opaque_literal,
23 true_literal,
24 false_literal,
25 empty_block,
26 return_void,
27 zero_literal,
28 one_literal,
29 void_type,
30 noreturn_type,
31 @"anytype",
32 @"continue",
33 @"break",
34 /// pub usingnamespace @import("std").c.builtins;
35 usingnamespace_builtins,
36 // After this, the tag requires a payload.
37
38 integer_literal,
39 float_literal,
40 string_literal,
41 char_literal,
42 identifier,
43 @"if",
44 /// if (!operand) break;
45 if_not_break,
46 @"while",
47 /// while (true) operand
48 while_true,
49 @"switch",
50 /// else => operand,
51 switch_else,
52 /// items => body,
53 switch_prong,
54 break_val,
55 @"return",
56 field_access,
57 array_access,
58 call,
59 var_decl,
60 func,
61 warning,
62 /// All enums are non-exhaustive
63 @"enum",
64 @"struct",
65 @"union",
66 array_init,
67 tuple,
68 container_init,
69 std_meta_cast,
70 /// _ = operand;
71 discard,
72
73 // a + b
74 add,
75 // a = b
76 add_assign,
77 // c = (a = b)
78 add_wrap,
79 add_wrap_assign,
80 sub,
81 sub_assign,
82 sub_wrap,
83 sub_wrap_assign,
84 mul,
85 mul_assign,
86 mul_wrap,
87 mul_wrap_assign,
88 div,
89 div_assign,
90 shl,
91 shl_assign,
92 shr,
93 shr_assign,
94 mod,
95 mod_assign,
96 @"and",
97 @"or",
98 less_than,
99 less_than_equal,
100 greater_than,
101 greater_than_equal,
102 equal,
103 not_equal,
104 bit_and,
105 bit_and_assign,
106 bit_or,
107 bit_or_assign,
108 bit_xor,
109 bit_xor_assign,
110 array_cat,
111 ellipsis3,
112 assign,
113
114 log2_int_type,
115 /// @import("std").math.Log2Int(operand)
116 std_math_Log2Int,
117 /// @intCast(lhs, rhs)
118 int_cast,
119 /// @rem(lhs, rhs)
120 rem,
121 /// @divTrunc(lhs, rhs)
122 div_trunc,
123 /// @boolToInt(operand)
124 bool_to_int,
125 /// @as(lhs, rhs)
126 as,
127 /// @truncate(lhs, rhs)
128 truncate,
129 /// @bitCast(lhs, rhs)
130 bit_cast,
131 /// @floatCast(lhs, rhs)
132 float_cast,
133 /// @floatToInt(lhs, rhs)
134 float_to_int,
135 /// @intToFloat(lhs, rhs)
136 int_to_float,
137 /// @intToEnum(lhs, rhs)
138 int_to_enum,
139 /// @enumToInt(operand)
140 enum_to_int,
141 /// @intToPtr(lhs, rhs)
142 int_to_ptr,
143 /// @ptrToInt(operand)
144 ptr_to_int,
145 /// @alignCast(lhs, rhs)
146 align_cast,
147 /// @ptrCast(lhs, rhs)
148 ptr_cast,
149
150 negate,
151 negate_wrap,
152 bit_not,
153 not,
154 address_of,
155 /// .?
156 unwrap,
157 /// .*
158 deref,
159
160 block,
161 /// { operand }
162 block_single,
163
164 sizeof,
165 alignof,
166 typeof,
167 type,
168
169 optional_type,
170 c_pointer,
171 single_pointer,
172 array_type,
173
174 /// @import("std").meta.sizeof(operand)
175 std_meta_sizeof,
176 /// @import("std").mem.zeroes(operand)
177 std_mem_zeroes,
178 /// @import("std").mem.zeroInit(lhs, rhs)
179 std_mem_zeroinit,
180 // pub const name = @compileError(msg);
181 fail_decl,
182 // var actual = mangled;
183 arg_redecl,
184 /// pub const alias = actual;
185 alias,
186 /// const name = init;
187 var_simple,
188 /// pub const name = init;
189 pub_var_simple,
190 /// pub const enum_field_name = @enumToInt(enum_name.field_name);
191 pub_enum_redecl,
192 enum_redecl,
193
194 /// pub inline fn name(params) return_type body
195 pub_inline_fn,
196
197 /// [0]type{}
198 empty_array,
199 /// [1]type{val} ** count
200 array_filler,
201
202 pub const last_no_payload_tag = Tag.usingnamespace_builtins;
203 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
204
205 pub fn Type(comptime t: Tag) type {
206 return switch (t) {
207 .declaration,
208 .null_literal,
209 .undefined_literal,
210 .opaque_literal,
211 .true_literal,
212 .false_literal,
213 .empty_block,
214 .usingnamespace_builtins,
215 .return_void,
216 .zero_literal,
217 .one_literal,
218 .void_type,
219 .noreturn_type,
220 .@"anytype",
221 .@"continue",
222 .@"break",
223 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
224
225 .std_mem_zeroes,
226 .@"return",
227 .discard,
228 .std_math_Log2Int,
229 .negate,
230 .negate_wrap,
231 .bit_not,
232 .not,
233 .optional_type,
234 .address_of,
235 .unwrap,
236 .deref,
237 .ptr_to_int,
238 .enum_to_int,
239 .empty_array,
240 .while_true,
241 .if_not_break,
242 .switch_else,
243 .block_single,
244 .std_meta_sizeof,
245 .bool_to_int,
246 .sizeof,
247 .alignof,
248 .typeof,
249 => Payload.UnOp,
250
251 .add,
252 .add_assign,
253 .add_wrap,
254 .add_wrap_assign,
255 .sub,
256 .sub_assign,
257 .sub_wrap,
258 .sub_wrap_assign,
259 .mul,
260 .mul_assign,
261 .mul_wrap,
262 .mul_wrap_assign,
263 .div,
264 .div_assign,
265 .shl,
266 .shl_assign,
267 .shr,
268 .shr_assign,
269 .mod,
270 .mod_assign,
271 .@"and",
272 .@"or",
273 .less_than,
274 .less_than_equal,
275 .greater_than,
276 .greater_than_equal,
277 .equal,
278 .not_equal,
279 .bit_and,
280 .bit_and_assign,
281 .bit_or,
282 .bit_or_assign,
283 .bit_xor,
284 .bit_xor_assign,
285 .div_trunc,
286 .rem,
287 .int_cast,
288 .as,
289 .truncate,
290 .bit_cast,
291 .float_cast,
292 .float_to_int,
293 .int_to_float,
294 .int_to_enum,
295 .int_to_ptr,
296 .array_cat,
297 .ellipsis3,
298 .assign,
299 .align_cast,
300 .array_access,
301 .std_mem_zeroinit,
302 .ptr_cast,
303 => Payload.BinOp,
304
305 .integer_literal,
306 .float_literal,
307 .string_literal,
308 .char_literal,
309 .identifier,
310 .warning,
311 .type,
312 => Payload.Value,
313 .@"if" => Payload.If,
314 .@"while" => Payload.While,
315 .@"switch", .array_init,.switch_prong => Payload.Switch,
316 .break_val => Payload.BreakVal,
317 .call => Payload.Call,
318 .var_decl => Payload.VarDecl,
319 .func => Payload.Func,
320 .@"enum" => Payload.Enum,
321 .@"struct", .@"union" => Payload.Record,
322 .tuple => Payload.TupleInit,
323 .container_init => Payload.ContainerInit,
324 .std_meta_cast => Payload.Infix,
325 .block => Payload.Block,
326 .c_pointer, .single_pointer => Payload.Pointer,
327 .array_type => Payload.Array,
328 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,
329 .log2_int_type => Payload.Log2IntType,
330 .var_simple, .pub_var_simple => Payload.SimpleVarDecl,
331 .pub_enum_redecl, .enum_redecl => Payload.EnumRedecl,
332 .array_filler => Payload.ArrayFiller,
333 .pub_inline_fn => Payload.PubInlineFn,
334 .field_access => Payload.FieldAccess,
335 };
336 }
337
338 pub fn init(comptime t: Tag) Node {
339 comptime std.debug.assert(@enumToInt(t) < Tag.no_payload_count);
340 return .{ .tag_if_small_enough = @enumToInt(t) };
341 }
342
343 pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Node {
344 const ptr = try ally.create(t.Type());
345 ptr.* = .{
346 .base = .{ .tag = t },
347 .data = data,
348 };
349 return Node{ .ptr_otherwise = &ptr.base };
350 }
351
352 pub fn Data(comptime t: Tag) type {
353 return std.meta.fieldInfo(t.Type(), .data).field_type;
354 }
355 };
356
357 pub fn tag(self: Node) Tag {
358 if (self.tag_if_small_enough < Tag.no_payload_count) {
359 return @intToEnum(Tag, @intCast(std.meta.Tag(Tag), self.tag_if_small_enough));
360 } else {
361 return self.ptr_otherwise.tag;
362 }
363 }
364
365 pub fn castTag(self: Node, comptime t: Tag) ?*t.Type() {
366 if (self.tag_if_small_enough < Tag.no_payload_count)
367 return null;
368
369 if (self.ptr_otherwise.tag == t)
370 return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise);
371
372 return null;
373 }
374
375 pub fn initPayload(payload: *Payload) Node {
376 std.debug.assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
377 return .{ .ptr_otherwise = payload };
378 }
379
380 pub fn isNoreturn(node: Node, break_counts: bool) bool {
381 switch (node.tag()) {
382 .block => {
383 const block_node = node.castTag(.block).?;
384 if (block_node.data.stmts.len == 0) return false;
385
386 const last = block_node.data.stmts[block_node.data.stmts.len - 1];
387 return last.isNoreturn(break_counts);
388 },
389 .@"switch" => {
390 const switch_node = node.castTag(.@"switch").?;
391
392 for (switch_node.data.cases) |case| {
393 const body = if (case.castTag(.switch_else)) |some|
394 some.data
395 else if (case.castTag(.switch_prong)) |some|
396 some.data.cond
397 else unreachable;
398
399 if (!body.isNoreturn(break_counts)) return false;
400 }
401 return true;
402 },
403 .@"return", .return_void => return true,
404 .break_val, .@"break" => if (break_counts) return true,
405 else => {},
406 }
407 return false;
408 }
409
410};
411
412pub const Payload = struct {
413 tag: Node.Tag,
414
415 pub const Infix = struct {
416 base: Payload,
417 data: struct {
418 lhs: Node,
419 rhs: Node,
420 },
421 };
422
423 pub const Value = struct {
424 base: Payload,
425 data: []const u8,
426 };
427
428 pub const UnOp = struct {
429 base: Payload,
430 data: Node,
431 };
432
433 pub const BinOp = struct {
434 base: Payload,
435 data: struct {
436 lhs: Node,
437 rhs: Node,
438 },
439 };
440
441 pub const If = struct {
442 base: Payload,
443 data: struct {
444 cond: Node,
445 then: Node,
446 @"else": ?Node,
447 },
448 };
449
450 pub const While = struct {
451 base: Payload,
452 data: struct {
453 cond: Node,
454 body: Node,
455 cont_expr: ?Node,
456 },
457 };
458
459 pub const Switch = struct {
460 base: Payload,
461 data: struct {
462 cond: Node,
463 cases: []Node,
464 },
465 };
466
467 pub const BreakVal = struct {
468 base: Payload,
469 data: struct {
470 label: ?[]const u8,
471 val: Node,
472 },
473 };
474
475 pub const Call = struct {
476 base: Payload,
477 data: struct {
478 lhs: Node,
479 args: []Node,
480 },
481 };
482
483 pub const VarDecl = struct {
484 base: Payload,
485 data: struct {
486 is_pub: bool,
487 is_const: bool,
488 is_extern: bool,
489 is_export: bool,
490 is_threadlocal: bool,
491 alignment: ?c_uint,
492 linksection_string: ?[]const u8,
493 name: []const u8,
494 type: Node,
495 init: ?Node,
496 },
497 };
498
499 pub const Func = struct {
500 base: Payload,
501 data: struct {
502 is_pub: bool,
503 is_extern: bool,
504 is_export: bool,
505 is_var_args: bool,
506 name: ?[]const u8,
507 linksection_string: ?[]const u8,
508 explicit_callconv: ?std.builtin.CallingConvention,
509 params: []Param,
510 return_type: Node,
511 body: ?Node,
512 alignment: ?c_uint,
513 },
514 };
515
516 pub const Param = struct {
517 is_noalias: bool,
518 name: ?[]const u8,
519 type: Node,
520 };
521
522 pub const Enum = struct {
523 base: Payload,
524 data: struct {
525 int_type: Node,
526 fields: []Field,
527 },
528
529 pub const Field = struct {
530 name: []const u8,
531 value: ?Node,
532 };
533 };
534
535 pub const Record = struct {
536 base: Payload,
537 data: struct {
538 is_packed: bool,
539 fields: []Field,
540 },
541
542 pub const Field = struct {
543 name: []const u8,
544 type: Node,
545 alignment: ?c_uint,
546 };
547 };
548
549 pub const TupleInit = struct {
550 base: Payload,
551 data: []Node,
552 };
553
554 pub const ContainerInit = struct {
555 base: Payload,
556 data: struct {
557 lhs: Node,
558 inits: []Initializer,
559 },
560
561 pub const Initializer = struct {
562 name: []const u8,
563 value: Node,
564 };
565 };
566
567 pub const Block = struct {
568 base: Payload,
569 data: struct {
570 label: ?[]const u8,
571 stmts: []Node,
572 },
573 };
574
575 pub const Array = struct {
576 base: Payload,
577 data: struct {
578 elem_type: Node,
579 len: usize,
580 },
581 };
582
583 pub const Pointer = struct {
584 base: Payload,
585 data: struct {
586 elem_type: Node,
587 is_const: bool,
588 is_volatile: bool,
589 },
590 };
591
592 pub const ArgRedecl = struct {
593 base: Payload,
594 data: struct {
595 actual: []const u8,
596 mangled: []const u8,
597 },
598 };
599
600 pub const Log2IntType = struct {
601 base: Payload,
602 data: std.math.Log2Int(u64),
603 };
604
605 pub const SimpleVarDecl = struct {
606 base: Payload,
607 data: struct {
608 name: []const u8,
609 init: Node,
610 },
611 };
612
613 pub const EnumRedecl = struct {
614 base: Payload,
615 data: struct {
616 enum_val_name: []const u8,
617 field_name: []const u8,
618 enum_name: []const u8,
619 },
620 };
621
622 pub const ArrayFiller = struct {
623 base: Payload,
624 data: struct {
625 type: Node,
626 filler: Node,
627 count: usize,
628 },
629 };
630
631 pub const PubInlineFn = struct {
632 base: Payload,
633 data: struct {
634 name: []const u8,
635 params: []Param,
636 return_type: Node,
637 body: Node,
638 },
639 };
640
641 pub const FieldAccess = struct {
642 base: Payload,
643 data: struct {
644 lhs: Node,
645 field_name: []const u8,
646 },
647 };
648};
649
650/// Converts the nodes into a Zig ast.
651/// Caller must free the source slice.
652pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree {
653 var ctx = Context{
654 .gpa = gpa,
655 .buf = std.ArrayList(u8).init(gpa),
656 };
657 defer ctx.buf.deinit();
658 defer ctx.nodes.deinit(gpa);
659 defer ctx.extra_data.deinit(gpa);
660 defer ctx.tokens.deinit(gpa);
661
662 // Estimate that each top level node has 10 child nodes.
663 const estimated_node_count = nodes.len * 10;
664 try ctx.nodes.ensureCapacity(gpa, estimated_node_count);
665 // Estimate that each each node has 2 tokens.
666 const estimated_tokens_count = estimated_node_count * 2;
667 try ctx.tokens.ensureCapacity(gpa, estimated_tokens_count);
668 // Estimate that each each token is 3 bytes long.
669 const estimated_buf_len = estimated_tokens_count * 3;
670 try ctx.buf.ensureCapacity(estimated_buf_len);
671
672 ctx.nodes.appendAssumeCapacity(.{
673 .tag = .root,
674 .main_token = 0,
675 .data = .{
676 .lhs = undefined,
677 .rhs = undefined,
678 },
679 });
680
681 const root_members = blk: {
682 var result = std.ArrayList(NodeIndex).init(gpa);
683 defer result.deinit();
684
685 for (nodes) |node| {
686 const res = try renderNode(&ctx, node);
687 if (node.tag() == .warning) continue;
688 try result.append(res);
689 }
690 break :blk try ctx.listToSpan(result.items);
691 };
692
693 ctx.nodes.items(.data)[0] = .{
694 .lhs = root_members.start,
695 .rhs = root_members.end,
696 };
697
698 try ctx.tokens.append(gpa, .{
699 .tag = .eof,
700 .start = @intCast(u32, ctx.buf.items.len),
701 });
702
703 return std.zig.ast.Tree{
704 .source = ctx.buf.toOwnedSlice(),
705 .tokens = ctx.tokens.toOwnedSlice(),
706 .nodes = ctx.nodes.toOwnedSlice(),
707 .extra_data = ctx.extra_data.toOwnedSlice(gpa),
708 .errors = &.{},
709 };
710}
711
712const NodeIndex = std.zig.ast.Node.Index;
713const NodeSubRange = std.zig.ast.Node.SubRange;
714const TokenIndex = std.zig.ast.TokenIndex;
715const TokenTag = std.zig.Token.Tag;
716
717const Context = struct {
718 gpa: *Allocator,
719 buf: std.ArrayList(u8) = .{},
720 nodes: std.zig.ast.NodeList = .{},
721 extra_data: std.ArrayListUnmanaged(std.zig.ast.Node.Index) = .{},
722 tokens: std.zig.ast.TokenList = .{},
723
724 fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex {
725 const start_index = c.buf.items.len;
726 try c.buf.writer().print(format ++ " ", args);
727
728 try c.tokens.append(c.gpa, .{
729 .tag = tag,
730 .start = @intCast(u32, start_index),
731 });
732
733 return @intCast(u32, c.tokens.len - 1);
734 }
735
736 fn addToken(c: *Context, tag: TokenTag, bytes: []const u8) Allocator.Error!TokenIndex {
737 return addTokenFmt(c, tag, "{s}", .{bytes});
738 }
739
740 fn addIdentifier(c: *Context, bytes: []const u8) Allocator.Error!TokenIndex {
741 return addTokenFmt(c, .identifier, "{s}", .{std.zig.fmtId(bytes)});
742 }
743
744 fn listToSpan(c: *Context, list: []const NodeIndex) Allocator.Error!NodeSubRange {
745 try c.extra_data.appendSlice(c.gpa, list);
746 return NodeSubRange{
747 .start = @intCast(NodeIndex, c.extra_data.items.len - list.len),
748 .end = @intCast(NodeIndex, c.extra_data.items.len),
749 };
750 }
751
752 fn addNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex {
753 const result = @intCast(NodeIndex, c.nodes.len);
754 try c.nodes.append(c.gpa, elem);
755 return result;
756 }
757
758 fn addExtra(c: *Context, extra: anytype) Allocator.Error!NodeIndex {
759 const fields = std.meta.fields(@TypeOf(extra));
760 try c.extra_data.ensureCapacity(c.gpa, c.extra_data.items.len + fields.len);
761 const result = @intCast(u32, c.extra_data.items.len);
762 inline for (fields) |field| {
763 comptime std.debug.assert(field.field_type == NodeIndex);
764 c.extra_data.appendAssumeCapacity(@field(extra, field.name));
765 }
766 return result;
767 }
768};
769
770fn renderNodes(c: *Context, nodes: []const Node) Allocator.Error!NodeSubRange {
771 var result = std.ArrayList(NodeIndex).init(c.gpa);
772 defer result.deinit();
773
774 for (nodes) |node| {
775 const res = try renderNode(c, node);
776 if (node.tag() == .warning) continue;
777 try result.append(res);
778 }
779
780 return try c.listToSpan(result.items);
781}
782
783fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
784 switch (node.tag()) {
785 .declaration => unreachable,
786 .warning => {
787 const payload = node.castTag(.warning).?.data;
788 try c.buf.appendSlice(payload);
789 try c.buf.append('\n');
790 return @as(NodeIndex, 0); // error: integer value 0 cannot be coerced to type 'std.mem.Allocator.Error!u32'
791 },
792 .usingnamespace_builtins => {
793 // pub usingnamespace @import("std").c.builtins;
794 _ = try c.addToken(.keyword_pub, "pub");
795 const usingnamespace_token = try c.addToken(.keyword_usingnamespace, "usingnamespace");
796 const import_node = try renderStdImport(c, "c", "builtins");
797 _ = try c.addToken(.semicolon, ";");
798
799 return c.addNode(.{
800 .tag = .@"usingnamespace",
801 .main_token = usingnamespace_token,
802 .data = .{
803 .lhs = import_node,
804 .rhs = undefined,
805 },
806 });
807 },
808 .std_math_Log2Int => {
809 const payload = node.castTag(.std_math_Log2Int).?.data;
810 const import_node = try renderStdImport(c, "math", "Log2Int");
811 return renderCall(c, import_node, &.{payload});
812 },
813 .std_meta_cast => {
814 const payload = node.castTag(.std_meta_cast).?.data;
815 const import_node = try renderStdImport(c, "meta", "cast");
816 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
817 },
818 .std_meta_sizeof => {
819 const payload = node.castTag(.std_meta_sizeof).?.data;
820 const import_node = try renderStdImport(c, "meta", "sizeof");
821 return renderCall(c, import_node, &.{payload});
822 },
823 .std_mem_zeroes => {
824 const payload = node.castTag(.std_mem_zeroes).?.data;
825 const import_node = try renderStdImport(c, "mem", "zeroes");
826 return renderCall(c, import_node, &.{payload});
827 },
828 .std_mem_zeroinit => {
829 const payload = node.castTag(.std_mem_zeroinit).?.data;
830 const import_node = try renderStdImport(c, "mem", "zeroInit");
831 return renderCall(c, import_node, &.{ payload.lhs, payload.rhs });
832 },
833 .call => {
834 const payload = node.castTag(.call).?.data;
835 const lhs = try renderNode(c, payload.lhs);
836 return renderCall(c, lhs, payload.args);
837 },
838 .null_literal => return c.addNode(.{
839 .tag = .null_literal,
840 .main_token = try c.addToken(.keyword_null, "null"),
841 .data = undefined,
842 }),
843 .undefined_literal => return c.addNode(.{
844 .tag = .undefined_literal,
845 .main_token = try c.addToken(.keyword_undefined, "undefined"),
846 .data = undefined,
847 }),
848 .true_literal => return c.addNode(.{
849 .tag = .true_literal,
850 .main_token = try c.addToken(.keyword_true, "true"),
851 .data = undefined,
852 }),
853 .false_literal => return c.addNode(.{
854 .tag = .false_literal,
855 .main_token = try c.addToken(.keyword_false, "false"),
856 .data = undefined,
857 }),
858 .zero_literal => return c.addNode(.{
859 .tag = .integer_literal,
860 .main_token = try c.addToken(.integer_literal, "0"),
861 .data = undefined,
862 }),
863 .one_literal => return c.addNode(.{
864 .tag = .integer_literal,
865 .main_token = try c.addToken(.integer_literal, "1"),
866 .data = undefined,
867 }),
868 .void_type => return c.addNode(.{
869 .tag = .identifier,
870 .main_token = try c.addToken(.identifier, "void"),
871 .data = undefined,
872 }),
873 .noreturn_type => return c.addNode(.{
874 .tag = .identifier,
875 .main_token = try c.addToken(.identifier, "noreturn"),
876 .data = undefined,
877 }),
878 .@"continue" => return c.addNode(.{
879 .tag = .@"continue",
880 .main_token = try c.addToken(.keyword_continue, "continue"),
881 .data = .{
882 .lhs = 0,
883 .rhs = undefined,
884 },
885 }),
886 .return_void => return c.addNode(.{
887 .tag = .@"return",
888 .main_token = try c.addToken(.keyword_return, "return"),
889 .data = .{
890 .lhs = 0,
891 .rhs = undefined,
892 },
893 }),
894 .@"break" => return c.addNode(.{
895 .tag = .@"break",
896 .main_token = try c.addToken(.keyword_break, "break"),
897 .data = .{
898 .lhs = 0,
899 .rhs = 0,
900 },
901 }),
902 .break_val => {
903 const payload = node.castTag(.break_val).?.data;
904 const tok = try c.addToken(.keyword_break, "break");
905 const break_label = if (payload.label) |some| blk: {
906 _ = try c.addToken(.colon, ":");
907 break :blk try c.addIdentifier(some);
908 } else 0;
909 return c.addNode(.{
910 .tag = .@"break",
911 .main_token = tok,
912 .data = .{
913 .lhs = break_label,
914 .rhs = try renderNode(c, payload.val),
915 },
916 });
917 },
918 .@"return" => {
919 const payload = node.castTag(.@"return").?.data;
920 return c.addNode(.{
921 .tag = .@"return",
922 .main_token = try c.addToken(.keyword_return, "return"),
923 .data = .{
924 .lhs = try renderNode(c, payload),
925 .rhs = undefined,
926 },
927 });
928 },
929 .type => {
930 const payload = node.castTag(.type).?.data;
931 return c.addNode(.{
932 .tag = .identifier,
933 .main_token = try c.addToken(.identifier, payload),
934 .data = undefined,
935 });
936 },
937 .log2_int_type => {
938 const payload = node.castTag(.log2_int_type).?.data;
939 return c.addNode(.{
940 .tag = .identifier,
941 .main_token = try c.addTokenFmt(.identifier, "u{d}", .{payload}),
942 .data = undefined,
943 });
944 },
945 .identifier => {
946 const payload = node.castTag(.identifier).?.data;
947 return c.addNode(.{
948 .tag = .identifier,
949 .main_token = try c.addIdentifier(payload),
950 .data = undefined,
951 });
952 },
953 .float_literal => {
954 const payload = node.castTag(.float_literal).?.data;
955 return c.addNode(.{
956 .tag = .float_literal,
957 .main_token = try c.addToken(.float_literal, payload),
958 .data = undefined,
959 });
960 },
961 .integer_literal => {
962 const payload = node.castTag(.integer_literal).?.data;
963 return c.addNode(.{
964 .tag = .integer_literal,
965 .main_token = try c.addToken(.integer_literal, payload),
966 .data = undefined,
967 });
968 },
969 .string_literal => {
970 const payload = node.castTag(.string_literal).?.data;
971 return c.addNode(.{
972 .tag = .identifier,
973 .main_token = try c.addToken(.string_literal, payload),
974 .data = undefined,
975 });
976 },
977 .char_literal => {
978 const payload = node.castTag(.char_literal).?.data;
979 return c.addNode(.{
980 .tag = .identifier,
981 .main_token = try c.addToken(.char_literal, payload),
982 .data = undefined,
983 });
984 },
985 .fail_decl => {
986 const payload = node.castTag(.fail_decl).?.data;
987 // pub const name = @compileError(msg);
988 _ = try c.addToken(.keyword_pub, "pub");
989 const const_tok = try c.addToken(.keyword_const, "const");
990 _ = try c.addIdentifier(payload.actual);
991 _ = try c.addToken(.equal, "=");
992
993 const compile_error_tok = try c.addToken(.builtin, "@compileError");
994 _ = try c.addToken(.l_paren, "(");
995 const err_msg_tok = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(payload.mangled)});
996 const err_msg = try c.addNode(.{
997 .tag = .string_literal,
998 .main_token = err_msg_tok,
999 .data = undefined,
1000 });
1001 _ = try c.addToken(.r_paren, ")");
1002 const compile_error = try c.addNode(.{
1003 .tag = .builtin_call_two,
1004 .main_token = compile_error_tok,
1005 .data = .{
1006 .lhs = err_msg,
1007 .rhs = 0,
1008 },
1009 });
1010 _ = try c.addToken(.semicolon, ";");
1011
1012 return c.addNode(.{
1013 .tag = .simple_var_decl,
1014 .main_token = const_tok,
1015 .data = .{
1016 .lhs = 0,
1017 .rhs = compile_error,
1018 },
1019 });
1020 },
1021 .pub_var_simple, .var_simple => {
1022 const payload = @fieldParentPtr(Payload.SimpleVarDecl, "base", node.ptr_otherwise).data;
1023 if (node.tag() == .pub_var_simple) _ = try c.addToken(.keyword_pub, "pub");
1024 const const_tok = try c.addToken(.keyword_const, "const");
1025 _ = try c.addIdentifier(payload.name);
1026 _ = try c.addToken(.equal, "=");
1027
1028 const init = try renderNode(c, payload.init);
1029 _ = try c.addToken(.semicolon, ";");
1030
1031 return c.addNode(.{
1032 .tag = .simple_var_decl,
1033 .main_token = const_tok,
1034 .data = .{
1035 .lhs = 0,
1036 .rhs = init,
1037 },
1038 });
1039 },
1040 .var_decl => return renderVar(c, node),
1041 .arg_redecl, .alias => {
1042 const payload = @fieldParentPtr(Payload.ArgRedecl, "base", node.ptr_otherwise).data;
1043 if (node.tag() == .alias) _ = try c.addToken(.keyword_pub, "pub");
1044 const mut_tok = if (node.tag() == .alias)
1045 try c.addToken(.keyword_const, "const")
1046 else
1047 try c.addToken(.keyword_var, "var");
1048 _ = try c.addIdentifier(payload.actual);
1049 _ = try c.addToken(.equal, "=");
1050
1051 const init = try c.addNode(.{
1052 .tag = .identifier,
1053 .main_token = try c.addIdentifier(payload.mangled),
1054 .data = undefined,
1055 });
1056 _ = try c.addToken(.semicolon, ";");
1057
1058 return c.addNode(.{
1059 .tag = .simple_var_decl,
1060 .main_token = mut_tok,
1061 .data = .{
1062 .lhs = 0,
1063 .rhs = init,
1064 },
1065 });
1066 },
1067 .int_cast => {
1068 const payload = node.castTag(.int_cast).?.data;
1069 return renderBuiltinCall(c, "@intCast", &.{ payload.lhs, payload.rhs });
1070 },
1071 .rem => {
1072 const payload = node.castTag(.rem).?.data;
1073 return renderBuiltinCall(c, "@rem", &.{ payload.lhs, payload.rhs });
1074 },
1075 .div_trunc => {
1076 const payload = node.castTag(.div_trunc).?.data;
1077 return renderBuiltinCall(c, "@divTrunc", &.{ payload.lhs, payload.rhs });
1078 },
1079 .bool_to_int => {
1080 const payload = node.castTag(.bool_to_int).?.data;
1081 return renderBuiltinCall(c, "@boolToInt", &.{payload});
1082 },
1083 .as => {
1084 const payload = node.castTag(.as).?.data;
1085 return renderBuiltinCall(c, "@as", &.{ payload.lhs, payload.rhs });
1086 },
1087 .truncate => {
1088 const payload = node.castTag(.truncate).?.data;
1089 return renderBuiltinCall(c, "@truncate", &.{ payload.lhs, payload.rhs });
1090 },
1091 .bit_cast => {
1092 const payload = node.castTag(.bit_cast).?.data;
1093 return renderBuiltinCall(c, "@bitCast", &.{ payload.lhs, payload.rhs });
1094 },
1095 .float_cast => {
1096 const payload = node.castTag(.float_cast).?.data;
1097 return renderBuiltinCall(c, "@floatCast", &.{ payload.lhs, payload.rhs });
1098 },
1099 .float_to_int => {
1100 const payload = node.castTag(.float_to_int).?.data;
1101 return renderBuiltinCall(c, "@floatToInt", &.{ payload.lhs, payload.rhs });
1102 },
1103 .int_to_float => {
1104 const payload = node.castTag(.int_to_float).?.data;
1105 return renderBuiltinCall(c, "@intToFloat", &.{ payload.lhs, payload.rhs });
1106 },
1107 .int_to_enum => {
1108 const payload = node.castTag(.int_to_enum).?.data;
1109 return renderBuiltinCall(c, "@intToEnum", &.{ payload.lhs, payload.rhs });
1110 },
1111 .enum_to_int => {
1112 const payload = node.castTag(.enum_to_int).?.data;
1113 return renderBuiltinCall(c, "@enumToInt", &.{payload});
1114 },
1115 .int_to_ptr => {
1116 const payload = node.castTag(.int_to_ptr).?.data;
1117 return renderBuiltinCall(c, "@intToPtr", &.{ payload.lhs, payload.rhs });
1118 },
1119 .ptr_to_int => {
1120 const payload = node.castTag(.ptr_to_int).?.data;
1121 return renderBuiltinCall(c, "@ptrToInt", &.{payload});
1122 },
1123 .align_cast => {
1124 const payload = node.castTag(.align_cast).?.data;
1125 return renderBuiltinCall(c, "@alignCast", &.{ payload.lhs, payload.rhs });
1126 },
1127 .ptr_cast => {
1128 const payload = node.castTag(.ptr_cast).?.data;
1129 return renderBuiltinCall(c, "@ptrCast", &.{ payload.lhs, payload.rhs });
1130 },
1131 .sizeof => {
1132 const payload = node.castTag(.sizeof).?.data;
1133 return renderBuiltinCall(c, "@sizeOf", &.{payload});
1134 },
1135 .alignof => {
1136 const payload = node.castTag(.alignof).?.data;
1137 return renderBuiltinCall(c, "@alignOf", &.{payload});
1138 },
1139 .typeof => {
1140 const payload = node.castTag(.typeof).?.data;
1141 return renderBuiltinCall(c, "@TypeOf", &.{payload});
1142 },
1143 .negate => return renderPrefixOp(c, node, .negation, .minus, "-"),
1144 .negate_wrap => return renderPrefixOp(c, node, .negation_wrap, .minus_percent, "-%"),
1145 .bit_not => return renderPrefixOp(c, node, .bit_not, .tilde, "~"),
1146 .not => return renderPrefixOp(c, node, .bool_not, .bang, "!"),
1147 .optional_type => return renderPrefixOp(c, node, .optional_type, .question_mark, "?"),
1148 .address_of => return renderPrefixOp(c, node, .address_of, .ampersand, "&"),
1149 .deref => {
1150 const payload = node.castTag(.deref).?.data;
1151 const operand = try renderNodeGrouped(c, payload);
1152 const deref_tok = try c.addToken(.period_asterisk, ".*");
1153 return c.addNode(.{
1154 .tag = .deref,
1155 .main_token = deref_tok,
1156 .data = .{
1157 .lhs = operand,
1158 .rhs = undefined,
1159 },
1160 });
1161 },
1162 .unwrap => {
1163 const payload = node.castTag(.unwrap).?.data;
1164 const operand = try renderNodeGrouped(c, payload);
1165 const period = try c.addToken(.period, ".");
1166 const question_mark = try c.addToken(.question_mark, "?");
1167 return c.addNode(.{
1168 .tag = .unwrap_optional,
1169 .main_token = period,
1170 .data = .{
1171 .lhs = operand,
1172 .rhs = question_mark,
1173 },
1174 });
1175 },
1176 .c_pointer, .single_pointer => {
1177 const payload = @fieldParentPtr(Payload.Pointer, "base", node.ptr_otherwise).data;
1178
1179 const asterisk = if (node.tag() == .single_pointer)
1180 try c.addToken(.asterisk, "*")
1181 else blk: {
1182 _ = try c.addToken(.l_bracket, "[");
1183 const res = try c.addToken(.asterisk, "*");
1184 _ = try c.addIdentifier("c");
1185 _ = try c.addToken(.r_bracket, "]");
1186 break :blk res;
1187 };
1188 if (payload.is_const) _ = try c.addToken(.keyword_const, "const");
1189 if (payload.is_volatile) _ = try c.addToken(.keyword_volatile, "volatile");
1190 const elem_type = try renderNodeGrouped(c, payload.elem_type);
1191
1192 return c.addNode(.{
1193 .tag = .ptr_type_aligned,
1194 .main_token = asterisk,
1195 .data = .{
1196 .lhs = 0,
1197 .rhs = elem_type,
1198 },
1199 });
1200 },
1201 .add => return renderBinOpGrouped(c, node, .add, .plus, "+"),
1202 .add_assign => return renderBinOp(c, node, .assign_add, .plus_equal, "+="),
1203 .add_wrap => return renderBinOpGrouped(c, node, .add_wrap, .plus_percent, "+%"),
1204 .add_wrap_assign => return renderBinOp(c, node, .assign_add_wrap, .plus_percent_equal, "+%="),
1205 .sub => return renderBinOpGrouped(c, node, .sub, .minus, "-"),
1206 .sub_assign => return renderBinOp(c, node, .assign_sub, .minus_equal, "-="),
1207 .sub_wrap => return renderBinOpGrouped(c, node, .sub_wrap, .minus_percent, "-%"),
1208 .sub_wrap_assign => return renderBinOp(c, node, .assign_sub_wrap, .minus_percent_equal, "-%="),
1209 .mul => return renderBinOpGrouped(c, node, .mul, .asterisk, "*"),
1210 .mul_assign => return renderBinOp(c, node, .assign_mul, .asterisk_equal, "*="),
1211 .mul_wrap => return renderBinOpGrouped(c, node, .mul_wrap, .asterisk_percent, "*%"),
1212 .mul_wrap_assign => return renderBinOp(c, node, .assign_mul_wrap, .asterisk_percent_equal, "*%="),
1213 .div => return renderBinOpGrouped(c, node, .div, .slash, "/"),
1214 .div_assign => return renderBinOp(c, node, .assign_div, .slash_equal, "/="),
1215 .shl => return renderBinOpGrouped(c, node, .bit_shift_left, .angle_bracket_angle_bracket_left, "<<"),
1216 .shl_assign => return renderBinOp(c, node, .assign_bit_shift_left, .angle_bracket_angle_bracket_left_equal, "<<="),
1217 .shr => return renderBinOpGrouped(c, node, .bit_shift_right, .angle_bracket_angle_bracket_right, ">>"),
1218 .shr_assign => return renderBinOp(c, node, .assign_bit_shift_right, .angle_bracket_angle_bracket_right_equal, ">>="),
1219 .mod => return renderBinOpGrouped(c, node, .mod, .percent, "%"),
1220 .mod_assign => return renderBinOp(c, node, .assign_mod, .percent_equal, "%="),
1221 .@"and" => return renderBinOpGrouped(c, node, .bool_and, .keyword_and, "and"),
1222 .@"or" => return renderBinOpGrouped(c, node, .bool_or, .keyword_or, "or"),
1223 .less_than => return renderBinOpGrouped(c, node, .less_than, .angle_bracket_left, "<"),
1224 .less_than_equal => return renderBinOpGrouped(c, node, .less_or_equal, .angle_bracket_left_equal, "<="),
1225 .greater_than => return renderBinOpGrouped(c, node, .greater_than, .angle_bracket_right, ">="),
1226 .greater_than_equal => return renderBinOpGrouped(c, node, .greater_or_equal, .angle_bracket_right_equal, ">="),
1227 .equal => return renderBinOpGrouped(c, node, .equal_equal, .equal_equal, "=="),
1228 .not_equal => return renderBinOpGrouped(c, node, .bang_equal, .bang_equal, "!="),
1229 .bit_and => return renderBinOpGrouped(c, node, .bit_and, .ampersand, "&"),
1230 .bit_and_assign => return renderBinOp(c, node, .assign_bit_and, .ampersand_equal, "&="),
1231 .bit_or => return renderBinOpGrouped(c, node, .bit_or, .pipe, "|"),
1232 .bit_or_assign => return renderBinOp(c, node, .assign_bit_or, .pipe_equal, "|="),
1233 .bit_xor => return renderBinOpGrouped(c, node, .bit_xor, .caret, "^"),
1234 .bit_xor_assign => return renderBinOp(c, node, .assign_bit_xor, .caret_equal, "^="),
1235 .array_cat => return renderBinOp(c, node, .array_cat, .plus_plus, "++"),
1236 .ellipsis3 => return renderBinOpGrouped(c, node, .switch_range, .ellipsis3, "..."),
1237 .assign => return renderBinOp(c, node, .assign, .equal, "="),
1238 .empty_block => {
1239 const l_brace = try c.addToken(.l_brace, "{");
1240 _ = try c.addToken(.r_brace, "}");
1241 return c.addNode(.{
1242 .tag = .block_two,
1243 .main_token = l_brace,
1244 .data = .{
1245 .lhs = 0,
1246 .rhs = 0,
1247 },
1248 });
1249 },
1250 .block_single => {
1251 const payload = node.castTag(.block_single).?.data;
1252 const l_brace = try c.addToken(.l_brace, "{");
1253
1254 const stmt = try renderNode(c, payload);
1255 try addSemicolonIfNeeded(c, payload);
1256
1257 _ = try c.addToken(.r_brace, "}");
1258 return c.addNode(.{
1259 .tag = .block_two_semicolon,
1260 .main_token = l_brace,
1261 .data = .{
1262 .lhs = stmt,
1263 .rhs = 0,
1264 },
1265 });
1266 },
1267 .block => {
1268 const payload = node.castTag(.block).?.data;
1269 if (payload.label) |some| {
1270 _ = try c.addIdentifier(some);
1271 _ = try c.addToken(.colon, ":");
1272 }
1273 const l_brace = try c.addToken(.l_brace, "{");
1274
1275 var stmts = std.ArrayList(NodeIndex).init(c.gpa);
1276 defer stmts.deinit();
1277 for (payload.stmts) |stmt| {
1278 const res = try renderNode(c, stmt);
1279 if (res == 0) continue;
1280 try addSemicolonIfNeeded(c, stmt);
1281 try stmts.append(res);
1282 }
1283 const span = try c.listToSpan(stmts.items);
1284 _ = try c.addToken(.r_brace, "}");
1285
1286 const semicolon = c.tokens.items(.tag)[c.tokens.len - 2] == .semicolon;
1287 return c.addNode(.{
1288 .tag = if (semicolon) .block_semicolon else .block,
1289 .main_token = l_brace,
1290 .data = .{
1291 .lhs = span.start,
1292 .rhs = span.end,
1293 },
1294 });
1295 },
1296 .func => return renderFunc(c, node),
1297 .pub_inline_fn => return renderMacroFunc(c, node),
1298 .discard => {
1299 const payload = node.castTag(.discard).?.data;
1300 const lhs = try c.addNode(.{
1301 .tag = .identifier,
1302 .main_token = try c.addToken(.identifier, "_"),
1303 .data = undefined,
1304 });
1305 return c.addNode(.{
1306 .tag = .assign,
1307 .main_token = try c.addToken(.equal, "="),
1308 .data = .{
1309 .lhs = lhs,
1310 .rhs = try renderNode(c, payload),
1311 },
1312 });
1313 },
1314 .@"while" => {
1315 const payload = node.castTag(.@"while").?.data;
1316 const while_tok = try c.addToken(.keyword_while, "while");
1317 _ = try c.addToken(.l_paren, "(");
1318 const cond = try renderNode(c, payload.cond);
1319 _ = try c.addToken(.r_paren, ")");
1320
1321 const cont_expr = if (payload.cont_expr) |some| blk: {
1322 _ = try c.addToken(.colon, ":");
1323 _ = try c.addToken(.l_paren, "(");
1324 const res = try renderNode(c, some);
1325 _ = try c.addToken(.r_paren, ")");
1326 break :blk res;
1327 } else 0;
1328 const body = try renderNode(c, payload.body);
1329
1330 if (cont_expr == 0) {
1331 return c.addNode(.{
1332 .tag = .while_simple,
1333 .main_token = while_tok,
1334 .data = .{
1335 .lhs = cond,
1336 .rhs = body,
1337 },
1338 });
1339 } else {
1340 return c.addNode(.{
1341 .tag = .while_cont,
1342 .main_token = while_tok,
1343 .data = .{
1344 .lhs = cond,
1345 .rhs = try c.addExtra(std.zig.ast.Node.WhileCont{
1346 .cont_expr = cont_expr,
1347 .then_expr = body,
1348 }),
1349 },
1350 });
1351 }
1352 },
1353 .while_true => {
1354 const payload = node.castTag(.while_true).?.data;
1355 const while_tok = try c.addToken(.keyword_while, "while");
1356 _ = try c.addToken(.l_paren, "(");
1357 const cond = try c.addNode(.{
1358 .tag = .true_literal,
1359 .main_token = try c.addToken(.keyword_true, "true"),
1360 .data = undefined,
1361 });
1362 _ = try c.addToken(.r_paren, ")");
1363 const body = try renderNode(c, payload);
1364
1365 return c.addNode(.{
1366 .tag = .while_simple,
1367 .main_token = while_tok,
1368 .data = .{
1369 .lhs = cond,
1370 .rhs = body,
1371 },
1372 });
1373 },
1374 .@"if" => {
1375 const payload = node.castTag(.@"if").?.data;
1376 const if_tok = try c.addToken(.keyword_if, "if");
1377 _ = try c.addToken(.l_paren, "(");
1378 const cond = try renderNode(c, payload.cond);
1379 _ = try c.addToken(.r_paren, ")");
1380
1381 const then_expr = try renderNode(c, payload.then);
1382 const else_node = payload.@"else" orelse return c.addNode(.{
1383 .tag = .if_simple,
1384 .main_token = if_tok,
1385 .data = .{
1386 .lhs = cond,
1387 .rhs = then_expr,
1388 },
1389 });
1390 _ = try c.addToken(.keyword_else, "else");
1391 const else_expr = try renderNode(c, else_node);
1392
1393 return c.addNode(.{
1394 .tag = .@"if",
1395 .main_token = if_tok,
1396 .data = .{
1397 .lhs = cond,
1398 .rhs = try c.addExtra(std.zig.ast.Node.If{
1399 .then_expr = then_expr,
1400 .else_expr = else_expr,
1401 }),
1402 },
1403 });
1404 },
1405 .if_not_break => {
1406 const payload = node.castTag(.if_not_break).?.data;
1407 const if_tok = try c.addToken(.keyword_if, "if");
1408 _ = try c.addToken(.l_paren, "(");
1409 const cond = try c.addNode(.{
1410 .tag = .bool_not,
1411 .main_token = try c.addToken(.bang, "!"),
1412 .data = .{
1413 .lhs = try renderNodeGrouped(c, payload),
1414 .rhs = undefined,
1415 },
1416 });
1417 _ = try c.addToken(.r_paren, ")");
1418 const then_expr = try c.addNode(.{
1419 .tag = .@"break",
1420 .main_token = try c.addToken(.keyword_break, "break"),
1421 .data = .{
1422 .lhs = 0,
1423 .rhs = 0,
1424 },
1425 });
1426
1427 return c.addNode(.{
1428 .tag = .if_simple,
1429 .main_token = if_tok,
1430 .data = .{
1431 .lhs = cond,
1432 .rhs = then_expr,
1433 },
1434 });
1435 },
1436 .@"switch" => {
1437 const payload = node.castTag(.@"switch").?.data;
1438 const switch_tok = try c.addToken(.keyword_switch, "switch");
1439 _ = try c.addToken(.l_paren, "(");
1440 const cond = try renderNode(c, payload.cond);
1441 _ = try c.addToken(.r_paren, ")");
1442
1443 _ = try c.addToken(.l_brace, "{");
1444 var cases = try c.gpa.alloc(NodeIndex, payload.cases.len);
1445 defer c.gpa.free(cases);
1446 for (payload.cases) |case, i| {
1447 cases[i] = try renderNode(c, case);
1448 _ = try c.addToken(.comma, ",");
1449 }
1450 const span = try c.listToSpan(cases);
1451 _ = try c.addToken(.r_brace, "}");
1452 return c.addNode(.{
1453 .tag = .switch_comma,
1454 .main_token = switch_tok,
1455 .data = .{
1456 .lhs = cond,
1457 .rhs = try c.addExtra(NodeSubRange{
1458 .start = span.start,
1459 .end = span.end,
1460 }),
1461 },
1462 });
1463 },
1464 .switch_else => {
1465 const payload = node.castTag(.switch_else).?.data;
1466 _ = try c.addToken(.keyword_else, "else");
1467 return c.addNode(.{
1468 .tag = .switch_case_one,
1469 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"),
1470 .data = .{
1471 .lhs = 0,
1472 .rhs = try renderNode(c, payload),
1473 },
1474 });
1475 },
1476 .switch_prong => {
1477 const payload = node.castTag(.switch_prong).?.data;
1478 var items = try c.gpa.alloc(NodeIndex, std.math.max(payload.cases.len, 1));
1479 defer c.gpa.free(items);
1480 items[0] = 0;
1481 for (payload.cases) |item, i| {
1482 if (i != 0) _ = try c.addToken(.comma, ",");
1483 items[i] = try renderNode(c, item);
1484 }
1485 _ = try c.addToken(.r_brace, "}");
1486 if (items.len < 2) {
1487 return c.addNode(.{
1488 .tag = .switch_case_one,
1489 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"),
1490 .data = .{
1491 .lhs = items[0],
1492 .rhs = try renderNode(c, payload.cond),
1493 },
1494 });
1495 } else {
1496 const span = try c.listToSpan(items);
1497 return c.addNode(.{
1498 .tag = .switch_case,
1499 .main_token = try c.addToken(.equal_angle_bracket_right, "=>"),
1500 .data = .{
1501 .lhs = try c.addExtra(NodeSubRange{
1502 .start = span.start,
1503 .end = span.end,
1504 }),
1505 .rhs = try renderNode(c, payload.cond),
1506 },
1507 });
1508 }
1509 },
1510 .opaque_literal => {
1511 const opaque_tok = try c.addToken(.keyword_opaque, "opaque");
1512 _ = try c.addToken(.l_brace, "{");
1513 _ = try c.addToken(.r_brace, "}");
1514
1515 return c.addNode(.{
1516 .tag = .container_decl_two,
1517 .main_token = opaque_tok,
1518 .data = .{
1519 .lhs = 0,
1520 .rhs = 0,
1521 },
1522 });
1523 },
1524 .array_access => {
1525 const payload = node.castTag(.array_access).?.data;
1526 const lhs = try renderNode(c, payload.lhs);
1527 const l_bracket = try c.addToken(.l_bracket, "[");
1528 const index_expr = try renderNode(c, payload.rhs);
1529 _ = try c.addToken(.r_bracket, "]");
1530 return c.addNode(.{
1531 .tag = .array_access,
1532 .main_token = l_bracket,
1533 .data = .{
1534 .lhs = lhs,
1535 .rhs = index_expr,
1536 },
1537 });
1538 },
1539 .array_type => {
1540 const payload = node.castTag(.array_type).?.data;
1541 return renderArrayType(c, payload.len, payload.elem_type);
1542 },
1543 .array_filler => {
1544 const payload = node.castTag(.array_filler).?.data;
1545
1546 const type_expr = try renderArrayType(c, 1, payload.type);
1547 const l_brace = try c.addToken(.l_brace, "{");
1548 const val = try renderNode(c, payload.filler);
1549 _ = try c.addToken(.r_brace, "}");
1550
1551 const init = try c.addNode(.{
1552 .tag = .array_init_one,
1553 .main_token = l_brace,
1554 .data = .{
1555 .lhs = type_expr,
1556 .rhs = val,
1557 },
1558 });
1559 return c.addNode(.{
1560 .tag = .array_cat,
1561 .main_token = try c.addToken(.asterisk_asterisk, "**"),
1562 .data = .{
1563 .lhs = init,
1564 .rhs = try c.addNode(.{
1565 .tag = .integer_literal,
1566 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{payload.count}),
1567 .data = undefined,
1568 }),
1569 },
1570 });
1571 },
1572 .empty_array => {
1573 const payload = node.castTag(.empty_array).?.data;
1574
1575 const type_expr = try renderArrayType(c, 0, payload);
1576 return renderArrayInit(c, type_expr, &.{});
1577 },
1578 .array_init => {
1579 const payload = node.castTag(.array_init).?.data;
1580 const type_expr = try renderNode(c, payload.cond);
1581 return renderArrayInit(c, type_expr, payload.cases);
1582 },
1583 .field_access => {
1584 const payload = node.castTag(.field_access).?.data;
1585 const lhs = try renderNode(c, payload.lhs);
1586 return renderFieldAccess(c, lhs, payload.field_name);
1587 },
1588 .@"struct", .@"union" => return renderRecord(c, node),
1589 .@"enum" => {
1590 const payload = node.castTag(.@"enum").?.data;
1591 _ = try c.addToken(.keyword_extern, "extern");
1592 const enum_tok = try c.addToken(.keyword_enum, "enum");
1593 _ = try c.addToken(.l_paren, "(");
1594 const arg_expr = try renderNode(c, payload.int_type);
1595 _ = try c.addToken(.r_paren, ")");
1596 _ = try c.addToken(.l_brace, "{");
1597 const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.fields.len + 1, 1));
1598 defer c.gpa.free(members);
1599 members[0] = 0;
1600
1601 for (payload.fields) |field, i| {
1602 const name_tok = try c.addIdentifier(field.name);
1603 const value_expr = if (field.value) |some| blk: {
1604 _ = try c.addToken(.equal, "=");
1605 break :blk try renderNode(c, some);
1606 } else 0;
1607
1608 members[i] = try c.addNode(.{
1609 .tag = .container_field_init,
1610 .main_token = name_tok,
1611 .data = .{
1612 .lhs = 0,
1613 .rhs = value_expr,
1614 },
1615 });
1616 _ = try c.addToken(.comma, ",");
1617 }
1618 // make non-exhaustive
1619 members[payload.fields.len] = try c.addNode(.{
1620 .tag = .container_field_init,
1621 .main_token = try c.addIdentifier("_"),
1622 .data = .{
1623 .lhs = 0,
1624 .rhs = 0,
1625 },
1626 });
1627 _ = try c.addToken(.comma, ",");
1628 _ = try c.addToken(.r_brace, "}");
1629
1630 const span = try c.listToSpan(members);
1631 return c.addNode(.{
1632 .tag = .container_decl_arg_comma,
1633 .main_token = enum_tok,
1634 .data = .{
1635 .lhs = arg_expr,
1636 .rhs = try c.addExtra(NodeSubRange{
1637 .start = span.start,
1638 .end = span.end,
1639 }),
1640 },
1641 });
1642 },
1643 .pub_enum_redecl, .enum_redecl => {
1644 const payload = @fieldParentPtr(Payload.EnumRedecl, "base", node.ptr_otherwise).data;
1645 if (node.tag() == .pub_enum_redecl) _ = try c.addToken(.keyword_pub, "pub");
1646 const const_tok = try c.addToken(.keyword_const, "const");
1647 _ = try c.addIdentifier(payload.enum_val_name);
1648 _ = try c.addToken(.equal, "=");
1649
1650 const enum_to_int_tok = try c.addToken(.builtin, "@enumToInt");
1651 _ = try c.addToken(.l_paren, "(");
1652 const enum_name = try c.addNode(.{
1653 .tag = .identifier,
1654 .main_token = try c.addIdentifier(payload.enum_name),
1655 .data = undefined,
1656 });
1657 const field_access = try renderFieldAccess(c, enum_name, payload.field_name);
1658 const init_node = try c.addNode(.{
1659 .tag = .builtin_call_two,
1660 .main_token = enum_to_int_tok,
1661 .data = .{
1662 .lhs = field_access,
1663 .rhs = 0,
1664 },
1665 });
1666 _ = try c.addToken(.r_paren, ")");
1667 _ = try c.addToken(.semicolon, ";");
1668
1669 return c.addNode(.{
1670 .tag = .simple_var_decl,
1671 .main_token = const_tok,
1672 .data = .{
1673 .lhs = 0,
1674 .rhs = init_node,
1675 },
1676 });
1677 },
1678 .tuple => {
1679 const payload = node.castTag(.tuple).?.data;
1680 _ = try c.addToken(.period, ".");
1681 const l_brace = try c.addToken(.l_brace, "{");
1682 var inits = try c.gpa.alloc(NodeIndex, std.math.max(payload.len, 2));
1683 defer c.gpa.free(inits);
1684 inits[0] = 0;
1685 inits[1] = 0;
1686 for (payload) |init, i| {
1687 if (i != 0) _ = try c.addToken(.comma, ",");
1688 inits[i] = try renderNode(c, init);
1689 }
1690 _ = try c.addToken(.r_brace, "}");
1691 if (payload.len < 3) {
1692 return c.addNode(.{
1693 .tag = .array_init_dot_two,
1694 .main_token = l_brace,
1695 .data = .{
1696 .lhs = inits[0],
1697 .rhs = inits[1],
1698 },
1699 });
1700 } else {
1701 const span = try c.listToSpan(inits);
1702 return c.addNode(.{
1703 .tag = .array_init_dot,
1704 .main_token = l_brace,
1705 .data = .{
1706 .lhs = span.start,
1707 .rhs = span.end,
1708 },
1709 });
1710 }
1711 },
1712 .container_init => {
1713 const payload = node.castTag(.container_init).?.data;
1714 const lhs = try renderNode(c, payload.lhs);
1715
1716 const l_brace = try c.addToken(.l_brace, "{");
1717 var inits = try c.gpa.alloc(NodeIndex, std.math.max(payload.inits.len, 1));
1718 defer c.gpa.free(inits);
1719 inits[0] = 0;
1720 for (payload.inits) |init, i| {
1721 _ = try c.addToken(.period, ".");
1722 _ = try c.addIdentifier(init.name);
1723 _ = try c.addToken(.equal, "=");
1724 inits[i] = try renderNode(c, init.value);
1725 _ = try c.addToken(.comma, ",");
1726 }
1727 _ = try c.addToken(.r_brace, "}");
1728
1729 if (payload.inits.len < 2) {
1730 return c.addNode(.{
1731 .tag = .struct_init_one_comma,
1732 .main_token = l_brace,
1733 .data = .{
1734 .lhs = lhs,
1735 .rhs = inits[0],
1736 },
1737 });
1738 } else {
1739 const span = try c.listToSpan(inits);
1740 return c.addNode(.{
1741 .tag = .struct_init_comma,
1742 .main_token = l_brace,
1743 .data = .{
1744 .lhs = lhs,
1745 .rhs = try c.addExtra(NodeSubRange{
1746 .start = span.start,
1747 .end = span.end,
1748 }),
1749 },
1750 });
1751 }
1752 },
1753 .@"anytype" => unreachable, // Handled in renderParams
1754 }
1755}
1756
1757fn renderRecord(c: *Context, node: Node) !NodeIndex {
1758 const payload = @fieldParentPtr(Payload.Record, "base", node.ptr_otherwise).data;
1759 if (payload.is_packed)
1760 _ = try c.addToken(.keyword_packed, "packed")
1761 else
1762 _ = try c.addToken(.keyword_extern, "extern");
1763 const kind_tok = if (node.tag() == .@"struct")
1764 try c.addToken(.keyword_struct, "struct")
1765 else
1766 try c.addToken(.keyword_union, "union");
1767
1768 _ = try c.addToken(.l_brace, "{");
1769 const members = try c.gpa.alloc(NodeIndex, std.math.max(payload.fields.len, 2));
1770 defer c.gpa.free(members);
1771 members[0] = 0;
1772 members[1] = 0;
1773
1774 for (payload.fields) |field, i| {
1775 const name_tok = try c.addIdentifier(field.name);
1776 _ = try c.addToken(.colon, ":");
1777 const type_expr = try renderNode(c, field.type);
1778
1779 const alignment = field.alignment orelse {
1780 members[i] = try c.addNode(.{
1781 .tag = .container_field_init,
1782 .main_token = name_tok,
1783 .data = .{
1784 .lhs = type_expr,
1785 .rhs = 0,
1786 },
1787 });
1788 _ = try c.addToken(.comma, ",");
1789 continue;
1790 };
1791 _ = try c.addToken(.keyword_align, "align");
1792 _ = try c.addToken(.l_paren, "(");
1793 const align_expr = try c.addNode(.{
1794 .tag = .integer_literal,
1795 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{alignment}),
1796 .data = undefined,
1797 });
1798 _ = try c.addToken(.r_paren, ")");
1799
1800 members[i] = try c.addNode(.{
1801 .tag = .container_field_align,
1802 .main_token = name_tok,
1803 .data = .{
1804 .lhs = type_expr,
1805 .rhs = align_expr,
1806 },
1807 });
1808 _ = try c.addToken(.comma, ",");
1809 }
1810 _ = try c.addToken(.r_brace, "}");
1811
1812 if (members.len <= 2) {
1813 return c.addNode(.{
1814 .tag = .container_decl_two_comma,
1815 .main_token = kind_tok,
1816 .data = .{
1817 .lhs = members[0],
1818 .rhs = members[1],
1819 },
1820 });
1821 } else {
1822 const span = try c.listToSpan(members);
1823 return c.addNode(.{
1824 .tag = .container_decl_comma,
1825 .main_token = kind_tok,
1826 .data = .{
1827 .lhs = span.start,
1828 .rhs = span.end,
1829 },
1830 });
1831 }
1832}
1833
1834fn renderFieldAccess(c: *Context, lhs: NodeIndex, field_name: []const u8) !NodeIndex {
1835 return c.addNode(.{
1836 .tag = .field_access,
1837 .main_token = try c.addToken(.period, "."),
1838 .data = .{
1839 .lhs = lhs,
1840 .rhs = try c.addIdentifier(field_name),
1841 },
1842 });
1843}
1844
1845fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex {
1846 const l_brace = try c.addToken(.l_brace, "{");
1847 var rendered = try c.gpa.alloc(NodeIndex, std.math.max(inits.len, 1));
1848 defer c.gpa.free(rendered);
1849 rendered[0] = 0;
1850 for (inits) |init, i| {
1851 rendered[i] = try renderNode(c, init);
1852 _ = try c.addToken(.comma, ",");
1853 }
1854 _ = try c.addToken(.r_brace, "}");
1855 if (inits.len < 2) {
1856 return c.addNode(.{
1857 .tag = .array_init_one_comma,
1858 .main_token = l_brace,
1859 .data = .{
1860 .lhs = lhs,
1861 .rhs = rendered[0],
1862 },
1863 });
1864 } else {
1865 const span = try c.listToSpan(rendered);
1866 return c.addNode(.{
1867 .tag = .array_init_comma,
1868 .main_token = l_brace,
1869 .data = .{
1870 .lhs = lhs,
1871 .rhs = try c.addExtra(NodeSubRange{
1872 .start = span.start,
1873 .end = span.end,
1874 }),
1875 },
1876 });
1877 }
1878}
1879
1880fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
1881 const l_bracket = try c.addToken(.l_bracket, "[");
1882 const len_expr = try c.addNode(.{
1883 .tag = .integer_literal,
1884 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{len}),
1885 .data = undefined,
1886 });
1887 _ = try c.addToken(.r_bracket, "]");
1888 const elem_type_expr = try renderNode(c, elem_type);
1889 return c.addNode(.{
1890 .tag = .array_type,
1891 .main_token = l_bracket,
1892 .data = .{
1893 .lhs = len_expr,
1894 .rhs = elem_type_expr,
1895 },
1896 });
1897}
1898
1899fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
1900 switch (node.tag()) {
1901 .warning => unreachable,
1902 .var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .block_single, .@"switch" => {},
1903 .while_true => {
1904 const payload = node.castTag(.while_true).?.data;
1905 return addSemicolonIfNotBlock(c, payload, .yes_if);
1906 },
1907 .@"while" => {
1908 const payload = node.castTag(.@"while").?.data;
1909 return addSemicolonIfNotBlock(c, payload.body, .yes_if);
1910 },
1911 .@"if" => {
1912 const payload = node.castTag(.@"if").?.data;
1913 if (payload.@"else") |some|
1914 return addSemicolonIfNotBlock(c, some, .no_if);
1915 return addSemicolonIfNotBlock(c, payload.then, .no_if);
1916 },
1917 else => _ = try c.addToken(.semicolon, ";"),
1918 }
1919}
1920
1921fn addSemicolonIfNotBlock(c: *Context, node: Node, if_needs_semicolon: enum{ yes_if, no_if}) !void {
1922 switch (node.tag()) {
1923 .block, .empty_block, .block_single => {},
1924 .@"if" => {
1925 if (if_needs_semicolon == .yes_if) {
1926 _ = try c.addToken(.semicolon, ";");
1927 return;
1928 }
1929
1930 const payload = node.castTag(.@"if").?.data;
1931 if (payload.@"else") |some|
1932 return addSemicolonIfNotBlock(c, some, .no_if);
1933 return addSemicolonIfNotBlock(c, payload.then, .no_if);
1934 },
1935 else => _ = try c.addToken(.semicolon, ";"),
1936 }
1937}
1938
1939fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
1940 switch (node.tag()) {
1941 .declaration => unreachable,
1942 .null_literal,
1943 .undefined_literal,
1944 .true_literal,
1945 .false_literal,
1946 .return_void,
1947 .zero_literal,
1948 .one_literal,
1949 .void_type,
1950 .noreturn_type,
1951 .@"anytype",
1952 .div_trunc,
1953 .rem,
1954 .int_cast,
1955 .as,
1956 .truncate,
1957 .bit_cast,
1958 .float_cast,
1959 .float_to_int,
1960 .int_to_float,
1961 .int_to_enum,
1962 .int_to_ptr,
1963 .std_mem_zeroes,
1964 .std_math_Log2Int,
1965 .log2_int_type,
1966 .ptr_to_int,
1967 .enum_to_int,
1968 .sizeof,
1969 .alignof,
1970 .typeof,
1971 .std_meta_sizeof,
1972 .std_meta_cast,
1973 .std_mem_zeroinit,
1974 .integer_literal,
1975 .float_literal,
1976 .string_literal,
1977 .char_literal,
1978 .identifier,
1979 .field_access,
1980 .ptr_cast,
1981 .type,
1982 .array_access,
1983 .align_cast,
1984 .optional_type,
1985 .c_pointer,
1986 .single_pointer,
1987 .unwrap,
1988 .deref,
1989 .address_of,
1990 .not,
1991 .negate,
1992 .negate_wrap,
1993 .bit_not,
1994 .func,
1995 .call,
1996 .array_type,
1997 .bool_to_int,
1998 => {
1999 // no grouping needed
2000 return renderNode(c, node);
2001 },
2002
2003 .opaque_literal,
2004 .empty_array,
2005 .block_single,
2006 .add,
2007 .add_wrap,
2008 .sub,
2009 .sub_wrap,
2010 .mul,
2011 .mul_wrap,
2012 .div,
2013 .shl,
2014 .shr,
2015 .mod,
2016 .@"and",
2017 .@"or",
2018 .less_than,
2019 .less_than_equal,
2020 .greater_than,
2021 .greater_than_equal,
2022 .equal,
2023 .not_equal,
2024 .bit_and,
2025 .bit_or,
2026 .bit_xor,
2027 .empty_block,
2028 .array_cat,
2029 .array_filler,
2030 .@"if",
2031 .@"enum",
2032 .@"struct",
2033 .@"union",
2034 .array_init,
2035 .tuple,
2036 .container_init,
2037 .block,
2038 => return c.addNode(.{
2039 .tag = .grouped_expression,
2040 .main_token = try c.addToken(.l_paren, "("),
2041 .data = .{
2042 .lhs = try renderNode(c, node),
2043 .rhs = try c.addToken(.r_paren, ")"),
2044 },
2045 }),
2046 .ellipsis3,
2047 .switch_prong,
2048 .warning,
2049 .var_decl,
2050 .fail_decl,
2051 .arg_redecl,
2052 .alias,
2053 .var_simple,
2054 .pub_var_simple,
2055 .pub_enum_redecl,
2056 .enum_redecl,
2057 .@"while",
2058 .@"switch",
2059 .@"break",
2060 .break_val,
2061 .pub_inline_fn,
2062 .discard,
2063 .@"continue",
2064 .@"return",
2065 .usingnamespace_builtins,
2066 .while_true,
2067 .if_not_break,
2068 .switch_else,
2069 .add_assign,
2070 .add_wrap_assign,
2071 .sub_assign,
2072 .sub_wrap_assign,
2073 .mul_assign,
2074 .mul_wrap_assign,
2075 .div_assign,
2076 .shl_assign,
2077 .shr_assign,
2078 .mod_assign,
2079 .bit_and_assign,
2080 .bit_or_assign,
2081 .bit_xor_assign,
2082 .assign,
2083 => {
2084 // these should never appear in places where grouping might be needed.
2085 unreachable;
2086 },
2087 }
2088}
2089
2090fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
2091 const payload = @fieldParentPtr(Payload.UnOp, "base", node.ptr_otherwise).data;
2092 return c.addNode(.{
2093 .tag = tag,
2094 .main_token = try c.addToken(tok_tag, bytes),
2095 .data = .{
2096 .lhs = try renderNodeGrouped(c, payload),
2097 .rhs = undefined,
2098 },
2099 });
2100}
2101
2102fn renderBinOpGrouped(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
2103 const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data;
2104 const lhs = try renderNodeGrouped(c, payload.lhs);
2105 return c.addNode(.{
2106 .tag = tag,
2107 .main_token = try c.addToken(tok_tag, bytes),
2108 .data = .{
2109 .lhs = lhs,
2110 .rhs = try renderNodeGrouped(c, payload.rhs),
2111 },
2112 });
2113}
2114
2115fn renderBinOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex {
2116 const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data;
2117 const lhs = try renderNode(c, payload.lhs);
2118 return c.addNode(.{
2119 .tag = tag,
2120 .main_token = try c.addToken(tok_tag, bytes),
2121 .data = .{
2122 .lhs = lhs,
2123 .rhs = try renderNode(c, payload.rhs),
2124 },
2125 });
2126}
2127
2128fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeIndex {
2129 const import_tok = try c.addToken(.builtin, "@import");
2130 _ = try c.addToken(.l_paren, "(");
2131 const std_tok = try c.addToken(.string_literal, "\"std\"");
2132 const std_node = try c.addNode(.{
2133 .tag = .string_literal,
2134 .main_token = std_tok,
2135 .data = undefined,
2136 });
2137 _ = try c.addToken(.r_paren, ")");
2138
2139 const import_node = try c.addNode(.{
2140 .tag = .builtin_call_two,
2141 .main_token = import_tok,
2142 .data = .{
2143 .lhs = std_node,
2144 .rhs = 0,
2145 },
2146 });
2147
2148 var access_chain = import_node;
2149 access_chain = try renderFieldAccess(c, access_chain, first);
2150 access_chain = try renderFieldAccess(c, access_chain, second);
2151 return access_chain;
2152}
2153
2154fn renderCall(c: *Context, lhs: NodeIndex, args: []const Node) !NodeIndex {
2155 const lparen = try c.addToken(.l_paren, "(");
2156 const res = switch (args.len) {
2157 0 => try c.addNode(.{
2158 .tag = .call_one,
2159 .main_token = lparen,
2160 .data = .{
2161 .lhs = lhs,
2162 .rhs = 0,
2163 },
2164 }),
2165 1 => blk: {
2166 const arg = try renderNode(c, args[0]);
2167 break :blk try c.addNode(.{
2168 .tag = .call_one,
2169 .main_token = lparen,
2170 .data = .{
2171 .lhs = lhs,
2172 .rhs = arg,
2173 },
2174 });
2175 },
2176 else => blk: {
2177 var rendered = try c.gpa.alloc(NodeIndex, args.len);
2178 defer c.gpa.free(rendered);
2179
2180 for (args) |arg, i| {
2181 if (i != 0) _ = try c.addToken(.comma, ",");
2182 rendered[i] = try renderNode(c, arg);
2183 }
2184 const span = try c.listToSpan(rendered);
2185 break :blk try c.addNode(.{
2186 .tag = .call,
2187 .main_token = lparen,
2188 .data = .{
2189 .lhs = lhs,
2190 .rhs = try c.addExtra(NodeSubRange{
2191 .start = span.start,
2192 .end = span.end,
2193 }),
2194 },
2195 });
2196 },
2197 };
2198 _ = try c.addToken(.r_paren, ")");
2199 return res;
2200}
2201
2202fn renderBuiltinCall(c: *Context, builtin: []const u8, args: []const Node) !NodeIndex {
2203 const builtin_tok = try c.addToken(.builtin, builtin);
2204 _ = try c.addToken(.l_paren, "(");
2205 var arg_1: NodeIndex = 0;
2206 var arg_2: NodeIndex = 0;
2207 switch (args.len) {
2208 0 => {},
2209 1 => {
2210 arg_1 = try renderNode(c, args[0]);
2211 },
2212 2 => {
2213 arg_1 = try renderNode(c, args[0]);
2214 _ = try c.addToken(.comma, ",");
2215 arg_2 = try renderNode(c, args[1]);
2216 },
2217 else => unreachable, // expand this function as needed.
2218 }
2219
2220 _ = try c.addToken(.r_paren, ")");
2221 return c.addNode(.{
2222 .tag = .builtin_call_two,
2223 .main_token = builtin_tok,
2224 .data = .{
2225 .lhs = arg_1,
2226 .rhs = arg_2,
2227 },
2228 });
2229}
2230
2231fn renderVar(c: *Context, node: Node) !NodeIndex {
2232 const payload = node.castTag(.var_decl).?.data;
2233 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");
2234 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
2235 if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
2236 if (payload.is_threadlocal) _ = try c.addToken(.keyword_threadlocal, "threadlocal");
2237 const mut_tok = if (payload.is_const)
2238 try c.addToken(.keyword_const, "const")
2239 else
2240 try c.addToken(.keyword_var, "var");
2241 _ = try c.addIdentifier(payload.name);
2242 _ = try c.addToken(.colon, ":");
2243 const type_node = try renderNode(c, payload.type);
2244
2245 const align_node = if (payload.alignment) |some| blk: {
2246 _ = try c.addToken(.keyword_align, "align");
2247 _ = try c.addToken(.l_paren, "(");
2248 const res = try c.addNode(.{
2249 .tag = .integer_literal,
2250 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),
2251 .data = undefined,
2252 });
2253 _ = try c.addToken(.r_paren, ")");
2254 break :blk res;
2255 } else 0;
2256
2257 const section_node = if (payload.linksection_string) |some| blk: {
2258 _ = try c.addToken(.keyword_linksection, "linksection");
2259 _ = try c.addToken(.l_paren, "(");
2260 const res = try c.addNode(.{
2261 .tag = .string_literal,
2262 .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
2263 .data = undefined,
2264 });
2265 _ = try c.addToken(.r_paren, ")");
2266 break :blk res;
2267 } else 0;
2268
2269 const init_node = if (payload.init) |some| blk: {
2270 _ = try c.addToken(.equal, "=");
2271 break :blk try renderNode(c, some);
2272 } else 0;
2273 _ = try c.addToken(.semicolon, ";");
2274
2275 if (section_node == 0) {
2276 if (align_node == 0) {
2277 return c.addNode(.{
2278 .tag = .simple_var_decl,
2279 .main_token = mut_tok,
2280 .data = .{
2281 .lhs = type_node,
2282 .rhs = init_node,
2283 },
2284 });
2285 } else {
2286 return c.addNode(.{
2287 .tag = .local_var_decl,
2288 .main_token = mut_tok,
2289 .data = .{
2290 .lhs = try c.addExtra(std.zig.ast.Node.LocalVarDecl{
2291 .type_node = type_node,
2292 .align_node = align_node,
2293 }),
2294 .rhs = init_node,
2295 },
2296 });
2297 }
2298 } else {
2299 return c.addNode(.{
2300 .tag = .global_var_decl,
2301 .main_token = mut_tok,
2302 .data = .{
2303 .lhs = try c.addExtra(std.zig.ast.Node.GlobalVarDecl{
2304 .type_node = type_node,
2305 .align_node = align_node,
2306 .section_node = section_node,
2307 }),
2308 .rhs = init_node,
2309 },
2310 });
2311 }
2312}
2313
2314fn renderFunc(c: *Context, node: Node) !NodeIndex {
2315 const payload = node.castTag(.func).?.data;
2316 if (payload.is_pub) _ = try c.addToken(.keyword_pub, "pub");
2317 if (payload.is_extern) _ = try c.addToken(.keyword_extern, "extern");
2318 if (payload.is_export) _ = try c.addToken(.keyword_export, "export");
2319 const fn_token = try c.addToken(.keyword_fn, "fn");
2320 if (payload.name) |some| _ = try c.addIdentifier(some);
2321
2322 const params = try renderParams(c, payload.params, payload.is_var_args);
2323 defer params.deinit();
2324 var span: NodeSubRange = undefined;
2325 if (params.items.len > 1) span = try c.listToSpan(params.items);
2326
2327 const align_expr = if (payload.alignment) |some| blk: {
2328 _ = try c.addToken(.keyword_align, "align");
2329 _ = try c.addToken(.l_paren, "(");
2330 const res = try c.addNode(.{
2331 .tag = .integer_literal,
2332 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{some}),
2333 .data = undefined,
2334 });
2335 _ = try c.addToken(.r_paren, ")");
2336 break :blk res;
2337 } else 0;
2338
2339 const section_expr = if (payload.linksection_string) |some| blk: {
2340 _ = try c.addToken(.keyword_linksection, "linksection");
2341 _ = try c.addToken(.l_paren, "(");
2342 const res = try c.addNode(.{
2343 .tag = .string_literal,
2344 .main_token = try c.addTokenFmt(.string_literal, "\"{s}\"", .{std.zig.fmtEscapes(some)}),
2345 .data = undefined,
2346 });
2347 _ = try c.addToken(.r_paren, ")");
2348 break :blk res;
2349 } else 0;
2350
2351 const callconv_expr = if (payload.explicit_callconv) |some| blk: {
2352 _ = try c.addToken(.keyword_callconv, "callconv");
2353 _ = try c.addToken(.l_paren, "(");
2354 _ = try c.addToken(.period, ".");
2355 const res = try c.addNode(.{
2356 .tag = .enum_literal,
2357 .main_token = try c.addTokenFmt(.identifier, "{s}", .{@tagName(some)}),
2358 .data = undefined,
2359 });
2360 _ = try c.addToken(.r_paren, ")");
2361 break :blk res;
2362 } else 0;
2363
2364 const return_type_expr = try renderNode(c, payload.return_type);
2365
2366 const fn_proto = try blk: {
2367 if (align_expr == 0 and section_expr == 0 and callconv_expr == 0) {
2368 if (params.items.len < 2)
2369 break :blk c.addNode(.{
2370 .tag = .fn_proto_simple,
2371 .main_token = fn_token,
2372 .data = .{
2373 .lhs = params.items[0],
2374 .rhs = return_type_expr,
2375 },
2376 })
2377 else
2378 break :blk c.addNode(.{
2379 .tag = .fn_proto_multi,
2380 .main_token = fn_token,
2381 .data = .{
2382 .lhs = try c.addExtra(NodeSubRange{
2383 .start = span.start,
2384 .end = span.end,
2385 }),
2386 .rhs = return_type_expr,
2387 },
2388 });
2389 }
2390 if (params.items.len < 2)
2391 break :blk c.addNode(.{
2392 .tag = .fn_proto_one,
2393 .main_token = fn_token,
2394 .data = .{
2395 .lhs = try c.addExtra(std.zig.ast.Node.FnProtoOne{
2396 .param = params.items[0],
2397 .align_expr = align_expr,
2398 .section_expr = section_expr,
2399 .callconv_expr = callconv_expr,
2400 }),
2401 .rhs = return_type_expr,
2402 },
2403 })
2404 else
2405 break :blk c.addNode(.{
2406 .tag = .fn_proto,
2407 .main_token = fn_token,
2408 .data = .{
2409 .lhs = try c.addExtra(std.zig.ast.Node.FnProto{
2410 .params_start = span.start,
2411 .params_end = span.end,
2412 .align_expr = align_expr,
2413 .section_expr = section_expr,
2414 .callconv_expr = callconv_expr,
2415 }),
2416 .rhs = return_type_expr,
2417 },
2418 });
2419 };
2420
2421 const body = if (payload.body) |some|
2422 try renderNode(c, some)
2423 else if (payload.is_extern) blk: {
2424 _ = try c.addToken(.semicolon, ";");
2425 break :blk 0;
2426 } else return fn_proto;
2427
2428 return c.addNode(.{
2429 .tag = .fn_decl,
2430 .main_token = fn_token,
2431 .data = .{
2432 .lhs = fn_proto,
2433 .rhs = body,
2434 },
2435 });
2436}
2437
2438fn renderMacroFunc(c: *Context, node: Node) !NodeIndex {
2439 const payload = node.castTag(.pub_inline_fn).?.data;
2440 _ = try c.addToken(.keyword_pub, "pub");
2441 const fn_token = try c.addToken(.keyword_fn, "fn");
2442 _ = try c.addIdentifier(payload.name);
2443
2444 const params = try renderParams(c, payload.params, false);
2445 defer params.deinit();
2446 var span: NodeSubRange = undefined;
2447 if (params.items.len > 1) span = try c.listToSpan(params.items);
2448
2449 const callconv_expr = blk: {
2450 _ = try c.addToken(.keyword_callconv, "callconv");
2451 _ = try c.addToken(.l_paren, "(");
2452 _ = try c.addToken(.period, ".");
2453 const res = try c.addNode(.{
2454 .tag = .enum_literal,
2455 .main_token = try c.addToken(.identifier, "Inline"),
2456 .data = undefined,
2457 });
2458 _ = try c.addToken(.r_paren, ")");
2459 break :blk res;
2460 };
2461 const return_type_expr = try renderNodeGrouped(c, payload.return_type);
2462
2463 const fn_proto = try blk: {
2464 if (params.items.len < 2)
2465 break :blk c.addNode(.{
2466 .tag = .fn_proto_one,
2467 .main_token = fn_token,
2468 .data = .{
2469 .lhs = try c.addExtra(std.zig.ast.Node.FnProtoOne{
2470 .param = params.items[0],
2471 .align_expr = 0,
2472 .section_expr = 0,
2473 .callconv_expr = callconv_expr,
2474 }),
2475 .rhs = return_type_expr,
2476 },
2477 })
2478 else
2479 break :blk c.addNode(.{
2480 .tag = .fn_proto,
2481 .main_token = fn_token,
2482 .data = .{
2483 .lhs = try c.addExtra(std.zig.ast.Node.FnProto{
2484 .params_start = span.start,
2485 .params_end = span.end,
2486 .align_expr = 0,
2487 .section_expr = 0,
2488 .callconv_expr = callconv_expr,
2489 }),
2490 .rhs = return_type_expr,
2491 },
2492 });
2493 };
2494 return c.addNode(.{
2495 .tag = .fn_decl,
2496 .main_token = fn_token,
2497 .data = .{
2498 .lhs = fn_proto,
2499 .rhs = try renderNode(c, payload.body),
2500 },
2501 });
2502}
2503
2504fn renderParams(c: *Context, params: []Payload.Param, is_var_args: bool) !std.ArrayList(NodeIndex) {
2505 _ = try c.addToken(.l_paren, "(");
2506 var rendered = std.ArrayList(NodeIndex).init(c.gpa);
2507 errdefer rendered.deinit();
2508 try rendered.ensureCapacity(std.math.max(params.len, 1));
2509
2510 for (params) |param, i| {
2511 if (i != 0) _ = try c.addToken(.comma, ",");
2512 if (param.is_noalias) _ = try c.addToken(.keyword_noalias, "noalias");
2513 if (param.name) |some| {
2514 _ = try c.addIdentifier(some);
2515 _ = try c.addToken(.colon, ":");
2516 }
2517 if (param.type.tag() == .@"anytype") {
2518 _ = try c.addToken(.keyword_anytype, "anytype");
2519 continue;
2520 }
2521 rendered.appendAssumeCapacity(try renderNode(c, param.type));
2522 }
2523 if (is_var_args) {
2524 if (params.len != 0) _ = try c.addToken(.comma, ",");
2525 _ = try c.addToken(.ellipsis3, "...");
2526 }
2527 _ = try c.addToken(.r_paren, ")");
2528
2529 if (rendered.items.len == 0) rendered.appendAssumeCapacity(0);
2530 return rendered;
2531}
src/type.zig+65
......@@ -28,6 +28,8 @@ pub const Type = extern union {
2828 .i32,
2929 .u64,
3030 .i64,
31 .u128,
32 .i128,
3133 .usize,
3234 .isize,
3335 .c_short,
......@@ -357,6 +359,8 @@ pub const Type = extern union {
357359 .i32,
358360 .u64,
359361 .i64,
362 .u128,
363 .i128,
360364 .usize,
361365 .isize,
362366 .c_short,
......@@ -506,6 +510,8 @@ pub const Type = extern union {
506510 .i32,
507511 .u64,
508512 .i64,
513 .u128,
514 .i128,
509515 .usize,
510516 .isize,
511517 .c_short,
......@@ -772,6 +778,8 @@ pub const Type = extern union {
772778 .i32,
773779 .u64,
774780 .i64,
781 .u128,
782 .i128,
775783 .usize,
776784 .isize,
777785 .c_short,
......@@ -868,6 +876,7 @@ pub const Type = extern union {
868876 .i16, .u16 => return 2,
869877 .i32, .u32 => return 4,
870878 .i64, .u64 => return 8,
879 .u128, .i128 => return 16,
871880
872881 .isize,
873882 .usize,
......@@ -1010,6 +1019,7 @@ pub const Type = extern union {
10101019 .i16, .u16 => return 2,
10111020 .i32, .u32 => return 4,
10121021 .i64, .u64 => return 8,
1022 .u128, .i128 => return 16,
10131023
10141024 .@"anyframe", .anyframe_T, .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
10151025
......@@ -1109,6 +1119,8 @@ pub const Type = extern union {
11091119 .i32,
11101120 .u64,
11111121 .i64,
1122 .u128,
1123 .i128,
11121124 .usize,
11131125 .isize,
11141126 .c_short,
......@@ -1191,6 +1203,8 @@ pub const Type = extern union {
11911203 .i32,
11921204 .u64,
11931205 .i64,
1206 .u128,
1207 .i128,
11941208 .usize,
11951209 .isize,
11961210 .c_short,
......@@ -1278,6 +1292,8 @@ pub const Type = extern union {
12781292 .i32,
12791293 .u64,
12801294 .i64,
1295 .u128,
1296 .i128,
12811297 .usize,
12821298 .isize,
12831299 .c_short,
......@@ -1359,6 +1375,8 @@ pub const Type = extern union {
13591375 .i32,
13601376 .u64,
13611377 .i64,
1378 .u128,
1379 .i128,
13621380 .usize,
13631381 .isize,
13641382 .c_short,
......@@ -1440,6 +1458,8 @@ pub const Type = extern union {
14401458 .i32,
14411459 .u64,
14421460 .i64,
1461 .u128,
1462 .i128,
14431463 .usize,
14441464 .isize,
14451465 .c_short,
......@@ -1522,6 +1542,8 @@ pub const Type = extern union {
15221542 .i32,
15231543 .u64,
15241544 .i64,
1545 .u128,
1546 .i128,
15251547 .usize,
15261548 .isize,
15271549 .c_short,
......@@ -1660,6 +1682,8 @@ pub const Type = extern union {
16601682 .i32 => unreachable,
16611683 .u64 => unreachable,
16621684 .i64 => unreachable,
1685 .u128 => unreachable,
1686 .i128 => unreachable,
16631687 .usize => unreachable,
16641688 .isize => unreachable,
16651689 .c_short => unreachable,
......@@ -1776,6 +1800,8 @@ pub const Type = extern union {
17761800 .i32,
17771801 .u64,
17781802 .i64,
1803 .u128,
1804 .i128,
17791805 .usize,
17801806 .isize,
17811807 .c_short,
......@@ -1856,6 +1882,8 @@ pub const Type = extern union {
18561882 .i32,
18571883 .u64,
18581884 .i64,
1885 .u128,
1886 .i128,
18591887 .usize,
18601888 .isize,
18611889 .c_short,
......@@ -2009,6 +2037,8 @@ pub const Type = extern union {
20092037 .i16,
20102038 .i32,
20112039 .i64,
2040 .u128,
2041 .i128,
20122042 => true,
20132043 };
20142044 }
......@@ -2061,6 +2091,8 @@ pub const Type = extern union {
20612091 .i16,
20622092 .i32,
20632093 .i64,
2094 .u128,
2095 .i128,
20642096 .optional,
20652097 .optional_single_mut_pointer,
20662098 .optional_single_const_pointer,
......@@ -2167,6 +2199,8 @@ pub const Type = extern union {
21672199 .i32 => .{ .signedness = .signed, .bits = 32 },
21682200 .u64 => .{ .signedness = .unsigned, .bits = 64 },
21692201 .i64 => .{ .signedness = .signed, .bits = 64 },
2202 .u128 => .{ .signedness = .unsigned, .bits = 128 },
2203 .i128 => .{ .signedness = .signed, .bits = 128 },
21702204 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
21712205 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
21722206 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
......@@ -2227,6 +2261,8 @@ pub const Type = extern union {
22272261 .i32,
22282262 .u64,
22292263 .i64,
2264 .u128,
2265 .i128,
22302266 .optional,
22312267 .optional_single_mut_pointer,
22322268 .optional_single_const_pointer,
......@@ -2333,6 +2369,8 @@ pub const Type = extern union {
23332369 .i32,
23342370 .u64,
23352371 .i64,
2372 .u128,
2373 .i128,
23362374 .usize,
23372375 .isize,
23382376 .c_short,
......@@ -2417,6 +2455,8 @@ pub const Type = extern union {
24172455 .i32,
24182456 .u64,
24192457 .i64,
2458 .u128,
2459 .i128,
24202460 .usize,
24212461 .isize,
24222462 .c_short,
......@@ -2500,6 +2540,8 @@ pub const Type = extern union {
25002540 .i32,
25012541 .u64,
25022542 .i64,
2543 .u128,
2544 .i128,
25032545 .usize,
25042546 .isize,
25052547 .c_short,
......@@ -2583,6 +2625,8 @@ pub const Type = extern union {
25832625 .i32,
25842626 .u64,
25852627 .i64,
2628 .u128,
2629 .i128,
25862630 .usize,
25872631 .isize,
25882632 .c_short,
......@@ -2663,6 +2707,8 @@ pub const Type = extern union {
26632707 .i32,
26642708 .u64,
26652709 .i64,
2710 .u128,
2711 .i128,
26662712 .usize,
26672713 .isize,
26682714 .c_short,
......@@ -2743,6 +2789,8 @@ pub const Type = extern union {
27432789 .i32,
27442790 .u64,
27452791 .i64,
2792 .u128,
2793 .i128,
27462794 .usize,
27472795 .isize,
27482796 .c_short,
......@@ -2793,6 +2841,8 @@ pub const Type = extern union {
27932841 .i32,
27942842 .u64,
27952843 .i64,
2844 .u128,
2845 .i128,
27962846 .usize,
27972847 .isize,
27982848 .c_short,
......@@ -2874,6 +2924,8 @@ pub const Type = extern union {
28742924 .i32,
28752925 .u64,
28762926 .i64,
2927 .u128,
2928 .i128,
28772929 .usize,
28782930 .isize,
28792931 .c_short,
......@@ -2971,6 +3023,8 @@ pub const Type = extern union {
29713023 .i32,
29723024 .u64,
29733025 .i64,
3026 .u128,
3027 .i128,
29743028 .usize,
29753029 .isize,
29763030 .c_short,
......@@ -3060,6 +3114,8 @@ pub const Type = extern union {
30603114 .i32,
30613115 .u64,
30623116 .i64,
3117 .u128,
3118 .i128,
30633119 .usize,
30643120 .isize,
30653121 .c_short,
......@@ -3193,6 +3249,8 @@ pub const Type = extern union {
31933249 i32,
31943250 u64,
31953251 i64,
3252 u128,
3253 i128,
31963254 usize,
31973255 isize,
31983256 c_short,
......@@ -3277,6 +3335,8 @@ pub const Type = extern union {
32773335 .i32,
32783336 .u64,
32793337 .i64,
3338 .u128,
3339 .i128,
32803340 .usize,
32813341 .isize,
32823342 .c_short,
......@@ -3352,6 +3412,11 @@ pub const Type = extern union {
33523412 };
33533413 }
33543414
3415 pub fn init(comptime t: Tag) Type {
3416 comptime std.debug.assert(@enumToInt(t) < Tag.no_payload_count);
3417 return .{ .tag_if_small_enough = @enumToInt(t) };
3418 }
3419
33553420 pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Type {
33563421 const ptr = try ally.create(t.Type());
33573422 ptr.* = .{
src/zig_clang.cpp+5
......@@ -2244,6 +2244,11 @@ unsigned ZigClangAPSInt_getNumWords(const ZigClangAPSInt *self) {
22442244 return casted->getNumWords();
22452245}
22462246
2247bool ZigClangAPSInt_lessThanEqual(const ZigClangAPSInt *self, uint64_t rhs) {
2248 auto casted = reinterpret_cast<const llvm::APSInt *>(self);
2249 return casted->ule(rhs);
2250}
2251
22472252uint64_t ZigClangAPInt_getLimitedValue(const ZigClangAPInt *self, uint64_t limit) {
22482253 auto casted = reinterpret_cast<const llvm::APInt *>(self);
22492254 return casted->getLimitedValue(limit);
src/zig_clang.h+1
......@@ -1097,6 +1097,7 @@ ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPSInt_negate(const struct Zig
10971097ZIG_EXTERN_C void ZigClangAPSInt_free(const struct ZigClangAPSInt *self);
10981098ZIG_EXTERN_C const uint64_t *ZigClangAPSInt_getRawData(const struct ZigClangAPSInt *self);
10991099ZIG_EXTERN_C unsigned ZigClangAPSInt_getNumWords(const struct ZigClangAPSInt *self);
1100ZIG_EXTERN_C bool ZigClangAPSInt_lessThanEqual(const struct ZigClangAPSInt *self, uint64_t rhs);
11001101
11011102ZIG_EXTERN_C uint64_t ZigClangAPInt_getLimitedValue(const struct ZigClangAPInt *self, uint64_t limit);
11021103
test/run_translated_c.zig+17
......@@ -3,6 +3,14 @@ const tests = @import("tests.zig");
33const nl = std.cstr.line_sep;
44
55pub fn addCases(cases: *tests.RunTranslatedCContext) void {
6 cases.add("failed macros are only declared once",
7 \\#define FOO =
8 \\#define FOO =
9 \\#define PtrToPtr64(p) ((void *POINTER_64) p)
10 \\#define STRUC_ALIGNED_STACK_COPY(t,s) ((CONST t *)(s))
11 \\int main(void) {}
12 , "");
13
614 cases.add("parenthesized string literal",
715 \\void foo(const char *s) {}
816 \\int main(void) {
......@@ -922,4 +930,13 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
922930 \\ return 0;
923931 \\}
924932 , "");
933
934 cases.add("Use correct break label for statement expression in nested scope",
935 \\#include <stdlib.h>
936 \\int main(void) {
937 \\ int x = ({1, ({2; 3;});});
938 \\ if (x != 3) abort();
939 \\ return 0;
940 \\}
941 , "");
925942}
test/translate_c.zig+483-291
......@@ -3,12 +3,206 @@ const std = @import("std");
33const CrossTarget = std.zig.CrossTarget;
44
55pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("variadic function demoted to prototype",
6 cases.add("if as while stmt has semicolon",
7 \\void foo() {
8 \\ while (1) if (1) {
9 \\ int a = 1;
10 \\ } else {
11 \\ int b = 2;
12 \\ }
13 \\}
14 , &[_][]const u8{
15 \\pub export fn foo() void {
16 \\ while (true) if (true) {
17 \\ var a: c_int = 1;
18 \\ } else {
19 \\ var b: c_int = 2;
20 \\ };
21 \\}
22 });
23
24 cases.add("conditional operator cast to void",
25 \\int bar();
26 \\void foo() {
27 \\ int a;
28 \\ a ? a = 2 : bar();
29 \\}
30 , &[_][]const u8{
31 \\pub extern fn bar(...) c_int;
32 \\pub export fn foo() void {
33 \\ var a: c_int = undefined;
34 \\ if (a != 0) a = 2 else _ = bar();
35 \\}
36 });
37
38 cases.add("struct in struct init to zero",
39 \\struct Foo {
40 \\ int a;
41 \\ struct Bar {
42 \\ int a;
43 \\ } b;
44 \\} a = {};
45 \\#define PTR void *
46 , &[_][]const u8{
47 \\pub const struct_Bar = extern struct {
48 \\ a: c_int,
49 \\};
50 \\pub const struct_Foo = extern struct {
51 \\ a: c_int,
52 \\ b: struct_Bar,
53 \\};
54 \\pub export var a: struct_Foo = struct_Foo{
55 \\ .a = 0,
56 \\ .b = @import("std").mem.zeroes(struct_Bar),
57 \\};
58 ,
59 \\pub const PTR = ?*c_void;
60 });
61
62 cases.add("scoped enum",
63 \\void foo() {
64 \\ enum Foo {
65 \\ A,
66 \\ B,
67 \\ C,
68 \\ };
69 \\ enum Foo a = B;
70 \\ {
71 \\ enum Foo {
72 \\ A,
73 \\ B,
74 \\ C,
75 \\ };
76 \\ enum Foo a = B;
77 \\ }
78 \\}
79 , &[_][]const u8{
80 \\pub export fn foo() void {
81 \\ const enum_Foo = extern enum(c_int) {
82 \\ A,
83 \\ B,
84 \\ C,
85 \\ _,
86 \\ };
87 \\ const A = @enumToInt(enum_Foo.A);
88 \\ const B = @enumToInt(enum_Foo.B);
89 \\ const C = @enumToInt(enum_Foo.C);
90 \\ var a: enum_Foo = @intToEnum(enum_Foo, B);
91 \\ {
92 \\ const enum_Foo = extern enum(c_int) {
93 \\ A,
94 \\ B,
95 \\ C,
96 \\ _,
97 \\ };
98 \\ const A_2 = @enumToInt(enum_Foo.A);
99 \\ const B_3 = @enumToInt(enum_Foo.B);
100 \\ const C_4 = @enumToInt(enum_Foo.C);
101 \\ var a_5: enum_Foo = @intToEnum(enum_Foo, B_3);
102 \\ }
103 \\}
104 });
105
106 cases.add("scoped record",
107 \\void foo() {
108 \\ struct Foo {
109 \\ int A;
110 \\ int B;
111 \\ int C;
112 \\ };
113 \\ struct Foo a = {0};
114 \\ {
115 \\ struct Foo {
116 \\ int A;
117 \\ int B;
118 \\ int C;
119 \\ };
120 \\ struct Foo a = {0};
121 \\ }
122 \\}
123 , &[_][]const u8{
124 \\pub export fn foo() void {
125 \\ const struct_Foo = extern struct {
126 \\ A: c_int,
127 \\ B: c_int,
128 \\ C: c_int,
129 \\ };
130 \\ var a: struct_Foo = struct_Foo{
131 \\ .A = @as(c_int, 0),
132 \\ .B = 0,
133 \\ .C = 0,
134 \\ };
135 \\ {
136 \\ const struct_Foo_1 = extern struct {
137 \\ A: c_int,
138 \\ B: c_int,
139 \\ C: c_int,
140 \\ };
141 \\ var a_2: struct_Foo_1 = struct_Foo_1{
142 \\ .A = @as(c_int, 0),
143 \\ .B = 0,
144 \\ .C = 0,
145 \\ };
146 \\ }
147 \\}
148 });
149
150 cases.add("scoped typedef",
151 \\void foo() {
152 \\ typedef union {
153 \\ int A;
154 \\ int B;
155 \\ int C;
156 \\ } Foo;
157 \\ Foo a = {0};
158 \\ {
159 \\ typedef union {
160 \\ int A;
161 \\ int B;
162 \\ int C;
163 \\ } Foo;
164 \\ Foo a = {0};
165 \\ }
166 \\}
167 , &[_][]const u8{
168 \\pub export fn foo() void {
169 \\ const union_unnamed_1 = extern union {
170 \\ A: c_int,
171 \\ B: c_int,
172 \\ C: c_int,
173 \\ };
174 \\ const Foo = union_unnamed_1;
175 \\ var a: Foo = Foo{
176 \\ .A = @as(c_int, 0),
177 \\ };
178 \\ {
179 \\ const union_unnamed_2 = extern union {
180 \\ A: c_int,
181 \\ B: c_int,
182 \\ C: c_int,
183 \\ };
184 \\ const Foo_1 = union_unnamed_2;
185 \\ var a_2: Foo_1 = Foo_1{
186 \\ .A = @as(c_int, 0),
187 \\ };
188 \\ }
189 \\}
190 });
191
192 cases.add("use cast param as macro fn return type",
193 \\#define MEM_PHYSICAL_TO_K0(x) (void*)((u32)(x) + SYS_BASE_CACHED)
194 , &[_][]const u8{
195 \\pub fn MEM_PHYSICAL_TO_K0(x: anytype) callconv(.Inline) ?*c_void {
196 \\ return @import("std").meta.cast(?*c_void, @import("std").meta.cast(u32, x) + SYS_BASE_CACHED);
197 \\}
198 });
199
200 cases.add("variadic function demoted to extern",
7201 \\int foo(int bar, ...) {
8202 \\ return 1;
9203 \\}
10204 , &[_][]const u8{
11 \\warning: TODO unable to translate variadic function, demoted to declaration
205 \\warning: TODO unable to translate variadic function, demoted to extern
12206 \\pub extern fn foo(bar: c_int, ...) c_int;
13207 });
14208
......@@ -21,11 +215,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
21215 \\ Foo *bar;
22216 \\} Bar;
23217 , &[_][]const u8{
24 \\const struct_unnamed_1 = //
25 ,
26 \\warning: unsupported type: 'Atomic'
27 \\ opaque {}; //
28 ,
218 \\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo
219 \\const struct_unnamed_1 = opaque {};
29220 \\pub const Foo = struct_unnamed_1;
30221 \\const struct_unnamed_2 = extern struct {
31222 \\ bar: ?*Foo,
......@@ -43,8 +234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
43234 ,
44235 \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);
45236 ,
46 \\pub fn _AL_READ3BYTES(p: anytype) callconv(.Inline) @TypeOf(((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16)) {
47 \\ return ((@import("std").meta.cast([*c]u8, p)).* | (((@import("std").meta.cast([*c]u8, p)) + 1).* << 8)) | (((@import("std").meta.cast([*c]u8, p)) + 2).* << 16);
237 \\pub fn _AL_READ3BYTES(p: anytype) callconv(.Inline) @TypeOf((@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + 1).* << 8)) | ((@import("std").meta.cast([*c]u8, p) + 2).* << 16)) {
238 \\ return (@import("std").meta.cast([*c]u8, p).* | ((@import("std").meta.cast([*c]u8, p) + 1).* << 8)) | ((@import("std").meta.cast([*c]u8, p) + 2).* << 16);
48239 \\}
49240 });
50241
......@@ -57,7 +248,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
57248 \\pub export var bar: f32 = @import("std").mem.zeroes(f32);
58249 \\threadlocal var bar_1: c_int = 2;
59250 \\pub export fn foo() c_int {
60 \\ _ = bar_1;
61251 \\ return 0;
62252 \\}
63253 });
......@@ -107,7 +297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
107297 \\ int i1;
108298 \\} boom_t;
109299 \\#define FOO ((boom_t){1})
110 , &[_][]const u8{ // TODO properly translate this
300 , &[_][]const u8{
111301 \\pub const struct_Color = extern struct {
112302 \\ r: u8,
113303 \\ g: u8,
......@@ -127,7 +317,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
127317 \\};
128318 \\pub const boom_t = struct_boom_t;
129319 ,
130 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{ 1 });
320 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{1});
131321 });
132322
133323 cases.add("complex switch",
......@@ -142,14 +332,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
142332 \\ }
143333 \\}
144334 , &[_][]const u8{ // TODO properly translate this
145 \\pub const main = @compileError("unable to translate function");
335 \\source.h:5:13: warning: TODO complex switch
336 ,
337 \\source.h:1:5: warning: unable to translate function, demoted to extern
338 \\pub extern fn main() c_int;
146339 });
147340
148341 cases.add("correct semicolon after infixop",
149342 \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
150343 , &[_][]const u8{
151 \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf(((_fp.*._flags) & _IO_ERR_SEEN) != 0) {
152 \\ return ((_fp.*._flags) & _IO_ERR_SEEN) != 0;
344 \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != 0) {
345 \\ return (_fp.*._flags & _IO_ERR_SEEN) != 0;
153346 \\}
154347 });
155348
......@@ -193,9 +386,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
193386 \\pub export fn foo() void {
194387 \\ while (false) while (false) {};
195388 \\ while (true) while (false) {};
196 \\ while (true) while (true) {
197 \\ if (!false) break;
198 \\ };
389 \\ while (true) {}
199390 \\}
200391 });
201392
......@@ -245,15 +436,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
245436 \\ volatile _Atomic int abufused[12];
246437 \\};
247438 , &[_][]const u8{
248 \\pub const struct_arcan_shmif_page = //
249 ,
250 \\warning: unsupported type: 'Atomic'
251 \\ opaque {}; //
252 ,
253 \\ warning: struct demoted to opaque type - unable to translate type of field abufused
254 , // TODO should be `addr: *struct_arcan_shmif_page`
439 \\source.h:4:8: warning: struct demoted to opaque type - unable to translate type of field abufused
440 \\pub const struct_arcan_shmif_page = opaque {};
255441 \\pub const struct_arcan_shmif_cont = extern struct {
256 \\ addr: [*c]struct_arcan_shmif_page,
442 \\ addr: ?*struct_arcan_shmif_page,
257443 \\};
258444 });
259445
......@@ -293,22 +479,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
293479 , &[_][]const u8{
294480 \\pub const uuid_t = [16]u8;
295481 \\pub const UUID_NULL: uuid_t = [16]u8{
296 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
297 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
298 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
299 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
300 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
301 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
302 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
303 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
304 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
305 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
306 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
307 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
308 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
309 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
310 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
311 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),
482 \\ 0,
483 \\ 0,
484 \\ 0,
485 \\ 0,
486 \\ 0,
487 \\ 0,
488 \\ 0,
489 \\ 0,
490 \\ 0,
491 \\ 0,
492 \\ 0,
493 \\ 0,
494 \\ 0,
495 \\ 0,
496 \\ 0,
497 \\ 0,
312498 \\};
313499 });
314500
......@@ -362,10 +548,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
362548 \\};
363549 \\pub export var ub: union_unnamed_1 = union_unnamed_1{
364550 \\ .c = [4]u8{
365 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))),
366 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))),
367 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))),
368 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))),
551 \\ 'a',
552 \\ 'b',
553 \\ 'b',
554 \\ 'a',
369555 \\ },
370556 \\};
371557 });
......@@ -492,7 +678,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
492678 , &[_][]const u8{
493679 \\pub export fn foo() void {
494680 \\ var a: c_int = undefined;
495 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
681 \\ var b: u8 = 123;
496682 \\ const c: c_int = undefined;
497683 \\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440));
498684 \\ var e: c_int = 10;
......@@ -514,8 +700,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
514700 \\ var a: c_int = undefined;
515701 \\ _ = @as(c_int, 1);
516702 \\ _ = "hey";
517 \\ _ = (@as(c_int, 1) + @as(c_int, 1));
518 \\ _ = (@as(c_int, 1) - @as(c_int, 1));
703 \\ _ = @as(c_int, 1) + @as(c_int, 1);
704 \\ _ = @as(c_int, 1) - @as(c_int, 1);
519705 \\ a = 1;
520706 \\}
521707 });
......@@ -559,9 +745,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
559745 \\ '2',
560746 \\ 0,
561747 \\};
562 \\pub export fn foo() void {
563 \\ _ = v2;
564 \\}
748 \\pub export fn foo() void {}
565749 });
566750
567751 cases.add("simple function definition",
......@@ -634,9 +818,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
634818 \\ var a: c_int = undefined;
635819 \\ var b: c_int = undefined;
636820 \\ var c: c_int = undefined;
637 \\ c = (a + b);
638 \\ c = (a - b);
639 \\ c = (a * b);
821 \\ c = a + b;
822 \\ c = a - b;
823 \\ c = a * b;
640824 \\ c = @divTrunc(a, b);
641825 \\ c = @rem(a, b);
642826 \\ return 0;
......@@ -645,11 +829,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
645829 \\ var a: c_uint = undefined;
646830 \\ var b: c_uint = undefined;
647831 \\ var c: c_uint = undefined;
648 \\ c = (a +% b);
649 \\ c = (a -% b);
650 \\ c = (a *% b);
651 \\ c = (a / b);
652 \\ c = (a % b);
832 \\ c = a +% b;
833 \\ c = a -% b;
834 \\ c = a *% b;
835 \\ c = a / b;
836 \\ c = a % b;
653837 \\ return 0;
654838 \\}
655839 });
......@@ -914,13 +1098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
9141098 \\ ;;;;;
9151099 \\}
9161100 , &[_][]const u8{
917 \\pub export fn foo() void {
918 \\ {}
919 \\ {}
920 \\ {}
921 \\ {}
922 \\ {}
923 \\}
1101 \\pub export fn foo() void {}
9241102 });
9251103
9261104 if (std.Target.current.os.tag != .windows) {
......@@ -1335,11 +1513,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13351513 \\extern enum enum_ty my_enum;
13361514 \\enum enum_ty { FOO };
13371515 , &[_][]const u8{
1338 \\pub const FOO = @enumToInt(enum_enum_ty.FOO);
13391516 \\pub const enum_enum_ty = extern enum(c_int) {
13401517 \\ FOO,
13411518 \\ _,
13421519 \\};
1520 \\pub const FOO = @enumToInt(enum_enum_ty.FOO);
13431521 \\pub extern var my_enum: enum_enum_ty;
13441522 });
13451523
......@@ -1448,7 +1626,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14481626 , &[_][]const u8{
14491627 \\pub fn foo() callconv(.C) void {
14501628 \\ var arr: [10]u8 = [1]u8{
1451 \\ @bitCast(u8, @truncate(i8, @as(c_int, 1))),
1629 \\ 1,
14521630 \\ } ++ [1]u8{0} ** 9;
14531631 \\ var arr1: [10][*c]u8 = [1][*c]u8{
14541632 \\ null,
......@@ -1481,48 +1659,48 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14811659 \\ p,
14821660 \\};
14831661 , &[_][]const u8{
1484 \\pub const a = @enumToInt(enum_unnamed_1.a);
1485 \\pub const b = @enumToInt(enum_unnamed_1.b);
1486 \\pub const c = @enumToInt(enum_unnamed_1.c);
14871662 \\const enum_unnamed_1 = extern enum(c_int) {
14881663 \\ a,
14891664 \\ b,
14901665 \\ c,
14911666 \\ _,
14921667 \\};
1668 \\pub const a = @enumToInt(enum_unnamed_1.a);
1669 \\pub const b = @enumToInt(enum_unnamed_1.b);
1670 \\pub const c = @enumToInt(enum_unnamed_1.c);
14931671 \\pub const d = enum_unnamed_1;
1494 \\pub const e = @enumToInt(enum_unnamed_2.e);
1495 \\pub const f = @enumToInt(enum_unnamed_2.f);
1496 \\pub const g = @enumToInt(enum_unnamed_2.g);
14971672 \\const enum_unnamed_2 = extern enum(c_int) {
14981673 \\ e = 0,
14991674 \\ f = 4,
15001675 \\ g = 5,
15011676 \\ _,
15021677 \\};
1678 \\pub const e = @enumToInt(enum_unnamed_2.e);
1679 \\pub const f = @enumToInt(enum_unnamed_2.f);
1680 \\pub const g = @enumToInt(enum_unnamed_2.g);
15031681 \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
1504 \\pub const i = @enumToInt(enum_unnamed_3.i);
1505 \\pub const j = @enumToInt(enum_unnamed_3.j);
1506 \\pub const k = @enumToInt(enum_unnamed_3.k);
15071682 \\const enum_unnamed_3 = extern enum(c_int) {
15081683 \\ i,
15091684 \\ j,
15101685 \\ k,
15111686 \\ _,
15121687 \\};
1688 \\pub const i = @enumToInt(enum_unnamed_3.i);
1689 \\pub const j = @enumToInt(enum_unnamed_3.j);
1690 \\pub const k = @enumToInt(enum_unnamed_3.k);
15131691 \\pub const struct_Baz = extern struct {
15141692 \\ l: enum_unnamed_3,
15151693 \\ m: d,
15161694 \\};
1517 \\pub const n = @enumToInt(enum_i.n);
1518 \\pub const o = @enumToInt(enum_i.o);
1519 \\pub const p = @enumToInt(enum_i.p);
15201695 \\pub const enum_i = extern enum(c_int) {
15211696 \\ n,
15221697 \\ o,
15231698 \\ p,
15241699 \\ _,
15251700 \\};
1701 \\pub const n = @enumToInt(enum_i.n);
1702 \\pub const o = @enumToInt(enum_i.o);
1703 \\pub const p = @enumToInt(enum_i.p);
15261704 ,
15271705 \\pub const Baz = struct_Baz;
15281706 });
......@@ -1639,7 +1817,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16391817 cases.add("macro pointer cast",
16401818 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
16411819 , &[_][]const u8{
1642 \\pub const NRF_GPIO = (@import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE));
1820 \\pub const NRF_GPIO = @import("std").meta.cast([*c]NRF_GPIO_Type, NRF_GPIO_BASE);
16431821 });
16441822
16451823 cases.add("basic macro function",
......@@ -1701,13 +1879,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17011879 \\ unsigned d = 440;
17021880 \\}
17031881 , &[_][]const u8{
1704 \\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
1705 \\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));
1882 \\pub var a: c_long = 2;
1883 \\pub var b: c_long = 2;
17061884 \\pub var c: c_int = 4;
17071885 \\pub export fn foo(arg_c_1: u8) void {
17081886 \\ var c_1 = arg_c_1;
17091887 \\ var a_2: c_int = undefined;
1710 \\ var b_3: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));
1888 \\ var b_3: u8 = 123;
17111889 \\ b_3 = @bitCast(u8, @truncate(i8, a_2));
17121890 \\ {
17131891 \\ var d: c_int = 5;
......@@ -1723,17 +1901,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17231901 \\}
17241902 , &[_][]const u8{
17251903 \\pub export fn foo() c_int {
1726 \\ _ = (blk: {
1904 \\ _ = blk: {
17271905 \\ _ = @as(c_int, 2);
17281906 \\ break :blk @as(c_int, 4);
1729 \\ });
1730 \\ return (blk: {
1731 \\ _ = (blk_1: {
1907 \\ };
1908 \\ return blk: {
1909 \\ _ = blk_1: {
17321910 \\ _ = @as(c_int, 2);
17331911 \\ break :blk_1 @as(c_int, 4);
1734 \\ });
1912 \\ };
17351913 \\ break :blk @as(c_int, 6);
1736 \\ });
1914 \\ };
17371915 \\}
17381916 });
17391917
......@@ -1780,20 +1958,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17801958 \\ while (true) {
17811959 \\ var a_1: c_int = 4;
17821960 \\ a_1 = 9;
1783 \\ return (blk: {
1961 \\ return blk: {
17841962 \\ _ = @as(c_int, 6);
17851963 \\ break :blk a_1;
1786 \\ });
1964 \\ };
17871965 \\ }
17881966 \\ while (true) {
17891967 \\ var a_1: c_int = 2;
17901968 \\ a_1 = 12;
1791 \\ if (!true) break;
1792 \\ }
1793 \\ while (true) {
1794 \\ a = 7;
1795 \\ if (!true) break;
17961969 \\ }
1970 \\ while (true) a = 7;
17971971 \\ return 0;
17981972 \\}
17991973 });
......@@ -1813,16 +1987,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18131987 \\ var b: c_int = 4;
18141988 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
18151989 \\ var a: c_int = 2;
1816 \\ _ = (blk: {
1817 \\ _ = (blk_1: {
1990 \\ _ = blk: {
1991 \\ _ = blk_1: {
18181992 \\ a = 6;
18191993 \\ break :blk_1 @as(c_int, 5);
1820 \\ });
1994 \\ };
18211995 \\ break :blk @as(c_int, 7);
1822 \\ });
1996 \\ };
18231997 \\ }
18241998 \\ }
1825 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));
1999 \\ var i: u8 = 2;
18262000 \\}
18272001 });
18282002
......@@ -1830,7 +2004,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18302004 \\unsigned anyerror = 2;
18312005 \\#define noreturn _Noreturn
18322006 , &[_][]const u8{
1833 \\pub export var anyerror_1: c_uint = @bitCast(c_uint, @as(c_int, 2));
2007 \\pub export var anyerror_1: c_uint = 2;
18342008 ,
18352009 \\pub const noreturn_2 = @compileError("unable to translate C expr: unexpected token .Keyword_noreturn");
18362010 });
......@@ -1844,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18442018 \\pub export var a: f32 = @floatCast(f32, 3.1415);
18452019 \\pub export var b: f64 = 3.1415;
18462020 \\pub export var c: c_int = @floatToInt(c_int, 3.1415);
1847 \\pub export var d: f64 = @intToFloat(f64, @as(c_int, 3));
2021 \\pub export var d: f64 = 3;
18482022 });
18492023
18502024 cases.add("conditional operator",
......@@ -1854,7 +2028,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18542028 \\}
18552029 , &[_][]const u8{
18562030 \\pub export fn bar() c_int {
1857 \\ if ((if (true) @as(c_int, 5) else (if (true) @as(c_int, 4) else @as(c_int, 6))) != 0) _ = @as(c_int, 2);
2031 \\ if ((if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6)) != 0) _ = @as(c_int, 2);
18582032 \\ return if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6);
18592033 \\}
18602034 });
......@@ -1870,34 +2044,47 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
18702044 \\ default:
18712045 \\ res = 3 * i;
18722046 \\ break;
2047 \\ break;
18732048 \\ case 4:
2049 \\ case 5:
2050 \\ res = 69;
2051 \\ {
18742052 \\ res = 5;
2053 \\ return;
2054 \\ }
2055 \\ case 6:
2056 \\ res = 1;
2057 \\ return;
18752058 \\ }
18762059 \\}
18772060 , &[_][]const u8{
18782061 \\pub export fn switch_fn(arg_i: c_int) void {
18792062 \\ var i = arg_i;
18802063 \\ var res: c_int = 0;
1881 \\ @"switch": {
1882 \\ case_2: {
1883 \\ default: {
1884 \\ case_1: {
1885 \\ case: {
1886 \\ switch (i) {
1887 \\ @as(c_int, 0) => break :case,
1888 \\ @as(c_int, 1)...@as(c_int, 3) => break :case_1,
1889 \\ else => break :default,
1890 \\ @as(c_int, 4) => break :case_2,
1891 \\ }
1892 \\ }
1893 \\ res = 1;
1894 \\ }
1895 \\ res = 2;
2064 \\ switch (i) {
2065 \\ @as(c_int, 0) => {
2066 \\ res = 1;
2067 \\ res = 2;
2068 \\ res = @as(c_int, 3) * i;
2069 \\ },
2070 \\ @as(c_int, 1)...@as(c_int, 3) => {
2071 \\ res = 2;
2072 \\ res = @as(c_int, 3) * i;
2073 \\ },
2074 \\ else => {
2075 \\ res = @as(c_int, 3) * i;
2076 \\ },
2077 \\ @as(c_int, 4), @as(c_int, 5) => {
2078 \\ res = 69;
2079 \\ {
2080 \\ res = 5;
2081 \\ return;
18962082 \\ }
1897 \\ res = (@as(c_int, 3) * i);
1898 \\ break :@"switch";
1899 \\ }
1900 \\ res = 5;
2083 \\ },
2084 \\ @as(c_int, 6) => {
2085 \\ res = 1;
2086 \\ return;
2087 \\ },
19012088 \\ }
19022089 \\}
19032090 });
......@@ -1973,13 +2160,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19732160 \\ Two,
19742161 \\};
19752162 , &[_][]const u8{
1976 \\pub const One = @enumToInt(enum_unnamed_1.One);
1977 \\pub const Two = @enumToInt(enum_unnamed_1.Two);
19782163 \\const enum_unnamed_1 = extern enum(c_int) {
19792164 \\ One,
19802165 \\ Two,
19812166 \\ _,
19822167 \\};
2168 \\pub const One = @enumToInt(enum_unnamed_1.One);
2169 \\pub const Two = @enumToInt(enum_unnamed_1.Two);
19832170 });
19842171
19852172 cases.add("c style cast",
......@@ -1993,7 +2180,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
19932180 \\}
19942181 });
19952182
1996 // TODO translate-c should in theory be able to figure out to drop all these casts
19972183 cases.add("escape sequences",
19982184 \\const char *escapes() {
19992185 \\char a = '\'',
......@@ -2012,17 +2198,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
20122198 \\
20132199 , &[_][]const u8{
20142200 \\pub export fn escapes() [*c]const u8 {
2015 \\ var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\'')));
2016 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\')));
2017 \\ var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07')));
2018 \\ var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08')));
2019 \\ var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c')));
2020 \\ var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n')));
2021 \\ var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r')));
2022 \\ var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t')));
2023 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b')));
2024 \\ var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00')));
2025 \\ var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"')));
2201 \\ var a: u8 = '\'';
2202 \\ var b: u8 = '\\';
2203 \\ var c: u8 = '\x07';
2204 \\ var d: u8 = '\x08';
2205 \\ var e: u8 = '\x0c';
2206 \\ var f: u8 = '\n';
2207 \\ var g: u8 = '\r';
2208 \\ var h: u8 = '\t';
2209 \\ var i: u8 = '\x0b';
2210 \\ var j: u8 = '\x00';
2211 \\ var k: u8 = '\"';
20262212 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
20272213 \\}
20282214 });
......@@ -2043,12 +2229,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
20432229 \\pub export fn foo() void {
20442230 \\ var a: c_int = 2;
20452231 \\ while (true) {
2046 \\ a = (a - @as(c_int, 1));
2232 \\ a = a - @as(c_int, 1);
20472233 \\ if (!(a != 0)) break;
20482234 \\ }
20492235 \\ var b: c_int = 2;
20502236 \\ while (true) {
2051 \\ b = (b - @as(c_int, 1));
2237 \\ b = b - @as(c_int, 1);
20522238 \\ if (!(b != 0)) break;
20532239 \\ }
20542240 \\}
......@@ -2084,25 +2270,28 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
20842270 \\ C,
20852271 \\ _,
20862272 \\};
2273 \\pub const FooA = @enumToInt(enum_Foo.A);
2274 \\pub const FooB = @enumToInt(enum_Foo.B);
2275 \\pub const FooC = @enumToInt(enum_Foo.C);
20872276 \\pub const SomeTypedef = c_int;
20882277 \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
20892278 \\ var a = arg_a;
20902279 \\ var b = arg_b;
20912280 \\ var c = arg_c;
20922281 \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);
2093 \\ var e: c_int = @boolToInt(((a != 0) and (b != 0)));
2094 \\ var f: c_int = @boolToInt(((b != 0) and (c != null)));
2095 \\ var g: c_int = @boolToInt(((a != 0) and (c != null)));
2096 \\ var h: c_int = @boolToInt(((a != 0) or (b != 0)));
2097 \\ var i: c_int = @boolToInt(((b != 0) or (c != null)));
2098 \\ var j: c_int = @boolToInt(((a != 0) or (c != null)));
2099 \\ var k: c_int = @boolToInt(((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0)));
2100 \\ var l: c_int = @boolToInt(((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0)));
2101 \\ var m: c_int = @boolToInt(((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0)));
2282 \\ var e: c_int = @boolToInt((a != 0) and (b != 0));
2283 \\ var f: c_int = @boolToInt((b != 0) and (c != null));
2284 \\ var g: c_int = @boolToInt((a != 0) and (c != null));
2285 \\ var h: c_int = @boolToInt((a != 0) or (b != 0));
2286 \\ var i: c_int = @boolToInt((b != 0) or (c != null));
2287 \\ var j: c_int = @boolToInt((a != 0) or (c != null));
2288 \\ var k: c_int = @boolToInt((a != 0) or (@bitCast(c_int, @enumToInt(d)) != 0));
2289 \\ var l: c_int = @boolToInt((@bitCast(c_int, @enumToInt(d)) != 0) and (b != 0));
2290 \\ var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0));
21022291 \\ var td: SomeTypedef = 44;
2103 \\ var o: c_int = @boolToInt(((td != 0) or (b != 0)));
2104 \\ var p: c_int = @boolToInt(((c != null) and (td != 0)));
2105 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
2292 \\ var o: c_int = @boolToInt((td != 0) or (b != 0));
2293 \\ var p: c_int = @boolToInt((c != null) and (td != 0));
2294 \\ return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p;
21062295 \\}
21072296 ,
21082297 \\pub const Foo = enum_Foo;
......@@ -2129,6 +2318,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
21292318 \\ B,
21302319 \\ _,
21312320 \\};
2321 \\pub const BarA = @enumToInt(enum_Bar.A);
2322 \\pub const BarB = @enumToInt(enum_Bar.B);
21322323 \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
21332324 ,
21342325 \\pub const Foo = struct_Foo;
......@@ -2143,7 +2334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
21432334 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
21442335 \\ var a = arg_a;
21452336 \\ var b = arg_b;
2146 \\ return ((a & b) ^ (a | b));
2337 \\ return (a & b) ^ (a | b);
21472338 \\}
21482339 });
21492340
......@@ -2162,13 +2353,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
21622353 \\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int {
21632354 \\ var a = arg_a;
21642355 \\ var b = arg_b;
2165 \\ var c: c_int = @boolToInt((a < b));
2166 \\ var d: c_int = @boolToInt((a > b));
2167 \\ var e: c_int = @boolToInt((a <= b));
2168 \\ var f: c_int = @boolToInt((a >= b));
2169 \\ var g: c_int = @boolToInt((c < d));
2170 \\ var h: c_int = @boolToInt((e < f));
2171 \\ var i: c_int = @boolToInt((g < h));
2356 \\ var c: c_int = @boolToInt(a < b);
2357 \\ var d: c_int = @boolToInt(a > b);
2358 \\ var e: c_int = @boolToInt(a <= b);
2359 \\ var f: c_int = @boolToInt(a >= b);
2360 \\ var g: c_int = @boolToInt(c < d);
2361 \\ var h: c_int = @boolToInt(e < f);
2362 \\ var i: c_int = @boolToInt(g < h);
21722363 \\ return i;
21732364 \\}
21742365 });
......@@ -2215,11 +2406,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22152406 \\}
22162407 , &[_][]const u8{
22172408 \\pub export fn foo() c_int {
2218 \\ return (blk: {
2409 \\ return blk: {
22192410 \\ var a: c_int = 1;
22202411 \\ _ = a;
22212412 \\ break :blk a;
2222 \\ });
2413 \\ };
22232414 \\}
22242415 });
22252416
......@@ -2289,8 +2480,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22892480 , &[_][]const u8{
22902481 \\pub export fn foo() void {
22912482 \\ var a: [10]c_longlong = undefined;
2292 \\ var i: c_longlong = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));
2293 \\ a[@intCast(usize, i)] = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));
2483 \\ var i: c_longlong = 0;
2484 \\ a[@intCast(usize, i)] = 0;
22942485 \\}
22952486 });
22962487
......@@ -2302,8 +2493,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
23022493 , &[_][]const u8{
23032494 \\pub export fn foo() void {
23042495 \\ var a: [10]c_uint = undefined;
2305 \\ var i: c_uint = @bitCast(c_uint, @as(c_int, 0));
2306 \\ a[i] = @bitCast(c_uint, @as(c_int, 0));
2496 \\ var i: c_uint = 0;
2497 \\ a[i] = 0;
23072498 \\}
23082499 });
23092500
......@@ -2371,9 +2562,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
23712562 \\ var a: c_int = 2;
23722563 \\ }
23732564 \\ if ((blk: {
2374 \\ _ = @as(c_int, 2);
2375 \\ break :blk @as(c_int, 5);
2376 \\ }) != 0) {
2565 \\ _ = @as(c_int, 2);
2566 \\ break :blk @as(c_int, 5);
2567 \\ }) != 0) {
23772568 \\ var a: c_int = 2;
23782569 \\ }
23792570 \\}
......@@ -2395,6 +2586,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
23952586 \\ C,
23962587 \\ _,
23972588 \\};
2589 \\pub const A = @enumToInt(enum_SomeEnum.A);
2590 \\pub const B = @enumToInt(enum_SomeEnum.B);
2591 \\pub const C = @enumToInt(enum_SomeEnum.C);
23982592 \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
23992593 \\ var a = arg_a;
24002594 \\ var b = arg_b;
......@@ -2484,10 +2678,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
24842678 \\ var f: ?fn () callconv(.C) void = foo;
24852679 \\ var b: ?fn () callconv(.C) c_int = baz;
24862680 \\ f.?();
2487 \\ (f).?();
2681 \\ f.?();
24882682 \\ foo();
24892683 \\ _ = b.?();
2490 \\ _ = (b).?();
2684 \\ _ = b.?();
24912685 \\ _ = baz();
24922686 \\}
24932687 });
......@@ -2508,31 +2702,31 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
25082702 , &[_][]const u8{
25092703 \\pub export fn foo() void {
25102704 \\ var i: c_int = 0;
2511 \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
2705 \\ var u: c_uint = 0;
25122706 \\ i += 1;
25132707 \\ i -= 1;
25142708 \\ u +%= 1;
25152709 \\ u -%= 1;
2516 \\ i = (blk: {
2710 \\ i = blk: {
25172711 \\ const ref = &i;
25182712 \\ ref.* += 1;
25192713 \\ break :blk ref.*;
2520 \\ });
2521 \\ i = (blk: {
2714 \\ };
2715 \\ i = blk: {
25222716 \\ const ref = &i;
25232717 \\ ref.* -= 1;
25242718 \\ break :blk ref.*;
2525 \\ });
2526 \\ u = (blk: {
2719 \\ };
2720 \\ u = blk: {
25272721 \\ const ref = &u;
25282722 \\ ref.* +%= 1;
25292723 \\ break :blk ref.*;
2530 \\ });
2531 \\ u = (blk: {
2724 \\ };
2725 \\ u = blk: {
25322726 \\ const ref = &u;
25332727 \\ ref.* -%= 1;
25342728 \\ break :blk ref.*;
2535 \\ });
2729 \\ };
25362730 \\}
25372731 });
25382732
......@@ -2595,67 +2789,67 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
25952789 , &[_][]const u8{
25962790 \\pub export fn foo() void {
25972791 \\ var a: c_int = 0;
2598 \\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));
2599 \\ a += (blk: {
2792 \\ var b: c_uint = 0;
2793 \\ a += blk: {
26002794 \\ const ref = &a;
2601 \\ ref.* = ref.* + @as(c_int, 1);
2795 \\ ref.* += @as(c_int, 1);
26022796 \\ break :blk ref.*;
2603 \\ });
2604 \\ a -= (blk: {
2797 \\ };
2798 \\ a -= blk: {
26052799 \\ const ref = &a;
2606 \\ ref.* = ref.* - @as(c_int, 1);
2800 \\ ref.* -= @as(c_int, 1);
26072801 \\ break :blk ref.*;
2608 \\ });
2609 \\ a *= (blk: {
2802 \\ };
2803 \\ a *= blk: {
26102804 \\ const ref = &a;
2611 \\ ref.* = ref.* * @as(c_int, 1);
2805 \\ ref.* *= @as(c_int, 1);
26122806 \\ break :blk ref.*;
2613 \\ });
2614 \\ a &= (blk: {
2807 \\ };
2808 \\ a &= blk: {
26152809 \\ const ref = &a;
2616 \\ ref.* = ref.* & @as(c_int, 1);
2810 \\ ref.* &= @as(c_int, 1);
26172811 \\ break :blk ref.*;
2618 \\ });
2619 \\ a |= (blk: {
2812 \\ };
2813 \\ a |= blk: {
26202814 \\ const ref = &a;
2621 \\ ref.* = ref.* | @as(c_int, 1);
2815 \\ ref.* |= @as(c_int, 1);
26222816 \\ break :blk ref.*;
2623 \\ });
2624 \\ a ^= (blk: {
2817 \\ };
2818 \\ a ^= blk: {
26252819 \\ const ref = &a;
2626 \\ ref.* = ref.* ^ @as(c_int, 1);
2820 \\ ref.* ^= @as(c_int, 1);
26272821 \\ break :blk ref.*;
2628 \\ });
2629 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {
2822 \\ };
2823 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), blk: {
26302824 \\ const ref = &a;
2631 \\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2825 \\ ref.* >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
26322826 \\ break :blk ref.*;
2633 \\ }));
2634 \\ a <<= @intCast(@import("std").math.Log2Int(c_int), (blk: {
2827 \\ });
2828 \\ a <<= @intCast(@import("std").math.Log2Int(c_int), blk: {
26352829 \\ const ref = &a;
2636 \\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2830 \\ ref.* <<= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
26372831 \\ break :blk ref.*;
2638 \\ }));
2639 \\ a = @divTrunc(a, (blk: {
2832 \\ });
2833 \\ a = @divTrunc(a, blk: {
26402834 \\ const ref = &a;
26412835 \\ ref.* = @divTrunc(ref.*, @as(c_int, 1));
26422836 \\ break :blk ref.*;
2643 \\ }));
2644 \\ a = @rem(a, (blk: {
2837 \\ });
2838 \\ a = @rem(a, blk: {
26452839 \\ const ref = &a;
26462840 \\ ref.* = @rem(ref.*, @as(c_int, 1));
26472841 \\ break :blk ref.*;
2648 \\ }));
2649 \\ b /= (blk: {
2842 \\ });
2843 \\ b /= blk: {
26502844 \\ const ref = &b;
2651 \\ ref.* = ref.* / @bitCast(c_uint, @as(c_int, 1));
2845 \\ ref.* /= @bitCast(c_uint, @as(c_int, 1));
26522846 \\ break :blk ref.*;
2653 \\ });
2654 \\ b %= (blk: {
2847 \\ };
2848 \\ b %= blk: {
26552849 \\ const ref = &b;
2656 \\ ref.* = ref.* % @bitCast(c_uint, @as(c_int, 1));
2850 \\ ref.* %= @bitCast(c_uint, @as(c_int, 1));
26572851 \\ break :blk ref.*;
2658 \\ });
2852 \\ };
26592853 \\}
26602854 });
26612855
......@@ -2673,47 +2867,47 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
26732867 \\}
26742868 , &[_][]const u8{
26752869 \\pub export fn foo() void {
2676 \\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0));
2677 \\ a +%= (blk: {
2870 \\ var a: c_uint = 0;
2871 \\ a +%= blk: {
26782872 \\ const ref = &a;
2679 \\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1));
2873 \\ ref.* +%= @bitCast(c_uint, @as(c_int, 1));
26802874 \\ break :blk ref.*;
2681 \\ });
2682 \\ a -%= (blk: {
2875 \\ };
2876 \\ a -%= blk: {
26832877 \\ const ref = &a;
2684 \\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1));
2878 \\ ref.* -%= @bitCast(c_uint, @as(c_int, 1));
26852879 \\ break :blk ref.*;
2686 \\ });
2687 \\ a *%= (blk: {
2880 \\ };
2881 \\ a *%= blk: {
26882882 \\ const ref = &a;
2689 \\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1));
2883 \\ ref.* *%= @bitCast(c_uint, @as(c_int, 1));
26902884 \\ break :blk ref.*;
2691 \\ });
2692 \\ a &= (blk: {
2885 \\ };
2886 \\ a &= blk: {
26932887 \\ const ref = &a;
2694 \\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1));
2888 \\ ref.* &= @bitCast(c_uint, @as(c_int, 1));
26952889 \\ break :blk ref.*;
2696 \\ });
2697 \\ a |= (blk: {
2890 \\ };
2891 \\ a |= blk: {
26982892 \\ const ref = &a;
2699 \\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1));
2893 \\ ref.* |= @bitCast(c_uint, @as(c_int, 1));
27002894 \\ break :blk ref.*;
2701 \\ });
2702 \\ a ^= (blk: {
2895 \\ };
2896 \\ a ^= blk: {
27032897 \\ const ref = &a;
2704 \\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1));
2898 \\ ref.* ^= @bitCast(c_uint, @as(c_int, 1));
27052899 \\ break :blk ref.*;
2706 \\ });
2707 \\ a >>= @intCast(@import("std").math.Log2Int(c_uint), (blk: {
2900 \\ };
2901 \\ a >>= @intCast(@import("std").math.Log2Int(c_uint), blk: {
27082902 \\ const ref = &a;
2709 \\ ref.* = ref.* >> @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2903 \\ ref.* >>= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
27102904 \\ break :blk ref.*;
2711 \\ }));
2712 \\ a <<= @intCast(@import("std").math.Log2Int(c_uint), (blk: {
2905 \\ });
2906 \\ a <<= @intCast(@import("std").math.Log2Int(c_uint), blk: {
27132907 \\ const ref = &a;
2714 \\ ref.* = ref.* << @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
2908 \\ ref.* <<= @intCast(@import("std").math.Log2Int(c_int), @as(c_int, 1));
27152909 \\ break :blk ref.*;
2716 \\ }));
2910 \\ });
27172911 \\}
27182912 });
27192913
......@@ -2733,35 +2927,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
27332927 , &[_][]const u8{
27342928 \\pub export fn foo() void {
27352929 \\ var i: c_int = 0;
2736 \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));
2930 \\ var u: c_uint = 0;
27372931 \\ i += 1;
27382932 \\ i -= 1;
27392933 \\ u +%= 1;
27402934 \\ u -%= 1;
2741 \\ i = (blk: {
2935 \\ i = blk: {
27422936 \\ const ref = &i;
27432937 \\ const tmp = ref.*;
27442938 \\ ref.* += 1;
27452939 \\ break :blk tmp;
2746 \\ });
2747 \\ i = (blk: {
2940 \\ };
2941 \\ i = blk: {
27482942 \\ const ref = &i;
27492943 \\ const tmp = ref.*;
27502944 \\ ref.* -= 1;
27512945 \\ break :blk tmp;
2752 \\ });
2753 \\ u = (blk: {
2946 \\ };
2947 \\ u = blk: {
27542948 \\ const ref = &u;
27552949 \\ const tmp = ref.*;
27562950 \\ ref.* +%= 1;
27572951 \\ break :blk tmp;
2758 \\ });
2759 \\ u = (blk: {
2952 \\ };
2953 \\ u = blk: {
27602954 \\ const ref = &u;
27612955 \\ const tmp = ref.*;
27622956 \\ ref.* -%= 1;
27632957 \\ break :blk tmp;
2764 \\ });
2958 \\ };
27652959 \\}
27662960 });
27672961
......@@ -2854,15 +3048,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
28543048 \\ Foo1,
28553049 \\};
28563050 , &[_][]const u8{
2857 \\pub const FooA = @enumToInt(enum_Foo.A);
2858 \\pub const FooB = @enumToInt(enum_Foo.B);
2859 \\pub const Foo1 = @enumToInt(enum_Foo.@"1");
28603051 \\pub const enum_Foo = extern enum(c_int) {
28613052 \\ A = 2,
28623053 \\ B = 5,
28633054 \\ @"1" = 6,
28643055 \\ _,
28653056 \\};
3057 \\pub const FooA = @enumToInt(enum_Foo.A);
3058 \\pub const FooB = @enumToInt(enum_Foo.B);
3059 \\pub const Foo1 = @enumToInt(enum_Foo.@"1");
28663060 ,
28673061 \\pub const Foo = enum_Foo;
28683062 });
......@@ -2872,13 +3066,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
28723066 \\#define BAR (void*) a
28733067 \\#define BAZ (uint32_t)(2)
28743068 , &[_][]const u8{
2875 \\pub fn FOO(bar: anytype) callconv(.Inline) @TypeOf(baz((@import("std").meta.cast(?*c_void, baz)))) {
2876 \\ return baz((@import("std").meta.cast(?*c_void, baz)));
3069 \\pub fn FOO(bar: anytype) callconv(.Inline) @TypeOf(baz(@import("std").meta.cast(?*c_void, baz))) {
3070 \\ return baz(@import("std").meta.cast(?*c_void, baz));
28773071 \\}
28783072 ,
2879 \\pub const BAR = (@import("std").meta.cast(?*c_void, a));
3073 \\pub const BAR = @import("std").meta.cast(?*c_void, a);
28803074 ,
2881 \\pub const BAZ = (@import("std").meta.cast(u32, 2));
3075 \\pub const BAZ = @import("std").meta.cast(u32, 2);
28823076 });
28833077
28843078 cases.add("macro with cast to unsigned short, long, and long long",
......@@ -2886,9 +3080,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
28863080 \\#define CURLAUTH_BASIC ((unsigned long) 1)
28873081 \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1)
28883082 , &[_][]const u8{
2889 \\pub const CURLAUTH_BASIC_BUT_USHORT = (@import("std").meta.cast(c_ushort, 1));
2890 \\pub const CURLAUTH_BASIC = (@import("std").meta.cast(c_ulong, 1));
2891 \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = (@import("std").meta.cast(c_ulonglong, 1));
3083 \\pub const CURLAUTH_BASIC_BUT_USHORT = @import("std").meta.cast(c_ushort, 1);
3084 \\pub const CURLAUTH_BASIC = @import("std").meta.cast(c_ulong, 1);
3085 \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, 1);
28923086 });
28933087
28943088 cases.add("macro conditional operator",
......@@ -2904,9 +3098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29043098 \\}
29053099 , &[_][]const u8{
29063100 \\pub fn foo() callconv(.C) void {
2907 \\ if (true) while (true) {
2908 \\ if (!false) break;
2909 \\ };
3101 \\ if (true) {}
29103102 \\}
29113103 });
29123104
......@@ -2923,27 +3115,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
29233115 \\}
29243116 });
29253117
2926 // TODO: detect to use different block labels here
2927 cases.add("nested assignment",
2928 \\int foo(int *p, int x) {
2929 \\ return *p++ = x;
2930 \\}
2931 , &[_][]const u8{
2932 \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {
2933 \\ var p = arg_p;
2934 \\ var x = arg_x;
2935 \\ return blk: {
2936 \\ const tmp = x;
2937 \\ (blk_1: {
2938 \\ const ref = &p;
2939 \\ const tmp_2 = ref.*;
2940 \\ ref.* += 1;
2941 \\ break :blk_1 tmp_2;
2942 \\ }).?.* = tmp;
2943 \\ break :blk tmp;
2944 \\ };
2945 \\}
2946 });
3118 // TODO fix zig fmt here
3119 // cases.add("nested assignment",
3120 // \\int foo(int *p, int x) {
3121 // \\ return *p++ = x;
3122 // \\}
3123 // , &[_][]const u8{
3124 // \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {
3125 // \\ var p = arg_p;
3126 // \\ var x = arg_x;
3127 // \\ return blk: {
3128 // \\ const tmp = x;
3129 // \\ (blk_1: {
3130 // \\ const ref = &p;
3131 // \\ const tmp_2 = ref.*;
3132 // \\ ref.* += 1;
3133 // \\ break :blk_1 tmp_2;
3134 // \\ }).?.* = tmp;
3135 // \\ break :blk tmp;
3136 // \\ };
3137 // \\}
3138 // });
29473139
29483140 cases.add("widening and truncating integer casting to different signedness",
29493141 \\unsigned long foo(void) {
......@@ -3033,10 +3225,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
30333225 , &[_][]const u8{
30343226 \\pub export fn foo(arg_x: bool) bool {
30353227 \\ var x = arg_x;
3036 \\ var a: bool = (@as(c_int, @boolToInt(x)) != @as(c_int, 1));
3037 \\ var b: bool = (@as(c_int, @boolToInt(a)) != @as(c_int, 0));
3228 \\ var a: bool = @as(c_int, @boolToInt(x)) != @as(c_int, 1);
3229 \\ var b: bool = @as(c_int, @boolToInt(a)) != @as(c_int, 0);
30383230 \\ var c: bool = @ptrToInt(foo) != 0;
3039 \\ return foo((@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b))));
3231 \\ return foo(@as(c_int, @boolToInt(c)) != @as(c_int, @boolToInt(b)));
30403232 \\}
30413233 });
30423234
......@@ -3106,8 +3298,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
31063298 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
31073299 \\
31083300 , &[_][]const u8{
3109 \\pub fn DefaultScreen(dpy: anytype) callconv(.Inline) @TypeOf((@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen) {
3110 \\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;
3301 \\pub fn DefaultScreen(dpy: anytype) callconv(.Inline) @TypeOf(@import("std").meta.cast(_XPrivDisplay, dpy).*.default_screen) {
3302 \\ return @import("std").meta.cast(_XPrivDisplay, dpy).*.default_screen;
31113303 \\}
31123304 });
31133305
......@@ -3115,9 +3307,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
31153307 \\#define NULL ((void*)0)
31163308 \\#define FOO ((int)0x8000)
31173309 , &[_][]const u8{
3118 \\pub const NULL = (@import("std").meta.cast(?*c_void, 0));
3310 \\pub const NULL = @import("std").meta.cast(?*c_void, 0);
31193311 ,
3120 \\pub const FOO = (@import("std").meta.cast(c_int, 0x8000));
3312 \\pub const FOO = @import("std").meta.cast(c_int, 0x8000);
31213313 });
31223314
31233315 if (std.Target.current.abi == .msvc) {