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...@@ -577,6 +577,7 @@ set(ZIG_STAGE2_SOURCES
577 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"577 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"
578 "${CMAKE_SOURCE_DIR}/src/zir.zig"578 "${CMAKE_SOURCE_DIR}/src/zir.zig"
579 "${CMAKE_SOURCE_DIR}/src/zir_sema.zig"579 "${CMAKE_SOURCE_DIR}/src/zir_sema.zig"
580 "${CMAKE_SOURCE_DIR}/src/translate_c/ast.zig"
580)581)
581582
582if(MSVC)583if(MSVC)
lib/std/zig/parser_test.zig+6-6
...@@ -3695,12 +3695,12 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {...@@ -3695,12 +3695,12 @@ test "zig fmt: hexadeciaml float literals with underscore separators" {
3695 );3695 );
3696}3696}
36973697
3698//test "zig fmt: C var args" {3698test "zig fmt: C var args" {
3699// try testCanonical(3699 try testCanonical(
3700// \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;3700 \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;
3701// \\3701 \\
3702// );3702 );
3703//}3703}
37043704
3705//test "zig fmt: Only indent multiline string literals in function calls" {3705//test "zig fmt: Only indent multiline string literals in function calls" {
3706// try testCanonical(3706// 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...@@ -556,14 +556,11 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
556556
557 .builtin_call_two, .builtin_call_two_comma => {557 .builtin_call_two, .builtin_call_two_comma => {
558 if (datas[node].lhs == 0) {558 if (datas[node].lhs == 0) {
559 const params = [_]ast.Node.Index{};559 return renderBuiltinCall(ais, tree, main_tokens[node], &.{}, space);
560 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
561 } else if (datas[node].rhs == 0) {560 } else if (datas[node].rhs == 0) {
562 const params = [_]ast.Node.Index{datas[node].lhs};561 return renderBuiltinCall(ais, tree, main_tokens[node], &.{datas[node].lhs}, space);
563 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
564 } else {562 } else {
565 const params = [_]ast.Node.Index{ datas[node].lhs, datas[node].rhs };563 return renderBuiltinCall(ais, tree, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space);
566 return renderBuiltinCall(ais, tree, main_tokens[node], &params, space);
567 }564 }
568 },565 },
569 .builtin_call, .builtin_call_comma => {566 .builtin_call, .builtin_call_comma => {
...@@ -1319,7 +1316,7 @@ fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.full.FnProto, space: S...@@ -1319,7 +1316,7 @@ fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.full.FnProto, space: S
1319 .r_paren => break,1316 .r_paren => break,
1320 .comma => {1317 .comma => {
1321 try renderToken(ais, tree, last_param_token, .space); // ,1318 try renderToken(ais, tree, last_param_token, .space); // ,
1322 last_param_token += 1;1319 continue;
1323 },1320 },
1324 else => {}, // Parameter type without a name.1321 else => {}, // Parameter type without a name.
1325 }1322 }
src/Compilation.zig+1-1
...@@ -1334,7 +1334,7 @@ pub fn update(self: *Compilation) !void {...@@ -1334,7 +1334,7 @@ pub fn update(self: *Compilation) !void {
1334 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);1334 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
1335 }1335 }
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;
1338 if (!use_stage1) {1338 if (!use_stage1) {
1339 if (self.bin_file.options.module) |module| {1339 if (self.bin_file.options.module) |module| {
1340 module.compile_log_text.shrinkAndFree(module.gpa, 0);1340 module.compile_log_text.shrinkAndFree(module.gpa, 0);
src/astgen.zig+32-38
...@@ -2935,8 +2935,11 @@ fn identifier(...@@ -2935,8 +2935,11 @@ fn identifier(
2935 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});2935 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
2936 }2936 }
29372937
2938 if (getSimplePrimitiveValue(ident_name)) |typed_value| {2938 if (simple_types.get(ident_name)) |val_tag| {
2939 const result = try addZIRInstConst(mod, scope, src, typed_value);2939 const result = try addZIRInstConst(mod, scope, src, TypedValue{
2940 .ty = Type.initTag(.type),
2941 .val = Value.initTag(val_tag),
2942 });
2940 return rvalue(mod, scope, rl, result);2943 return rvalue(mod, scope, rl, result);
2941 }2944 }
29422945
...@@ -3617,42 +3620,33 @@ fn callExpr(...@@ -3617,42 +3620,33 @@ fn callExpr(
3617 return rvalue(mod, scope, rl, result);3620 return rvalue(mod, scope, rl, result);
3618}3621}
36193622
3620fn getSimplePrimitiveValue(name: []const u8) ?TypedValue {3623pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
3621 const simple_types = std.ComptimeStringMap(Value.Tag, .{3624 .{ "u8", .u8_type },
3622 .{ "u8", .u8_type },3625 .{ "i8", .i8_type },
3623 .{ "i8", .i8_type },3626 .{ "isize", .isize_type },
3624 .{ "isize", .isize_type },3627 .{ "usize", .usize_type },
3625 .{ "usize", .usize_type },3628 .{ "c_short", .c_short_type },
3626 .{ "c_short", .c_short_type },3629 .{ "c_ushort", .c_ushort_type },
3627 .{ "c_ushort", .c_ushort_type },3630 .{ "c_int", .c_int_type },
3628 .{ "c_int", .c_int_type },3631 .{ "c_uint", .c_uint_type },
3629 .{ "c_uint", .c_uint_type },3632 .{ "c_long", .c_long_type },
3630 .{ "c_long", .c_long_type },3633 .{ "c_ulong", .c_ulong_type },
3631 .{ "c_ulong", .c_ulong_type },3634 .{ "c_longlong", .c_longlong_type },
3632 .{ "c_longlong", .c_longlong_type },3635 .{ "c_ulonglong", .c_ulonglong_type },
3633 .{ "c_ulonglong", .c_ulonglong_type },3636 .{ "c_longdouble", .c_longdouble_type },
3634 .{ "c_longdouble", .c_longdouble_type },3637 .{ "f16", .f16_type },
3635 .{ "f16", .f16_type },3638 .{ "f32", .f32_type },
3636 .{ "f32", .f32_type },3639 .{ "f64", .f64_type },
3637 .{ "f64", .f64_type },3640 .{ "f128", .f128_type },
3638 .{ "f128", .f128_type },3641 .{ "c_void", .c_void_type },
3639 .{ "c_void", .c_void_type },3642 .{ "bool", .bool_type },
3640 .{ "bool", .bool_type },3643 .{ "void", .void_type },
3641 .{ "void", .void_type },3644 .{ "type", .type_type },
3642 .{ "type", .type_type },3645 .{ "anyerror", .anyerror_type },
3643 .{ "anyerror", .anyerror_type },3646 .{ "comptime_int", .comptime_int_type },
3644 .{ "comptime_int", .comptime_int_type },3647 .{ "comptime_float", .comptime_float_type },
3645 .{ "comptime_float", .comptime_float_type },3648 .{ "noreturn", .noreturn_type },
3646 .{ "noreturn", .noreturn_type },3649});
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}
36563650
3657fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {3651fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {
3658 const tree = scope.tree();3652 const tree = scope.tree();
src/clang.zig+7-4
...@@ -127,6 +127,9 @@ pub const APSInt = opaque {...@@ -127,6 +127,9 @@ pub const APSInt = opaque {
127127
128 pub const getNumWords = ZigClangAPSInt_getNumWords;128 pub const getNumWords = ZigClangAPSInt_getNumWords;
129 extern fn ZigClangAPSInt_getNumWords(*const APSInt) c_uint;129 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;
130};133};
131134
132pub const ASTContext = opaque {135pub const ASTContext = opaque {
...@@ -270,12 +273,12 @@ pub const CompoundAssignOperator = opaque {...@@ -270,12 +273,12 @@ pub const CompoundAssignOperator = opaque {
270273
271pub const CompoundStmt = opaque {274pub const CompoundStmt = opaque {
272 pub const body_begin = ZigClangCompoundStmt_body_begin;275 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
275 pub const body_end = ZigClangCompoundStmt_body_end;278 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;
279};282};
280283
281pub const ConditionalOperator = opaque {};284pub const ConditionalOperator = opaque {};
...@@ -407,7 +410,7 @@ pub const Expr = opaque {...@@ -407,7 +410,7 @@ pub const Expr = opaque {
407 pub const getBeginLoc = ZigClangExpr_getBeginLoc;410 pub const getBeginLoc = ZigClangExpr_getBeginLoc;
408 extern fn ZigClangExpr_getBeginLoc(*const Expr) SourceLocation;411 extern fn ZigClangExpr_getBeginLoc(*const Expr) SourceLocation;
409412
410 pub const EvaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;413 pub const evaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
411 extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstExprUsage, *const ASTContext) bool;414 extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstExprUsage, *const ASTContext) bool;
412};415};
413416
src/translate_c.zig+1786-3707
...@@ -3,23 +3,24 @@...@@ -3,23 +3,24 @@
33
4const std = @import("std");4const std = @import("std");
5const assert = std.debug.assert;5const assert = std.debug.assert;
6const ast = std.zig.ast;
7const Token = std.zig.Token;
8const clang = @import("clang.zig");6const clang = @import("clang.zig");
9const ctok = std.c.tokenizer;7const ctok = std.c.tokenizer;
10const CToken = std.c.Token;8const CToken = std.c.Token;
11const mem = std.mem;9const mem = std.mem;
12const math = std.math;10const math = std.math;
11const ast = @import("translate_c/ast.zig");
12const Node = ast.Node;
13const Tag = Node.Tag;
1314
14const CallingConvention = std.builtin.CallingConvention;15const CallingConvention = std.builtin.CallingConvention;
1516
16pub const ClangErrMsg = clang.Stage2ErrorMsg;17pub const ClangErrMsg = clang.Stage2ErrorMsg;
1718
18pub const Error = error{OutOfMemory};19pub const Error = std.mem.Allocator.Error;
19const TypeError = Error || error{UnsupportedType};20const TypeError = Error || error{UnsupportedType};
20const TransError = TypeError || error{UnsupportedTranslation};21const TransError = TypeError || error{UnsupportedTranslation};
2122
22const SymbolTable = std.StringArrayHashMap(*ast.Node);23const SymbolTable = std.StringArrayHashMap(Node);
23const AliasList = std.ArrayList(struct {24const AliasList = std.ArrayList(struct {
24 alias: []const u8,25 alias: []const u8,
25 name: []const u8,26 name: []const u8,
...@@ -30,23 +31,11 @@ const Scope = struct {...@@ -30,23 +31,11 @@ const Scope = struct {
30 parent: ?*Scope,31 parent: ?*Scope,
3132
32 const Id = enum {33 const Id = enum {
33 Switch,34 block,
34 Block,35 root,
35 Root,36 condition,
36 Condition,37 loop,
37 Loop,38 do_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,
50 };39 };
5140
52 /// Used for the scope of condition expressions, for example `if (cond)`.41 /// Used for the scope of condition expressions, for example `if (cond)`.
...@@ -67,16 +56,15 @@ const Scope = struct {...@@ -67,16 +56,15 @@ const Scope = struct {
67 }56 }
68 };57 };
6958
70 /// Represents an in-progress ast.Node.Block. This struct is stack-allocated.59 /// Represents an in-progress Node.Block. This struct is stack-allocated.
71 /// When it is deinitialized, it produces an ast.Node.Block which is allocated60 /// When it is deinitialized, it produces an Node.Block which is allocated
72 /// into the main arena.61 /// into the main arena.
73 const Block = struct {62 const Block = struct {
74 base: Scope,63 base: Scope,
75 statements: std.ArrayList(*ast.Node),64 statements: std.ArrayList(Node),
76 variables: AliasList,65 variables: AliasList,
77 label: ?ast.TokenIndex,
78 mangle_count: u32 = 0,66 mangle_count: u32 = 0,
79 lbrace: ast.TokenIndex,67 label: ?[]const u8 = null,
8068
81 /// When the block corresponds to a function, keep track of the return type69 /// When the block corresponds to a function, keep track of the return type
82 /// so that the return expression can be cast, if necessary70 /// so that the return expression can be cast, if necessary
...@@ -85,17 +73,14 @@ const Scope = struct {...@@ -85,17 +73,14 @@ const Scope = struct {
85 fn init(c: *Context, parent: *Scope, labeled: bool) !Block {73 fn init(c: *Context, parent: *Scope, labeled: bool) !Block {
86 var blk = Block{74 var blk = Block{
87 .base = .{75 .base = .{
88 .id = .Block,76 .id = .block,
89 .parent = parent,77 .parent = parent,
90 },78 },
91 .statements = std.ArrayList(*ast.Node).init(c.gpa),79 .statements = std.ArrayList(Node).init(c.gpa),
92 .variables = AliasList.init(c.gpa),80 .variables = AliasList.init(c.gpa),
93 .label = null,
94 .lbrace = try appendToken(c, .LBrace, "{"),
95 };81 };
96 if (labeled) {82 if (labeled) {
97 blk.label = try appendIdentifier(c, try blk.makeMangledName(c, "blk"));83 blk.label = try blk.makeMangledName(c, "blk");
98 _ = try appendToken(c, .Colon, ":");
99 }84 }
100 return blk;85 return blk;
101 }86 }
...@@ -106,31 +91,24 @@ const Scope = struct {...@@ -106,31 +91,24 @@ const Scope = struct {
106 self.* = undefined;91 self.* = undefined;
107 }92 }
10893
109 fn complete(self: *Block, c: *Context) !*ast.Node {94 fn complete(self: *Block, c: *Context) !Node {
110 // We reserve 1 extra statement if the parent is a Loop. This is in case of95 if (self.base.parent.?.id == .do_loop) {
111 // do while, we want to put `if (cond) break;` at the end.96 // We reserve 1 extra statement if the parent is a do_loop. This is in case of
112 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);97 // do while, we want to put `if (cond) break;` at the end.
113 const rbrace = try appendToken(c, .RBrace, "}");98 const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .do_loop);
114 if (self.label) |label| {99 var stmts = try c.arena.alloc(Node, alloc_len);
115 const node = try ast.Node.LabeledBlock.alloc(c.arena, alloc_len);100 stmts.len = self.statements.items.len;
116 node.* = .{101 mem.copy(Node, stmts, self.statements.items);
117 .statements_len = self.statements.items.len,102 return Tag.block.create(c.arena, .{
118 .lbrace = self.lbrace,103 .label = self.label,
119 .rbrace = rbrace,104 .stmts = stmts,
120 .label = label,105 });
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;
133 }106 }
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 });
134 }112 }
135113
136 /// Given the desired name, return a name that does not shadow anything from outer scopes.114 /// Given the desired name, return a name that does not shadow anything from outer scopes.
...@@ -174,19 +152,27 @@ const Scope = struct {...@@ -174,19 +152,27 @@ const Scope = struct {
174 sym_table: SymbolTable,152 sym_table: SymbolTable,
175 macro_table: SymbolTable,153 macro_table: SymbolTable,
176 context: *Context,154 context: *Context,
155 nodes: std.ArrayList(Node),
177156
178 fn init(c: *Context) Root {157 fn init(c: *Context) Root {
179 return .{158 return .{
180 .base = .{159 .base = .{
181 .id = .Root,160 .id = .root,
182 .parent = null,161 .parent = null,
183 },162 },
184 .sym_table = SymbolTable.init(c.arena),163 .sym_table = SymbolTable.init(c.gpa),
185 .macro_table = SymbolTable.init(c.arena),164 .macro_table = SymbolTable.init(c.gpa),
186 .context = c,165 .context = c,
166 .nodes = std.ArrayList(Node).init(c.gpa),
187 };167 };
188 }168 }
189169
170 fn deinit(scope: *Root) void {
171 scope.sym_table.deinit();
172 scope.macro_table.deinit();
173 scope.nodes.deinit();
174 }
175
190 /// Check if the global scope contains this name, without looking into the "future", e.g.176 /// Check if the global scope contains this name, without looking into the "future", e.g.
191 /// ignore the preprocessed decl and macro names.177 /// ignore the preprocessed decl and macro names.
192 fn containsNow(scope: *Root, name: []const u8) bool {178 fn containsNow(scope: *Root, name: []const u8) bool {
...@@ -205,20 +191,20 @@ const Scope = struct {...@@ -205,20 +191,20 @@ const Scope = struct {
205 var scope = inner;191 var scope = inner;
206 while (true) {192 while (true) {
207 switch (scope.id) {193 switch (scope.id) {
208 .Root => unreachable,194 .root => unreachable,
209 .Block => return @fieldParentPtr(Block, "base", scope),195 .block => return @fieldParentPtr(Block, "base", scope),
210 .Condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c),196 .condition => return @fieldParentPtr(Condition, "base", scope).getBlockScope(c),
211 else => scope = scope.parent.?,197 else => scope = scope.parent.?,
212 }198 }
213 }199 }
214 }200 }
215201
216 fn findBlockReturnType(inner: *Scope, c: *Context) ?clang.QualType {202 fn findBlockReturnType(inner: *Scope, c: *Context) clang.QualType {
217 var scope = inner;203 var scope = inner;
218 while (true) {204 while (true) {
219 switch (scope.id) {205 switch (scope.id) {
220 .Root => return null,206 .root => unreachable,
221 .Block => {207 .block => {
222 const block = @fieldParentPtr(Block, "base", scope);208 const block = @fieldParentPtr(Block, "base", scope);
223 if (block.return_type) |qt| return qt;209 if (block.return_type) |qt| return qt;
224 scope = scope.parent.?;210 scope = scope.parent.?;
...@@ -230,17 +216,17 @@ const Scope = struct {...@@ -230,17 +216,17 @@ const Scope = struct {
230216
231 fn getAlias(scope: *Scope, name: []const u8) []const u8 {217 fn getAlias(scope: *Scope, name: []const u8) []const u8 {
232 return switch (scope.id) {218 return switch (scope.id) {
233 .Root => return name,219 .root => return name,
234 .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),220 .block => @fieldParentPtr(Block, "base", scope).getAlias(name),
235 .Switch, .Loop, .Condition => scope.parent.?.getAlias(name),221 .loop, .do_loop, .condition => scope.parent.?.getAlias(name),
236 };222 };
237 }223 }
238224
239 fn contains(scope: *Scope, name: []const u8) bool {225 fn contains(scope: *Scope, name: []const u8) bool {
240 return switch (scope.id) {226 return switch (scope.id) {
241 .Root => @fieldParentPtr(Root, "base", scope).contains(name),227 .root => @fieldParentPtr(Root, "base", scope).contains(name),
242 .Block => @fieldParentPtr(Block, "base", scope).contains(name),228 .block => @fieldParentPtr(Block, "base", scope).contains(name),
243 .Switch, .Loop, .Condition => scope.parent.?.contains(name),229 .loop, .do_loop, .condition => scope.parent.?.contains(name),
244 };230 };
245 }231 }
246232
...@@ -248,20 +234,26 @@ const Scope = struct {...@@ -248,20 +234,26 @@ const Scope = struct {
248 var scope = inner;234 var scope = inner;
249 while (true) {235 while (true) {
250 switch (scope.id) {236 switch (scope.id) {
251 .Root => unreachable,237 .root => unreachable,
252 .Switch => return scope,238 .loop, .do_loop => return scope,
253 .Loop => return scope,
254 else => scope = scope.parent.?,239 else => scope = scope.parent.?,
255 }240 }
256 }241 }
257 }242 }
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 {
260 var scope = inner;246 var scope = inner;
261 while (true) {247 while (true) {
262 switch (scope.id) {248 switch (scope.id) {
263 .Root => unreachable,249 .root => {
264 .Switch => return @fieldParentPtr(Switch, "base", scope),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 },
265 else => scope = scope.parent.?,257 else => scope = scope.parent.?,
266 }258 }
267 }259 }
...@@ -271,18 +263,12 @@ const Scope = struct {...@@ -271,18 +263,12 @@ const Scope = struct {
271pub const Context = struct {263pub const Context = struct {
272 gpa: *mem.Allocator,264 gpa: *mem.Allocator,
273 arena: *mem.Allocator,265 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,
279 source_manager: *clang.SourceManager,266 source_manager: *clang.SourceManager,
280 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},267 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},
281 alias_list: AliasList,268 alias_list: AliasList,
282 global_scope: *Scope.Root,269 global_scope: *Scope.Root,
283 clang_context: *clang.ASTContext,270 clang_context: *clang.ASTContext,
284 mangle_count: u32 = 0,271 mangle_count: u32 = 0,
285 root_decls: std.ArrayListUnmanaged(*ast.Node) = .{},
286 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},272 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
287273
288 /// This one is different than the root scope's name table. This contains274 /// This one is different than the root scope's name table. This contains
...@@ -311,90 +297,15 @@ pub const Context = struct {...@@ -311,90 +297,15 @@ pub const Context = struct {
311 const column = c.source_manager.getSpellingColumnNumber(spelling_loc);297 const column = c.source_manager.getSpellingColumnNumber(spelling_loc);
312 return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });298 return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });
313 }299 }
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 }
348};300};
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
391pub fn translate(302pub fn translate(
392 gpa: *mem.Allocator,303 gpa: *mem.Allocator,
393 args_begin: [*]?[*]const u8,304 args_begin: [*]?[*]const u8,
394 args_end: [*]?[*]const u8,305 args_end: [*]?[*]const u8,
395 errors: *[]ClangErrMsg,306 errors: *[]ClangErrMsg,
396 resources_path: [*:0]const u8,307 resources_path: [*:0]const u8,
397) !ast.Tree {308) !std.zig.ast.Tree {
398 const ast_unit = clang.LoadFromCommandLine(309 const ast_unit = clang.LoadFromCommandLine(
399 args_begin,310 args_begin,
400 args_end,311 args_end,
...@@ -407,28 +318,15 @@ pub fn translate(...@@ -407,28 +318,15 @@ pub fn translate(
407 };318 };
408 defer ast_unit.delete();319 defer ast_unit.delete();
409320
410 var source_buffer = std.ArrayList(u8).init(gpa);
411 defer source_buffer.deinit();
412
413 // For memory that has the same lifetime as the Tree that we return321 // For memory that has the same lifetime as the Tree that we return
414 // from this function.322 // from this function.
415 var arena = std.heap.ArenaAllocator.init(gpa);323 var arena = std.heap.ArenaAllocator.init(gpa);
416 errdefer arena.deinit();324 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
426 var context = Context{326 var context = Context{
427 .gpa = gpa,327 .gpa = gpa,
428 .arena = &arena.allocator,328 .arena = &arena.allocator,
429 .source_buffer = &source_buffer,
430 .source_manager = ast_unit.getSourceManager(),329 .source_manager = ast_unit.getSourceManager(),
431 .err = undefined,
432 .alias_list = AliasList.init(gpa),330 .alias_list = AliasList.init(gpa),
433 .global_scope = try arena.allocator.create(Scope.Root),331 .global_scope = try arena.allocator.create(Scope.Root),
434 .clang_context = ast_unit.getASTContext(),332 .clang_context = ast_unit.getASTContext(),
...@@ -437,20 +335,17 @@ pub fn translate(...@@ -437,20 +335,17 @@ pub fn translate(
437 defer {335 defer {
438 context.decl_table.deinit(gpa);336 context.decl_table.deinit(gpa);
439 context.alias_list.deinit();337 context.alias_list.deinit();
440 context.token_ids.deinit(gpa);
441 context.token_locs.deinit(gpa);
442 context.errors.deinit(gpa);
443 context.global_names.deinit(gpa);338 context.global_names.deinit(gpa);
444 context.root_decls.deinit(gpa);
445 context.opaque_demotes.deinit(gpa);339 context.opaque_demotes.deinit(gpa);
340 context.global_scope.deinit();
446 }341 }
447342
448 try addCBuiltinsNamespace(&context);343 try context.global_scope.nodes.append(Tag.usingnamespace_builtins.init());
449344
450 try prepopulateGlobalNameTable(ast_unit, &context);345 try prepopulateGlobalNameTable(ast_unit, &context);
451346
452 if (!ast_unit.visitLocalTopLevelDecls(&context, declVisitorC)) {347 if (!ast_unit.visitLocalTopLevelDecls(&context, declVisitorC)) {
453 return context.err;348 return error.OutOfMemory;
454 }349 }
455350
456 try transPreprocessorEntities(&context, ast_unit);351 try transPreprocessorEntities(&context, ast_unit);
...@@ -458,38 +353,17 @@ pub fn translate(...@@ -458,38 +353,17 @@ pub fn translate(
458 try addMacros(&context);353 try addMacros(&context);
459 for (context.alias_list.items) |alias| {354 for (context.alias_list.items) |alias| {
460 if (!context.global_scope.sym_table.contains(alias.alias)) {355 if (!context.global_scope.sym_table.contains(alias.alias)) {
461 try createAlias(&context, alias);356 const node = try Tag.alias.create(context.arena, .{ .actual = alias.alias, .mangled = alias.name });
462 }357 try addTopLevelDecl(&context, alias.alias, node);
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});
473 }358 }
474 }359 }
475360
476 const tree = try arena.allocator.create(ast.Tree);361 return ast.render(gpa, context.global_scope.nodes.items);
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;
488}362}
489363
490fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {364fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
491 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {365 if (!ast_unit.visitLocalTopLevelDecls(c, declVisitorNamesOnlyC)) {
492 return c.err;366 return error.OutOfMemory;
493 }367 }
494368
495 // TODO if we see #undef, delete it from the table369 // TODO if we see #undef, delete it from the table
...@@ -512,19 +386,13 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {...@@ -512,19 +386,13 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
512386
513fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {387fn declVisitorNamesOnlyC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {
514 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));388 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
515 declVisitorNamesOnly(c, decl) catch |err| {389 declVisitorNamesOnly(c, decl) catch return false;
516 c.err = err;
517 return false;
518 };
519 return true;390 return true;
520}391}
521392
522fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {393fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {
523 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));394 const c = @ptrCast(*Context, @alignCast(@alignOf(Context), context));
524 declVisitor(c, decl) catch |err| {395 declVisitor(c, decl) catch return false;
525 c.err = err;
526 return false;
527 };
528 return true;396 return true;
529}397}
530398
...@@ -541,13 +409,13 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {...@@ -541,13 +409,13 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
541 return visitFnDecl(c, @ptrCast(*const clang.FunctionDecl, decl));409 return visitFnDecl(c, @ptrCast(*const clang.FunctionDecl, decl));
542 },410 },
543 .Typedef => {411 .Typedef => {
544 _ = try transTypeDef(c, @ptrCast(*const clang.TypedefNameDecl, decl), true);412 try transTypeDef(c, &c.global_scope.base, @ptrCast(*const clang.TypedefNameDecl, decl));
545 },413 },
546 .Enum => {414 .Enum => {
547 _ = try transEnumDecl(c, @ptrCast(*const clang.EnumDecl, decl));415 try transEnumDecl(c, &c.global_scope.base, @ptrCast(*const clang.EnumDecl, decl));
548 },416 },
549 .Record => {417 .Record => {
550 _ = try transRecordDecl(c, @ptrCast(*const clang.RecordDecl, decl));418 try transRecordDecl(c, &c.global_scope.base, @ptrCast(*const clang.RecordDecl, decl));
551 },419 },
552 .Var => {420 .Var => {
553 return visitVarDecl(c, @ptrCast(*const clang.VarDecl, decl), null);421 return visitVarDecl(c, @ptrCast(*const clang.VarDecl, decl), null);
...@@ -557,7 +425,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {...@@ -557,7 +425,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
557 },425 },
558 else => {426 else => {
559 const decl_name = try c.str(decl.getDeclKindName());427 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});
561 },429 },
562 }430 }
563}431}
...@@ -573,7 +441,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -573,7 +441,6 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
573 return visitFnDecl(c, def);441 return visitFnDecl(c, def);
574 }442 }
575443
576 const rp = makeRestorePoint(c);
577 const fn_decl_loc = fn_decl.getLocation();444 const fn_decl_loc = fn_decl.getLocation();
578 const has_body = fn_decl.hasBody();445 const has_body = fn_decl.hasBody();
579 const storage_class = fn_decl.getStorageClass();446 const storage_class = fn_decl.getStorageClass();
...@@ -617,9 +484,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -617,9 +484,9 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
617 decl_ctx.has_body = false;484 decl_ctx.has_body = false;
618 decl_ctx.storage_class = .Extern;485 decl_ctx.storage_class = .Extern;
619 decl_ctx.is_export = false;486 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", .{});
621 }488 }
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) {
623 error.UnsupportedType => {490 error.UnsupportedType => {
624 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});491 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
625 },492 },
...@@ -628,7 +495,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -628,7 +495,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
628 },495 },
629 .FunctionNoProto => blk: {496 .FunctionNoProto => blk: {
630 const fn_no_proto_type = @ptrCast(*const clang.FunctionType, fn_type);497 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) {
632 error.UnsupportedType => {499 error.UnsupportedType => {
633 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});500 return failDecl(c, fn_decl_loc, fn_name, "unable to resolve prototype of function", .{});
634 },501 },
...@@ -639,124 +506,99 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {...@@ -639,124 +506,99 @@ fn visitFnDecl(c: *Context, fn_decl: *const clang.FunctionDecl) Error!void {
639 };506 };
640507
641 if (!decl_ctx.has_body) {508 if (!decl_ctx.has_body) {
642 const semi_tok = try appendToken(c, .Semicolon, ";");509 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
643 return addTopLevelDecl(c, fn_name, &proto_node.base);
644 }510 }
645511
646 // actual function definition with body512 // actual function definition with body
647 const body_stmt = fn_decl.getBody();513 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);
649 block_scope.return_type = return_qt;515 block_scope.return_type = return_qt;
650 defer block_scope.deinit();516 defer block_scope.deinit();
651517
652 var scope = &block_scope.base;518 var scope = &block_scope.base;
653519
654 var param_id: c_uint = 0;520 var param_id: c_uint = 0;
655 for (proto_node.params()) |*param, i| {521 for (proto_node.data.params) |*param, i| {
656 const param_name = if (param.name_token) |name_tok|522 const param_name = param.name orelse {
657 tokenSlice(c, name_tok)523 proto_node.data.is_extern = true;
658 else524 proto_node.data.is_export = false;
659 return failDecl(c, fn_decl_loc, fn_name, "function {s} parameter has no name", .{fn_name});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
661 const c_param = fn_decl.getParamDecl(param_id);529 const c_param = fn_decl.getParamDecl(param_id);
662 const qual_type = c_param.getOriginalType();530 const qual_type = c_param.getOriginalType();
663 const is_const = qual_type.isConstQualified();531 const is_const = qual_type.isConstQualified();
664532
665 const mangled_param_name = try block_scope.makeMangledName(c, param_name);533 const mangled_param_name = try block_scope.makeMangledName(c, param_name);
534 param.name = mangled_param_name;
666535
667 if (!is_const) {536 if (!is_const) {
668 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});537 const bare_arg_name = try std.fmt.allocPrint(c.arena, "arg_{s}", .{mangled_param_name});
669 const arg_name = try block_scope.makeMangledName(c, bare_arg_name);538 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");541 const redecl_node = try Tag.arg_redecl.create(c.arena, .{ .actual = mangled_param_name, .mangled = arg_name });
672 const name_tok = try appendIdentifier(c, mangled_param_name);542 try block_scope.statements.append(redecl_node);
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, ":");
687 }543 }
688544
689 param_id += 1;545 param_id += 1;
690 }546 }
691547
692 const casted_body = @ptrCast(*const clang.CompoundStmt, body_stmt);548 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) {
694 error.OutOfMemory => |e| return e,550 error.OutOfMemory => |e| return e,
695 error.UnsupportedTranslation,551 error.UnsupportedTranslation,
696 error.UnsupportedType,552 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 },
698 };559 };
699 // add return statement if the function didn't have one560 // add return statement if the function didn't have one
700 blk: {561 blk: {
701 if (fn_ty.getNoReturnAttr()) break :blk;562 const maybe_body = try block_scope.complete(c);
702 if (isCVoid(return_qt)) break :blk;563 if (fn_ty.getNoReturnAttr() or isCVoid(return_qt) or maybe_body.isNoreturn(false)) {
703564 proto_node.data.body = maybe_body;
704 if (block_scope.statements.items.len > 0) {565 break :blk;
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 }
719 }566 }
720567
721 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{568 const rhs = transZeroInitExpr(c, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {
722 .ltoken = try appendToken(rp.c, .Keyword_return, "return"),569 error.OutOfMemory => |e| return e,
723 .tag = .Return,570 error.UnsupportedTranslation,
724 }, .{571 error.UnsupportedType,
725 .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, return_qt.getTypePtr()) catch |err| switch (err) {572 => {
726 error.OutOfMemory => |e| return e,573 proto_node.data.is_extern = true;
727 error.UnsupportedTranslation,574 proto_node.data.is_export = false;
728 error.UnsupportedType,575 try warn(c, &c.global_scope.base, fn_decl_loc, "unable to create a return value for function, demoted to extern", .{});
729 => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),576 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
730 },577 },
731 });578 };
732 _ = try appendToken(rp.c, .Semicolon, ";");579 const ret = try Tag.@"return".create(c.arena, rhs);
733 try block_scope.statements.append(&return_expr.base);580 try block_scope.statements.append(ret);
581 proto_node.data.body = try block_scope.complete(c);
734 }582 }
735583
736 const body_node = try block_scope.complete(rp.c);584 return addTopLevelDecl(c, fn_name, Node.initPayload(&proto_node.base));
737 proto_node.setBodyNode(body_node);
738 return addTopLevelDecl(c, fn_name, &proto_node.base);
739}585}
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 {
742 return if (decl_init) |init_expr|588 return if (decl_init) |init_expr|
743 transQualTypeInitialized(rp, qt, init_expr, loc)589 transQualTypeInitialized(c, scope, qt, init_expr, loc)
744 else590 else
745 transQualType(rp, qt, loc);591 transQualType(c, scope, qt, loc);
746}592}
593
747/// if mangled_name is not null, this var decl was declared in a block scope.594/// if mangled_name is not null, this var decl was declared in a block scope.
748fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void {595fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]const u8) Error!void {
749 const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());596 const var_name = mangled_name orelse try c.str(@ptrCast(*const clang.NamedDecl, var_decl).getName_bytes_begin());
750 if (c.global_scope.sym_table.contains(var_name))597 if (c.global_scope.sym_table.contains(var_name))
751 return; // Avoid processing this decl twice598 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;
760 const scope = &c.global_scope.base;602 const scope = &c.global_scope.base;
761603
762 // TODO https://github.com/ziglang/zig/issues/3756604 // TODO https://github.com/ziglang/zig/issues/3756
...@@ -775,211 +617,148 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co...@@ -775,211 +617,148 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
775 // does the same as:617 // does the same as:
776 // extern int foo;618 // extern int foo;
777 // int foo = 2;619 // int foo = 2;
778 const extern_tok = if (storage_class == .Extern and !has_init)620 var is_extern = storage_class == .Extern and !has_init;
779 try appendToken(c, .Keyword_extern, "extern")621 var is_export = !is_extern and storage_class != .Static;
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);
791622
792 _ = try appendToken(c, .Colon, ":");623 const type_node = transQualTypeMaybeInitialized(c, scope, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
793
794 const type_node = transQualTypeMaybeInitialized(rp, qual_type, decl_init, var_decl_loc) catch |err| switch (err) {
795 error.UnsupportedTranslation, error.UnsupportedType => {624 error.UnsupportedTranslation, error.UnsupportedType => {
796 return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{});625 return failDecl(c, var_decl_loc, checked_name, "unable to resolve variable type", .{});
797 },626 },
798 error.OutOfMemory => |e| return e,627 error.OutOfMemory => |e| return e,
799 };628 };
800629
801 var eq_tok: ast.TokenIndex = undefined;630 var init_node: ?Node = null;
802 var init_node: ?*ast.Node = null;
803631
804 // If the initialization expression is not present, initialize with undefined.632 // If the initialization expression is not present, initialize with undefined.
805 // If it is an integer literal, we can skip the @as since it will be redundant633 // If it is an integer literal, we can skip the @as since it will be redundant
806 // with the variable type.634 // with the variable type.
807 if (has_init) {635 if (has_init) trans_init: {
808 eq_tok = try appendToken(c, .Equal, "=");
809 if (decl_init) |expr| {636 if (decl_init) |expr| {
810 const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)637 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)
812 else639 else
813 transExprCoercing(rp, scope, expr, .used, .r_value);640 transExprCoercing(c, scope, expr, .used);
814 init_node = node_or_error catch |err| switch (err) {641 init_node = node_or_error catch |err| switch (err) {
815 error.UnsupportedTranslation,642 error.UnsupportedTranslation,
816 error.UnsupportedType,643 error.UnsupportedType,
817 => {644 => {
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;
819 },649 },
820 error.OutOfMemory => |e| return e,650 error.OutOfMemory => |e| return e,
821 };651 };
652 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node.?)) {
653 init_node = try Tag.bool_to_int.create(c.arena, init_node.?);
654 }
822 } else {655 } else {
823 init_node = try transCreateNodeUndefinedLiteral(c);656 init_node = Tag.undefined_literal.init();
824 }657 }
825 } else if (storage_class != .Extern) {658 } else if (storage_class != .Extern) {
826 eq_tok = try appendToken(c, .Equal, "=");
827 // The C language specification states that variables with static or threadlocal659 // The C language specification states that variables with static or threadlocal
828 // storage without an initializer are initialized to a zero value.660 // storage without an initializer are initialized to a zero value.
829661
830 // @import("std").mem.zeroes(T)662 // @import("std").mem.zeroes(T)
831 const import_fn_call = try c.createBuiltinCall("@import", 1);663 init_node = try Tag.std_mem_zeroes.create(c.arena, type_node);
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;
843 }664 }
844665
845 const linksection_expr = blk: {666 const linksection_string = blk: {
846 var str_len: usize = undefined;667 var str_len: usize = undefined;
847 if (var_decl.getSectionAttribute(&str_len)) |str_ptr| {668 if (var_decl.getSectionAttribute(&str_len)) |str_ptr| {
848 _ = try appendToken(rp.c, .Keyword_linksection, "linksection");669 break :blk str_ptr[0..str_len];
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;
857 }670 }
858 break :blk null;671 break :blk null;
859 };672 };
860673
861 const align_expr = blk: {674 const alignment = blk: {
862 const alignment = var_decl.getAlignedAttribute(rp.c.clang_context);675 const alignment = var_decl.getAlignedAttribute(c.clang_context);
863 if (alignment != 0) {676 if (alignment != 0) {
864 _ = try appendToken(rp.c, .Keyword_align, "align");
865 _ = try appendToken(rp.c, .LParen, "(");
866 // Clang reports the alignment in bits677 // Clang reports the alignment in bits
867 const expr = try transCreateNodeInt(rp.c, alignment / 8);678 break :blk alignment / 8;
868 _ = try appendToken(rp.c, .RParen, ")");
869
870 break :blk expr;
871 }679 }
872 break :blk null;680 break :blk null;
873 };681 };
874682
875 const node = try ast.Node.VarDecl.create(c.arena, .{683 const node = try Tag.var_decl.create(c.arena, .{
876 .name_token = name_tok,684 .is_pub = is_pub,
877 .mut_token = mut_tok,685 .is_const = is_const,
878 .semicolon_token = try appendToken(c, .Semicolon, ";"),686 .is_extern = is_extern,
879 }, .{687 .is_export = is_export,
880 .visib_token = visib_tok,688 .is_threadlocal = is_threadlocal,
881 .thread_local_token = thread_local_token,689 .linksection_string = linksection_string,
882 .eq_token = eq_tok,690 .alignment = alignment,
883 .extern_export_token = extern_tok,691 .name = checked_name,
884 .type_node = type_node,692 .type = type_node,
885 .align_node = align_expr,693 .init = init_node,
886 .section_node = linksection_expr,
887 .init_node = init_node,
888 });694 });
889 return addTopLevelDecl(c, checked_name, &node.base);695 return addTopLevelDecl(c, checked_name, node);
890}696}
891697
892fn transTypeDefAsBuiltin(c: *Context, typedef_decl: *const clang.TypedefNameDecl, builtin_name: []const u8) !*ast.Node {698const builtin_typedef_map = std.ComptimeStringMap([]const u8, .{
893 _ = try c.decl_table.put(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin_name);699 .{ "uint8_t", "u8" },
894 return transCreateNodeIdentifier(c, builtin_name);700 .{ "int8_t", "i8" },
895}701 .{ "uint16_t", "u16" },
896702 .{ "int16_t", "i16" },
897fn checkForBuiltinTypedef(checked_name: []const u8) ?[]const u8 {703 .{ "uint32_t", "u32" },
898 const table = [_][2][]const u8{704 .{ "int32_t", "i32" },
899 .{ "uint8_t", "u8" },705 .{ "uint64_t", "u64" },
900 .{ "int8_t", "i8" },706 .{ "int64_t", "i64" },
901 .{ "uint16_t", "u16" },707 .{ "intptr_t", "isize" },
902 .{ "int16_t", "i16" },708 .{ "uintptr_t", "usize" },
903 .{ "uint32_t", "u32" },709 .{ "ssize_t", "isize" },
904 .{ "int32_t", "i32" },710 .{ "size_t", "usize" },
905 .{ "uint64_t", "u64" },711});
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}
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 {
923 if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name|714 if (c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl()))) |name|
924 return transCreateNodeIdentifier(c, name); // Avoid processing this decl twice715 return; // Avoid processing this decl twice
925 const rp = makeRestorePoint(c);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
929 // TODO https://github.com/ziglang/zig/issues/3756721 // TODO https://github.com/ziglang/zig/issues/3756
930 // TODO https://github.com/ziglang/zig/issues/1802722 // 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;723 var name: []const u8 = if (isZigPrimitiveType(bare_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ bare_name, c.getMangle() }) else bare_name;
932 if (checkForBuiltinTypedef(checked_name)) |builtin| {724 if (builtin_typedef_map.get(name)) |builtin| {
933 return transTypeDefAsBuiltin(c, typedef_decl, builtin);725 return c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), builtin);
934 }726 }
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, "=");
956 const child_qt = typedef_decl.getUnderlyingType();730 const child_qt = typedef_decl.getUnderlyingType();
957 const typedef_loc = typedef_decl.getLocation();731 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) {
959 error.UnsupportedType => {733 error.UnsupportedType => {
960 try failDecl(rp.c, typedef_loc, checked_name, "unable to resolve typedef child type", .{});734 return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{});
961 return null;
962 },735 },
963 error.OutOfMemory => |e| return e,736 error.OutOfMemory => |e| return e,
964 };737 };
965 const semicolon_token = try appendToken(rp.c, .Semicolon, ";");738
966739 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
967 const node = try ast.Node.VarDecl.create(rp.c.arena, .{740 payload.* = .{
968 .name_token = name_tok,741 .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(toplevel)] },
969 .mut_token = mut_tok,742 .data = .{
970 .semicolon_token = semicolon_token,743 .name = name,
971 }, .{744 .init = init_node,
972 .visib_token = visib_tok,745 },
973 .eq_token = eq_token,746 };
974 .init_node = init_node,747 const node = Node.initPayload(&payload.base);
975 });748
976 return &node.base;749 if (toplevel) {
750 try addTopLevelDecl(c, name, node);
751 } else {
752 try scope.appendNode(node);
753 }
977}754}
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 {
980 if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name|757 if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |name|
981 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice758 return; // Avoid processing this decl twice
982 const record_loc = record_decl.getLocation();759 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
984 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());763 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
985 var is_unnamed = false;764 var is_unnamed = false;
...@@ -991,46 +770,31 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as...@@ -991,46 +770,31 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as
991 }770 }
992771
993 var container_kind_name: []const u8 = undefined;772 var container_kind_name: []const u8 = undefined;
994 var container_kind: std.zig.Token.Id = undefined;773 var is_union = false;
995 if (record_decl.isUnion()) {774 if (record_decl.isUnion()) {
996 container_kind_name = "union";775 container_kind_name = "union";
997 container_kind = .Keyword_union;776 is_union = true;
998 } else if (record_decl.isStruct()) {777 } else if (record_decl.isStruct()) {
999 container_kind_name = "struct";778 container_kind_name = "struct";
1000 container_kind = .Keyword_struct;
1001 } else {779 } else {
1002 try emitWarning(c, record_loc, "record {s} is not a struct or union", .{bare_name});780 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), bare_name);
1003 return null;781 return failDecl(c, record_loc, bare_name, "record {s} is not a struct or union", .{bare_name});
1004 }782 }
1005783
1006 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });784 var name: []const u8 = 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);785 if (!toplevel) name = try bs.makeMangledName(c, name);
1008786 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
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);
1012787
1013 const eq_token = try appendToken(c, .Equal, "=");788 const is_pub = toplevel and !is_unnamed;
1014
1015 var semicolon: ast.TokenIndex = undefined;
1016 const init_node = blk: {789 const init_node = blk: {
1017 const rp = makeRestorePoint(c);
1018 const record_def = record_decl.getDefinition() orelse {790 const record_def = record_decl.getDefinition() orelse {
1019 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});791 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1020 const opaque_type = try transCreateNodeOpaqueType(c);792 break :blk Tag.opaque_literal.init();
1021 semicolon = try appendToken(c, .Semicolon, ";");
1022 break :blk opaque_type;
1023 };793 };
1024794
1025 const layout_tok = try if (record_decl.getPackedAttribute())795 const is_packed = record_decl.getPackedAttribute();
1026 appendToken(c, .Keyword_packed, "packed")796 var fields = std.ArrayList(ast.Payload.Record.Field).init(c.gpa);
1027 else797 defer fields.deinit();
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();
1034798
1035 var unnamed_field_count: u32 = 0;799 var unnamed_field_count: u32 = 0;
1036 var it = record_def.field_begin();800 var it = record_def.field_begin();
...@@ -1042,111 +806,88 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as...@@ -1042,111 +806,88 @@ fn transRecordDecl(c: *Context, record_decl: *const clang.RecordDecl) Error!?*as
1042806
1043 if (field_decl.isBitField()) {807 if (field_decl.isBitField()) {
1044 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});808 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1045 const opaque_type = try transCreateNodeOpaqueType(c);809 try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
1046 semicolon = try appendToken(c, .Semicolon, ";");810 break :blk Tag.opaque_literal.init();
1047 try emitWarning(c, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
1048 break :blk opaque_type;
1049 }811 }
1050812
1051 if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) {813 if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) {
1052 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});814 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1053 const opaque_type = try transCreateNodeOpaqueType(c);815 try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
1054 semicolon = try appendToken(c, .Semicolon, ";");816 break :blk Tag.opaque_literal.init();
1055 try emitWarning(c, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
1056 break :blk opaque_type;
1057 }817 }
1058818
1059 var is_anon = false;819 var is_anon = false;
1060 var raw_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());820 var field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
1061 if (field_decl.isAnonymousStructOrUnion() or raw_name.len == 0) {821 if (field_decl.isAnonymousStructOrUnion() or field_name.len == 0) {
1062 // Context.getMangle() is not used here because doing so causes unpredictable field names for anonymous fields.822 // 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});
1064 unnamed_field_count += 1;824 unnamed_field_count += 1;
1065 is_anon = true;825 is_anon = true;
1066 }826 }
1067 const field_name = try appendIdentifier(c, raw_name);827 const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) {
1068 _ = try appendToken(c, .Colon, ":");
1069 const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
1070 error.UnsupportedType => {828 error.UnsupportedType => {
1071 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});829 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
1072 const opaque_type = try transCreateNodeOpaqueType(c);830 try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name });
1073 semicolon = try appendToken(c, .Semicolon, ";");831 break :blk Tag.opaque_literal.init();
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;
1076 },832 },
1077 else => |e| return e,833 else => |e| return e,
1078 };834 };
1079835
1080 const align_expr = blk_2: {836 const alignment = blk_2: {
1081 const alignment = field_decl.getAlignedAttribute(c.clang_context);837 const alignment = field_decl.getAlignedAttribute(c.clang_context);
1082 if (alignment != 0) {838 if (alignment != 0) {
1083 _ = try appendToken(c, .Keyword_align, "align");
1084 _ = try appendToken(c, .LParen, "(");
1085 // Clang reports the alignment in bits839 // Clang reports the alignment in bits
1086 const expr = try transCreateNodeInt(c, alignment / 8);840 break :blk_2 alignment / 8;
1087 _ = try appendToken(c, .RParen, ")");
1088
1089 break :blk_2 expr;
1090 }841 }
1091 break :blk_2 null;842 break :blk_2 null;
1092 };843 };
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
1104 if (is_anon) {845 if (is_anon) {
1105 _ = try c.decl_table.put(846 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name);
1106 c.gpa,
1107 @ptrToInt(field_decl.getCanonicalDecl()),
1108 raw_name,
1109 );
1110 }847 }
1111848
1112 try fields_and_decls.append(&field_node.base);849 try fields.append(.{
1113 _ = try appendToken(c, .Comma, ",");850 .name = field_name,
851 .type = field_type,
852 .alignment = alignment,
853 });
1114 }854 }
1115 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);855
1116 container_node.* = .{856 const record_payload = try c.arena.create(ast.Payload.Record);
1117 .layout_token = layout_tok,857 record_payload.* = .{
1118 .kind_token = container_tok,858 .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] },
1119 .init_arg_expr = .None,859 .data = .{
1120 .fields_and_decls_len = fields_and_decls.items.len,860 .is_packed = is_packed,
1121 .lbrace_token = lbrace_token,861 .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items),
1122 .rbrace_token = try appendToken(c, .RBrace, "}"),862 },
1123 };863 };
1124 mem.copy(*ast.Node, container_node.fieldsAndDecls(), fields_and_decls.items);864 break :blk Node.initPayload(&record_payload.base);
1125 semicolon = try appendToken(c, .Semicolon, ";");
1126 break :blk &container_node.base;
1127 };865 };
1128866
1129 const node = try ast.Node.VarDecl.create(c.arena, .{867 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
1130 .name_token = name_tok,868 payload.* = .{
1131 .mut_token = mut_tok,869 .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
1132 .semicolon_token = semicolon,870 .data = .{
1133 }, .{871 .name = name,
1134 .visib_token = visib_tok,872 .init = init_node,
1135 .eq_token = eq_token,873 },
1136 .init_node = init_node,874 };
1137 });
1138875
1139 try addTopLevelDecl(c, name, &node.base);876 if (toplevel) {
1140 if (!is_unnamed)877 try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
1141 try c.alias_list.append(.{ .alias = bare_name, .name = name });878 if (!is_unnamed)
1142 return transCreateNodeIdentifier(c, name);879 try c.alias_list.append(.{ .alias = bare_name, .name = name });
880 } else {
881 try scope.appendNode(Node.initPayload(&payload.base));
882 }
1143}883}
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 {
1146 if (c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |name|886 if (c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |name|
1147 return try transCreateNodeIdentifier(c, name); // Avoid processing this decl twice887 return; // Avoid processing this decl twice
1148 const rp = makeRestorePoint(c);
1149 const enum_loc = enum_decl.getLocation();888 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
1151 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());892 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
1152 var is_unnamed = false;893 var is_unnamed = false;
...@@ -1155,13 +896,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node...@@ -1155,13 +896,13 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1155 is_unnamed = true;896 is_unnamed = true;
1156 }897 }
1157898
1158 const name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});899 var name: []const u8 = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
1159 _ = try c.decl_table.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), 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;903 const is_pub = toplevel and !is_unnamed;
1162 const mut_tok = try appendToken(c, .Keyword_const, "const");904 var redecls = std.ArrayList(Tag.enum_redecl.Data()).init(c.gpa);
1163 const name_tok = try appendIdentifier(c, name);905 defer redecls.deinit();
1164 const eq_token = try appendToken(c, .Equal, "=");
1165906
1166 const init_node = if (enum_decl.getDefinition()) |enum_def| blk: {907 const init_node = if (enum_decl.getDefinition()) |enum_def| blk: {
1167 var pure_enum = true;908 var pure_enum = true;
...@@ -1175,11 +916,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node...@@ -1175,11 +916,8 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1175 }916 }
1176 }917 }
1177918
1178 const extern_tok = try appendToken(c, .Keyword_extern, "extern");919 var fields = std.ArrayList(ast.Payload.Enum.Field).init(c.gpa);
1179 const container_tok = try appendToken(c, .Keyword_enum, "enum");920 defer fields.deinit();
1180
1181 var fields_and_decls = std.ArrayList(*ast.Node).init(c.gpa);
1182 defer fields_and_decls.deinit();
1183921
1184 const int_type = enum_decl.getIntegerType();922 const int_type = enum_decl.getIntegerType();
1185 // The underlying type may be null in case of forward-declared enum923 // 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...@@ -1187,30 +925,22 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1187 // default to the usual integer type used for all the enums.925 // default to the usual integer type used for all the enums.
1188926
1189 // default to c_int since msvc and gcc default to different types927 // default to c_int since msvc and gcc default to different types
1190 _ = try appendToken(c, .LParen, "(");928 const init_arg_expr = if (int_type.ptr != null and
1191 const init_arg_expr = ast.Node.ContainerDecl.InitArg{929 !isCBuiltinType(int_type, .UInt) and
1192 .Type = if (int_type.ptr != null and930 !isCBuiltinType(int_type, .Int))
1193 !isCBuiltinType(int_type, .UInt) and931 transQualType(c, scope, int_type, enum_loc) catch |err| switch (err) {
1194 !isCBuiltinType(int_type, .Int))932 error.UnsupportedType => {
1195 transQualType(rp, int_type, enum_loc) catch |err| switch (err) {933 return failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});
1196 error.UnsupportedType => {934 },
1197 try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{});935 else => |e| return e,
1198 return null;936 }
1199 },937 else
1200 else => |e| return e,938 try Tag.type.create(c.arena, "c_int");
1201 }
1202 else
1203 try transCreateNodeIdentifier(c, "c_int"),
1204 };
1205 _ = try appendToken(c, .RParen, ")");
1206
1207 const lbrace_token = try appendToken(c, .LBrace, "{");
1208939
1209 it = enum_def.enumerator_begin();940 it = enum_def.enumerator_begin();
1210 end_it = enum_def.enumerator_end();941 end_it = enum_def.enumerator_end();
1211 while (it.neq(end_it)) : (it = it.next()) {942 while (it.neq(end_it)) : (it = it.next()) {
1212 const enum_const = it.deref();943 const enum_const = it.deref();
1213
1214 const enum_val_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());944 const enum_val_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_const).getName_bytes_begin());
1215945
1216 const field_name = if (!is_unnamed and mem.startsWith(u8, enum_val_name, bare_name))946 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...@@ -1218,123 +948,62 @@ fn transEnumDecl(c: *Context, enum_decl: *const clang.EnumDecl) Error!?*ast.Node
1218 else948 else
1219 enum_val_name;949 enum_val_name;
1220950
1221 const field_name_tok = try appendIdentifier(c, field_name);951 const int_node = if (!pure_enum)
1222952 try transCreateNodeAPInt(c, enum_const.getInitVal())
1223 const int_node = if (!pure_enum) blk_2: {953 else
1224 _ = try appendToken(c, .Colon, "=");
1225 break :blk_2 try transCreateNodeAPInt(c, enum_const.getInitVal());
1226 } else
1227 null;954 null;
1228955
1229 const field_node = try c.arena.create(ast.Node.ContainerField);956 try fields.append(.{
1230 field_node.* = .{957 .name = field_name,
1231 .doc_comments = null,958 .value = int_node,
1232 .comptime_token = null,959 });
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, ",");
1241960
1242 // In C each enum value is in the global namespace. So we put them there too.961 // In C each enum value is in the global namespace. So we put them there too.
1243 // At this point we can rely on the enum emitting successfully.962 // At this point we can rely on the enum emitting successfully.
1244 const tld_visib_tok = try appendToken(c, .Keyword_pub, "pub");963 try redecls.append(.{
1245 const tld_mut_tok = try appendToken(c, .Keyword_const, "const");964 .enum_val_name = enum_val_name,
1246 const tld_name_tok = try appendIdentifier(c, enum_val_name);965 .field_name = field_name,
1247 const tld_eq_token = try appendToken(c, .Equal, "=");966 .enum_name = name,
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,
1271 });967 });
1272 try addTopLevelDecl(c, field_name, &tld_node.base);
1273 }968 }
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);970 break :blk try Tag.@"enum".create(c.arena, .{
1286 _ = try appendToken(c, .Comma, ",");971 .int_type = init_arg_expr,
1287 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, fields_and_decls.items.len);972 .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items),
1288 container_node.* = .{973 });
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;
1298 } else blk: {974 } else blk: {
1299 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});975 _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
1300 break :blk try transCreateNodeOpaqueType(c);976 break :blk Tag.opaque_literal.init();
1301 };977 };
1302978
1303 const semicolon_token = try appendToken(c, .Semicolon, ";");979 const payload = try c.arena.create(ast.Payload.SimpleVarDecl);
1304 const node = try ast.Node.VarDecl.create(c.arena, .{980 payload.* = .{
1305 .name_token = name_tok,981 .base = .{ .tag = ([2]Tag{ .var_simple, .pub_var_simple })[@boolToInt(is_pub)] },
1306 .mut_token = mut_tok,982 .data = .{
1307 .semicolon_token = semicolon_token,983 .name = name,
1308 }, .{984 .init = init_node,
1309 .visib_token = visib_tok,985 },
1310 .eq_token = eq_token,986 };
1311 .init_node = init_node,
1312 });
1313987
1314 try addTopLevelDecl(c, name, &node.base);988 if (toplevel) {
1315 if (!is_unnamed)989 try addTopLevelDecl(c, name, Node.initPayload(&payload.base));
1316 try c.alias_list.append(.{ .alias = bare_name, .name = name });990 if (!is_unnamed)
1317 return transCreateNodeIdentifier(c, name);991 try c.alias_list.append(.{ .alias = bare_name, .name = name });
1318}992 } else {
1319993 try scope.appendNode(Node.initPayload(&payload.base));
1320fn createAlias(c: *Context, alias: anytype) !void {994 }
1321 const visib_tok = try appendToken(c, .Keyword_pub, "pub");995
1322 const mut_tok = try appendToken(c, .Keyword_const, "const");996 for (redecls.items) |redecl| {
1323 const name_tok = try appendIdentifier(c, alias.alias);997 if (toplevel) {
1324 const eq_token = try appendToken(c, .Equal, "=");998 try addTopLevelDecl(c, redecl.field_name, try Tag.pub_enum_redecl.create(c.arena, redecl));
1325 const init_node = try transCreateNodeIdentifier(c, alias.name);999 } else {
1326 const semicolon_token = try appendToken(c, .Semicolon, ";");1000 try scope.appendNode(try Tag.enum_redecl.create(c.arena, .{
13271001 .enum_val_name = try bs.makeMangledName(c, redecl.enum_val_name),
1328 const node = try ast.Node.VarDecl.create(c.arena, .{1002 .field_name = redecl.field_name,
1329 .name_token = name_tok,1003 .enum_name = redecl.enum_name,
1330 .mut_token = mut_tok,1004 }));
1331 .semicolon_token = semicolon_token,1005 }
1332 }, .{1006 }
1333 .visib_token = visib_tok,
1334 .eq_token = eq_token,
1335 .init_node = init_node,
1336 });
1337 return addTopLevelDecl(c, alias.alias, &node.base);
1338}1007}
13391008
1340const ResultUsed = enum {1009const ResultUsed = enum {
...@@ -1342,317 +1011,252 @@ const ResultUsed = enum {...@@ -1342,317 +1011,252 @@ const ResultUsed = enum {
1342 unused,1011 unused,
1343};1012};
13441013
1345const LRValue = enum {
1346 l_value,
1347 r_value,
1348};
1349
1350fn transStmt(1014fn transStmt(
1351 rp: RestorePoint,1015 c: *Context,
1352 scope: *Scope,1016 scope: *Scope,
1353 stmt: *const clang.Stmt,1017 stmt: *const clang.Stmt,
1354 result_used: ResultUsed,1018 result_used: ResultUsed,
1355 lrvalue: LRValue,1019) TransError!Node {
1356) TransError!*ast.Node {
1357 const sc = stmt.getStmtClass();1020 const sc = stmt.getStmtClass();
1358 switch (sc) {1021 switch (sc) {
1359 .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used),1022 .BinaryOperatorClass => return transBinaryOperator(c, scope, @ptrCast(*const clang.BinaryOperator, stmt), result_used),
1360 .CompoundStmtClass => return transCompoundStmt(rp, scope, @ptrCast(*const clang.CompoundStmt, stmt)),1023 .CompoundStmtClass => return transCompoundStmt(c, scope, @ptrCast(*const clang.CompoundStmt, stmt)),
1361 .CStyleCastExprClass => return transCStyleCastExprClass(rp, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used, lrvalue),1024 .CStyleCastExprClass => return transCStyleCastExprClass(c, scope, @ptrCast(*const clang.CStyleCastExpr, stmt), result_used),
1362 .DeclStmtClass => return transDeclStmt(rp, scope, @ptrCast(*const clang.DeclStmt, stmt)),1025 .DeclStmtClass => return transDeclStmt(c, scope, @ptrCast(*const clang.DeclStmt, stmt)),
1363 .DeclRefExprClass => return transDeclRefExpr(rp, scope, @ptrCast(*const clang.DeclRefExpr, stmt), lrvalue),1026 .DeclRefExprClass => return transDeclRefExpr(c, scope, @ptrCast(*const clang.DeclRefExpr, stmt)),
1364 .ImplicitCastExprClass => return transImplicitCastExpr(rp, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used),1027 .ImplicitCastExprClass => return transImplicitCastExpr(c, scope, @ptrCast(*const clang.ImplicitCastExpr, stmt), result_used),
1365 .IntegerLiteralClass => return transIntegerLiteral(rp, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as),1028 .IntegerLiteralClass => return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, stmt), result_used, .with_as),
1366 .ReturnStmtClass => return transReturnStmt(rp, scope, @ptrCast(*const clang.ReturnStmt, stmt)),1029 .ReturnStmtClass => return transReturnStmt(c, scope, @ptrCast(*const clang.ReturnStmt, stmt)),
1367 .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),1030 .StringLiteralClass => return transStringLiteral(c, scope, @ptrCast(*const clang.StringLiteral, stmt), result_used),
1368 .ParenExprClass => {1031 .ParenExprClass => {
1369 const expr = try transExpr(rp, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used, lrvalue);1032 const expr = try transExpr(c, scope, @ptrCast(*const clang.ParenExpr, stmt).getSubExpr(), .used);
1370 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);1033 return maybeSuppressResult(c, scope, result_used, expr);
1371 const node = try rp.c.arena.create(ast.Node.GroupedExpression);1034 },
1372 node.* = .{1035 .InitListExprClass => return transInitListExpr(c, scope, @ptrCast(*const clang.InitListExpr, stmt), result_used),
1373 .lparen = try appendToken(rp.c, .LParen, "("),1036 .ImplicitValueInitExprClass => return transImplicitValueInitExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1374 .expr = expr,1037 .IfStmtClass => return transIfStmt(c, scope, @ptrCast(*const clang.IfStmt, stmt)),
1375 .rparen = try appendToken(rp.c, .RParen, ")"),1038 .WhileStmtClass => return transWhileLoop(c, scope, @ptrCast(*const clang.WhileStmt, stmt)),
1376 };1039 .DoStmtClass => return transDoWhileLoop(c, scope, @ptrCast(*const clang.DoStmt, stmt)),
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)),
1384 .NullStmtClass => {1040 .NullStmtClass => {
1385 const block = try rp.c.createBlock(0);1041 return Tag.empty_block.init();
1386 block.rbrace = try appendToken(rp.c, .RBrace, "}");1042 },
1387 return &block.base;1043 .ContinueStmtClass => return Tag.@"continue".init(),
1388 },1044 .BreakStmtClass => return Tag.@"break".init(),
1389 .ContinueStmtClass => return try transCreateNodeContinue(rp.c),1045 .ForStmtClass => return transForLoop(c, scope, @ptrCast(*const clang.ForStmt, stmt)),
1390 .BreakStmtClass => return transBreak(rp, scope),1046 .FloatingLiteralClass => return transFloatingLiteral(c, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
1391 .ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const clang.ForStmt, stmt)),
1392 .FloatingLiteralClass => return transFloatingLiteral(rp, scope, @ptrCast(*const clang.FloatingLiteral, stmt), result_used),
1393 .ConditionalOperatorClass => {1047 .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);
1395 },1049 },
1396 .BinaryConditionalOperatorClass => {1050 .BinaryConditionalOperatorClass => {
1397 return transBinaryConditionalOperator(rp, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used);1051 return transBinaryConditionalOperator(c, scope, @ptrCast(*const clang.BinaryConditionalOperator, stmt), result_used);
1398 },1052 },
1399 .SwitchStmtClass => return transSwitch(rp, scope, @ptrCast(*const clang.SwitchStmt, stmt)),1053 .SwitchStmtClass => return transSwitch(c, scope, @ptrCast(*const clang.SwitchStmt, stmt)),
1400 .CaseStmtClass => return transCase(rp, scope, @ptrCast(*const clang.CaseStmt, stmt)),1054 .CaseStmtClass, .DefaultStmtClass => {
1401 .DefaultStmtClass => return transDefault(rp, scope, @ptrCast(*const clang.DefaultStmt, stmt)),1055 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO complex switch", .{});
1402 .ConstantExprClass => return transConstantExpr(rp, scope, @ptrCast(*const clang.Expr, stmt), result_used),1056 },
1403 .PredefinedExprClass => return transPredefinedExpr(rp, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used),1057 .ConstantExprClass => return transConstantExpr(c, scope, @ptrCast(*const clang.Expr, stmt), result_used),
1404 .CharacterLiteralClass => return transCharLiteral(rp, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as),1058 .PredefinedExprClass => return transPredefinedExpr(c, scope, @ptrCast(*const clang.PredefinedExpr, stmt), result_used),
1405 .StmtExprClass => return transStmtExpr(rp, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used),1059 .CharacterLiteralClass => return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, stmt), result_used, .with_as),
1406 .MemberExprClass => return transMemberExpr(rp, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used),1060 .StmtExprClass => return transStmtExpr(c, scope, @ptrCast(*const clang.StmtExpr, stmt), result_used),
1407 .ArraySubscriptExprClass => return transArrayAccess(rp, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used),1061 .MemberExprClass => return transMemberExpr(c, scope, @ptrCast(*const clang.MemberExpr, stmt), result_used),
1408 .CallExprClass => return transCallExpr(rp, scope, @ptrCast(*const clang.CallExpr, stmt), result_used),1062 .ArraySubscriptExprClass => return transArrayAccess(c, scope, @ptrCast(*const clang.ArraySubscriptExpr, stmt), result_used),
1409 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(rp, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used),1063 .CallExprClass => return transCallExpr(c, scope, @ptrCast(*const clang.CallExpr, stmt), result_used),
1410 .UnaryOperatorClass => return transUnaryOperator(rp, scope, @ptrCast(*const clang.UnaryOperator, stmt), result_used),1064 .UnaryExprOrTypeTraitExprClass => return transUnaryExprOrTypeTraitExpr(c, scope, @ptrCast(*const clang.UnaryExprOrTypeTraitExpr, stmt), result_used),
1411 .CompoundAssignOperatorClass => return transCompoundAssignOperator(rp, scope, @ptrCast(*const clang.CompoundAssignOperator, 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),
1412 .OpaqueValueExprClass => {1067 .OpaqueValueExprClass => {
1413 const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;1068 const source_expr = @ptrCast(*const clang.OpaqueValueExpr, stmt).getSourceExpr().?;
1414 const expr = try transExpr(rp, scope, source_expr, .used, lrvalue);1069 const expr = try transExpr(c, scope, source_expr, .used);
1415 if (expr.tag == .GroupedExpression) return maybeSuppressResult(rp, scope, result_used, expr);1070 return maybeSuppressResult(c, 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);
1423 },1071 },
1424 else => {1072 else => {
1425 return revertAndWarn(1073 return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
1426 rp,
1427 error.UnsupportedTranslation,
1428 stmt.getBeginLoc(),
1429 "TODO implement translation of stmt class {s}",
1430 .{@tagName(sc)},
1431 );
1432 },1074 },
1433 }1075 }
1434}1076}
14351077
1436fn transBinaryOperator(1078fn transBinaryOperator(
1437 rp: RestorePoint,1079 c: *Context,
1438 scope: *Scope,1080 scope: *Scope,
1439 stmt: *const clang.BinaryOperator,1081 stmt: *const clang.BinaryOperator,
1440 result_used: ResultUsed,1082 result_used: ResultUsed,
1441) TransError!*ast.Node {1083) TransError!Node {
1442 const op = stmt.getOpcode();1084 const op = stmt.getOpcode();
1443 const qt = stmt.getType();1085 const qt = stmt.getType();
1444 var op_token: ast.TokenIndex = undefined;
1445 var op_id: ast.Node.Tag = undefined;
1446 switch (op) {1086 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()),
1448 .Comma => {1088 .Comma => {
1449 var block_scope = try Scope.Block.init(rp.c, scope, true);1089 var block_scope = try Scope.Block.init(c, scope, true);
1450 const lparen = try appendToken(rp.c, .LParen, "(");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);
1453 try block_scope.statements.append(lhs);1093 try block_scope.statements.append(lhs);
14541094
1455 const rhs = try transExpr(rp, &block_scope.base, stmt.getRHS(), .used, .r_value);1095 const rhs = try transExpr(c, &block_scope.base, stmt.getRHS(), .used);
1456 _ = try appendToken(rp.c, .Semicolon, ";");1096 const break_node = try Tag.break_val.create(c.arena, .{
1457 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs);1097 .label = block_scope.label,
1458 try block_scope.statements.append(&break_node.base);1098 .val = rhs,
1459 const block_node = try block_scope.complete(rp.c);1099 });
1460 const rparen = try appendToken(rp.c, .RParen, ")");1100 try block_scope.statements.append(break_node);
1461 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);1101 const block_node = try block_scope.complete(c);
1462 grouped_expr.* = .{1102 return maybeSuppressResult(c, scope, result_used, block_node);
1463 .lparen = lparen,
1464 .expr = block_node,
1465 .rparen = rparen,
1466 };
1467 return maybeSuppressResult(rp, scope, result_used, &grouped_expr.base);
1468 },1103 },
1469 .Div => {1104 .Div => {
1470 if (cIsSignedInteger(qt)) {1105 if (cIsSignedInteger(qt)) {
1471 // signed integer division uses @divTrunc1106 // signed integer division uses @divTrunc
1472 const div_trunc_node = try rp.c.createBuiltinCall("@divTrunc", 2);1107 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);
1473 div_trunc_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);1108 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);
1474 _ = try appendToken(rp.c, .Comma, ",");1109 const div_trunc = try Tag.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
1475 const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);1110 return maybeSuppressResult(c, scope, result_used, div_trunc);
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);
1479 }1111 }
1480 },1112 },
1481 .Rem => {1113 .Rem => {
1482 if (cIsSignedInteger(qt)) {1114 if (cIsSignedInteger(qt)) {
1483 // signed integer division uses @rem1115 // signed integer division uses @rem
1484 const rem_node = try rp.c.createBuiltinCall("@rem", 2);1116 const lhs = try transExpr(c, scope, stmt.getLHS(), .used);
1485 rem_node.params()[0] = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);1117 const rhs = try transExpr(c, scope, stmt.getRHS(), .used);
1486 _ = try appendToken(rp.c, .Comma, ",");1118 const rem = try Tag.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
1487 const rhs = try transExpr(rp, scope, stmt.getRHS(), .used, .r_value);1119 return maybeSuppressResult(c, scope, result_used, rem);
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);
1491 }1120 }
1492 },1121 },
1493 .Shl => {1122 .Shl => {
1494 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");1123 return transCreateNodeShiftOp(c, scope, stmt, .shl, result_used);
1495 return maybeSuppressResult(rp, scope, result_used, node);
1496 },1124 },
1497 .Shr => {1125 .Shr => {
1498 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");1126 return transCreateNodeShiftOp(c, scope, stmt, .shr, result_used);
1499 return maybeSuppressResult(rp, scope, result_used, node);
1500 },1127 },
1501 .LAnd => {1128 .LAnd => {
1502 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, result_used, true);1129 return transCreateNodeBoolInfixOp(c, scope, stmt, .@"and", result_used);
1503 return maybeSuppressResult(rp, scope, result_used, node);
1504 },1130 },
1505 .LOr => {1131 .LOr => {
1506 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, result_used, true);1132 return transCreateNodeBoolInfixOp(c, scope, stmt, .@"or", result_used);
1507 return maybeSuppressResult(rp, scope, result_used, node);
1508 },1133 },
1509 else => {},1134 else => {},
1510 }1135 }
1511 const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .l_value);1136 var op_id: Tag = undefined;
1512 switch (op) {1137 switch (op) {
1513 .Add => {1138 .Add => {
1514 if (cIsUnsignedInteger(qt)) {1139 if (cIsUnsignedInteger(qt)) {
1515 op_token = try appendToken(rp.c, .PlusPercent, "+%");1140 op_id = .add_wrap;
1516 op_id = .AddWrap;
1517 } else {1141 } else {
1518 op_token = try appendToken(rp.c, .Plus, "+");1142 op_id = .add;
1519 op_id = .Add;
1520 }1143 }
1521 },1144 },
1522 .Sub => {1145 .Sub => {
1523 if (cIsUnsignedInteger(qt)) {1146 if (cIsUnsignedInteger(qt)) {
1524 op_token = try appendToken(rp.c, .MinusPercent, "-%");1147 op_id = .sub_wrap;
1525 op_id = .SubWrap;
1526 } else {1148 } else {
1527 op_token = try appendToken(rp.c, .Minus, "-");1149 op_id = .sub;
1528 op_id = .Sub;
1529 }1150 }
1530 },1151 },
1531 .Mul => {1152 .Mul => {
1532 if (cIsUnsignedInteger(qt)) {1153 if (cIsUnsignedInteger(qt)) {
1533 op_token = try appendToken(rp.c, .AsteriskPercent, "*%");1154 op_id = .mul_wrap;
1534 op_id = .MulWrap;
1535 } else {1155 } else {
1536 op_token = try appendToken(rp.c, .Asterisk, "*");1156 op_id = .mul;
1537 op_id = .Mul;
1538 }1157 }
1539 },1158 },
1540 .Div => {1159 .Div => {
1541 // unsigned/float division uses the operator1160 // unsigned/float division uses the operator
1542 op_id = .Div;1161 op_id = .div;
1543 op_token = try appendToken(rp.c, .Slash, "/");
1544 },1162 },
1545 .Rem => {1163 .Rem => {
1546 // unsigned/float division uses the operator1164 // unsigned/float division uses the operator
1547 op_id = .Mod;1165 op_id = .mod;
1548 op_token = try appendToken(rp.c, .Percent, "%");
1549 },1166 },
1550 .LT => {1167 .LT => {
1551 op_id = .LessThan;1168 op_id = .less_than;
1552 op_token = try appendToken(rp.c, .AngleBracketLeft, "<");
1553 },1169 },
1554 .GT => {1170 .GT => {
1555 op_id = .GreaterThan;1171 op_id = .greater_than;
1556 op_token = try appendToken(rp.c, .AngleBracketRight, ">");
1557 },1172 },
1558 .LE => {1173 .LE => {
1559 op_id = .LessOrEqual;1174 op_id = .less_than_equal;
1560 op_token = try appendToken(rp.c, .AngleBracketLeftEqual, "<=");
1561 },1175 },
1562 .GE => {1176 .GE => {
1563 op_id = .GreaterOrEqual;1177 op_id = .greater_than_equal;
1564 op_token = try appendToken(rp.c, .AngleBracketRightEqual, ">=");
1565 },1178 },
1566 .EQ => {1179 .EQ => {
1567 op_id = .EqualEqual;1180 op_id = .equal;
1568 op_token = try appendToken(rp.c, .EqualEqual, "==");
1569 },1181 },
1570 .NE => {1182 .NE => {
1571 op_id = .BangEqual;1183 op_id = .not_equal;
1572 op_token = try appendToken(rp.c, .BangEqual, "!=");
1573 },1184 },
1574 .And => {1185 .And => {
1575 op_id = .BitAnd;1186 op_id = .bit_and;
1576 op_token = try appendToken(rp.c, .Ampersand, "&");
1577 },1187 },
1578 .Xor => {1188 .Xor => {
1579 op_id = .BitXor;1189 op_id = .bit_xor;
1580 op_token = try appendToken(rp.c, .Caret, "^");
1581 },1190 },
1582 .Or => {1191 .Or => {
1583 op_id = .BitOr;1192 op_id = .bit_or;
1584 op_token = try appendToken(rp.c, .Pipe, "|");
1585 },1193 },
1586 else => unreachable,1194 else => unreachable,
1587 }1195 }
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: {1200 const lhs = if (isBoolRes(lhs_uncasted))
1592 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);1201 try Tag.bool_to_int.create(c.arena, lhs_uncasted)
1593 cast_node.params()[0] = lhs_node;1202 else
1594 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1203 lhs_uncasted;
1595 break :init &cast_node.base;
1596 } else lhs_node;
15971204
1598 const rhs = if (isBoolRes(rhs_node)) init: {1205 const rhs = if (isBoolRes(rhs_uncasted))
1599 const cast_node = try rp.c.createBuiltinCall("@boolToInt", 1);1206 try Tag.bool_to_int.create(c.arena, rhs_uncasted)
1600 cast_node.params()[0] = rhs_node;1207 else
1601 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1208 rhs_uncasted;
1602 break :init &cast_node.base;
1603 } else rhs_node;
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);
1606}1211}
16071212
1608fn transCompoundStmtInline(1213fn transCompoundStmtInline(
1609 rp: RestorePoint,1214 c: *Context,
1610 parent_scope: *Scope,
1611 stmt: *const clang.CompoundStmt,1215 stmt: *const clang.CompoundStmt,
1612 block: *Scope.Block,1216 block: *Scope.Block,
1613) TransError!void {1217) TransError!void {
1614 var it = stmt.body_begin();1218 var it = stmt.body_begin();
1615 const end_it = stmt.body_end();1219 const end_it = stmt.body_end();
1616 while (it != end_it) : (it += 1) {1220 while (it != end_it) : (it += 1) {
1617 const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value);1221 const result = try transStmt(c, &block.base, it[0], .unused);
1618 try block.statements.append(result);1222 switch (result.tag()) {
1223 .declaration, .empty_block => {},
1224 else => try block.statements.append(result),
1225 }
1619 }1226 }
1620}1227}
16211228
1622fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!*ast.Node {1229fn transCompoundStmt(c: *Context, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!Node {
1623 var block_scope = try Scope.Block.init(rp.c, scope, false);1230 var block_scope = try Scope.Block.init(c, scope, false);
1624 defer block_scope.deinit();1231 defer block_scope.deinit();
1625 try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);1232 try transCompoundStmtInline(c, stmt, &block_scope);
1626 return try block_scope.complete(rp.c);1233 return try block_scope.complete(c);
1627}1234}
16281235
1629fn transCStyleCastExprClass(1236fn transCStyleCastExprClass(
1630 rp: RestorePoint,1237 c: *Context,
1631 scope: *Scope,1238 scope: *Scope,
1632 stmt: *const clang.CStyleCastExpr,1239 stmt: *const clang.CStyleCastExpr,
1633 result_used: ResultUsed,1240 result_used: ResultUsed,
1634 lrvalue: LRValue,1241) TransError!Node {
1635) TransError!*ast.Node {
1636 const sub_expr = stmt.getSubExpr();1242 const sub_expr = stmt.getSubExpr();
1637 const cast_node = (try transCCast(1243 const cast_node = (try transCCast(
1638 rp,1244 c,
1639 scope,1245 scope,
1640 stmt.getBeginLoc(),1246 stmt.getBeginLoc(),
1641 stmt.getType(),1247 stmt.getType(),
1642 sub_expr.getType(),1248 sub_expr.getType(),
1643 try transExpr(rp, scope, sub_expr, .used, lrvalue),1249 try transExpr(c, scope, sub_expr, .used),
1644 ));1250 ));
1645 return maybeSuppressResult(rp, scope, result_used, cast_node);1251 return maybeSuppressResult(c, scope, result_used, cast_node);
1646}1252}
16471253
1648fn transDeclStmtOne(1254fn transDeclStmtOne(
1649 rp: RestorePoint,1255 c: *Context,
1650 scope: *Scope,1256 scope: *Scope,
1651 decl: *const clang.Decl,1257 decl: *const clang.Decl,
1652 block_scope: *Scope.Block,1258 block_scope: *Scope.Block,
1653) TransError!*ast.Node {1259) TransError!void {
1654 const c = rp.c;
1655
1656 switch (decl.getKind()) {1260 switch (decl.getKind()) {
1657 .Var => {1261 .Var => {
1658 const var_decl = @ptrCast(*const clang.VarDecl, decl);1262 const var_decl = @ptrCast(*const clang.VarDecl, decl);
...@@ -1666,62 +1270,51 @@ fn transDeclStmtOne(...@@ -1666,62 +1270,51 @@ fn transDeclStmtOne(
1666 .Extern, .Static => {1270 .Extern, .Static => {
1667 // This is actually a global variable, put it in the global scope and reference it.1271 // This is actually a global variable, put it in the global scope and reference it.
1668 // `_ = mangled_name;`1272 // `_ = mangled_name;`
1669 try visitVarDecl(rp.c, var_decl, mangled_name);1273 return visitVarDecl(c, var_decl, mangled_name);
1670 return try maybeSuppressResult(rp, scope, .unused, try transCreateNodeIdentifier(rp.c, mangled_name));
1671 },1274 },
1672 else => {},1275 else => {},
1673 }1276 }
16741277
1675 const mut_tok = if (qual_type.isConstQualified())1278 const is_const = 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);
16801279
1681 _ = try appendToken(c, .Colon, ":");
1682 const loc = decl.getLocation();1280 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, "=");
1686 var init_node = if (decl_init) |expr|1283 var init_node = if (decl_init) |expr|
1687 if (expr.getStmtClass() == .StringLiteralClass)1284 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))
1689 else1286 else
1690 try transExprCoercing(rp, scope, expr, .used, .r_value)1287 try transExprCoercing(c, scope, expr, .used)
1691 else1288 else
1692 try transCreateNodeUndefinedLiteral(c);1289 Tag.undefined_literal.init();
1693 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {1290 if (!qualTypeIsBoolean(qual_type) and isBoolRes(init_node)) {
1694 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);1291 init_node = try Tag.bool_to_int.create(c.arena, init_node);
1695 builtin_node.params()[0] = init_node;
1696 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1697 init_node = &builtin_node.base;
1698 }1292 }
1699 const semicolon_token = try appendToken(c, .Semicolon, ";");1293 const node = try Tag.var_decl.create(c.arena, .{
1700 const node = try ast.Node.VarDecl.create(c.arena, .{1294 .is_pub = false,
1701 .name_token = name_tok,1295 .is_const = is_const,
1702 .mut_token = mut_tok,1296 .is_extern = false,
1703 .semicolon_token = semicolon_token,1297 .is_export = false,
1704 }, .{1298 .is_threadlocal = false,
1705 .eq_token = eq_token,1299 .linksection_string = null,
1706 .type_node = type_node,1300 .alignment = null,
1707 .init_node = init_node,1301 .name = mangled_name,
1302 .type = type_node,
1303 .init = init_node,
1708 });1304 });
1709 return &node.base;1305 try block_scope.statements.append(node);
1710 },1306 },
1711 .Typedef => {1307 .Typedef => {
1712 const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl);1308 try transTypeDef(c, scope, @ptrCast(*const clang.TypedefNameDecl, decl));
1713 const name = try c.str(@ptrCast(*const clang.NamedDecl, typedef_decl).getName_bytes_begin());1309 },
17141310 .Record => {
1715 const underlying_qual = typedef_decl.getUnderlyingType();1311 try transRecordDecl(c, scope, @ptrCast(*const clang.RecordDecl, decl));
1716 const underlying_type = underlying_qual.getTypePtr();1312 },
17171313 .Enum => {
1718 const mangled_name = try block_scope.makeMangledName(c, name);1314 try transEnumDecl(c, scope, @ptrCast(*const clang.EnumDecl, decl));
1719 const node = (try transCreateNodeTypedef(rp, typedef_decl, false, mangled_name)) orelse
1720 return error.UnsupportedTranslation;
1721 return node;
1722 },1315 },
1723 else => |kind| return revertAndWarn(1316 else => |kind| return fail(
1724 rp,1317 c,
1725 error.UnsupportedTranslation,1318 error.UnsupportedTranslation,
1726 decl.getLocation(),1319 decl.getLocation(),
1727 "TODO implement translation of DeclStmt kind {s}",1320 "TODO implement translation of DeclStmt kind {s}",
...@@ -1730,96 +1323,86 @@ fn transDeclStmtOne(...@@ -1730,96 +1323,86 @@ fn transDeclStmtOne(
1730 }1323 }
1731}1324}
17321325
1733fn transDeclStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.DeclStmt) TransError!*ast.Node {1326fn transDeclStmt(c: *Context, scope: *Scope, stmt: *const clang.DeclStmt) TransError!Node {
1734 const block_scope = scope.findBlockScope(rp.c) catch unreachable;1327 const block_scope = try scope.findBlockScope(c);
17351328
1736 var it = stmt.decl_begin();1329 var it = stmt.decl_begin();
1737 const end_it = stmt.decl_end();1330 const end_it = stmt.decl_end();
1738 assert(it != end_it);1331 while (it != end_it) : (it += 1) {
1739 while (true) : (it += 1) {1332 try transDeclStmtOne(c, scope, it[0], block_scope);
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 }
1747 }1333 }
1748 unreachable;1334 return Tag.declaration.init();
1749}1335}
17501336
1751fn transDeclRefExpr(1337fn transDeclRefExpr(
1752 rp: RestorePoint,1338 c: *Context,
1753 scope: *Scope,1339 scope: *Scope,
1754 expr: *const clang.DeclRefExpr,1340 expr: *const clang.DeclRefExpr,
1755 lrvalue: LRValue,1341) TransError!Node {
1756) TransError!*ast.Node {
1757 const value_decl = expr.getDecl();1342 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());
1759 const mangled_name = scope.getAlias(name);1344 const mangled_name = scope.getAlias(name);
1760 return transCreateNodeIdentifier(rp.c, mangled_name);1345 return Tag.identifier.create(c.arena, mangled_name);
1761}1346}
17621347
1763fn transImplicitCastExpr(1348fn transImplicitCastExpr(
1764 rp: RestorePoint,1349 c: *Context,
1765 scope: *Scope,1350 scope: *Scope,
1766 expr: *const clang.ImplicitCastExpr,1351 expr: *const clang.ImplicitCastExpr,
1767 result_used: ResultUsed,1352 result_used: ResultUsed,
1768) TransError!*ast.Node {1353) TransError!Node {
1769 const c = rp.c;
1770 const sub_expr = expr.getSubExpr();1354 const sub_expr = expr.getSubExpr();
1771 const dest_type = getExprQualType(c, @ptrCast(*const clang.Expr, expr));1355 const dest_type = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
1772 const src_type = getExprQualType(c, sub_expr);1356 const src_type = getExprQualType(c, sub_expr);
1773 switch (expr.getCastKind()) {1357 switch (expr.getCastKind()) {
1774 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {1358 .BitCast, .FloatingCast, .FloatingToIntegral, .IntegralToFloating, .IntegralCast, .PointerToIntegral, .IntegralToPointer => {
1775 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);1359 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1776 return try transCCast(rp, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);1360 const casted = try transCCast(c, scope, expr.getBeginLoc(), dest_type, src_type, sub_expr_node);
1361 return maybeSuppressResult(c, scope, result_used, casted);
1777 },1362 },
1778 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {1363 .LValueToRValue, .NoOp, .FunctionToPointerDecay => {
1779 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);1364 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1780 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);1365 return maybeSuppressResult(c, scope, result_used, sub_expr_node);
1781 },1366 },
1782 .ArrayToPointerDecay => {1367 .ArrayToPointerDecay => {
1783 if (exprIsNarrowStringLiteral(sub_expr)) {1368 if (exprIsNarrowStringLiteral(sub_expr)) {
1784 const sub_expr_node = try transExpr(rp, scope, sub_expr, .used, .r_value);1369 const sub_expr_node = try transExpr(c, scope, sub_expr, .used);
1785 return maybeSuppressResult(rp, scope, result_used, sub_expr_node);1370 return maybeSuppressResult(c, scope, result_used, sub_expr_node);
1786 }1371 }
17871372
1788 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");1373 const addr = try Tag.address_of.create(c.arena, try transExpr(c, scope, sub_expr, .used));
1789 prefix_op.rhs = try transExpr(rp, scope, sub_expr, .used, .r_value);1374 return maybeSuppressResult(c, scope, result_used, addr);
1790
1791 return maybeSuppressResult(rp, scope, result_used, &prefix_op.base);
1792 },1375 },
1793 .NullToPointer => {1376 .NullToPointer => {
1794 return try transCreateNodeNullLiteral(rp.c);1377 return Tag.null_literal.init();
1795 },1378 },
1796 .PointerToBoolean => {1379 .PointerToBoolean => {
1797 // @ptrToInt(val) != 01380 // @ptrToInt(val) != 0
1798 const ptr_to_int = try rp.c.createBuiltinCall("@ptrToInt", 1);1381 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, try transExpr(c, scope, sub_expr, .used));
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, ")");
18011382
1802 const op_token = try appendToken(rp.c, .BangEqual, "!=");1383 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = ptr_to_int, .rhs = Tag.zero_literal.init() });
1803 const rhs_node = try transCreateNodeInt(rp.c, 0);1384 return maybeSuppressResult(c, scope, result_used, ne);
1804 return transCreateNodeInfixOp(rp, scope, &ptr_to_int.base, .BangEqual, op_token, rhs_node, result_used, false);
1805 },1385 },
1806 .IntegralToBoolean => {1386 .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
1809 // The expression is already a boolean one, return it as-is1389 // The expression is already a boolean one, return it as-is
1810 if (isBoolRes(sub_expr_node))1390 if (isBoolRes(sub_expr_node))
1811 return sub_expr_node;1391 return maybeSuppressResult(c, scope, result_used, sub_expr_node);
18121392
1813 // val != 01393 // val != 0
1814 const op_token = try appendToken(rp.c, .BangEqual, "!=");1394 const ne = try Tag.not_equal.create(c.arena, .{ .lhs = sub_expr_node, .rhs = Tag.zero_literal.init() });
1815 const rhs_node = try transCreateNodeInt(rp.c, 0);1395 return maybeSuppressResult(c, scope, result_used, ne);
1816 return transCreateNodeInfixOp(rp, scope, sub_expr_node, .BangEqual, op_token, rhs_node, result_used, false);
1817 },1396 },
1818 .BuiltinFnToFnPtr => {1397 .BuiltinFnToFnPtr => {
1819 return transExpr(rp, scope, sub_expr, .used, .r_value);1398 return transExpr(c, scope, sub_expr, result_used);
1820 },1399 },
1821 else => |kind| return revertAndWarn(1400 .ToVoid => {
1822 rp,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,
1823 error.UnsupportedTranslation,1406 error.UnsupportedTranslation,
1824 @ptrCast(*const clang.Stmt, expr).getBeginLoc(),1407 @ptrCast(*const clang.Stmt, expr).getBeginLoc(),
1825 "TODO implement translation of CastKind {s}",1408 "TODO implement translation of CastKind {s}",
...@@ -1829,52 +1412,28 @@ fn transImplicitCastExpr(...@@ -1829,52 +1412,28 @@ fn transImplicitCastExpr(
1829}1412}
18301413
1831fn transBoolExpr(1414fn transBoolExpr(
1832 rp: RestorePoint,1415 c: *Context,
1833 scope: *Scope,1416 scope: *Scope,
1834 expr: *const clang.Expr,1417 expr: *const clang.Expr,
1835 used: ResultUsed,1418 used: ResultUsed,
1836 lrvalue: LRValue,1419) TransError!Node {
1837 grouped: bool,
1838) TransError!*ast.Node {
1839 if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) {1420 if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) {
1840 var is_zero: bool = undefined;1421 var is_zero: bool = undefined;
1841 if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, rp.c.clang_context))) {1422 if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) {
1842 return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});1423 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
1843 }1424 }
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)]) };
1845 }1426 }
18461427
1847 const lparen = if (grouped)1428 var res = try transExpr(c, scope, expr, used);
1848 try appendToken(rp.c, .LParen, "(")
1849 else
1850 undefined;
1851 var res = try transExpr(rp, scope, expr, used, lrvalue);
1852
1853 if (isBoolRes(res)) {1429 if (isBoolRes(res)) {
1854 if (!grouped and res.tag == .GroupedExpression) {1430 return maybeSuppressResult(c, scope, used, res);
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;
1861 }1431 }
18621432
1863 const ty = getExprQualType(rp.c, expr).getTypePtr();1433 const ty = getExprQualType(c, expr).getTypePtr();
1864 const node = try finishBoolExpr(rp, scope, expr.getBeginLoc(), ty, res, used);1434 const node = try finishBoolExpr(c, scope, expr.getBeginLoc(), ty, res, used);
18651435
1866 if (grouped) {1436 return maybeSuppressResult(c, scope, used, node);
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 }
1878}1437}
18791438
1880fn exprIsBooleanType(expr: *const clang.Expr) bool {1439fn exprIsBooleanType(expr: *const clang.Expr) bool {
...@@ -1900,34 +1459,32 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool {...@@ -1900,34 +1459,32 @@ fn exprIsNarrowStringLiteral(expr: *const clang.Expr) bool {
1900 }1459 }
1901}1460}
19021461
1903fn isBoolRes(res: *ast.Node) bool {1462fn isBoolRes(res: Node) bool {
1904 switch (res.tag) {1463 switch (res.tag()) {
1905 .BoolOr,1464 .@"or",
1906 .BoolAnd,1465 .@"and",
1907 .EqualEqual,1466 .equal,
1908 .BangEqual,1467 .not_equal,
1909 .LessThan,1468 .less_than,
1910 .GreaterThan,1469 .less_than_equal,
1911 .LessOrEqual,1470 .greater_than,
1912 .GreaterOrEqual,1471 .greater_than_equal,
1913 .BoolNot,1472 .not,
1914 .BoolLiteral,1473 .false_literal,
1474 .true_literal,
1915 => return true,1475 => return true,
1916
1917 .GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
1918
1919 else => return false,1476 else => return false,
1920 }1477 }
1921}1478}
19221479
1923fn finishBoolExpr(1480fn finishBoolExpr(
1924 rp: RestorePoint,1481 c: *Context,
1925 scope: *Scope,1482 scope: *Scope,
1926 loc: clang.SourceLocation,1483 loc: clang.SourceLocation,
1927 ty: *const clang.Type,1484 ty: *const clang.Type,
1928 node: *ast.Node,1485 node: Node,
1929 used: ResultUsed,1486 used: ResultUsed,
1930) TransError!*ast.Node {1487) TransError!Node {
1931 switch (ty.getTypeClass()) {1488 switch (ty.getTypeClass()) {
1932 .Builtin => {1489 .Builtin => {
1933 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);1490 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
...@@ -1959,42 +1516,38 @@ fn finishBoolExpr(...@@ -1959,42 +1516,38 @@ fn finishBoolExpr(
1959 .WChar_S,1516 .WChar_S,
1960 .Float16,1517 .Float16,
1961 => {1518 => {
1962 const op_token = try appendToken(rp.c, .BangEqual, "!=");1519 // node != 0
1963 const rhs_node = try transCreateNodeInt(rp.c, 0);1520 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
1964 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1965 },1521 },
1966 .NullPtr => {1522 .NullPtr => {
1967 const op_token = try appendToken(rp.c, .EqualEqual, "==");1523 // node == null
1968 const rhs_node = try transCreateNodeNullLiteral(rp.c);1524 return Tag.equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
1969 return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false);
1970 },1525 },
1971 else => {},1526 else => {},
1972 }1527 }
1973 },1528 },
1974 .Pointer => {1529 .Pointer => {
1975 const op_token = try appendToken(rp.c, .BangEqual, "!=");1530 // node != null
1976 const rhs_node = try transCreateNodeNullLiteral(rp.c);1531 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.null_literal.init() });
1977 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1978 },1532 },
1979 .Typedef => {1533 .Typedef => {
1980 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);1534 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
1981 const typedef_decl = typedef_ty.getDecl();1535 const typedef_decl = typedef_ty.getDecl();
1982 const underlying_type = typedef_decl.getUnderlyingType();1536 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);
1984 },1538 },
1985 .Enum => {1539 .Enum => {
1986 const op_token = try appendToken(rp.c, .BangEqual, "!=");1540 // node != 0
1987 const rhs_node = try transCreateNodeInt(rp.c, 0);1541 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
1988 return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
1989 },1542 },
1990 .Elaborated => {1543 .Elaborated => {
1991 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);1544 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);
1992 const named_type = elaborated_ty.getNamedType();1545 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);
1994 },1547 },
1995 else => {},1548 else => {},
1996 }1549 }
1997 return revertAndWarn(rp, error.UnsupportedType, loc, "unsupported bool expression type", .{});1550 return fail(c, error.UnsupportedType, loc, "unsupported bool expression type", .{});
1998}1551}
19991552
2000const SuppressCast = enum {1553const SuppressCast = enum {
...@@ -2002,21 +1555,21 @@ const SuppressCast = enum {...@@ -2002,21 +1555,21 @@ const SuppressCast = enum {
2002 no_as,1555 no_as,
2003};1556};
2004fn transIntegerLiteral(1557fn transIntegerLiteral(
2005 rp: RestorePoint,1558 c: *Context,
2006 scope: *Scope,1559 scope: *Scope,
2007 expr: *const clang.IntegerLiteral,1560 expr: *const clang.IntegerLiteral,
2008 result_used: ResultUsed,1561 result_used: ResultUsed,
2009 suppress_as: SuppressCast,1562 suppress_as: SuppressCast,
2010) TransError!*ast.Node {1563) TransError!Node {
2011 var eval_result: clang.ExprEvalResult = undefined;1564 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)) {
2013 const loc = expr.getBeginLoc();1566 const loc = expr.getBeginLoc();
2014 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});1567 return fail(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
2015 }1568 }
20161569
2017 if (suppress_as == .no_as) {1570 if (suppress_as == .no_as) {
2018 const int_lit_node = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());1571 const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt());
2019 return maybeSuppressResult(rp, scope, result_used, int_lit_node);1572 return maybeSuppressResult(c, scope, result_used, int_lit_node);
2020 }1573 }
20211574
2022 // Integer literals in C have types, and this can matter for several reasons.1575 // Integer literals in C have types, and this can matter for several reasons.
...@@ -2031,115 +1584,61 @@ fn transIntegerLiteral(...@@ -2031,115 +1584,61 @@ fn transIntegerLiteral(
20311584
2032 // @as(T, x)1585 // @as(T, x)
2033 const expr_base = @ptrCast(*const clang.Expr, expr);1586 const expr_base = @ptrCast(*const clang.Expr, expr);
2034 const as_node = try rp.c.createBuiltinCall("@as", 2);1587 const ty_node = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc());
2035 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());1588 const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());
2036 as_node.params()[0] = ty_node;1589 const as = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });
2037 _ = try appendToken(rp.c, .Comma, ",");1590 return maybeSuppressResult(c, scope, result_used, as);
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.?);
2050}1591}
20511592
2052fn transReturnStmt(1593fn transReturnStmt(
2053 rp: RestorePoint,1594 c: *Context,
2054 scope: *Scope,1595 scope: *Scope,
2055 expr: *const clang.ReturnStmt,1596 expr: *const clang.ReturnStmt,
2056) TransError!*ast.Node {1597) TransError!Node {
2057 const return_kw = try appendToken(rp.c, .Keyword_return, "return");1598 const val_expr = expr.getRetValue() orelse
2058 var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr|1599 return Tag.return_void.init();
2059 try transExprCoercing(rp, scope, val_expr, .used, .r_value)1600
2060 else1601 var rhs = try transExprCoercing(c, scope, val_expr, .used);
2061 null;1602 const return_qt = scope.findBlockReturnType(c);
2062 const return_qt = scope.findBlockReturnType(rp.c);1603 if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) {
2063 if (zigShouldCastBooleanReturnToInt(rhs, return_qt)) {1604 rhs = try Tag.bool_to_int.create(c.arena, rhs);
2064 const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);1605 }
2065 bool_to_int_node.params()[0] = rhs.?;1606 return Tag.@"return".create(c.arena, 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;
2078}1607}
20791608
2080fn transStringLiteral(1609fn transStringLiteral(
2081 rp: RestorePoint,1610 c: *Context,
2082 scope: *Scope,1611 scope: *Scope,
2083 stmt: *const clang.StringLiteral,1612 stmt: *const clang.StringLiteral,
2084 result_used: ResultUsed,1613 result_used: ResultUsed,
2085) TransError!*ast.Node {1614) TransError!Node {
2086 const kind = stmt.getKind();1615 const kind = stmt.getKind();
2087 switch (kind) {1616 switch (kind) {
2088 .Ascii, .UTF8 => {1617 .Ascii, .UTF8 => {
2089 var len: usize = undefined;1618 var len: usize = undefined;
2090 const bytes_ptr = stmt.getString_bytes_begin_size(&len);1619 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)});1621 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
2094 const node = try rp.c.arena.create(ast.Node.OneToken);1622 const node = try Tag.string_literal.create(c.arena, str);
2095 node.* = .{1623 return maybeSuppressResult(c, scope, result_used, node);
2096 .base = .{ .tag = .StringLiteral },
2097 .token = token,
2098 };
2099 return maybeSuppressResult(rp, scope, result_used, &node.base);
2100 },1624 },
2101 .UTF16, .UTF32, .Wide => {1625 .UTF16, .UTF32, .Wide => {
2102 const node = try transWideStringLiteral(rp, scope, stmt);1626 const str_type = @tagName(stmt.getKind());
2103 return maybeSuppressResult(rp, scope, result_used, node);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);
2104 },1634 },
2105 }1635 }
2106}1636}
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
2136/// Parse the size of an array back out from an ast Node.1638/// Parse the size of an array back out from an ast Node.
2137fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {1639fn zigArraySize(c: *Context, node: Node) TransError!usize {
2138 if (node.castTag(.ArrayType)) |array| {1640 if (node.castTag(.array_type)) |array| {
2139 if (array.len_expr.castTag(.IntegerLiteral)) |int_lit| {1641 return array.data.len;
2140 const tok = tokenSlice(c, int_lit.token);
2141 return std.fmt.parseUnsigned(usize, tok, 10) catch error.UnsupportedTranslation;
2142 }
2143 }1642 }
2144 return error.UnsupportedTranslation;1643 return error.UnsupportedTranslation;
2145}1644}
...@@ -2150,11 +1649,11 @@ fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {...@@ -2150,11 +1649,11 @@ fn zigArraySize(c: *Context, node: *ast.Node) TransError!usize {
2150/// than the array, truncate the string. If the array is larger than the1649/// than the array, truncate the string. If the array is larger than the
2151/// string literal, pad the array with 0's1650/// string literal, pad the array with 0's
2152fn transStringLiteralAsArray(1651fn transStringLiteralAsArray(
2153 rp: RestorePoint,1652 c: *Context,
2154 scope: *Scope,1653 scope: *Scope,
2155 stmt: *const clang.StringLiteral,1654 stmt: *const clang.StringLiteral,
2156 array_size: usize,1655 array_size: usize,
2157) TransError!*ast.Node {1656) TransError!Node {
2158 if (array_size == 0) return error.UnsupportedType;1657 if (array_size == 0) return error.UnsupportedType;
21591658
2160 const str_length = stmt.getLength();1659 const str_length = stmt.getLength();
...@@ -2163,40 +1662,25 @@ fn transStringLiteralAsArray(...@@ -2163,40 +1662,25 @@ fn transStringLiteralAsArray(
2163 const ty = expr_base.getType().getTypePtr();1662 const ty = expr_base.getType().getTypePtr();
2164 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);1663 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
21651664
2166 const ty_node = try rp.c.arena.create(ast.Node.ArrayType);1665 const elem_type = try transQualType(c, scope, const_arr_ty.getElementType(), expr_base.getBeginLoc());
2167 const op_token = try appendToken(rp.c, .LBracket, "[");1666 const arr_type = try Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_type });
2168 const len_expr = try transCreateNodeInt(rp.c, array_size);1667 const init_list = try c.arena.alloc(Node, 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();
21841668
2185 var i: c_uint = 0;1669 var i: c_uint = 0;
2186 const kind = stmt.getKind();1670 const kind = stmt.getKind();
2187 const narrow = kind == .Ascii or kind == .UTF8;1671 const narrow = kind == .Ascii or kind == .UTF8;
2188 while (i < str_length and i < array_size) : (i += 1) {1672 while (i < str_length and i < array_size) : (i += 1) {
2189 const code_unit = stmt.getCodeUnit(i);1673 const code_unit = stmt.getCodeUnit(i);
2190 init_list[i] = try transCreateCharLitNode(rp.c, narrow, code_unit);1674 init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);
2191 _ = try appendToken(rp.c, .Comma, ",");
2192 }1675 }
2193 while (i < array_size) : (i += 1) {1676 while (i < array_size) : (i += 1) {
2194 init_list[i] = try transCreateNodeInt(rp.c, 0);1677 init_list[i] = try transCreateNodeNumber(c, 0, .int);
2195 _ = try appendToken(rp.c, .Comma, ",");
2196 }1678 }
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 });
2200}1684}
22011685
2202fn cIsEnum(qt: clang.QualType) bool {1686fn cIsEnum(qt: clang.QualType) bool {
...@@ -2215,217 +1699,180 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {...@@ -2215,217 +1699,180 @@ fn cIntTypeForEnum(enum_qt: clang.QualType) clang.QualType {
2215}1699}
22161700
2217fn transCCast(1701fn transCCast(
2218 rp: RestorePoint,1702 c: *Context,
2219 scope: *Scope,1703 scope: *Scope,
2220 loc: clang.SourceLocation,1704 loc: clang.SourceLocation,
2221 dst_type: clang.QualType,1705 dst_type: clang.QualType,
2222 src_type: clang.QualType,1706 src_type: clang.QualType,
2223 expr: *ast.Node,1707 expr: Node,
2224) !*ast.Node {1708) !Node {
2225 if (qualTypeCanon(dst_type).isVoidType()) return expr;1709 if (qualTypeCanon(dst_type).isVoidType()) return expr;
2226 if (dst_type.eq(src_type)) return expr;1710 if (dst_type.eq(src_type)) return expr;
2227 if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))1711 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);
2229 if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {1715 if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
2230 // 1. If src_type is an enum, determine the underlying signed int type1716 // 1. If src_type is an enum, determine the underlying signed int type
2231 // 2. Extend or truncate without changing signed-ness.1717 // 2. Extend or truncate without changing signed-ness.
2232 // 3. Bit-cast to correct signed-ness1718 // 3. Bit-cast to correct signed-ness
2233 const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type);1719 const src_type_is_signed = cIsSignedInteger(src_type) or cIsEnum(src_type);
2234 const src_int_type = if (cIsInteger(src_type)) src_type else cIntTypeForEnum(src_type);1720 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);1721 var src_int_expr = if (cIsInteger(src_type)) expr else try Tag.enum_to_int.create(c.arena, 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, ",");
22411722
2242 if (isBoolRes(src_int_expr)) {1723 if (isBoolRes(src_int_expr)) {
2243 const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);1724 src_int_expr = try Tag.bool_to_int.create(c.arena, src_int_expr);
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;
2247 }1725 }
22481726
2249 switch (cIntTypeCmp(dst_type, src_int_type)) {1727 switch (cIntTypeCmp(dst_type, src_int_type)) {
2250 .lt => {1728 .lt => {
2251 // @truncate(SameSignSmallerInt, src_int_expr)1729 // @truncate(SameSignSmallerInt, src_int_expr)
2252 const trunc_node = try rp.c.createBuiltinCall("@truncate", 2);1730 const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
2253 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, src_type_is_signed);1731 src_int_expr = try Tag.truncate.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr });
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;
2260 },1732 },
2261 .gt => {1733 .gt => {
2262 // @as(SameSignBiggerInt, src_int_expr)1734 // @as(SameSignBiggerInt, src_int_expr)
2263 const as_node = try rp.c.createBuiltinCall("@as", 2);1735 const ty_node = try transQualTypeIntWidthOf(c, dst_type, src_type_is_signed);
2264 const ty_node = try transQualTypeIntWidthOf(rp.c, dst_type, src_type_is_signed);1736 src_int_expr = try Tag.as.create(c.arena, .{ .lhs = ty_node, .rhs = src_int_expr });
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;
2271 },1737 },
2272 .eq => {1738 .eq => {
2273 cast_node.params()[1] = src_int_expr;1739 // src_int_expr = src_int_expr
2274 },1740 },
2275 }1741 }
2276 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");1742 // @bitCast(dest_type, intermediate_value)
2277 return &cast_node.base;1743 return Tag.bit_cast.create(c.arena, .{ .lhs = dst_node, .rhs = src_int_expr });
2278 }1744 }
2279 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {1745 if (cIsInteger(dst_type) and qualTypeIsPtr(src_type)) {
2280 // @intCast(dest_type, @ptrToInt(val))1746 // @intCast(dest_type, @ptrToInt(val))
2281 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);1747 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
2282 cast_node.params()[0] = try transQualType(rp, dst_type, loc);1748 return Tag.int_cast.create(c.arena, .{ .lhs = dst_node, .rhs = ptr_to_int });
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;
2290 }1749 }
2291 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {1750 if (cIsInteger(src_type) and qualTypeIsPtr(dst_type)) {
2292 // @intToPtr(dest_type, val)1751 // @intToPtr(dest_type, val)
2293 const builtin_node = try rp.c.createBuiltinCall("@intToPtr", 2);1752 return Tag.int_to_ptr.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
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;
2299 }1753 }
2300 if (cIsFloating(src_type) and cIsFloating(dst_type)) {1754 if (cIsFloating(src_type) and cIsFloating(dst_type)) {
2301 const builtin_node = try rp.c.createBuiltinCall("@floatCast", 2);1755 // @floatCast(dest_type, val)
2302 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);1756 return Tag.float_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
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;
2307 }1757 }
2308 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {1758 if (cIsFloating(src_type) and !cIsFloating(dst_type)) {
2309 const builtin_node = try rp.c.createBuiltinCall("@floatToInt", 2);1759 // @floatToInt(dest_type, val)
2310 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);1760 return Tag.float_to_int.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
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;
2315 }1761 }
2316 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {1762 if (!cIsFloating(src_type) and cIsFloating(dst_type)) {
2317 const builtin_node = try rp.c.createBuiltinCall("@intToFloat", 2);1763 // @intToFloat(dest_type, val)
2318 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);1764 return Tag.int_to_float.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
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;
2323 }1765 }
2324 if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {1766 if (qualTypeIsBoolean(src_type) and !qualTypeIsBoolean(dst_type)) {
2325 // @boolToInt returns either a comptime_int or a u11767 // @boolToInt returns either a comptime_int or a u1
2326 // TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast1768 // TODO: if dst_type is 1 bit & signed (bitfield) we need @bitCast
2327 // instead of @as1769 // instead of @as
2328 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);1770 const bool_to_int = try Tag.bool_to_int.create(c.arena, expr);
2329 builtin_node.params()[0] = expr;1771 return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
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;
2339 }1772 }
2340 if (cIsEnum(dst_type)) {1773 if (cIsEnum(dst_type)) {
2341 const builtin_node = try rp.c.createBuiltinCall("@intToEnum", 2);1774 // @intToEnum(dest_type, val)
2342 builtin_node.params()[0] = try transQualType(rp, dst_type, loc);1775 return Tag.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
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;
2347 }1776 }
2348 if (cIsEnum(src_type) and !cIsEnum(dst_type)) {1777 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);
2350 }1780 }
2351 const cast_node = try rp.c.createBuiltinCall("@as", 2);1781 // @as(dest_type, val)
2352 cast_node.params()[0] = try transQualType(rp, dst_type, loc);1782 return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
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;
2364}1783}
23651784
2366fn transExpr(1785fn transExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
2367 rp: RestorePoint,1786 return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used);
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);
2374}1787}
23751788
2376/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore1789/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
2377/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.1790/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
2378fn transExprCoercing(1791fn transExprCoercing(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
2379 rp: RestorePoint,
2380 scope: *Scope,
2381 expr: *const clang.Expr,
2382 used: ResultUsed,
2383 lrvalue: LRValue,
2384) TransError!*ast.Node {
2385 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {1792 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
2386 .IntegerLiteralClass => {1793 .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);
2388 },1795 },
2389 .CharacterLiteralClass => {1796 .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);
2391 },1798 },
2392 .UnaryOperatorClass => {1799 .UnaryOperatorClass => {
2393 const un_expr = @ptrCast(*const clang.UnaryOperator, expr);1800 const un_expr = @ptrCast(*const clang.UnaryOperator, expr);
2394 if (un_expr.getOpcode() == .Extension) {1801 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 => {},
2396 }1819 }
2397 },1820 },
2398 else => {},1821 else => {},
2399 }1822 }
2400 return transExpr(rp, scope, expr, .used, .r_value);1823 return transExpr(c, scope, expr, .used);
2401}1824}
24021825
2403fn transInitListExprRecord(1826fn literalFitsInType(c: *Context, expr: *const clang.Expr, qt: clang.QualType) bool {
2404 rp: RestorePoint,1827 var width = qualTypeIntBitWidth(c, qt) catch 8;
2405 scope: *Scope,1828 if (width == 0) width = 8; // Byte is the smallest type.
2406 loc: clang.SourceLocation,1829 const is_signed = cIsSignedInteger(qt);
2407 expr: *const clang.InitListExpr,1830 const width_max_int = (@as(u64, 1) << math.lossyCast(u6, width - @boolToInt(is_signed))) - 1;
2408 ty: *const clang.Type,1831
2409 used: ResultUsed,1832 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
2410) TransError!*ast.Node {1833 .CharacterLiteralClass => {
2411 var is_union_type = false;1834 const char_lit = @ptrCast(*const clang.CharacterLiteral, expr);
2412 // Unions and Structs are both represented as RecordDecl1835 const val = char_lit.getValue();
2413 const record_ty = ty.getAsRecordType() orelse1836 // If the val is less than the max int then it fits.
2414 blk: {1837 return val <= width_max_int;
2415 is_union_type = true;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;
2416 break :blk ty.getAsUnionType();1865 break :blk ty.getAsUnionType();
2417 } orelse unreachable;1866 } orelse unreachable;
2418 const record_decl = record_ty.getDecl();1867 const record_decl = record_ty.getDecl();
2419 const record_def = record_decl.getDefinition() orelse1868 const record_def = record_decl.getDefinition() orelse
2420 unreachable;1869 unreachable;
24211870
2422 const ty_node = try transType(rp, ty, loc);1871 const ty_node = try transType(c, scope, ty, loc);
2423 const init_count = expr.getNumInits();1872 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);
2425 defer field_inits.deinit();1874 defer field_inits.deinit();
24261875
2427 _ = try appendToken(rp.c, .LBrace, "{");
2428
2429 var init_i: c_uint = 0;1876 var init_i: c_uint = 0;
2430 var it = record_def.field_begin();1877 var it = record_def.field_begin();
2431 const end_it = record_def.field_end();1878 const end_it = record_def.field_end();
...@@ -2443,78 +1890,34 @@ fn transInitListExprRecord(...@@ -2443,78 +1890,34 @@ fn transInitListExprRecord(
24431890
2444 // Generate the field assignment expression:1891 // Generate the field assignment expression:
2445 // .field_name = expr1892 // .field_name = expr
2446 const period_tok = try appendToken(rp.c, .Period, ".");1893 var raw_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
2447
2448 var raw_name = try rp.c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
2449 if (field_decl.isAnonymousStructOrUnion()) {1894 if (field_decl.isAnonymousStructOrUnion()) {
2450 const name = rp.c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;1895 const name = c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
2451 raw_name = try mem.dupe(rp.c.arena, u8, name);1896 raw_name = try mem.dupe(c.arena, u8, name);
2452 }1897 }
2453 const field_name_tok = try appendIdentifier(rp.c, raw_name);
24541898
2455 _ = try appendToken(rp.c, .Equal, "=");1899 try field_inits.append(.{
24561900 .name = raw_name,
2457 const field_init_node = try rp.c.arena.create(ast.Node.FieldInitializer);1901 .value = try transExpr(c, scope, elem_expr, .used),
2458 field_init_node.* = .{1902 });
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, ",");
2466 }1903 }
24671904
2468 const node = try ast.Node.StructInitializer.alloc(rp.c.arena, field_inits.items.len);1905 return Tag.container_init.create(c.arena, .{
2469 node.* = .{
2470 .lhs = ty_node,1906 .lhs = ty_node,
2471 .rtoken = try appendToken(rp.c, .RBrace, "}"),1907 .inits = try c.arena.dupe(ast.Payload.ContainerInit.Initializer, field_inits.items),
2472 .list_len = field_inits.items.len,1908 });
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;
2506}1909}
25071910
2508fn transInitListExprArray(1911fn transInitListExprArray(
2509 rp: RestorePoint,1912 c: *Context,
2510 scope: *Scope,1913 scope: *Scope,
2511 loc: clang.SourceLocation,1914 loc: clang.SourceLocation,
2512 expr: *const clang.InitListExpr,1915 expr: *const clang.InitListExpr,
2513 ty: *const clang.Type,1916 ty: *const clang.Type,
2514 used: ResultUsed,1917) TransError!Node {
2515) TransError!*ast.Node {
2516 const arr_type = ty.getAsArrayTypeUnsafe();1918 const arr_type = ty.getAsArrayTypeUnsafe();
2517 const child_qt = arr_type.getElementType();1919 const child_qt = arr_type.getElementType();
1920 const child_type = try transQualType(c, scope, child_qt, loc);
2518 const init_count = expr.getNumInits();1921 const init_count = expr.getNumInits();
2519 assert(@ptrCast(*const clang.Type, arr_type).isConstantArrayType());1922 assert(@ptrCast(*const clang.Type, arr_type).isConstantArrayType());
2520 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, arr_type);1923 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, arr_type);
...@@ -2523,125 +1926,83 @@ fn transInitListExprArray(...@@ -2523,125 +1926,83 @@ fn transInitListExprArray(
2523 const leftover_count = all_count - init_count;1926 const leftover_count = all_count - init_count;
25241927
2525 if (all_count == 0) {1928 if (all_count == 0) {
2526 return transCreateEmptyArray(rp, loc, child_qt.getTypePtr());1929 return Tag.empty_array.create(c.arena, child_type);
2527 }1930 }
25281931
2529 var init_node: *ast.Node.ArrayInitializer = undefined;1932 const init_node = if (init_count != 0) blk: {
2530 var cat_tok: ast.TokenIndex = undefined;1933 const init_list = try c.arena.alloc(Node, init_count);
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();
25461934
2547 var i: c_uint = 0;1935 for (init_list) |*init, i| {
2548 while (i < init_count) : (i += 1) {1936 const elem_expr = expr.getInit(@intCast(c_uint, i));
2549 const elem_expr = expr.getInit(i);1937 init.* = try transExprCoercing(c, scope, elem_expr, .used);
2550 init_list[i] = try transExpr(rp, scope, elem_expr, .used, .r_value);
2551 _ = try appendToken(rp.c, .Comma, ",");
2552 }1938 }
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 });
2554 if (leftover_count == 0) {1943 if (leftover_count == 0) {
2555 return &init_node.base;1944 return init_node;
2556 }1945 }
2557 cat_tok = try appendToken(rp.c, .PlusPlus, "++");1946 break :blk init_node;
2558 }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 };
2568 const filler_val_expr = expr.getArrayFiller();1949 const filler_val_expr = expr.getArrayFiller();
2569 filler_init_node.list()[0] = try transExpr(rp, scope, filler_val_expr, .used, .r_value);1950 const filler_node = try Tag.array_filler.create(c.arena, .{
2570 filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}");1951 .type = child_type,
25711952 .filler = try transExprCoercing(c, scope, filler_val_expr, .used),
2572 const rhs_node = if (leftover_count == 1)1953 .count = leftover_count,
2573 &filler_init_node.base1954 });
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 };
25851955
2586 if (init_count == 0) {1956 if (init_node) |some| {
2587 return rhs_node;1957 return Tag.array_cat.create(c.arena, .{ .lhs = some, .rhs = filler_node });
1958 } else {
1959 return filler_node;
2588 }1960 }
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;
2598}1961}
25991962
2600fn transInitListExpr(1963fn transInitListExpr(
2601 rp: RestorePoint,1964 c: *Context,
2602 scope: *Scope,1965 scope: *Scope,
2603 expr: *const clang.InitListExpr,1966 expr: *const clang.InitListExpr,
2604 used: ResultUsed,1967 used: ResultUsed,
2605) TransError!*ast.Node {1968) TransError!Node {
2606 const qt = getExprQualType(rp.c, @ptrCast(*const clang.Expr, expr));1969 const qt = getExprQualType(c, @ptrCast(*const clang.Expr, expr));
2607 var qual_type = qt.getTypePtr();1970 var qual_type = qt.getTypePtr();
2608 const source_loc = @ptrCast(*const clang.Expr, expr).getBeginLoc();1971 const source_loc = @ptrCast(*const clang.Expr, expr).getBeginLoc();
26091972
2610 if (qual_type.isRecordType()) {1973 if (qual_type.isRecordType()) {
2611 return transInitListExprRecord(1974 return maybeSuppressResult(c, scope, used, try transInitListExprRecord(
2612 rp,1975 c,
2613 scope,1976 scope,
2614 source_loc,1977 source_loc,
2615 expr,1978 expr,
2616 qual_type,1979 qual_type,
2617 used,1980 ));
2618 );
2619 } else if (qual_type.isArrayType()) {1981 } else if (qual_type.isArrayType()) {
2620 return transInitListExprArray(1982 return maybeSuppressResult(c, scope, used, try transInitListExprArray(
2621 rp,1983 c,
2622 scope,1984 scope,
2623 source_loc,1985 source_loc,
2624 expr,1986 expr,
2625 qual_type,1987 qual_type,
2626 used,1988 ));
2627 );
2628 } else {1989 } else {
2629 const type_name = rp.c.str(qual_type.getTypeClassName());1990 const type_name = c.str(qual_type.getTypeClassName());
2630 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});1991 return fail(c, error.UnsupportedType, source_loc, "unsupported initlist type: '{s}'", .{type_name});
2631 }1992 }
2632}1993}
26331994
2634fn transZeroInitExpr(1995fn transZeroInitExpr(
2635 rp: RestorePoint,1996 c: *Context,
2636 scope: *Scope,1997 scope: *Scope,
2637 source_loc: clang.SourceLocation,1998 source_loc: clang.SourceLocation,
2638 ty: *const clang.Type,1999 ty: *const clang.Type,
2639) TransError!*ast.Node {2000) TransError!Node {
2640 switch (ty.getTypeClass()) {2001 switch (ty.getTypeClass()) {
2641 .Builtin => {2002 .Builtin => {
2642 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);2003 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);
2643 switch (builtin_ty.getKind()) {2004 switch (builtin_ty.getKind()) {
2644 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),2005 .Bool => return Tag.false_literal.init(),
2645 .Char_U,2006 .Char_U,
2646 .UChar,2007 .UChar,
2647 .Char_S,2008 .Char_S,
...@@ -2662,126 +2023,112 @@ fn transZeroInitExpr(...@@ -2662,126 +2023,112 @@ fn transZeroInitExpr(
2662 .Float128,2023 .Float128,
2663 .Float16,2024 .Float16,
2664 .LongDouble,2025 .LongDouble,
2665 => return transCreateNodeInt(rp.c, 0),2026 => return Tag.zero_literal.init(),
2666 else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),2027 else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}),
2667 }2028 }
2668 },2029 },
2669 .Pointer => return transCreateNodeNullLiteral(rp.c),2030 .Pointer => return Tag.null_literal.init(),
2670 .Typedef => {2031 .Typedef => {
2671 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);2032 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
2672 const typedef_decl = typedef_ty.getDecl();2033 const typedef_decl = typedef_ty.getDecl();
2673 return transZeroInitExpr(2034 return transZeroInitExpr(
2674 rp,2035 c,
2675 scope,2036 scope,
2676 source_loc,2037 source_loc,
2677 typedef_decl.getUnderlyingType().getTypePtr(),2038 typedef_decl.getUnderlyingType().getTypePtr(),
2678 );2039 );
2679 },2040 },
2680 else => {},2041 else => return Tag.std_mem_zeroes.create(c.arena, try transType(c, scope, ty, source_loc)),
2681 }2042 }
2682
2683 return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{});
2684}2043}
26852044
2686fn transImplicitValueInitExpr(2045fn transImplicitValueInitExpr(
2687 rp: RestorePoint,2046 c: *Context,
2688 scope: *Scope,2047 scope: *Scope,
2689 expr: *const clang.Expr,2048 expr: *const clang.Expr,
2690 used: ResultUsed,2049 used: ResultUsed,
2691) TransError!*ast.Node {2050) TransError!Node {
2692 const source_loc = expr.getBeginLoc();2051 const source_loc = expr.getBeginLoc();
2693 const qt = getExprQualType(rp.c, expr);2052 const qt = getExprQualType(c, expr);
2694 const ty = qt.getTypePtr();2053 const ty = qt.getTypePtr();
2695 return transZeroInitExpr(rp, scope, source_loc, ty);2054 return transZeroInitExpr(c, scope, source_loc, ty);
2696}2055}
26972056
2698fn transIfStmt(2057fn transIfStmt(
2699 rp: RestorePoint,2058 c: *Context,
2700 scope: *Scope,2059 scope: *Scope,
2701 stmt: *const clang.IfStmt,2060 stmt: *const clang.IfStmt,
2702) TransError!*ast.Node {2061) TransError!Node {
2703 // if (c) t2062 // if (c) t
2704 // if (c) t else e2063 // if (c) t else e
2705 const if_node = try transCreateNodeIf(rp.c);
2706
2707 var cond_scope = Scope.Condition{2064 var cond_scope = Scope.Condition{
2708 .base = .{2065 .base = .{
2709 .parent = scope,2066 .parent = scope,
2710 .id = .Condition,2067 .id = .condition,
2711 },2068 },
2712 };2069 };
2713 defer cond_scope.deinit();2070 defer cond_scope.deinit();
2714 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());2071 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);2072 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
2716 _ = try appendToken(rp.c, .RParen, ")");
27172073
2718 if_node.body = try transStmt(rp, scope, stmt.getThen(), .unused, .r_value);2074 const then_body = try transStmt(c, scope, stmt.getThen(), .unused);
27192075 const else_body = if (stmt.getElse()) |expr|
2720 if (stmt.getElse()) |expr| {2076 try transStmt(c, scope, expr, .unused)
2721 if_node.@"else" = try transCreateNodeElse(rp.c);2077 else
2722 if_node.@"else".?.body = try transStmt(rp, scope, expr, .unused, .r_value);2078 null;
2723 }2079 return Tag.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body });
2724 _ = try appendToken(rp.c, .Semicolon, ";");
2725 return &if_node.base;
2726}2080}
27272081
2728fn transWhileLoop(2082fn transWhileLoop(
2729 rp: RestorePoint,2083 c: *Context,
2730 scope: *Scope,2084 scope: *Scope,
2731 stmt: *const clang.WhileStmt,2085 stmt: *const clang.WhileStmt,
2732) TransError!*ast.Node {2086) TransError!Node {
2733 const while_node = try transCreateNodeWhile(rp.c);
2734
2735 var cond_scope = Scope.Condition{2087 var cond_scope = Scope.Condition{
2736 .base = .{2088 .base = .{
2737 .parent = scope,2089 .parent = scope,
2738 .id = .Condition,2090 .id = .condition,
2739 },2091 },
2740 };2092 };
2741 defer cond_scope.deinit();2093 defer cond_scope.deinit();
2742 const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());2094 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);2095 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
2744 _ = try appendToken(rp.c, .RParen, ")");
27452096
2746 var loop_scope = Scope{2097 var loop_scope = Scope{
2747 .parent = scope,2098 .parent = scope,
2748 .id = .Loop,2099 .id = .loop,
2749 };2100 };
2750 while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2101 const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2751 _ = try appendToken(rp.c, .Semicolon, ";");2102 return Tag.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null });
2752 return &while_node.base;
2753}2103}
27542104
2755fn transDoWhileLoop(2105fn transDoWhileLoop(
2756 rp: RestorePoint,2106 c: *Context,
2757 scope: *Scope,2107 scope: *Scope,
2758 stmt: *const clang.DoStmt,2108 stmt: *const clang.DoStmt,
2759) TransError!*ast.Node {2109) TransError!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;
2765 var loop_scope = Scope{2110 var loop_scope = Scope{
2766 .parent = scope,2111 .parent = scope,
2767 .id = .Loop,2112 .id = .do_loop,
2768 };2113 };
27692114
2770 // if (!cond) break;2115 // if (!cond) break;
2771 const if_node = try transCreateNodeIf(rp.c);
2772 var cond_scope = Scope.Condition{2116 var cond_scope = Scope.Condition{
2773 .base = .{2117 .base = .{
2774 .parent = scope,2118 .parent = scope,
2775 .id = .Condition,2119 .id = .condition,
2776 },2120 },
2777 };2121 };
2778 defer cond_scope.deinit();2122 defer cond_scope.deinit();
2779 const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");2123 const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used);
2780 prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value, true);2124 const if_not_break = switch (cond.tag()) {
2781 _ = try appendToken(rp.c, .RParen, ")");2125 .false_literal => return transStmt(c, scope, stmt.getBody(), .unused),
2782 if_node.condition = &prefix_op.base;2126 .true_literal => {
2783 if_node.body = &(try transCreateNodeBreak(rp.c, null, null)).base;2127 const body_node = try transStmt(c, scope, stmt.getBody(), .unused);
2784 _ = try appendToken(rp.c, .Semicolon, ";");2128 return Tag.while_true.create(c.arena, body_node);
2129 },
2130 else => try Tag.if_not_break.create(c.arena, cond),
2131 };
27852132
2786 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {2133 const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
2787 // there's already a block in C, so we'll append our condition to it.2134 // there's already a block in C, so we'll append our condition to it.
...@@ -2794,8 +2141,11 @@ fn transDoWhileLoop(...@@ -2794,8 +2141,11 @@ fn transDoWhileLoop(
2794 // zig: b;2141 // zig: b;
2795 // zig: if (!cond) break;2142 // zig: if (!cond) break;
2796 // zig: }2143 // zig: }
2797 const node = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2144 const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2798 break :blk node.castTag(.Block).?;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;
2799 } else blk: {2149 } else blk: {
2800 // the C statement is without a block, so we need to create a block to contain it.2150 // the C statement is without a block, so we need to create a block to contain it.
2801 // c: do2151 // c: do
...@@ -2805,387 +2155,355 @@ fn transDoWhileLoop(...@@ -2805,387 +2155,355 @@ fn transDoWhileLoop(
2805 // zig: a;2155 // zig: a;
2806 // zig: if (!cond) break;2156 // zig: if (!cond) break;
2807 // zig: }2157 // zig: }
2808 new = true;2158 const statements = try c.arena.alloc(Node, 2);
2809 const block = try rp.c.createBlock(2);2159 statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused);
2810 block.statements_len = 1; // over-allocated so we can add another below2160 statements[1] = if_not_break;
2811 block.statements()[0] = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);2161 break :blk try Tag.block.create(c.arena, .{ .label = null, .stmts = statements });
2812 break :blk block;
2813 };2162 };
28142163 return Tag.while_true.create(c.arena, body_node);
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;
2822}2164}
28232165
2824fn transForLoop(2166fn transForLoop(
2825 rp: RestorePoint,2167 c: *Context,
2826 scope: *Scope,2168 scope: *Scope,
2827 stmt: *const clang.ForStmt,2169 stmt: *const clang.ForStmt,
2828) TransError!*ast.Node {2170) TransError!Node {
2829 var loop_scope = Scope{2171 var loop_scope = Scope{
2830 .parent = scope,2172 .parent = scope,
2831 .id = .Loop,2173 .id = .loop,
2832 };2174 };
28332175
2834 var block_scope: ?Scope.Block = null;2176 var block_scope: ?Scope.Block = null;
2835 defer if (block_scope) |*bs| bs.deinit();2177 defer if (block_scope) |*bs| bs.deinit();
28362178
2837 if (stmt.getInit()) |init| {2179 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);
2839 loop_scope.parent = &block_scope.?.base;2181 loop_scope.parent = &block_scope.?.base;
2840 const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);2182 const init_node = try transStmt(c, &block_scope.?.base, init, .unused);
2841 try block_scope.?.statements.append(init_node);2183 if (init_node.tag() != .declaration) try block_scope.?.statements.append(init_node);
2842 }2184 }
2843 var cond_scope = Scope.Condition{2185 var cond_scope = Scope.Condition{
2844 .base = .{2186 .base = .{
2845 .parent = &loop_scope,2187 .parent = &loop_scope,
2846 .id = .Condition,2188 .id = .condition,
2847 },2189 },
2848 };2190 };
2849 defer cond_scope.deinit();2191 defer cond_scope.deinit();
28502192
2851 const while_node = try transCreateNodeWhile(rp.c);2193 const cond = if (stmt.getCond()) |cond|
2852 while_node.condition = if (stmt.getCond()) |cond|2194 try transBoolExpr(c, &cond_scope.base, cond, .used)
2853 try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
2854 else2195 else
2855 try transCreateNodeBoolLiteral(rp.c, true);2196 Tag.true_literal.init();
2856 _ = try appendToken(rp.c, .RParen, ")");
28572197
2858 if (stmt.getInc()) |incr| {2198 const cont_expr = if (stmt.getInc()) |incr|
2859 _ = try appendToken(rp.c, .Colon, ":");2199 try transExpr(c, &cond_scope.base, incr, .unused)
2860 _ = try appendToken(rp.c, .LParen, "(");2200 else
2861 while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value);2201 null;
2862 _ = try appendToken(rp.c, .RParen, ")");
2863 }
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 });
2866 if (block_scope) |*bs| {2205 if (block_scope) |*bs| {
2867 try bs.statements.append(&while_node.base);2206 try bs.statements.append(while_node);
2868 return try bs.complete(rp.c);2207 return try bs.complete(c);
2869 } else {2208 } else {
2870 _ = try appendToken(rp.c, .Semicolon, ";");2209 return while_node;
2871 return &while_node.base;
2872 }2210 }
2873}2211}
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
2886fn transSwitch(2213fn transSwitch(
2887 rp: RestorePoint,2214 c: *Context,
2888 scope: *Scope,2215 scope: *Scope,
2889 stmt: *const clang.SwitchStmt,2216 stmt: *const clang.SwitchStmt,
2890) TransError!*ast.Node {2217) TransError!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
2896 var cond_scope = Scope.Condition{2218 var cond_scope = Scope.Condition{
2897 .base = .{2219 .base = .{
2898 .parent = scope,2220 .parent = scope,
2899 .id = .Condition,2221 .id = .condition,
2900 },2222 },
2901 };2223 };
2902 defer cond_scope.deinit();2224 defer cond_scope.deinit();
2903 const switch_expr = try transExpr(rp, &cond_scope.base, stmt.getCond(), .used, .r_value);2225 const switch_expr = try transExpr(c, &cond_scope.base, stmt.getCond(), .used);
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 };
29142226
2915 var switch_scope = Scope.Switch{2227 var cases = std.ArrayList(Node).init(c.gpa);
2916 .base = .{2228 defer cases.deinit();
2917 .id = .Switch,2229 var has_default = false;
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 };
29262230
2927 // tmp block that all statements will go before being picked up by a case or default2231 const body = stmt.getBody();
2928 var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, false);2232 assert(body.getStmtClass() == .CompoundStmtClass);
2929 defer block_scope.deinit();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 field2269 const res = try transSwitchProngStmt(c, scope, sub, it, end_it);
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, ",");
29642270
2965 if (switch_scope.case_index >= switch_scope.cases.len)2271 const switch_else = try Tag.switch_else.create(c.arena, res);
2966 return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});2272 try cases.append(switch_else);
2967 switch_scope.cases[switch_scope.case_index] = &else_prong.base;2273 },
2968 switch_scope.case_index += 1;2274 else => {}, // collected in transSwitchProngStmt
2275 }
2969 }2276 }
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);2278 if (!has_default) {
2975 switch_scope.pending_block.deinit();2279 const else_prong = try Tag.switch_else.create(c.arena, Tag.@"break".init());
2976 return result_node;2280 try cases.append(else_prong);
2977}2281 }
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, ",");
30112282
3012 if (switch_scope.case_index >= switch_scope.cases.len)2283 return Tag.@"switch".create(c.arena, .{
3013 return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});2284 .cond = switch_expr,
3014 switch_scope.cases[switch_scope.case_index] = &switch_prong.base;2285 .cases = try c.arena.dupe(Node, cases.items),
3015 switch_scope.case_index += 1;2286 });
2287}
30162288
3017 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);2289/// Collects all items for this case, returns the first statement after the labels.
3018 _ = try appendToken(rp.c, .Colon, ":");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 statements2305 if (seen_default) {
3021 try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);2306 items.items.len = 0;
3022 block_scope.statements.shrinkAndFree(0);2307 sub = case_stmt.getSubStmt();
2308 continue;
2309 }
30232310
3024 const pending_node = try switch_scope.pending_block.complete(rp.c);2311 const expr = if (case_stmt.getRHS()) |rhs| blk: {
3025 switch_scope.pending_block.deinit();2312 const lhs_node = try transExprCoercing(c, scope, case_stmt.getLHS(), .used);
3026 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);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 }
3031}2325}
30322326
3033fn transDefault(2327/// Collects all statements seen by this case into a block.
3034 rp: RestorePoint,2328/// Avoids creating a block if the first statement is a break or return.
2329fn transSwitchProngStmt(
2330 c: *Context,
3035 scope: *Scope,2331 scope: *Scope,
3036 stmt: *const clang.DefaultStmt,2332 stmt: *const clang.Stmt,
3037) TransError!*ast.Node {2333 parent_it: clang.CompoundStmt.ConstBodyIterator,
3038 const block_scope = scope.findBlockScope(rp.c) catch unreachable;2334 parent_end_it: clang.CompoundStmt.ConstBodyIterator,
3039 const switch_scope = scope.getSwitch();2335) TransError!Node {
3040 switch_scope.default_label = try block_scope.makeMangledName(rp.c, "default");2336 switch (stmt.getStmtClass()) {
3041 _ = try appendToken(rp.c, .Semicolon, ";");2337 .BreakStmtClass => return Tag.empty_block.init(),
30422338 .ReturnStmtClass => return transStmt(c, scope, stmt, .unused),
3043 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));2339 .CaseStmtClass, .DefaultStmtClass => unreachable,
3044 else_prong.expr = blk: {2340 else => {
3045 var br = try CtrlFlow.init(rp.c, .Break, switch_scope.default_label.?);2341 var block_scope = try Scope.Block.init(c, scope, false);
3046 break :blk &(try br.finish(null)).base;2342 defer block_scope.deinit();
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);
30612343
3062 const pending_node = try switch_scope.pending_block.complete(rp.c);2344 // we do not need to translate `stmt` since it is the first stmt of `parent_it`
3063 switch_scope.pending_block.deinit();2345 try transSwitchProngStmtInline(c, &block_scope, parent_it, parent_end_it);
3064 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);2346 return try block_scope.complete(c);
3065 try switch_scope.pending_block.statements.append(pending_node);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;
3068}2411}
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 {
3071 var result: clang.ExprEvalResult = undefined;2414 var result: clang.ExprEvalResult = undefined;
3072 if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, rp.c.clang_context))2415 if (!expr.evaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context))
3073 return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{});2416 return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{});
30742417
3075 var val_node: ?*ast.Node = null;
3076 switch (result.Val.getKind()) {2418 switch (result.Val.getKind()) {
3077 .Int => {2419 .Int => {
3078 // See comment in `transIntegerLiteral` for why this code is here.2420 // See comment in `transIntegerLiteral` for why this code is here.
3079 // @as(T, x)2421 // @as(T, x)
3080 const expr_base = @ptrCast(*const clang.Expr, expr);2422 const expr_base = @ptrCast(*const clang.Expr, expr);
3081 const as_node = try rp.c.createBuiltinCall("@as", 2);2423 const as_node = try Tag.as.create(c.arena, .{
3082 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());2424 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
3083 as_node.params()[0] = ty_node;2425 .rhs = try transCreateNodeAPInt(c, result.Val.getInt()),
3084 _ = try appendToken(rp.c, .Comma, ",");2426 });
30852427 return maybeSuppressResult(c, scope, used, as_node);
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);
3092 },2428 },
3093 else => {2429 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", .{});
3095 },2431 },
3096 }2432 }
3097}2433}
30982434
3099fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!*ast.Node {2435fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!Node {
3100 return transStringLiteral(rp, scope, expr.getFunctionName(), used);2436 return transStringLiteral(c, scope, expr.getFunctionName(), used);
3101}2437}
31022438
3103fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!*ast.Node {2439fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node {
3104 const node = try c.arena.create(ast.Node.OneToken);2440 return Tag.char_literal.create(c.arena, if (narrow)
3105 node.* = .{2441 try std.fmt.allocPrint(c.arena, "'{s}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})})
3106 .base = .{ .tag = .CharLiteral },2442 else
3107 .token = undefined,2443 try std.fmt.allocPrint(c.arena, "'\\u{{{x}}}'", .{val}));
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;
3116}2444}
31172445
3118fn transCharLiteral(2446fn transCharLiteral(
3119 rp: RestorePoint,2447 c: *Context,
3120 scope: *Scope,2448 scope: *Scope,
3121 stmt: *const clang.CharacterLiteral,2449 stmt: *const clang.CharacterLiteral,
3122 result_used: ResultUsed,2450 result_used: ResultUsed,
3123 suppress_as: SuppressCast,2451 suppress_as: SuppressCast,
3124) TransError!*ast.Node {2452) TransError!Node {
3125 const kind = stmt.getKind();2453 const kind = stmt.getKind();
3126 const val = stmt.getValue();2454 const val = stmt.getValue();
3127 const narrow = kind == .Ascii or kind == .UTF8;2455 const narrow = kind == .Ascii or kind == .UTF8;
3128 // C has a somewhat obscure feature called multi-character character constant2456 // C has a somewhat obscure feature called multi-character character constant
3129 // e.g. 'abcd'2457 // e.g. 'abcd'
3130 const int_lit_node = if (kind == .Ascii and val > 255)2458 const int_lit_node = if (kind == .Ascii and val > 255)
3131 try transCreateNodeInt(rp.c, val)2459 try transCreateNodeNumber(c, val, .int)
3132 else2460 else
3133 try transCreateCharLitNode(rp.c, narrow, val);2461 try transCreateCharLitNode(c, narrow, val);
31342462
3135 if (suppress_as == .no_as) {2463 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);
3137 }2465 }
3138 // See comment in `transIntegerLiteral` for why this code is here.2466 // See comment in `transIntegerLiteral` for why this code is here.
3139 // @as(T, x)2467 // @as(T, x)
3140 const expr_base = @ptrCast(*const clang.Expr, stmt);2468 const expr_base = @ptrCast(*const clang.Expr, stmt);
3141 const as_node = try rp.c.createBuiltinCall("@as", 2);2469 const as_node = try Tag.as.create(c.arena, .{
3142 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());2470 .lhs = try transQualType(c, scope, expr_base.getType(), expr_base.getBeginLoc()),
3143 as_node.params()[0] = ty_node;2471 .rhs = int_lit_node,
3144 _ = try appendToken(rp.c, .Comma, ",");2472 });
3145 as_node.params()[1] = int_lit_node;2473 return maybeSuppressResult(c, scope, result_used, as_node);
3146
3147 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3148 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
3149}2474}
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 {
3152 const comp = stmt.getSubStmt();2477 const comp = stmt.getSubStmt();
3153 if (used == .unused) {2478 if (used == .unused) {
3154 return transCompoundStmt(rp, scope, comp);2479 return transCompoundStmt(c, scope, comp);
3155 }2480 }
3156 const lparen = try appendToken(rp.c, .LParen, "(");2481 var block_scope = try Scope.Block.init(c, scope, true);
3157 var block_scope = try Scope.Block.init(rp.c, scope, true);
3158 defer block_scope.deinit();2482 defer block_scope.deinit();
31592483
3160 var it = comp.body_begin();2484 var it = comp.body_begin();
3161 const end_it = comp.body_end();2485 const end_it = comp.body_end();
3162 while (it != end_it - 1) : (it += 1) {2486 while (it != end_it - 1) : (it += 1) {
3163 const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);2487 const result = try transStmt(c, &block_scope.base, it[0], .unused);
3164 try block_scope.statements.append(result);2488 switch (result.tag()) {
2489 .declaration, .empty_block => {},
2490 else => try block_scope.statements.append(result),
2491 }
3165 }2492 }
3166 const break_node = blk: {2493 const break_node = try Tag.break_val.create(c.arena, .{
3167 var tmp = try CtrlFlow.init(rp.c, .Break, "blk");2494 .label = block_scope.label,
3168 const rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value);2495 .val = try transStmt(c, &block_scope.base, it[0], .used),
3169 break :blk try tmp.finish(rhs);2496 });
3170 };2497 try block_scope.statements.append(break_node);
3171 _ = try appendToken(rp.c, .Semicolon, ";");2498 const res = try block_scope.complete(c);
3172 try block_scope.statements.append(&break_node.base);2499 return maybeSuppressResult(c, scope, used, res);
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);
3182}2500}
31832501
3184fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node {2502fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!Node {
3185 var container_node = try transExpr(rp, scope, stmt.getBase(), .used, .r_value);2503 var container_node = try transExpr(c, scope, stmt.getBase(), .used);
31862504
3187 if (stmt.isArrow()) {2505 if (stmt.isArrow()) {
3188 container_node = try transCreateNodePtrDeref(rp.c, container_node);2506 container_node = try Tag.deref.create(c.arena, container_node);
3189 }2507 }
31902508
3191 const member_decl = stmt.getMemberDecl();2509 const member_decl = stmt.getMemberDecl();
...@@ -3196,19 +2514,18 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExp...@@ -3196,19 +2514,18 @@ fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExp
3196 if (decl_kind == .Field) {2514 if (decl_kind == .Field) {
3197 const field_decl = @ptrCast(*const clang.FieldDecl, member_decl);2515 const field_decl = @ptrCast(*const clang.FieldDecl, member_decl);
3198 if (field_decl.isAnonymousStructOrUnion()) {2516 if (field_decl.isAnonymousStructOrUnion()) {
3199 const name = rp.c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;2517 const name = c.decl_table.get(@ptrToInt(field_decl.getCanonicalDecl())).?;
3200 break :blk try mem.dupe(rp.c.arena, u8, name);2518 break :blk try mem.dupe(c.arena, u8, name);
3201 }2519 }
3202 }2520 }
3203 const decl = @ptrCast(*const clang.NamedDecl, member_decl);2521 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());
3205 };2523 };
32062524 const node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .field_name = name });
3207 const node = try transCreateNodeFieldAccess(rp.c, container_node, name);2525 return maybeSuppressResult(c, scope, result_used, node);
3208 return maybeSuppressResult(rp, scope, result_used, node);
3209}2526}
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 {
3212 var base_stmt = stmt.getBase();2529 var base_stmt = stmt.getBase();
32132530
3214 // Unwrap the base statement if it's an array decayed to a bare pointer type2531 // 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...@@ -3221,30 +2538,26 @@ fn transArrayAccess(rp: RestorePoint, scope: *Scope, stmt: *const clang.ArraySub
3221 }2538 }
3222 }2539 }
32232540
3224 const container_node = try transExpr(rp, scope, base_stmt, .used, .r_value);2541 const container_node = try transExpr(c, scope, base_stmt, .used);
3225 const node = try transCreateNodeArrayAccess(rp.c, container_node);
32262542
3227 // cast if the index is long long or signed2543 // cast if the index is long long or signed
3228 const subscr_expr = stmt.getIdx();2544 const subscr_expr = stmt.getIdx();
3229 const qt = getExprQualType(rp.c, subscr_expr);2545 const qt = getExprQualType(c, subscr_expr);
3230 const is_longlong = cIsLongLongInteger(qt);2546 const is_longlong = cIsLongLongInteger(qt);
3231 const is_signed = cIsSignedInteger(qt);2547 const is_signed = cIsSignedInteger(qt);
32322548
3233 if (is_longlong or is_signed) {2549 const rhs = if (is_longlong or is_signed) blk: {
3234 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);
3235 // check if long long first so that signed long long doesn't just become unsigned long long2550 // 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);2551 var typeid_node = if (is_longlong) try Tag.identifier.create(c.arena, "usize") else try transQualTypeIntWidthOf(c, qt, false);
3237 cast_node.params()[0] = typeid_node;2552 break :blk try Tag.int_cast.create(c.arena, .{ .lhs = typeid_node, .rhs = try transExpr(c, scope, subscr_expr, .used) });
3238 _ = try appendToken(rp.c, .Comma, ",");2553 } else
3239 cast_node.params()[1] = try transExpr(rp, scope, subscr_expr, .used, .r_value);2554 try transExpr(c, scope, subscr_expr, .used);
3240 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");2555
3241 node.rtoken = try appendToken(rp.c, .RBrace, "]");2556 const node = try Tag.array_access.create(c.arena, .{
3242 node.index_expr = &cast_node.base;2557 .lhs = container_node,
3243 } else {2558 .rhs = rhs,
3244 node.index_expr = try transExpr(rp, scope, subscr_expr, .used, .r_value);2559 });
3245 node.rtoken = try appendToken(rp.c, .RBrace, "]");2560 return maybeSuppressResult(c, scope, result_used, node);
3246 }
3247 return maybeSuppressResult(rp, scope, result_used, &node.base);
3248}2561}
32492562
3250/// Check if an expression is ultimately a reference to a function declaration2563/// Check if an expression is ultimately a reference to a function declaration
...@@ -3279,29 +2592,25 @@ fn cIsFunctionDeclRef(expr: *const clang.Expr) bool {...@@ -3279,29 +2592,25 @@ fn cIsFunctionDeclRef(expr: *const clang.Expr) bool {
3279 }2592 }
3280}2593}
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 {
3283 const callee = stmt.getCallee();2596 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
3286 var is_ptr = false;2599 var is_ptr = false;
3287 const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr);2600 const fn_ty = qualTypeGetFnProto(callee.getType(), &is_ptr);
32882601
3289 const fn_expr = if (is_ptr and fn_ty != null and !cIsFunctionDeclRef(callee))2602 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)
3291 else2604 else
3292 raw_fn_expr;2605 raw_fn_expr;
32932606
3294 const num_args = stmt.getNumArgs();2607 const num_args = stmt.getNumArgs();
3295 const node = try rp.c.createCall(fn_expr, num_args);2608 const args = try c.arena.alloc(Node, num_args);
3296 const call_params = node.params();
32972609
3298 const args = stmt.getArgs();2610 const c_args = stmt.getArgs();
3299 var i: usize = 0;2611 var i: usize = 0;
3300 while (i < num_args) : (i += 1) {2612 while (i < num_args) : (i += 1) {
3301 if (i != 0) {2613 var arg = try transExpr(c, scope, c_args[i], .used);
3302 _ = try appendToken(rp.c, .Comma, ",");
3303 }
3304 var call_param = try transExpr(rp, scope, args[i], .used, .r_value);
33052614
3306 // In C the result type of a boolean expression is int. If this result is passed as2615 // In C the result type of a boolean expression is int. If this result is passed as
3307 // an argument to a function whose parameter is also int, there is no cast. Therefore2616 // 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...@@ -3312,31 +2621,26 @@ fn transCallExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.CallExpr, r
3312 const param_count = fn_proto.getNumParams();2621 const param_count = fn_proto.getNumParams();
3313 if (i < param_count) {2622 if (i < param_count) {
3314 const param_qt = fn_proto.getParamType(@intCast(c_uint, i));2623 const param_qt = fn_proto.getParamType(@intCast(c_uint, i));
3315 if (isBoolRes(call_param) and cIsNativeInt(param_qt)) {2624 if (isBoolRes(arg) and cIsNativeInt(param_qt)) {
3316 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);2625 arg = try Tag.bool_to_int.create(c.arena, arg);
3317 builtin_node.params()[0] = call_param;
3318 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3319 call_param = &builtin_node.base;
3320 }2626 }
3321 }2627 }
3322 },2628 },
3323 else => {},2629 else => {},
3324 }2630 }
3325 }2631 }
3326 call_params[i] = call_param;2632 args[i] = arg;
3327 }2633 }
3328 node.rtoken = try appendToken(rp.c, .RParen, ")");2634 const node = try Tag.call.create(c.arena, .{ .lhs = fn_expr, .args = args });
3329
3330 if (fn_ty) |ty| {2635 if (fn_ty) |ty| {
3331 const canon = ty.getReturnType().getCanonicalType();2636 const canon = ty.getReturnType().getCanonicalType();
3332 const ret_ty = canon.getTypePtr();2637 const ret_ty = canon.getTypePtr();
3333 if (ret_ty.isVoidType()) {2638 if (ret_ty.isVoidType()) {
3334 _ = try appendToken(rp.c, .Semicolon, ";");2639 return node;
3335 return &node.base;
3336 }2640 }
3337 }2641 }
33382642
3339 return maybeSuppressResult(rp, scope, result_used, &node.base);2643 return maybeSuppressResult(c, scope, result_used, node);
3340}2644}
33412645
3342const ClangFunctionType = union(enum) {2646const ClangFunctionType = union(enum) {
...@@ -3371,38 +2675,29 @@ fn qualTypeGetFnProto(qt: clang.QualType, is_ptr: *bool) ?ClangFunctionType {...@@ -3371,38 +2675,29 @@ fn qualTypeGetFnProto(qt: clang.QualType, is_ptr: *bool) ?ClangFunctionType {
3371}2675}
33722676
3373fn transUnaryExprOrTypeTraitExpr(2677fn transUnaryExprOrTypeTraitExpr(
3374 rp: RestorePoint,2678 c: *Context,
3375 scope: *Scope,2679 scope: *Scope,
3376 stmt: *const clang.UnaryExprOrTypeTraitExpr,2680 stmt: *const clang.UnaryExprOrTypeTraitExpr,
3377 result_used: ResultUsed,2681 result_used: ResultUsed,
3378) TransError!*ast.Node {2682) TransError!Node {
3379 const loc = stmt.getBeginLoc();2683 const loc = stmt.getBeginLoc();
3380 const type_node = try transQualType(2684 const type_node = try transQualType(c, scope, stmt.getTypeOfArgument(), loc);
3381 rp,
3382 stmt.getTypeOfArgument(),
3383 loc,
3384 );
33852685
3386 const kind = stmt.getKind();2686 const kind = stmt.getKind();
3387 const kind_str = switch (kind) {2687 switch (kind) {
3388 .SizeOf => "@sizeOf",2688 .SizeOf => return Tag.sizeof.create(c.arena, type_node),
3389 .AlignOf => "@alignOf",2689 .AlignOf => return Tag.alignof.create(c.arena, type_node),
3390 .PreferredAlignOf,2690 .PreferredAlignOf,
3391 .VecStep,2691 .VecStep,
3392 .OpenMPRequiredSimdAlign,2692 .OpenMPRequiredSimdAlign,
3393 => return revertAndWarn(2693 => return fail(
3394 rp,2694 c,
3395 error.UnsupportedTranslation,2695 error.UnsupportedTranslation,
3396 loc,2696 loc,
3397 "Unsupported type trait kind {}",2697 "Unsupported type trait kind {}",
3398 .{kind},2698 .{kind},
3399 ),2699 ),
3400 };2700 }
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);
3406}2701}
34072702
3408fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {2703fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
...@@ -3415,95 +2710,79 @@ fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {...@@ -3415,95 +2710,79 @@ fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
3415 }2710 }
3416}2711}
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 {
3419 const op_expr = stmt.getSubExpr();2714 const op_expr = stmt.getSubExpr();
3420 switch (stmt.getOpcode()) {2715 switch (stmt.getOpcode()) {
3421 .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType()))2716 .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3422 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)2717 return transCreatePostCrement(c, scope, stmt, .add_wrap_assign, used)
3423 else2718 else
3424 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),2719 return transCreatePostCrement(c, scope, stmt, .add_assign, used),
3425 .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType()))2720 .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3426 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)2721 return transCreatePostCrement(c, scope, stmt, .sub_wrap_assign, used)
3427 else2722 else
3428 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),2723 return transCreatePostCrement(c, scope, stmt, .sub_assign, used),
3429 .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType()))2724 .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3430 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)2725 return transCreatePreCrement(c, scope, stmt, .add_wrap_assign, used)
3431 else2726 else
3432 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),2727 return transCreatePreCrement(c, scope, stmt, .add_assign, used),
3433 .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType()))2728 .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3434 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)2729 return transCreatePreCrement(c, scope, stmt, .sub_wrap_assign, used)
3435 else2730 else
3436 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),2731 return transCreatePreCrement(c, scope, stmt, .sub_assign, used),
3437 .AddrOf => {2732 .AddrOf => {
3438 if (cIsFunctionDeclRef(op_expr)) {2733 if (cIsFunctionDeclRef(op_expr)) {
3439 return transExpr(rp, scope, op_expr, used, .r_value);2734 return transExpr(c, scope, op_expr, used);
3440 }2735 }
3441 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");2736 return Tag.address_of.create(c.arena, try transExpr(c, scope, op_expr, used));
3442 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
3443 return &op_node.base;
3444 },2737 },
3445 .Deref => {2738 .Deref => {
3446 const value_node = try transExpr(rp, scope, op_expr, used, .r_value);2739 const node = try transExpr(c, scope, op_expr, used);
3447 var is_ptr = false;2740 var is_ptr = false;
3448 const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);2741 const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);
3449 if (fn_ty != null and is_ptr)2742 if (fn_ty != null and is_ptr)
3450 return value_node;2743 return node;
3451 const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);2744 const unwrapped = try Tag.unwrap.create(c.arena, node);
3452 return transCreateNodePtrDeref(rp.c, unwrapped);2745 return Tag.deref.create(c.arena, unwrapped);
3453 },2746 },
3454 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),2747 .Plus => return transExpr(c, scope, op_expr, used),
3455 .Minus => {2748 .Minus => {
3456 if (!qualTypeHasWrappingOverflow(op_expr.getType())) {2749 if (!qualTypeHasWrappingOverflow(op_expr.getType())) {
3457 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-");2750 return Tag.negate.create(c.arena, try transExpr(c, scope, op_expr, .used));
3458 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3459 return &op_node.base;
3460 } else if (cIsUnsignedInteger(op_expr.getType())) {2751 } else if (cIsUnsignedInteger(op_expr.getType())) {
3461 // we gotta emit 0 -% x2752 // use -% x for unsigned integers
3462 const zero = try transCreateNodeInt(rp.c, 0);2753 return Tag.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used));
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);
3466 } else2754 } 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", .{});
3468 },2756 },
3469 .Not => {2757 .Not => {
3470 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");2758 return Tag.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used));
3471 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3472 return &op_node.base;
3473 },2759 },
3474 .LNot => {2760 .LNot => {
3475 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");2761 return Tag.not.create(c.arena, try transBoolExpr(c, scope, op_expr, .used));
3476 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
3477 return &op_node.base;
3478 },2762 },
3479 .Extension => {2763 .Extension => {
3480 return transExpr(rp, scope, stmt.getSubExpr(), used, .l_value);2764 return transExpr(c, scope, stmt.getSubExpr(), used);
3481 },2765 },
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()}),
3483 }2767 }
3484}2768}
34852769
3486fn transCreatePreCrement(2770fn transCreatePreCrement(
3487 rp: RestorePoint,2771 c: *Context,
3488 scope: *Scope,2772 scope: *Scope,
3489 stmt: *const clang.UnaryOperator,2773 stmt: *const clang.UnaryOperator,
3490 op: ast.Node.Tag,2774 op: Tag,
3491 op_tok_id: std.zig.Token.Id,
3492 bytes: []const u8,
3493 used: ResultUsed,2775 used: ResultUsed,
3494) TransError!*ast.Node {2776) TransError!Node {
3495 const op_expr = stmt.getSubExpr();2777 const op_expr = stmt.getSubExpr();
34962778
3497 if (used == .unused) {2779 if (used == .unused) {
3498 // common case2780 // common case
3499 // c: ++expr2781 // c: ++expr
3500 // zig: expr += 12782 // zig: expr += 1
3501 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);2783 const lhs = try transExpr(c, scope, op_expr, .used);
3502 const token = try appendToken(rp.c, op_tok_id, bytes);2784 const rhs = Tag.one_literal.init();
3503 const one = try transCreateNodeInt(rp.c, 1);2785 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);
3504 if (scope.id != .Condition)
3505 _ = try appendToken(rp.c, .Semicolon, ";");
3506 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
3507 }2786 }
3508 // worst case2787 // worst case
3509 // c: ++expr2788 // c: ++expr
...@@ -3512,71 +2791,44 @@ fn transCreatePreCrement(...@@ -3512,71 +2791,44 @@ fn transCreatePreCrement(
3512 // zig: _ref.* += 1;2791 // zig: _ref.* += 1;
3513 // zig: break :blk _ref.*2792 // zig: break :blk _ref.*
3514 // zig: })2793 // zig: })
3515 var block_scope = try Scope.Block.init(rp.c, scope, true);2794 var block_scope = try Scope.Block.init(c, scope, true);
3516 defer block_scope.deinit();2795 defer block_scope.deinit();
3517 const ref = try block_scope.makeMangledName(rp.c, "ref");2796 const ref = try block_scope.makeMangledName(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);
35442797
3545 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);2798 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
3546 try block_scope.statements.append(&break_node.base);2799 const addr_of = try Tag.address_of.create(c.arena, expr);
3547 const block_node = try block_scope.complete(rp.c);2800 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
3548 // semicolon must immediately follow rbrace because it is the last token in a block2801 try block_scope.statements.append(ref_decl);
3549 _ = try appendToken(rp.c, .Semicolon, ";");2802
3550 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);2803 const lhs_node = try Tag.identifier.create(c.arena, ref);
3551 grouped_expr.* = .{2804 const ref_node = try Tag.deref.create(c.arena, lhs_node);
3552 .lparen = try appendToken(rp.c, .LParen, "("),2805 const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);
3553 .expr = block_node,2806 try block_scope.statements.append(node);
3554 .rparen = try appendToken(rp.c, .RParen, ")"),2807
3555 };2808 const break_node = try Tag.break_val.create(c.arena, .{
3556 return &grouped_expr.base;2809 .label = block_scope.label,
2810 .val = ref_node,
2811 });
2812 try block_scope.statements.append(break_node);
2813 return block_scope.complete(c);
3557}2814}
35582815
3559fn transCreatePostCrement(2816fn transCreatePostCrement(
3560 rp: RestorePoint,2817 c: *Context,
3561 scope: *Scope,2818 scope: *Scope,
3562 stmt: *const clang.UnaryOperator,2819 stmt: *const clang.UnaryOperator,
3563 op: ast.Node.Tag,2820 op: Tag,
3564 op_tok_id: std.zig.Token.Id,
3565 bytes: []const u8,
3566 used: ResultUsed,2821 used: ResultUsed,
3567) TransError!*ast.Node {2822) TransError!Node {
3568 const op_expr = stmt.getSubExpr();2823 const op_expr = stmt.getSubExpr();
35692824
3570 if (used == .unused) {2825 if (used == .unused) {
3571 // common case2826 // common case
3572 // c: ++expr2827 // c: expr++
3573 // zig: expr += 12828 // zig: expr += 1
3574 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);2829 const lhs = try transExpr(c, scope, op_expr, .used);
3575 const token = try appendToken(rp.c, op_tok_id, bytes);2830 const rhs = Tag.one_literal.init();
3576 const one = try transCreateNodeInt(rp.c, 1);2831 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, .used);
3577 if (scope.id != .Condition)
3578 _ = try appendToken(rp.c, .Semicolon, ";");
3579 return transCreateNodeInfixOp(rp, scope, expr, op, token, one, .used, false);
3580 }2832 }
3581 // worst case2833 // worst case
3582 // c: expr++2834 // c: expr++
...@@ -3586,93 +2838,56 @@ fn transCreatePostCrement(...@@ -3586,93 +2838,56 @@ fn transCreatePostCrement(
3586 // zig: _ref.* += 1;2838 // zig: _ref.* += 1;
3587 // zig: break :blk _tmp2839 // zig: break :blk _tmp
3588 // zig: })2840 // zig: })
3589 var block_scope = try Scope.Block.init(rp.c, scope, true);2841 var block_scope = try Scope.Block.init(c, scope, true);
3590 defer block_scope.deinit();2842 defer block_scope.deinit();
3591 const ref = try block_scope.makeMangledName(rp.c, "ref");2843 const ref = try block_scope.makeMangledName(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);
36292844
3630 const token = try appendToken(rp.c, op_tok_id, bytes);2845 const expr = try transExpr(c, &block_scope.base, op_expr, .used);
3631 const one = try transCreateNodeInt(rp.c, 1);2846 const addr_of = try Tag.address_of.create(c.arena, expr);
3632 _ = try appendToken(rp.c, .Semicolon, ";");2847 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
3633 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);2848 try block_scope.statements.append(ref_decl);
3634 try block_scope.statements.append(assign);
36352849
3636 const break_node = blk: {2850 const lhs_node = try Tag.identifier.create(c.arena, ref);
3637 var tmp_ctrl_flow = try CtrlFlow.initToken(rp.c, .Break, block_scope.label);2851 const ref_node = try Tag.deref.create(c.arena, lhs_node);
3638 const rhs = try transCreateNodeIdentifier(rp.c, tmp);2852
3639 break :blk try tmp_ctrl_flow.finish(rhs);2853 const tmp = try block_scope.makeMangledName(c, "tmp");
3640 };2854 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });
3641 try block_scope.statements.append(&break_node.base);2855 try block_scope.statements.append(tmp_decl);
3642 _ = try appendToken(rp.c, .Semicolon, ";");2856
3643 const block_node = try block_scope.complete(rp.c);2857 const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);
3644 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);2858 try block_scope.statements.append(node);
3645 grouped_expr.* = .{2859
3646 .lparen = try appendToken(rp.c, .LParen, "("),2860 const break_node = try Tag.break_val.create(c.arena, .{
3647 .expr = block_node,2861 .label = block_scope.label,
3648 .rparen = try appendToken(rp.c, .RParen, ")"),2862 .val = try Tag.identifier.create(c.arena, tmp),
3649 };2863 });
3650 return &grouped_expr.base;2864 try block_scope.statements.append(break_node);
2865 return block_scope.complete(c);
3651}2866}
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 {
3654 switch (stmt.getOpcode()) {2869 switch (stmt.getOpcode()) {
3655 .MulAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))2870 .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)
3657 else2872 else
3658 return transCreateCompoundAssign(rp, scope, stmt, .AssignMul, .AsteriskEqual, "*=", .Mul, .Asterisk, "*", used),2873 return transCreateCompoundAssign(c, scope, stmt, .mul_assign, used),
3659 .AddAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))2874 .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)
3661 else2876 else
3662 return transCreateCompoundAssign(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", .Add, .Plus, "+", used),2877 return transCreateCompoundAssign(c, scope, stmt, .add_assign, used),
3663 .SubAssign => if (qualTypeHasWrappingOverflow(stmt.getType()))2878 .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)
3665 else2880 else
3666 return transCreateCompoundAssign(rp, scope, stmt, .AssignSub, .MinusPercentEqual, "-=", .Sub, .Minus, "-", used),2881 return transCreateCompoundAssign(c, scope, stmt, .sub_assign, used),
3667 .DivAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignDiv, .SlashEqual, "/=", .Div, .Slash, "/", used),2882 .DivAssign => return transCreateCompoundAssign(c, scope, stmt, .div_assign, used),
3668 .RemAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignMod, .PercentEqual, "%=", .Mod, .Percent, "%", used),2883 .RemAssign => return transCreateCompoundAssign(c, scope, stmt, .mod_assign, used),
3669 .ShlAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftLeft, .AngleBracketAngleBracketLeftEqual, "<<=", .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<", used),2884 .ShlAssign => return transCreateCompoundAssign(c, scope, stmt, .shl_assign, used),
3670 .ShrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitShiftRight, .AngleBracketAngleBracketRightEqual, ">>=", .BitShiftRight, .AngleBracketAngleBracketRight, ">>", used),2885 .ShrAssign => return transCreateCompoundAssign(c, scope, stmt, .shr_assign, used),
3671 .AndAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitAnd, .AmpersandEqual, "&=", .BitAnd, .Ampersand, "&", used),2886 .AndAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_and_assign, used),
3672 .XorAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitXor, .CaretEqual, "^=", .BitXor, .Caret, "^", used),2887 .XorAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_xor_assign, used),
3673 .OrAssign => return transCreateCompoundAssign(rp, scope, stmt, .AssignBitOr, .PipeEqual, "|=", .BitOr, .Pipe, "|", used),2888 .OrAssign => return transCreateCompoundAssign(c, scope, stmt, .bit_or_assign, used),
3674 else => return revertAndWarn(2889 else => return fail(
3675 rp,2890 c,
3676 error.UnsupportedTranslation,2891 error.UnsupportedTranslation,
3677 stmt.getBeginLoc(),2892 stmt.getBeginLoc(),
3678 "unsupported C translation {}",2893 "unsupported C translation {}",
...@@ -3682,25 +2897,20 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const cla...@@ -3682,25 +2897,20 @@ fn transCompoundAssignOperator(rp: RestorePoint, scope: *Scope, stmt: *const cla
3682}2897}
36832898
3684fn transCreateCompoundAssign(2899fn transCreateCompoundAssign(
3685 rp: RestorePoint,2900 c: *Context,
3686 scope: *Scope,2901 scope: *Scope,
3687 stmt: *const clang.CompoundAssignOperator,2902 stmt: *const clang.CompoundAssignOperator,
3688 assign_op: ast.Node.Tag,2903 op: 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,
3694 used: ResultUsed,2904 used: ResultUsed,
3695) TransError!*ast.Node {2905) TransError!Node {
3696 const is_shift = bin_op == .BitShiftLeft or bin_op == .BitShiftRight;2906 const is_shift = op == .shl_assign or op == .shr_assign;
3697 const is_div = bin_op == .Div;2907 const is_div = op == .div_assign;
3698 const is_mod = bin_op == .Mod;2908 const is_mod = op == .mod_assign;
3699 const lhs = stmt.getLHS();2909 const lhs = stmt.getLHS();
3700 const rhs = stmt.getRHS();2910 const rhs = stmt.getRHS();
3701 const loc = stmt.getBeginLoc();2911 const loc = stmt.getBeginLoc();
3702 const lhs_qt = getExprQualType(rp.c, lhs);2912 const lhs_qt = getExprQualType(c, lhs);
3703 const rhs_qt = getExprQualType(rp.c, rhs);2913 const rhs_qt = getExprQualType(c, rhs);
3704 const is_signed = cIsSignedInteger(lhs_qt);2914 const is_signed = cIsSignedInteger(lhs_qt);
3705 const requires_int_cast = blk: {2915 const requires_int_cast = blk: {
3706 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);2916 const are_integers = cIsInteger(lhs_qt) and cIsInteger(rhs_qt);
...@@ -3712,146 +2922,100 @@ fn transCreateCompoundAssign(...@@ -3712,146 +2922,100 @@ fn transCreateCompoundAssign(
3712 // c: lhs += rhs2922 // c: lhs += rhs
3713 // zig: lhs += rhs2923 // zig: lhs += rhs
3714 if ((is_mod or is_div) and is_signed) {2924 if ((is_mod or is_div) and is_signed) {
3715 const op_token = try appendToken(rp.c, .Equal, "=");2925 const lhs_node = try transExpr(c, scope, lhs, .used);
3716 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);2926 const rhs_node = try transExpr(c, scope, rhs, .used);
3717 const builtin = if (is_mod) "@rem" else "@divTrunc";2927 const builtin = if (is_mod)
3718 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);2928 try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })
3719 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);2929 else
3720 builtin_node.params()[0] = lhs_node;2930 try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
3721 _ = try appendToken(rp.c, .Comma, ",");2931
3722 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);2932 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);
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;
3732 }2933 }
37332934
3734 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);2935 const lhs_node = try transExpr(c, scope, lhs, .used);
3735 const eq_token = try appendToken(rp.c, assign_tok_id, assign_bytes);
3736 var rhs_node = if (is_shift or requires_int_cast)2936 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)
3738 else2938 else
3739 try transExpr(rp, scope, rhs, .used, .r_value);2939 try transExpr(c, scope, rhs, .used);
37402940
3741 if (is_shift or requires_int_cast) {2941 if (is_shift or requires_int_cast) {
3742 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);2942 // @intCast(rhs)
3743 const cast_to_type = if (is_shift)2943 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)
3745 else2945 else
3746 try transQualType(rp, getExprQualType(rp.c, lhs), loc);2946 try transQualType(c, scope, getExprQualType(c, lhs), loc);
3747 cast_node.params()[0] = cast_to_type;2947
3748 _ = try appendToken(rp.c, .Comma, ",");2948 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
3749 cast_node.params()[1] = rhs_node;
3750 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3751 rhs_node = &cast_node.base;
3752 }2949 }
3753 if (scope.id != .Condition)2950
3754 _ = try appendToken(rp.c, .Semicolon, ";");2951 return transCreateNodeInfixOp(c, scope, op, lhs_node, rhs_node, .used);
3755 return transCreateNodeInfixOp(rp, scope, lhs_node, assign_op, eq_token, rhs_node, .used, false);
3756 }2952 }
3757 // worst case2953 // worst case
3758 // c: lhs += rhs2954 // c: lhs += rhs
3759 // zig: (blk: {2955 // zig: (blk: {
3760 // zig: const _ref = &lhs;2956 // zig: const _ref = &lhs;
3761 // zig: _ref.* = _ref.* + rhs;2957 // zig: _ref.* += rhs;
3762 // zig: break :blk _ref.*2958 // zig: break :blk _ref.*
3763 // zig: })2959 // zig: })
3764 var block_scope = try Scope.Block.init(rp.c, scope, true);2960 var block_scope = try Scope.Block.init(c, scope, true);
3765 defer block_scope.deinit();2961 defer block_scope.deinit();
3766 const ref = try block_scope.makeMangledName(rp.c, "ref");2962 const ref = try block_scope.makeMangledName(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);
37842963
3785 const lhs_node = try transCreateNodeIdentifier(rp.c, ref);2964 const expr = try transExpr(c, &block_scope.base, lhs, .used);
3786 const ref_node = try transCreateNodePtrDeref(rp.c, lhs_node);2965 const addr_of = try Tag.address_of.create(c.arena, expr);
3787 _ = try appendToken(rp.c, .Semicolon, ";");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
3789 if ((is_mod or is_div) and is_signed) {2972 if ((is_mod or is_div) and is_signed) {
3790 const op_token = try appendToken(rp.c, .Equal, "=");2973 const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
3791 const op_node = try rp.c.arena.create(ast.Node.SimpleInfixOp);2974 const builtin = if (is_mod)
3792 const builtin = if (is_mod) "@rem" else "@divTrunc";2975 try Tag.rem.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node })
3793 const builtin_node = try rp.c.createBuiltinCall(builtin, 2);2976 else
3794 builtin_node.params()[0] = try transCreateNodePtrDeref(rp.c, lhs_node);2977 try Tag.div_trunc.create(c.arena, .{ .lhs = ref_node, .rhs = rhs_node });
3795 _ = try appendToken(rp.c, .Comma, ",");2978
3796 builtin_node.params()[1] = try transExpr(rp, scope, rhs, .used, .r_value);2979 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, ref_node, builtin, .used);
3797 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");2980 try block_scope.statements.append(assign);
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);
3807 } else {2981 } else {
3808 const bin_token = try appendToken(rp.c, bin_tok_id, bin_bytes);2982 var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
3809 var rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
38102983
3811 if (is_shift or requires_int_cast) {2984 if (is_shift or requires_int_cast) {
3812 const cast_node = try rp.c.createBuiltinCall("@intCast", 2);2985 // @intCast(rhs)
3813 const cast_to_type = if (is_shift)2986 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)
3815 else2988 else
3816 try transQualType(rp, getExprQualType(rp.c, lhs), loc);2989 try transQualType(c, scope, getExprQualType(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 }
38232990
3824 const rhs_bin = try transCreateNodeInfixOp(rp, scope, ref_node, bin_op, bin_token, rhs_node, .used, false);2991 rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
3825 _ = try appendToken(rp.c, .Semicolon, ";");2992 }
38262993
3827 const ass_eq_token = try appendToken(rp.c, .Equal, "=");2994 const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);
3828 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, .Assign, ass_eq_token, rhs_bin, .used, false);
3829 try block_scope.statements.append(assign);2995 try block_scope.statements.append(assign);
3830 }2996 }
38312997
3832 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);2998 const break_node = try Tag.break_val.create(c.arena, .{
3833 try block_scope.statements.append(&break_node.base);2999 .label = block_scope.label,
3834 const block_node = try block_scope.complete(rp.c);3000 .val = ref_node,
3835 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);3001 });
3836 grouped_expr.* = .{3002 try block_scope.statements.append(break_node);
3837 .lparen = try appendToken(rp.c, .LParen, "("),3003 return block_scope.complete(c);
3838 .expr = block_node,
3839 .rparen = try appendToken(rp.c, .RParen, ")"),
3840 };
3841 return &grouped_expr.base;
3842}3004}
38433005
3844fn transCPtrCast(3006fn transCPtrCast(
3845 rp: RestorePoint,3007 c: *Context,
3008 scope: *Scope,
3846 loc: clang.SourceLocation,3009 loc: clang.SourceLocation,
3847 dst_type: clang.QualType,3010 dst_type: clang.QualType,
3848 src_type: clang.QualType,3011 src_type: clang.QualType,
3849 expr: *ast.Node,3012 expr: Node,
3850) !*ast.Node {3013) !Node {
3851 const ty = dst_type.getTypePtr();3014 const ty = dst_type.getTypePtr();
3852 const child_type = ty.getPointeeType();3015 const child_type = ty.getPointeeType();
3853 const src_ty = src_type.getTypePtr();3016 const src_ty = src_type.getTypePtr();
3854 const src_child_type = src_ty.getPointeeType();3017 const src_child_type = src_ty.getPointeeType();
3018 const dst_type_node = try transType(c, scope, ty, loc);
38553019
3856 if ((src_child_type.isConstQualified() and3020 if ((src_child_type.isConstQualified() and
3857 !child_type.isConstQualified()) or3021 !child_type.isConstQualified()) or
...@@ -3859,80 +3023,47 @@ fn transCPtrCast(...@@ -3859,80 +3023,47 @@ fn transCPtrCast(
3859 !child_type.isVolatileQualified()))3023 !child_type.isVolatileQualified()))
3860 {3024 {
3861 // Casting away const or volatile requires us to use @intToPtr3025 // Casting away const or volatile requires us to use @intToPtr
3862 const inttoptr_node = try rp.c.createBuiltinCall("@intToPtr", 2);3026 const ptr_to_int = try Tag.ptr_to_int.create(c.arena, expr);
3863 const dst_type_node = try transType(rp, ty, loc);3027 const int_to_ptr = try Tag.int_to_ptr.create(c.arena, .{ .lhs = dst_type_node, .rhs = ptr_to_int });
3864 inttoptr_node.params()[0] = dst_type_node;3028 return int_to_ptr;
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;
3874 } else {3029 } else {
3875 // Implicit downcasting from higher to lower alignment values is forbidden,3030 // Implicit downcasting from higher to lower alignment values is forbidden,
3876 // use @alignCast to side-step this problem3031 // use @alignCast to side-step this problem
3877 const ptrcast_node = try rp.c.createBuiltinCall("@ptrCast", 2);3032 const rhs = if (qualTypeCanon(child_type).isVoidType())
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()) {
3883 // void has 1-byte alignment, so @alignCast is not needed3033 // void has 1-byte alignment, so @alignCast is not needed
3884 ptrcast_node.params()[1] = expr;3034 expr
3885 } else if (typeIsOpaque(rp.c, qualTypeCanon(child_type), loc)) {3035 else if (typeIsOpaque(c, qualTypeCanon(child_type), loc))
3886 // For opaque types a ptrCast is enough3036 // For opaque types a ptrCast is enough
3887 ptrcast_node.params()[1] = expr;3037 expr
3888 } else {3038 else blk: {
3889 const aligncast_node = try rp.c.createBuiltinCall("@alignCast", 2);3039 const child_type_node = try transQualType(c, scope, child_type, loc);
3890 const alignof_node = try rp.c.createBuiltinCall("@alignOf", 1);3040 const alignof = try Tag.alignof.create(c.arena, child_type_node);
3891 const child_type_node = try transQualType(rp, child_type, loc);3041 const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr });
3892 alignof_node.params()[0] = child_type_node;3042 break :blk align_cast;
3893 alignof_node.rparen_token = try appendToken(rp.c, .RParen, ")");3043 };
3894 aligncast_node.params()[0] = &alignof_node.base;3044 return Tag.ptr_cast.create(c.arena, .{ .lhs = dst_type_node, .rhs = rhs });
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;
3903 }3045 }
3904}3046}
39053047
3906fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {3048fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!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 {
3923 // TODO use something more accurate3049 // TODO use something more accurate
3924 const dbl = stmt.getValueAsApproximateDouble();3050 var dbl = stmt.getValueAsApproximateDouble();
3925 const node = try rp.c.arena.create(ast.Node.OneToken);3051 const is_negative = dbl < 0;
3926 node.* = .{3052 if (is_negative) dbl = -dbl;
3927 .base = .{ .tag = .FloatLiteral },3053 const str = try std.fmt.allocPrint(c.arena, "{d}", .{dbl});
3928 .token = try appendTokenFmt(rp.c, .FloatLiteral, "{d}", .{dbl}),3054 var node = if (dbl == std.math.floor(dbl))
3929 };3055 try Tag.integer_literal.create(c.arena, str)
3930 return maybeSuppressResult(rp, scope, used, &node.base);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);
3931}3060}
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 {
3934 // GNU extension of the ternary operator where the middle expression is3063 // GNU extension of the ternary operator where the middle expression is
3935 // omitted, the conditition itself is returned if it evaluates to true3064 // 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);
3936 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);3067 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);
3937 const cond_expr = casted_stmt.getCond();3068 const cond_expr = casted_stmt.getCond();
3938 const true_expr = casted_stmt.getTrueExpr();3069 const true_expr = casted_stmt.getTrueExpr();
...@@ -3943,184 +3074,149 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const...@@ -3943,184 +3074,149 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
3943 // const _cond_temp = (cond_expr);3074 // const _cond_temp = (cond_expr);
3944 // break :blk if (_cond_temp) _cond_temp else (false_expr);3075 // break :blk if (_cond_temp) _cond_temp else (false_expr);
3945 // })3076 // })
3946 const lparen = try appendToken(rp.c, .LParen, "(");3077 var block_scope = try Scope.Block.init(c, scope, true);
3947
3948 var block_scope = try Scope.Block.init(rp.c, scope, true);
3949 defer block_scope.deinit();3078 defer block_scope.deinit();
39503079
3951 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");3080 const mangled_name = try block_scope.makeMangledName(c, "cond_temp");
3952 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");3081 const init_node = try transExpr(c, &block_scope.base, cond_expr, .used);
3953 const name_tok = try appendIdentifier(rp.c, mangled_name);3082 const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = mangled_name, .init = init_node });
3954 const eq_token = try appendToken(rp.c, .Equal, "=");3083 try block_scope.statements.append(ref_decl);
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);
39683084
3969 const if_node = try transCreateNodeIf(rp.c);
3970 var cond_scope = Scope.Condition{3085 var cond_scope = Scope.Condition{
3971 .base = .{3086 .base = .{
3972 .parent = &block_scope.base,3087 .parent = &block_scope.base,
3973 .id = .Condition,3088 .id = .condition,
3974 },3089 },
3975 };3090 };
3976 defer cond_scope.deinit();3091 defer cond_scope.deinit();
3977 const tmp_var_node = try transCreateNodeIdentifier(rp.c, mangled_name);3092
39783093 const cond_ident = try Tag.identifier.create(c.arena, mangled_name);
3979 const ty = getExprQualType(rp.c, cond_expr).getTypePtr();3094 const ty = getExprQualType(c, cond_expr).getTypePtr();
3980 const cond_node = try finishBoolExpr(rp, &cond_scope.base, cond_expr.getBeginLoc(), ty, tmp_var_node, used);3095 const cond_node = try finishBoolExpr(c, &cond_scope.base, cond_expr.getBeginLoc(), ty, cond_ident, .used);
3981 if_node.condition = cond_node;3096 var then_body = cond_ident;
3982 _ = try appendToken(rp.c, .RParen, ")");3097 if (!res_is_bool and isBoolRes(init_node)) {
39833098 then_body = try Tag.bool_to_int.create(c.arena, then_body);
3984 if_node.body = try transCreateNodeIdentifier(rp.c, mangled_name);3099 }
3985 if_node.@"else" = try transCreateNodeElse(rp.c);3100
3986 if_node.@"else".?.body = try transExpr(rp, &block_scope.base, false_expr, .used, .r_value);3101 var else_body = try transExpr(c, &block_scope.base, false_expr, .used);
3987 _ = try appendToken(rp.c, .Semicolon, ";");3102 if (!res_is_bool and isBoolRes(else_body)) {
39883103 else_body = try Tag.bool_to_int.create(c.arena, else_body);
3989 const break_node = try break_node_tmp.finish(&if_node.base);3104 }
3990 _ = try appendToken(rp.c, .Semicolon, ";");3105 const if_node = try Tag.@"if".create(c.arena, .{
3991 try block_scope.statements.append(&break_node.base);3106 .cond = cond_node,
3992 const block_node = try block_scope.complete(rp.c);3107 .then = then_body,
39933108 .@"else" = else_body,
3994 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);3109 });
3995 grouped_expr.* = .{3110 const break_node = try Tag.break_val.create(c.arena, .{
3996 .lparen = lparen,3111 .label = block_scope.label,
3997 .expr = block_node,3112 .val = if_node,
3998 .rparen = try appendToken(rp.c, .RParen, ")"),3113 });
3999 };3114 try block_scope.statements.append(break_node);
4000 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);3115 const res = try block_scope.complete(c);
3116 return maybeSuppressResult(c, scope, used, res);
4001}3117}
40023118
4003fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!*ast.Node {3119fn transConditionalOperator(c: *Context, scope: *Scope, stmt: *const clang.ConditionalOperator, used: ResultUsed) TransError!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);
4007 var cond_scope = Scope.Condition{3120 var cond_scope = Scope.Condition{
4008 .base = .{3121 .base = .{
4009 .parent = scope,3122 .parent = scope,
4010 .id = .Condition,3123 .id = .condition,
4011 },3124 },
4012 };3125 };
4013 defer cond_scope.deinit();3126 defer cond_scope.deinit();
40143127
3128 const qt = @ptrCast(*const clang.Expr, stmt).getType();
3129 const res_is_bool = qualTypeIsBoolean(qt);
4015 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);3130 const casted_stmt = @ptrCast(*const clang.AbstractConditionalOperator, stmt);
4016 const cond_expr = casted_stmt.getCond();3131 const cond_expr = casted_stmt.getCond();
4017 const true_expr = casted_stmt.getTrueExpr();3132 const true_expr = casted_stmt.getTrueExpr();
4018 const false_expr = casted_stmt.getFalseExpr();3133 const false_expr = casted_stmt.getFalseExpr();
40193134
4020 if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);3135 const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used);
4021 _ = try appendToken(rp.c, .RParen, ")");
40223136
4023 if_node.body = try transExpr(rp, scope, true_expr, .used, .r_value);3137 var then_body = try transExpr(c, scope, true_expr, used);
40243138 if (!res_is_bool and isBoolRes(then_body)) {
4025 if_node.@"else" = try transCreateNodeElse(rp.c);3139 then_body = try Tag.bool_to_int.create(c.arena, then_body);
4026 if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);3140 }
40273141
4028 if (grouped) {3142 var else_body = try transExpr(c, scope, false_expr, used);
4029 const rparen = try appendToken(rp.c, .RParen, ")");3143 if (!res_is_bool and isBoolRes(else_body)) {
4030 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);3144 else_body = try Tag.bool_to_int.create(c.arena, else_body);
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);
4039 }3145 }
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;
4040}3154}
40413155
4042fn maybeSuppressResult(3156fn maybeSuppressResult(
4043 rp: RestorePoint,3157 c: *Context,
4044 scope: *Scope,3158 scope: *Scope,
4045 used: ResultUsed,3159 used: ResultUsed,
4046 result: *ast.Node,3160 result: Node,
4047) TransError!*ast.Node {3161) TransError!Node {
4048 if (used == .used) return result;3162 if (used == .used) return result;
4049 if (scope.id != .Condition) {3163 return Tag.discard.create(c.arena, result);
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;
4069}3164}
40703165
4071fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {3166fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
4072 try c.root_decls.append(c.gpa, decl_node);
4073 _ = try c.global_scope.sym_table.put(name, decl_node);3167 _ = try c.global_scope.sym_table.put(name, decl_node);
3168 try c.global_scope.nodes.append(decl_node);
4074}3169}
40753170
4076/// Translate a qual type for a variable with an initializer. The initializer3171/// Translate a qual type for a variable with an initializer. The initializer
4077/// only matters for incomplete arrays, since the size of the array is determined3172/// only matters for incomplete arrays, since the size of the array is determined
4078/// by the size of the initializer3173/// by the size of the initializer
4079fn transQualTypeInitialized(3174fn transQualTypeInitialized(
4080 rp: RestorePoint,3175 c: *Context,
3176 scope: *Scope,
4081 qt: clang.QualType,3177 qt: clang.QualType,
4082 decl_init: *const clang.Expr,3178 decl_init: *const clang.Expr,
4083 source_loc: clang.SourceLocation,3179 source_loc: clang.SourceLocation,
4084) TypeError!*ast.Node {3180) TypeError!Node {
4085 const ty = qt.getTypePtr();3181 const ty = qt.getTypePtr();
4086 if (ty.getTypeClass() == .IncompleteArray) {3182 if (ty.getTypeClass() == .IncompleteArray) {
4087 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);3183 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
4090 switch (decl_init.getStmtClass()) {3186 switch (decl_init.getStmtClass()) {
4091 .StringLiteralClass => {3187 .StringLiteralClass => {
4092 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);3188 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);
4093 const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator3189 const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator
4094 const array_size = @intCast(usize, string_lit_size);3190 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 });
4096 },3192 },
4097 .InitListExprClass => {3193 .InitListExprClass => {
4098 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);3194 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);
4099 const size = init_expr.getNumInits();3195 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 });
4101 },3197 },
4102 else => {},3198 else => {},
4103 }3199 }
4104 }3200 }
4105 return transQualType(rp, qt, source_loc);3201 return transQualType(c, scope, qt, source_loc);
4106}3202}
41073203
4108fn transQualType(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!*ast.Node {3204fn transQualType(c: *Context, scope: *Scope, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node {
4109 return transType(rp, qt.getTypePtr(), source_loc);3205 return transType(c, scope, qt.getTypePtr(), source_loc);
4110}3206}
41113207
4112/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.3208/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
4113/// Asserts the type is an integer.3209/// 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 {
4115 return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);3211 return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);
4116}3212}
41173213
4118/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.3214/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.
4119/// Asserts the type is an integer.3215/// 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 {
4121 assert(ty.getTypeClass() == .Builtin);3217 assert(ty.getTypeClass() == .Builtin);
4122 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);3218 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()) {
4124 .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",3220 .Char_U, .Char_S, .UChar, .SChar, .Char8 => if (is_signed) "i8" else "u8",
4125 .UShort, .Short => if (is_signed) "c_short" else "c_ushort",3221 .UShort, .Short => if (is_signed) "c_short" else "c_ushort",
4126 .UInt, .Int => if (is_signed) "c_int" else "c_uint",3222 .UInt, .Int => if (is_signed) "c_int" else "c_uint",
...@@ -4149,7 +3245,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool {...@@ -4149,7 +3245,7 @@ fn qualTypeIsBoolean(qt: clang.QualType) bool {
4149 return qualTypeCanon(qt).isBooleanType();3245 return qualTypeCanon(qt).isBooleanType();
4150}3246}
41513247
4152fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !u32 {3248fn qualTypeIntBitWidth(c: *Context, qt: clang.QualType) !u32 {
4153 const ty = qt.getTypePtr();3249 const ty = qt.getTypePtr();
41543250
4155 switch (ty.getTypeClass()) {3251 switch (ty.getTypeClass()) {
...@@ -4173,7 +3269,7 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S...@@ -4173,7 +3269,7 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S
4173 .Typedef => {3269 .Typedef => {
4174 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);3270 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
4175 const typedef_decl = typedef_ty.getDecl();3271 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
4178 if (mem.eql(u8, type_name, "uint8_t") or mem.eql(u8, type_name, "int8_t")) {3274 if (mem.eql(u8, type_name, "uint8_t") or mem.eql(u8, type_name, "int8_t")) {
4179 return 8;3275 return 8;
...@@ -4189,55 +3285,19 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S...@@ -4189,55 +3285,19 @@ fn qualTypeIntBitWidth(rp: RestorePoint, qt: clang.QualType, source_loc: clang.S
4189 },3285 },
4190 else => return 0,3286 else => return 0,
4191 }3287 }
4192
4193 unreachable;
4194}3288}
41953289
4196fn qualTypeToLog2IntRef(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) !*ast.Node {3290fn qualTypeToLog2IntRef(c: *Context, scope: *Scope, qt: clang.QualType, source_loc: clang.SourceLocation) !Node {
4197 const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);3291 const int_bit_width = try qualTypeIntBitWidth(c, qt);
41983292
4199 if (int_bit_width != 0) {3293 if (int_bit_width != 0) {
4200 // we can perform the log2 now.3294 // we can perform the log2 now.
4201 const cast_bit_width = math.log2_int(u64, int_bit_width);3295 const cast_bit_width = math.log2_int(u64, int_bit_width);
4202 const node = try rp.c.arena.create(ast.Node.OneToken);3296 return Tag.log2_int_type.create(c.arena, cast_bit_width);
4203 node.* = .{3297 }
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, ")");
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);
4241}3301}
42423302
4243fn qualTypeChildIsFnProto(qt: clang.QualType) bool {3303fn qualTypeChildIsFnProto(qt: clang.QualType) bool {
...@@ -4401,28 +3461,22 @@ fn cIsLongLongInteger(qt: clang.QualType) bool {...@@ -4401,28 +3461,22 @@ fn cIsLongLongInteger(qt: clang.QualType) bool {
4401 };3461 };
4402}3462}
4403fn transCreateNodeAssign(3463fn transCreateNodeAssign(
4404 rp: RestorePoint,3464 c: *Context,
4405 scope: *Scope,3465 scope: *Scope,
4406 result_used: ResultUsed,3466 result_used: ResultUsed,
4407 lhs: *const clang.Expr,3467 lhs: *const clang.Expr,
4408 rhs: *const clang.Expr,3468 rhs: *const clang.Expr,
4409) !*ast.Node {3469) !Node {
4410 // common case3470 // common case
4411 // c: lhs = rhs3471 // c: lhs = rhs
4412 // zig: lhs = rhs3472 // zig: lhs = rhs
4413 if (result_used == .unused) {3473 if (result_used == .unused) {
4414 const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);3474 const lhs_node = try transExpr(c, scope, lhs, .used);
4415 const eq_token = try appendToken(rp.c, .Equal, "=");3475 var rhs_node = try transExprCoercing(c, scope, rhs, .used);
4416 var rhs_node = try transExprCoercing(rp, scope, rhs, .used, .r_value);
4417 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {3476 if (!exprIsBooleanType(lhs) and isBoolRes(rhs_node)) {
4418 const builtin_node = try rp.c.createBuiltinCall("@boolToInt", 1);3477 rhs_node = try Tag.bool_to_int.create(c.arena, rhs_node);
4419 builtin_node.params()[0] = rhs_node;
4420 builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")");
4421 rhs_node = &builtin_node.base;
4422 }3478 }
4423 if (scope.id != .Condition)3479 return transCreateNodeInfixOp(c, scope, .assign, lhs_node, rhs_node, .used);
4424 _ = try appendToken(rp.c, .Semicolon, ";");
4425 return transCreateNodeInfixOp(rp, scope, lhs_node, .Assign, eq_token, rhs_node, .used, false);
4426 }3480 }
44273481
4428 // worst case3482 // worst case
...@@ -4432,176 +3486,62 @@ fn transCreateNodeAssign(...@@ -4432,176 +3486,62 @@ fn transCreateNodeAssign(
4432 // zig: lhs = _tmp;3486 // zig: lhs = _tmp;
4433 // zig: break :blk _tmp3487 // zig: break :blk _tmp
4434 // zig: })3488 // zig: })
4435 var block_scope = try Scope.Block.init(rp.c, scope, true);3489 var block_scope = try Scope.Block.init(c, scope, true);
4436 defer block_scope.deinit();3490 defer block_scope.deinit();
44373491
4438 const tmp = try block_scope.makeMangledName(rp.c, "tmp");3492 const tmp = try block_scope.makeMangledName(c, "tmp");
4439 const mut_tok = try appendToken(rp.c, .Keyword_const, "const");3493 const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
4440 const name_tok = try appendIdentifier(rp.c, tmp);3494 const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node });
4441 const eq_token = try appendToken(rp.c, .Equal, "=");3495 try block_scope.statements.append(tmp_decl);
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}
44923496
4493fn transCreateNodeSimplePrefixOp(3497 const lhs_node = try transExpr(c, &block_scope.base, lhs, .used);
4494 c: *Context,3498 const tmp_ident = try Tag.identifier.create(c.arena, tmp);
4495 comptime tag: ast.Node.Tag,3499 const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs_node, tmp_ident, .used);
4496 op_tok_id: std.zig.Token.Id,3500 try block_scope.statements.append(assign);
4497 bytes: []const u8,3501
4498) !*ast.Node.SimplePrefixOp {3502 const break_node = try Tag.break_val.create(c.arena, .{
4499 const node = try c.arena.create(ast.Node.SimplePrefixOp);3503 .label = block_scope.label,
4500 node.* = .{3504 .val = tmp_ident,
4501 .base = .{ .tag = tag },3505 });
4502 .op_token = try appendToken(c, op_tok_id, bytes),3506 try block_scope.statements.append(break_node);
4503 .rhs = undefined, // translate and set afterward3507 return block_scope.complete(c);
4504 };
4505 return node;
4506}3508}
45073509
4508fn transCreateNodeInfixOp(3510fn transCreateNodeInfixOp(
4509 rp: RestorePoint,3511 c: *Context,
4510 scope: *Scope,3512 scope: *Scope,
4511 lhs_node: *ast.Node,3513 op: Tag,
4512 op: ast.Node.Tag,3514 lhs: Node,
4513 op_token: ast.TokenIndex,3515 rhs: Node,
4514 rhs_node: *ast.Node,
4515 used: ResultUsed,3516 used: ResultUsed,
4516 grouped: bool,3517) !Node {
4517) !*ast.Node {3518 const payload = try c.arena.create(ast.Payload.BinOp);
4518 var lparen = if (grouped)3519 payload.* = .{
4519 try appendToken(rp.c, .LParen, "(")
4520 else
4521 null;
4522 const node = try rp.c.arena.create(ast.Node.SimpleInfixOp);
4523 node.* = .{
4524 .base = .{ .tag = op },3520 .base = .{ .tag = op },
4525 .op_token = op_token,3521 .data = .{
4526 .lhs = lhs_node,3522 .lhs = lhs,
4527 .rhs = rhs_node,3523 .rhs = rhs,
4528 };3524 },
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,
4536 };3525 };
4537 return maybeSuppressResult(rp, scope, used, &grouped_expr.base);3526 return maybeSuppressResult(c, scope, used, Node.initPayload(&payload.base));
4538}3527}
45393528
4540fn transCreateNodeBoolInfixOp(3529fn transCreateNodeBoolInfixOp(
4541 rp: RestorePoint,3530 c: *Context,
4542 scope: *Scope,3531 scope: *Scope,
4543 stmt: *const clang.BinaryOperator,3532 stmt: *const clang.BinaryOperator,
4544 op: ast.Node.Tag,3533 op: Tag,
4545 used: ResultUsed,3534 used: ResultUsed,
4546 grouped: bool,3535) !Node {
4547) !*ast.Node {3536 std.debug.assert(op == .@"and" or op == .@"or");
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);
45563537
4557 return transCreateNodeInfixOp(3538 const lhs = try transBoolExpr(c, scope, stmt.getLHS(), .used);
4558 rp,3539 const rhs = try transBoolExpr(c, scope, stmt.getRHS(), .used);
4559 scope,
4560 lhs_hode,
4561 op,
4562 op_token,
4563 rhs,
4564 used,
4565 grouped,
4566 );
4567}
45683540
4569fn transCreateNodePtrType(3541 return transCreateNodeInfixOp(c, scope, op, lhs, rhs, used);
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;
4602}3542}
46033543
4604fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {3544fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
4605 const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) {3545 const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) {
4606 error.Overflow => return error.OutOfMemory,3546 error.Overflow => return error.OutOfMemory,
4607 };3547 };
...@@ -4637,418 +3577,96 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {...@@ -4637,418 +3577,96 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {
4637 else => @compileError("unimplemented"),3577 else => @compileError("unimplemented"),
4638 }3578 }
46393579
4640 const big: math.big.int.Const = .{ .limbs = limbs, .positive = !is_negative };3580 const big: math.big.int.Const = .{ .limbs = limbs, .positive = true };
4641 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {3581 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
4642 error.OutOfMemory => return error.OutOfMemory,3582 error.OutOfMemory => return error.OutOfMemory,
4643 };3583 };
4644 defer c.arena.free(str);3584 const res = try Tag.integer_literal.create(c.arena, str);
4645 const token = try appendToken(c, .IntegerLiteral, str);3585 if (is_negative) return Tag.negate.create(c.arena, res);
4646 const node = try c.arena.create(ast.Node.OneToken);3586 return res;
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;
4672}3587}
46733588
4674fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {3589fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node {
4675 const token = if (value)3590 const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}";
4676 try appendToken(c, .Keyword_true, "true")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)
4677 else3594 else
4678 try appendToken(c, .Keyword_false, "false");3595 return Tag.integer_literal.create(c.arena, str);
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;
4696}3596}
46973597
4698fn transCreateNodeFloat(c: *Context, str: []const u8) !*ast.Node {3598fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: Node, proto_alias: *ast.Payload.Func) !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 {
4724 const scope = &c.global_scope.base;3599 const scope = &c.global_scope.base;
47253600
4726 const pub_tok = try appendToken(c, .Keyword_pub, "pub");3601 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
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);
4732 defer fn_params.deinit();3602 defer fn_params.deinit();
47333603
4734 for (proto_alias.params()) |param, i| {3604 for (proto_alias.data.params) |param, i| {
4735 if (i != 0) {3605 const param_name = param.name orelse
4736 _ = try appendToken(c, .Comma, ",");3606 try std.fmt.allocPrint(c.arena, "arg_{d}", .{c.getMangle()});
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, ":");
47423607
4743 (try fn_params.addOne()).* = .{3608 try fn_params.append(.{
4744 .doc_comments = null,3609 .name = param_name,
4745 .comptime_token = null,3610 .type = param.type,
4746 .noalias_token = param.noalias_token,3611 .is_noalias = param.is_noalias,
4747 .name_token = param_name_tok,3612 });
4748 .param_type = param.param_type,
4749 };
4750 }3613 }
47513614
4752 _ = try appendToken(c, .RParen, ")");3615 const init = if (ref.castTag(.var_decl)) |v|
47533616 v.data.init.?
4754 _ = try appendToken(c, .Keyword_callconv, "callconv");3617 else if (ref.castTag(.var_simple) orelse ref.castTag(.pub_var_simple)) |v|
4755 _ = try appendToken(c, .LParen, "(");3618 v.data.init
4756 const callconv_expr = try transCreateNodeEnumLiteral(c, "Inline");3619 else
4757 _ = try appendToken(c, .RParen, ")");3620 unreachable;
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();
47663621
3622 const unwrap_expr = try Tag.unwrap.create(c.arena, init);
3623 const args = try c.arena.alloc(Node, fn_params.items.len);
4767 for (fn_params.items) |param, i| {3624 for (fn_params.items) |param, i| {
4768 if (i != 0) {3625 args[i] = try Tag.identifier.create(c.arena, param.name.?);
4769 _ = try appendToken(c, .Comma, ",");
4770 }
4771 call_params[i] = try transCreateNodeIdentifier(c, tokenSlice(c, param.name_token.?));
4772 }3626 }
4773 call_expr.rtoken = try appendToken(c, .RParen, ")");3627 const call_expr = try Tag.call.create(c.arena, .{
47743628 .lhs = unwrap_expr,
4775 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{3629 .args = args,
4776 .ltoken = return_kw,
4777 .tag = .Return,
4778 }, .{
4779 .rhs = &call_expr.base,
4780 });3630 });
4781 _ = try appendToken(c, .Semicolon, ";");3631 const return_expr = try Tag.@"return".create(c.arena, call_expr);
47823632 const block = try Tag.block_single.create(c.arena, return_expr);
4783 const block = try ast.Node.Block.alloc(c.arena, 1);3633
4784 block.* = .{3634 return Tag.pub_inline_fn.create(c.arena, .{
4785 .lbrace = block_lbrace,3635 .name = name,
4786 .statements_len = 1,3636 .params = try c.arena.dupe(ast.Payload.Param, fn_params.items),
4787 .rbrace = try appendToken(c, .RBrace, "}"),3637 .return_type = proto_alias.data.return_type,
4788 };3638 .body = block,
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,
4800 });3639 });
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;
4967}3640}
49683641
4969fn transCreateNodeShiftOp(3642fn transCreateNodeShiftOp(
4970 rp: RestorePoint,3643 c: *Context,
4971 scope: *Scope,3644 scope: *Scope,
4972 stmt: *const clang.BinaryOperator,3645 stmt: *const clang.BinaryOperator,
4973 op: ast.Node.Tag,3646 op: Tag,
4974 op_tok_id: std.zig.Token.Id,3647 used: ResultUsed,
4975 bytes: []const u8,3648) !Node {
4976) !*ast.Node {3649 std.debug.assert(op == .shl or op == .shr);
4977 std.debug.assert(op == .BitShiftLeft or op == .BitShiftRight);
49783650
4979 const lhs_expr = stmt.getLHS();3651 const lhs_expr = stmt.getLHS();
4980 const rhs_expr = stmt.getRHS();3652 const rhs_expr = stmt.getRHS();
4981 const rhs_location = rhs_expr.getBeginLoc();3653 const rhs_location = rhs_expr.getBeginLoc();
4982 // lhs >> @as(u5, rh)3654 // lhs >> @as(u5, rh)
49833655
4984 const lhs = try transExpr(rp, scope, lhs_expr, .used, .l_value);3656 const lhs = try transExpr(c, scope, lhs_expr, .used);
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,
50313657
5032 fn activate(self: RestorePoint) void {3658 const rhs_type = try qualTypeToLog2IntRef(c, scope, stmt.getType(), rhs_location);
5033 self.c.token_ids.shrinkAndFree(self.c.gpa, self.token_index);3659 const rhs = try transExprCoercing(c, scope, rhs_expr, .used);
5034 self.c.token_locs.shrinkAndFree(self.c.gpa, self.token_index);3660 const rhs_casted = try Tag.int_cast.create(c.arena, .{ .lhs = rhs_type, .rhs = rhs });
5035 self.c.source_buffer.shrinkAndFree(self.src_buf_index);
5036 }
5037};
50383661
5039fn makeRestorePoint(c: *Context) RestorePoint {3662 return transCreateNodeInfixOp(c, scope, op, lhs, rhs_casted, used);
5040 return RestorePoint{
5041 .c = c,
5042 .token_index = c.token_ids.items.len,
5043 .src_buf_index = c.source_buffer.items.len,
5044 };
5045}3663}
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 {
5048 switch (ty.getTypeClass()) {3666 switch (ty.getTypeClass()) {
5049 .Builtin => {3667 .Builtin => {
5050 const builtin_ty = @ptrCast(*const clang.BuiltinType, ty);3668 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()) {
5052 .Void => "c_void",3670 .Void => "c_void",
5053 .Bool => "bool",3671 .Bool => "bool",
5054 .Char_U, .UChar, .Char_S, .Char8 => "u8",3672 .Char_U, .UChar, .Char_S, .Char8 => "u8",
...@@ -5068,112 +3686,100 @@ fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLo...@@ -5068,112 +3686,100 @@ fn transType(rp: RestorePoint, ty: *const clang.Type, source_loc: clang.SourceLo
5068 .Float128 => "f128",3686 .Float128 => "f128",
5069 .Float16 => "f16",3687 .Float16 => "f16",
5070 .LongDouble => "c_longdouble",3688 .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", .{}),
5072 });3690 });
5073 },3691 },
5074 .FunctionProto => {3692 .FunctionProto => {
5075 const fn_proto_ty = @ptrCast(*const clang.FunctionProtoType, ty);3693 const fn_proto_ty = @ptrCast(*const clang.FunctionProtoType, ty);
5076 const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false);3694 const fn_proto = try transFnProto(c, null, fn_proto_ty, source_loc, null, false);
5077 return &fn_proto.base;3695 return Node.initPayload(&fn_proto.base);
5078 },3696 },
5079 .FunctionNoProto => {3697 .FunctionNoProto => {
5080 const fn_no_proto_ty = @ptrCast(*const clang.FunctionType, ty);3698 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);3699 const fn_proto = try transFnNoProto(c, fn_no_proto_ty, source_loc, null, false);
5082 return &fn_proto.base;3700 return Node.initPayload(&fn_proto.base);
5083 },3701 },
5084 .Paren => {3702 .Paren => {
5085 const paren_ty = @ptrCast(*const clang.ParenType, ty);3703 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);
5087 },3705 },
5088 .Pointer => {3706 .Pointer => {
5089 const child_qt = ty.getPointeeType();3707 const child_qt = ty.getPointeeType();
5090 if (qualTypeChildIsFnProto(child_qt)) {3708 if (qualTypeChildIsFnProto(child_qt)) {
5091 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");3709 return Tag.optional_type.create(c.arena, try transQualType(c, scope, child_qt, source_loc));
5092 optional_node.rhs = try transQualType(rp, child_qt, source_loc);
5093 return &optional_node.base;
5094 }3710 }
5095 if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) {3711 const is_const = child_qt.isConstQualified();
5096 const optional_node = try transCreateNodeSimplePrefixOp(rp.c, .OptionalType, .QuestionMark, "?");3712 const is_volatile = child_qt.isVolatileQualified();
5097 const pointer_node = try transCreateNodePtrType(3713 const elem_type = try transQualType(c, scope, child_qt, source_loc);
5098 rp.c,3714 if (typeIsOpaque(c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(c, child_qt)) {
5099 child_qt.isConstQualified(),3715 const ptr = try Tag.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
5100 child_qt.isVolatileQualified(),3716 return Tag.optional_type.create(c.arena, ptr);
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;
5106 }3717 }
5107 const pointer_node = try transCreateNodePtrType(3718
5108 rp.c,3719 return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
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;
5115 },3720 },
5116 .ConstantArray => {3721 .ConstantArray => {
5117 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);3722 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
51183723
5119 const size_ap_int = const_arr_ty.getSize();3724 const size_ap_int = const_arr_ty.getSize();
5120 const size = size_ap_int.getLimitedValue(math.maxInt(usize));3725 const size = size_ap_int.getLimitedValue(math.maxInt(usize));
5121 const elem_ty = const_arr_ty.getElementType().getTypePtr();3726 const elem_type = try transType(c, scope, const_arr_ty.getElementType().getTypePtr(), source_loc);
5122 return try transCreateNodeArrayType(rp, source_loc, elem_ty, size);3727
3728 return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type });
5123 },3729 },
5124 .IncompleteArray => {3730 .IncompleteArray => {
5125 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);3731 const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty);
51263732
5127 const child_qt = incomplete_array_ty.getElementType();3733 const child_qt = incomplete_array_ty.getElementType();
5128 var node = try transCreateNodePtrType(3734 const is_const = child_qt.isConstQualified();
5129 rp.c,3735 const is_volatile = child_qt.isVolatileQualified();
5130 child_qt.isConstQualified(),3736 const elem_type = try transQualType(c, scope, child_qt, source_loc);
5131 child_qt.isVolatileQualified(),3737
5132 .Identifier,3738 return Tag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type });
5133 );
5134 node.rhs = try transQualType(rp, child_qt, source_loc);
5135 return &node.base;
5136 },3739 },
5137 .Typedef => {3740 .Typedef => {
5138 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);3741 const typedef_ty = @ptrCast(*const clang.TypedefType, ty);
51393742
5140 const typedef_decl = typedef_ty.getDecl();3743 const typedef_decl = typedef_ty.getDecl();
5141 return (try transTypeDef(rp.c, typedef_decl, false)) orelse3744 try transTypeDef(c, scope, typedef_decl);
5142 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{});3745 const name = c.decl_table.get(@ptrToInt(typedef_decl.getCanonicalDecl())).?;
3746 return Tag.identifier.create(c.arena, name);
5143 },3747 },
5144 .Record => {3748 .Record => {
5145 const record_ty = @ptrCast(*const clang.RecordType, ty);3749 const record_ty = @ptrCast(*const clang.RecordType, ty);
51463750
5147 const record_decl = record_ty.getDecl();3751 const record_decl = record_ty.getDecl();
5148 return (try transRecordDecl(rp.c, record_decl)) orelse3752 try transRecordDecl(c, scope, record_decl);
5149 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{});3753 const name = c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl())).?;
3754 return Tag.identifier.create(c.arena, name);
5150 },3755 },
5151 .Enum => {3756 .Enum => {
5152 const enum_ty = @ptrCast(*const clang.EnumType, ty);3757 const enum_ty = @ptrCast(*const clang.EnumType, ty);
51533758
5154 const enum_decl = enum_ty.getDecl();3759 const enum_decl = enum_ty.getDecl();
5155 return (try transEnumDecl(rp.c, enum_decl)) orelse3760 try transEnumDecl(c, scope, enum_decl);
5156 revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});3761 const name = c.decl_table.get(@ptrToInt(enum_decl.getCanonicalDecl())).?;
3762 return Tag.identifier.create(c.arena, name);
5157 },3763 },
5158 .Elaborated => {3764 .Elaborated => {
5159 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, ty);3765 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);
5161 },3767 },
5162 .Decayed => {3768 .Decayed => {
5163 const decayed_ty = @ptrCast(*const clang.DecayedType, ty);3769 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);
5165 },3771 },
5166 .Attributed => {3772 .Attributed => {
5167 const attributed_ty = @ptrCast(*const clang.AttributedType, ty);3773 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);
5169 },3775 },
5170 .MacroQualified => {3776 .MacroQualified => {
5171 const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, ty);3777 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);
5173 },3779 },
5174 else => {3780 else => {
5175 const type_name = rp.c.str(ty.getTypeClassName());3781 const type_name = c.str(ty.getTypeClassName());
5176 return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});3782 return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name});
5177 },3783 },
5178 }3784 }
5179}3785}
...@@ -5239,7 +3845,7 @@ const FnDeclContext = struct {...@@ -5239,7 +3845,7 @@ const FnDeclContext = struct {
5239};3845};
52403846
5241fn transCC(3847fn transCC(
5242 rp: RestorePoint,3848 c: *Context,
5243 fn_ty: *const clang.FunctionType,3849 fn_ty: *const clang.FunctionType,
5244 source_loc: clang.SourceLocation,3850 source_loc: clang.SourceLocation,
5245) !CallingConvention {3851) !CallingConvention {
...@@ -5252,8 +3858,8 @@ fn transCC(...@@ -5252,8 +3858,8 @@ fn transCC(
5252 .X86ThisCall => return CallingConvention.Thiscall,3858 .X86ThisCall => return CallingConvention.Thiscall,
5253 .AAPCS => return CallingConvention.AAPCS,3859 .AAPCS => return CallingConvention.AAPCS,
5254 .AAPCS_VFP => return CallingConvention.AAPCSVFP,3860 .AAPCS_VFP => return CallingConvention.AAPCSVFP,
5255 else => return revertAndWarn(3861 else => return fail(
5256 rp,3862 c,
5257 error.UnsupportedType,3863 error.UnsupportedType,
5258 source_loc,3864 source_loc,
5259 "unsupported calling convention: {s}",3865 "unsupported calling convention: {s}",
...@@ -5263,33 +3869,33 @@ fn transCC(...@@ -5263,33 +3869,33 @@ fn transCC(
5263}3869}
52643870
5265fn transFnProto(3871fn transFnProto(
5266 rp: RestorePoint,3872 c: *Context,
5267 fn_decl: ?*const clang.FunctionDecl,3873 fn_decl: ?*const clang.FunctionDecl,
5268 fn_proto_ty: *const clang.FunctionProtoType,3874 fn_proto_ty: *const clang.FunctionProtoType,
5269 source_loc: clang.SourceLocation,3875 source_loc: clang.SourceLocation,
5270 fn_decl_context: ?FnDeclContext,3876 fn_decl_context: ?FnDeclContext,
5271 is_pub: bool,3877 is_pub: bool,
5272) !*ast.Node.FnProto {3878) !*ast.Payload.Func {
5273 const fn_ty = @ptrCast(*const clang.FunctionType, fn_proto_ty);3879 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);
5275 const is_var_args = fn_proto_ty.isVariadic();3881 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);
5277}3883}
52783884
5279fn transFnNoProto(3885fn transFnNoProto(
5280 rp: RestorePoint,3886 c: *Context,
5281 fn_ty: *const clang.FunctionType,3887 fn_ty: *const clang.FunctionType,
5282 source_loc: clang.SourceLocation,3888 source_loc: clang.SourceLocation,
5283 fn_decl_context: ?FnDeclContext,3889 fn_decl_context: ?FnDeclContext,
5284 is_pub: bool,3890 is_pub: bool,
5285) !*ast.Node.FnProto {3891) !*ast.Payload.Func {
5286 const cc = try transCC(rp, fn_ty, source_loc);3892 const cc = try transCC(c, fn_ty, source_loc);
5287 const is_var_args = if (fn_decl_context) |ctx| (!ctx.is_export and ctx.storage_class != .Static) else true;3893 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);
5289}3895}
52903896
5291fn finishTransFnProto(3897fn finishTransFnProto(
5292 rp: RestorePoint,3898 c: *Context,
5293 fn_decl: ?*const clang.FunctionDecl,3899 fn_decl: ?*const clang.FunctionDecl,
5294 fn_proto_ty: ?*const clang.FunctionProtoType,3900 fn_proto_ty: ?*const clang.FunctionProtoType,
5295 fn_ty: *const clang.FunctionType,3901 fn_ty: *const clang.FunctionType,
...@@ -5298,128 +3904,78 @@ fn finishTransFnProto(...@@ -5298,128 +3904,78 @@ fn finishTransFnProto(
5298 is_var_args: bool,3904 is_var_args: bool,
5299 cc: CallingConvention,3905 cc: CallingConvention,
5300 is_pub: bool,3906 is_pub: bool,
5301) !*ast.Node.FnProto {3907) !*ast.Payload.Func {
5302 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;3908 const is_export = if (fn_decl_context) |ctx| ctx.is_export else false;
5303 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;3909 const is_extern = if (fn_decl_context) |ctx| !ctx.has_body else false;
3910 const scope = &c.global_scope.base;
53043911
5305 // TODO check for always_inline attribute3912 // TODO check for always_inline attribute
5306 // TODO check for align attribute3913 // TODO check for align attribute
53073914
5308 // pub extern fn name(...) T3915 var fn_params = std.ArrayList(ast.Payload.Param).init(c.gpa);
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);
5321 defer fn_params.deinit();3916 defer fn_params.deinit();
5322 const param_count: usize = if (fn_proto_ty != null) fn_proto_ty.?.getNumParams() else 0;3917 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 node3918 try fn_params.ensureCapacity(param_count);
53243919
5325 var i: usize = 0;3920 var i: usize = 0;
5326 while (i < param_count) : (i += 1) {3921 while (i < param_count) : (i += 1) {
5327 const param_qt = fn_proto_ty.?.getParamType(@intCast(c_uint, i));3922 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;3925 const param_name: ?[]const u8 =
53303926 if (fn_decl) |decl|
5331 const param_name_tok: ?ast.TokenIndex = blk: {3927 blk: {
5332 if (fn_decl) |decl| {3928 const param = decl.getParamDecl(@intCast(c_uint, i));
5333 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());
5334 const param_name: []const u8 = try rp.c.str(@ptrCast(*const clang.NamedDecl, param).getName_bytes_begin());3930 if (param_name.len < 1)
5335 if (param_name.len < 1)3931 break :blk null;
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 };
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
5347 fn_params.addOneAssumeCapacity().* = .{3937 fn_params.addOneAssumeCapacity().* = .{
5348 .doc_comments = null,3938 .is_noalias = is_noalias,
5349 .comptime_token = null,3939 .name = param_name,
5350 .noalias_token = noalias_tok,3940 .type = type_node,
5351 .name_token = param_name_tok,
5352 .param_type = .{ .type_expr = type_node },
5353 };3941 };
5354
5355 if (i + 1 < param_count) {
5356 _ = try appendToken(rp.c, .Comma, ",");
5357 }
5358 }3942 }
53593943
5360 const var_args_token: ?ast.TokenIndex = if (is_var_args) blk: {3944 const linksection_string = 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: {
5370 if (fn_decl) |decl| {3945 if (fn_decl) |decl| {
5371 var str_len: usize = undefined;3946 var str_len: usize = undefined;
5372 if (decl.getSectionAttribute(&str_len)) |str_ptr| {3947 if (decl.getSectionAttribute(&str_len)) |str_ptr| {
5373 _ = try appendToken(rp.c, .Keyword_linksection, "linksection");3948 break :blk str_ptr[0..str_len];
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;
5382 }3949 }
5383 }3950 }
5384 break :blk null;3951 break :blk null;
5385 };3952 };
53863953
5387 const align_expr = blk: {3954 const alignment = blk: {
5388 if (fn_decl) |decl| {3955 if (fn_decl) |decl| {
5389 const alignment = decl.getAlignedAttribute(rp.c.clang_context);3956 const alignment = decl.getAlignedAttribute(c.clang_context);
5390 if (alignment != 0) {3957 if (alignment != 0) {
5391 _ = try appendToken(rp.c, .Keyword_align, "align");
5392 _ = try appendToken(rp.c, .LParen, "(");
5393 // Clang reports the alignment in bits3958 // Clang reports the alignment in bits
5394 const expr = try transCreateNodeInt(rp.c, alignment / 8);3959 break :blk alignment / 8;
5395 _ = try appendToken(rp.c, .RParen, ")");
5396
5397 break :blk expr;
5398 }3960 }
5399 }3961 }
5400 break :blk null;3962 break :blk null;
5401 };3963 };
54023964
5403 const callconv_expr = if ((is_export or is_extern) and cc == .C) null else blk: {3965 const explicit_callconv = if ((is_export or is_extern) and cc == .C) null else cc;
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 };
54103966
5411 const return_type_node = blk: {3967 const return_type_node = blk: {
5412 if (fn_ty.getNoReturnAttr()) {3968 if (fn_ty.getNoReturnAttr()) {
5413 break :blk try transCreateNodeIdentifier(rp.c, "noreturn");3969 break :blk Tag.noreturn_type.init();
5414 } else {3970 } else {
5415 const return_qt = fn_ty.getReturnType();3971 const return_qt = fn_ty.getReturnType();
5416 if (isCVoid(return_qt)) {3972 if (isCVoid(return_qt)) {
5417 // convert primitive c_void to actual void (only for return type)3973 // 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();
5419 } else {3975 } 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) {
5421 error.UnsupportedType => {3977 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", .{});
5423 return err;3979 return err;
5424 },3980 },
5425 error.OutOfMemory => |e| return e,3981 error.OutOfMemory => |e| return e,
...@@ -5427,116 +3983,57 @@ fn finishTransFnProto(...@@ -5427,116 +3983,57 @@ fn finishTransFnProto(
5427 }3983 }
5428 }3984 }
5429 };3985 };
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.4007fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void {
5432 var body_node: ?*ast.Node = null;4008 const args_prefix = .{c.locStr(loc)};
5433 if (fn_decl_context) |ctx| {4009 const value = try std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, args_prefix ++ args);
5434 if (ctx.has_body) {4010 try scope.appendNode(try Tag.warning.create(c.arena, value));
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;
5458}4011}
54594012
5460fn revertAndWarn(4013fn fail(
5461 rp: RestorePoint,4014 c: *Context,
5462 err: anytype,4015 err: anytype,
5463 source_loc: clang.SourceLocation,4016 source_loc: clang.SourceLocation,
5464 comptime format: []const u8,4017 comptime format: []const u8,
5465 args: anytype,4018 args: anytype,
5466) (@TypeOf(err) || error{OutOfMemory}) {4019) (@TypeOf(err) || error{OutOfMemory}) {
5467 rp.activate();4020 try warn(c, &c.global_scope.base, source_loc, format, args);
5468 try emitWarning(rp.c, source_loc, format, args);
5469 return err;4021 return err;
5470}4022}
54714023
5472fn emitWarning(c: *Context, loc: clang.SourceLocation, 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 {
5473 const args_prefix = .{c.locStr(loc)};4025 // location
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 {
5478 // pub const name = @compileError(msg);4026 // pub const name = @compileError(msg);
5479 const pub_tok = try appendToken(c, .Keyword_pub, "pub");4027 const fail_msg = try std.fmt.allocPrint(c.arena, format, args);
5480 const const_tok = try appendToken(c, .Keyword_const, "const");4028 try addTopLevelDecl(c, name, try Tag.fail_decl.create(c.arena, .{ .actual = name, .mangled = fail_msg }));
5481 const name_tok = try appendIdentifier(c, name);4029 const location_comment = try std.fmt.allocPrint(c.arena, "// {s}", .{c.locStr(loc)});
5482 const eq_tok = try appendToken(c, .Equal, "=");4030 try c.global_scope.nodes.append(try Tag.warning.create(c.arena, location_comment));
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});
5519}4031}
55204032
5521fn appendTokenFmt(c: *Context, token_id: Token.Id, comptime format: []const u8, args: anytype) !ast.TokenIndex {4033pub fn freeErrors(errors: []ClangErrMsg) void {
5522 assert(token_id != .Invalid);4034 errors.ptr.delete(errors.len);
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;
5537}4035}
55384036
5539// TODO hook up with codegen
5540fn isZigPrimitiveType(name: []const u8) bool {4037fn isZigPrimitiveType(name: []const u8) bool {
5541 if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {4038 if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
5542 for (name[1..]) |c| {4039 for (name[1..]) |c| {
...@@ -5547,56 +4044,7 @@ fn isZigPrimitiveType(name: []const u8) bool {...@@ -5547,56 +4044,7 @@ fn isZigPrimitiveType(name: []const u8) bool {
5547 }4044 }
5548 return true;4045 return true;
5549 }4046 }
5550 // void is invalid in c so it doesn't need to be checked.4047 return @import("astgen.zig").simple_types.has(name);
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);
5600}4048}
56014049
5602const MacroCtx = struct {4050const MacroCtx = struct {
...@@ -5717,27 +4165,13 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -5717,27 +4165,13 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
5717fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {4165fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
5718 const scope = &c.global_scope.base;4166 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
5725 const init_node = try parseCExpr(c, m, scope);4168 const init_node = try parseCExpr(c, m, scope);
5726 const last = m.next().?;4169 const last = m.next().?;
5727 if (last != .Eof and last != .Nl)4170 if (last != .Eof and last != .Nl)
5728 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});4171 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
57294172
5730 const semicolon_token = try appendToken(c, .Semicolon, ";");4173 const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
5731 const node = try ast.Node.VarDecl.create(c.arena, .{4174 _ = try c.global_scope.macro_table.put(m.name, var_decl);
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);
5741}4175}
57424176
5743fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {4177fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
...@@ -5745,16 +4179,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5745,16 +4179,11 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5745 defer block_scope.deinit();4179 defer block_scope.deinit();
5746 const scope = &block_scope.base;4180 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
5753 if (m.next().? != .LParen) {4182 if (m.next().? != .LParen) {
5754 return m.fail(c, "unable to translate C expr: expected '('", .{});4183 return m.fail(c, "unable to translate C expr: expected '('", .{});
5755 }4184 }
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);
5758 defer fn_params.deinit();4187 defer fn_params.deinit();
57594188
5760 while (true) {4189 while (true) {
...@@ -5762,120 +4191,82 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -5762,120 +4191,82 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5762 _ = m.next();4191 _ = m.next();
57634192
5764 const mangled_name = try block_scope.makeMangledName(c, m.slice());4193 const mangled_name = try block_scope.makeMangledName(c, m.slice());
5765 const param_name_tok = try appendIdentifier(c, mangled_name);4194 try fn_params.append(.{
5766 _ = try appendToken(c, .Colon, ":");4195 .is_noalias = false,
57674196 .name = mangled_name,
5768 const any_type = try c.arena.create(ast.Node.OneToken);4197 .type = Tag.@"anytype".init(),
5769 any_type.* = .{4198 });
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 };
57814199
5782 if (m.peek().? != .Comma) break;4200 if (m.peek().? != .Comma) break;
5783 _ = m.next();4201 _ = m.next();
5784 _ = try appendToken(c, .Comma, ",");
5785 }4202 }
57864203
5787 if (m.next().? != .RParen) {4204 if (m.next().? != .RParen) {
5788 return m.fail(c, "unable to translate C expr: expected ')'", .{});4205 return m.fail(c, "unable to translate C expr: expected ')'", .{});
5789 }4206 }
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");
5801 const expr = try parseCExpr(c, m, scope);4208 const expr = try parseCExpr(c, m, scope);
5802 const last = m.next().?;4209 const last = m.next().?;
5803 if (last != .Eof and last != .Nl)4210 if (last != .Eof and last != .Nl)
5804 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});4211 return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
5805 _ = try appendToken(c, .Semicolon, ";");4212
5806 const type_of_arg = if (!expr.tag.isBlock()) expr else blk: {4213 const typeof_arg = if (expr.castTag(.block)) |some| blk: {
5807 const stmts = expr.blockStatements();4214 const stmts = some.data.stmts;
5808 const blk_last = stmts[stmts.len - 1];4215 const blk_last = stmts[stmts.len - 1];
5809 const br = blk_last.cast(ast.Node.ControlFlowExpression).?;4216 const br = blk_last.castTag(.break_val).?;
5810 break :blk br.getRHS().?;4217 break :blk br.data.val;
5811 };4218 } else expr;
5812 type_of.params()[0] = type_of_arg;4219 const return_type = if (typeof_arg.castTag(.std_meta_cast)) |some|
5813 type_of.rparen_token = try appendToken(c, .RParen, ")");4220 some.data.lhs
5814 const return_expr = try ast.Node.ControlFlowExpression.create(c.arena, .{4221 else
5815 .ltoken = return_kw,4222 try Tag.typeof.create(c.arena, typeof_arg);
5816 .tag = .Return,
5817 }, .{
5818 .rhs = expr,
5819 });
58204223
5821 try block_scope.statements.append(&return_expr.base);4224 const return_expr = try Tag.@"return".create(c.arena, expr);
5822 const block_node = try block_scope.complete(c);4225 try block_scope.statements.append(return_expr);
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);
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);
5836}4234}
58374235
5838const ParseError = Error || error{ParseError};4236const 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 {
5841 // TODO parseCAssignExpr here4239 // TODO parseCAssignExpr here
5842 const node = try parseCCondExpr(c, m, scope);4240 const node = try parseCCondExpr(c, m, scope);
5843 if (m.next().? != .Comma) {4241 if (m.next().? != .Comma) {
5844 m.i -= 1;4242 m.i -= 1;
5845 return node;4243 return node;
5846 }4244 }
5847 _ = try appendToken(c, .Semicolon, ";");
5848 var block_scope = try Scope.Block.init(c, scope, true);4245 var block_scope = try Scope.Block.init(c, scope, true);
5849 defer block_scope.deinit();4246 defer block_scope.deinit();
58504247
5851 var last = node;4248 var last = node;
5852 while (true) {4249 while (true) {
5853 // suppress result4250 // suppress result
5854 const lhs = try transCreateNodeIdentifier(c, "_");4251 const ignore = try Tag.discard.create(c.arena, last);
5855 const op_token = try appendToken(c, .Equal, "=");4252 try block_scope.statements.append(ignore);
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);
58644253
5865 last = try parseCCondExpr(c, m, scope);4254 last = try parseCCondExpr(c, m, scope);
5866 _ = try appendToken(c, .Semicolon, ";");
5867 if (m.next().? != .Comma) {4255 if (m.next().? != .Comma) {
5868 m.i -= 1;4256 m.i -= 1;
5869 break;4257 break;
5870 }4258 }
5871 }4259 }
58724260
5873 const break_node = try transCreateNodeBreak(c, block_scope.label, last);4261 const break_node = try Tag.break_val.create(c.arena, .{
5874 try block_scope.statements.append(&break_node.base);4262 .label = block_scope.label,
4263 .val = last,
4264 });
4265 try block_scope.statements.append(break_node);
5875 return try block_scope.complete(c);4266 return try block_scope.complete(c);
5876}4267}
58774268
5878fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {4269fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node {
5879 var lit_bytes = m.slice();4270 var lit_bytes = m.slice();
58804271
5881 switch (m.list[m.i].id) {4272 switch (m.list[m.i].id) {
...@@ -5895,11 +4286,10 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {...@@ -5895,11 +4286,10 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
5895 }4286 }
58964287
5897 if (suffix == .none) {4288 if (suffix == .none) {
5898 return transCreateNodeInt(c, lit_bytes);4289 return transCreateNodeNumber(c, lit_bytes, .int);
5899 }4290 }
59004291
5901 const cast_node = try c.createBuiltinCall("@as", 2);4292 const type_node = try Tag.type.create(c.arena, switch (suffix) {
5902 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (suffix) {
5903 .u => "c_uint",4293 .u => "c_uint",
5904 .l => "c_long",4294 .l => "c_long",
5905 .lu => "c_ulong",4295 .lu => "c_ulong",
...@@ -5913,27 +4303,22 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {...@@ -5913,27 +4303,22 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!*ast.Node {
5913 .llu => 3,4303 .llu => 3,
5914 else => unreachable,4304 else => unreachable,
5915 }];4305 }];
5916 _ = try appendToken(c, .Comma, ",");4306 const rhs = try transCreateNodeNumber(c, lit_bytes, .int);
5917 cast_node.params()[1] = try transCreateNodeInt(c, lit_bytes);4307 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
5918 cast_node.rparen_token = try appendToken(c, .RParen, ")");
5919 return &cast_node.base;
5920 },4308 },
5921 .FloatLiteral => |suffix| {4309 .FloatLiteral => |suffix| {
5922 if (lit_bytes[0] == '.')4310 if (lit_bytes[0] == '.')
5923 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});4311 lit_bytes = try std.fmt.allocPrint(c.arena, "0{s}", .{lit_bytes});
5924 if (suffix == .none) {4312 if (suffix == .none) {
5925 return transCreateNodeFloat(c, lit_bytes);4313 return transCreateNodeNumber(c, lit_bytes, .float);
5926 }4314 }
5927 const cast_node = try c.createBuiltinCall("@as", 2);4315 const type_node = try Tag.type.create(c.arena, switch (suffix) {
5928 cast_node.params()[0] = try transCreateNodeIdentifier(c, switch (suffix) {
5929 .f => "f32",4316 .f => "f32",
5930 .l => "c_longdouble",4317 .l => "c_longdouble",
5931 else => unreachable,4318 else => unreachable,
5932 });4319 });
5933 _ = try appendToken(c, .Comma, ",");4320 const rhs = try transCreateNodeNumber(c, lit_bytes[0 .. lit_bytes.len - 1], .float);
5934 cast_node.params()[1] = try transCreateNodeFloat(c, lit_bytes[0 .. lit_bytes.len - 1]);4321 return Tag.as.create(c.arena, .{ .lhs = type_node, .rhs = rhs });
5935 cast_node.rparen_token = try appendToken(c, .RParen, ")");
5936 return &cast_node.base;
5937 },4322 },
5938 else => unreachable,4323 else => unreachable,
5939 }4324 }
...@@ -6099,79 +4484,62 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {...@@ -6099,79 +4484,62 @@ fn zigifyEscapeSequences(ctx: *Context, m: *MacroCtx) ![]const u8 {
6099 return bytes[0..i];4484 return bytes[0..i];
6100}4485}
61014486
6102fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4487fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6103 const tok = m.next().?;4488 const tok = m.next().?;
6104 const slice = m.slice();4489 const slice = m.slice();
6105 switch (tok) {4490 switch (tok) {
6106 .CharLiteral => {4491 .CharLiteral => {
6107 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {4492 if (slice[0] != '\'' or slice[1] == '\\' or slice.len == 3) {
6108 const token = try appendToken(c, .CharLiteral, try zigifyEscapeSequences(c, m));4493 return Tag.char_literal.create(c.arena, 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;
6115 } else {4494 } else {
6116 const token = try appendTokenFmt(c, .IntegerLiteral, "0x{x}", .{slice[1 .. slice.len - 1]});4495 const str = try std.fmt.allocPrint(c.arena, "0x{x}", .{slice[1 .. slice.len - 1]});
6117 const node = try c.arena.create(ast.Node.OneToken);4496 return Tag.integer_literal.create(c.arena, str);
6118 node.* = .{
6119 .base = .{ .tag = .IntegerLiteral },
6120 .token = token,
6121 };
6122 return &node.base;
6123 }4497 }
6124 },4498 },
6125 .StringLiteral => {4499 .StringLiteral => {
6126 const token = try appendToken(c, .StringLiteral, try zigifyEscapeSequences(c, m));4500 return Tag.string_literal.create(c.arena, 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;
6133 },4501 },
6134 .IntegerLiteral, .FloatLiteral => {4502 .IntegerLiteral, .FloatLiteral => {
6135 return parseCNumLit(c, m);4503 return parseCNumLit(c, m);
6136 },4504 },
6137 // eventually this will be replaced by std.c.parse which will handle these correctly4505 // eventually this will be replaced by std.c.parse which will handle these correctly
6138 .Keyword_void => return transCreateNodeIdentifierUnchecked(c, "c_void"),4506 .Keyword_void => return Tag.type.create(c.arena, "c_void"),
6139 .Keyword_bool => return transCreateNodeIdentifierUnchecked(c, "bool"),4507 .Keyword_bool => return Tag.type.create(c.arena, "bool"),
6140 .Keyword_double => return transCreateNodeIdentifierUnchecked(c, "f64"),4508 .Keyword_double => return Tag.type.create(c.arena, "f64"),
6141 .Keyword_long => return transCreateNodeIdentifierUnchecked(c, "c_long"),4509 .Keyword_long => return Tag.type.create(c.arena, "c_long"),
6142 .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"),4510 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
6143 .Keyword_float => return transCreateNodeIdentifierUnchecked(c, "f32"),4511 .Keyword_float => return Tag.type.create(c.arena, "f32"),
6144 .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"),4512 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
6145 .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "u8"),4513 .Keyword_char => return Tag.type.create(c.arena, "u8"),
6146 .Keyword_unsigned => if (m.next()) |t| switch (t) {4514 .Keyword_unsigned => if (m.next()) |t| switch (t) {
6147 .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "u8"),4515 .Keyword_char => return Tag.type.create(c.arena, "u8"),
6148 .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_ushort"),4516 .Keyword_short => return Tag.type.create(c.arena, "c_ushort"),
6149 .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_uint"),4517 .Keyword_int => return Tag.type.create(c.arena, "c_uint"),
6150 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {4518 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
6151 _ = m.next();4519 _ = m.next();
6152 return transCreateNodeIdentifierUnchecked(c, "c_ulonglong");4520 return Tag.type.create(c.arena, "c_ulonglong");
6153 } else return transCreateNodeIdentifierUnchecked(c, "c_ulong"),4521 } else return Tag.type.create(c.arena, "c_ulong"),
6154 else => {4522 else => {
6155 m.i -= 1;4523 m.i -= 1;
6156 return transCreateNodeIdentifierUnchecked(c, "c_uint");4524 return Tag.type.create(c.arena, "c_uint");
6157 },4525 },
6158 } else {4526 } else {
6159 return transCreateNodeIdentifierUnchecked(c, "c_uint");4527 return Tag.type.create(c.arena, "c_uint");
6160 },4528 },
6161 .Keyword_signed => if (m.next()) |t| switch (t) {4529 .Keyword_signed => if (m.next()) |t| switch (t) {
6162 .Keyword_char => return transCreateNodeIdentifierUnchecked(c, "i8"),4530 .Keyword_char => return Tag.type.create(c.arena, "i8"),
6163 .Keyword_short => return transCreateNodeIdentifierUnchecked(c, "c_short"),4531 .Keyword_short => return Tag.type.create(c.arena, "c_short"),
6164 .Keyword_int => return transCreateNodeIdentifierUnchecked(c, "c_int"),4532 .Keyword_int => return Tag.type.create(c.arena, "c_int"),
6165 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {4533 .Keyword_long => if (m.peek() != null and m.peek().? == .Keyword_long) {
6166 _ = m.next();4534 _ = m.next();
6167 return transCreateNodeIdentifierUnchecked(c, "c_longlong");4535 return Tag.type.create(c.arena, "c_longlong");
6168 } else return transCreateNodeIdentifierUnchecked(c, "c_long"),4536 } else return Tag.type.create(c.arena, "c_long"),
6169 else => {4537 else => {
6170 m.i -= 1;4538 m.i -= 1;
6171 return transCreateNodeIdentifierUnchecked(c, "c_int");4539 return Tag.type.create(c.arena, "c_int");
6172 },4540 },
6173 } else {4541 } else {
6174 return transCreateNodeIdentifierUnchecked(c, "c_int");4542 return Tag.type.create(c.arena, "c_int");
6175 },4543 },
6176 .Keyword_enum, .Keyword_struct, .Keyword_union => {4544 .Keyword_enum, .Keyword_struct, .Keyword_union => {
6177 // struct Foo will be declared as struct_Foo by transRecordDecl4545 // struct Foo will be declared as struct_Foo by transRecordDecl
...@@ -6181,17 +4549,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*...@@ -6181,17 +4549,12 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
6181 return error.ParseError;4549 return error.ParseError;
6182 }4550 }
61834551
6184 const ident_token = try appendTokenFmt(c, .Identifier, "{s}_{s}", .{ slice, m.slice() });4552 const name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ slice, m.slice() });
6185 const identifier = try c.arena.create(ast.Node.OneToken);4553 return Tag.identifier.create(c.arena, name);
6186 identifier.* = .{
6187 .base = .{ .tag = .Identifier },
6188 .token = ident_token,
6189 };
6190 return &identifier.base;
6191 },4554 },
6192 .Identifier => {4555 .Identifier => {
6193 const mangled_name = scope.getAlias(slice);4556 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);
6195 },4558 },
6196 .LParen => {4559 .LParen => {
6197 const inner_node = try parseCExpr(c, m, scope);4560 const inner_node = try parseCExpr(c, m, scope);
...@@ -6221,10 +4584,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*...@@ -6221,10 +4584,6 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
6221 },4584 },
6222 else => return inner_node,4585 else => return inner_node,
6223 }4586 }
6224
6225 // hack to get zig fmt to render a comma in builtin calls
6226 _ = try appendToken(c, .Comma, ",");
6227
6228 const node_to_cast = try parseCExpr(c, m, scope);4587 const node_to_cast = try parseCExpr(c, m, scope);
62294588
6230 if (saw_l_paren and m.next().? != .RParen) {4589 if (saw_l_paren and m.next().? != .RParen) {
...@@ -6232,28 +4591,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*...@@ -6232,28 +4591,7 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
6232 return error.ParseError;4591 return error.ParseError;
6233 }4592 }
62344593
6235 const lparen = try appendToken(c, .LParen, "(");4594 return Tag.std_meta_cast.create(c.arena, .{ .lhs = inner_node, .rhs = node_to_cast });
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;
6257 },4595 },
6258 else => {4596 else => {
6259 try m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(tok)});4597 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!*...@@ -6262,447 +4600,256 @@ fn parseCPrimaryExprInner(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*
6262 }4600 }
6263}4601}
62644602
6265fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4603fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6266 var node = try parseCPrimaryExprInner(c, m, scope);4604 var node = try parseCPrimaryExprInner(c, m, scope);
6267 // In C the preprocessor would handle concatting strings while expanding macros.4605 // In C the preprocessor would handle concatting strings while expanding macros.
6268 // This should do approximately the same by concatting any strings and identifiers4606 // This should do approximately the same by concatting any strings and identifiers
6269 // after a primary expression.4607 // after a primary expression.
6270 while (true) {4608 while (true) {
6271 var op_token: ast.TokenIndex = undefined;
6272 var op_id: ast.Node.Tag = undefined;
6273 switch (m.peek().?) {4609 switch (m.peek().?) {
6274 .StringLiteral, .Identifier => {},4610 .StringLiteral, .Identifier => {},
6275 else => break,4611 else => break,
6276 }4612 }
6277 const op_node = try c.arena.create(ast.Node.SimpleInfixOp);4613 node = try Tag.array_cat.create(c.arena, .{ .lhs = node, .rhs = try parseCPrimaryExprInner(c, m, scope) });
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;
6285 }4614 }
6286 return node;4615 return node;
6287}4616}
62884617
6289fn nodeIsInfixOp(tag: ast.Node.Tag) bool {4618fn macroBoolToInt(c: *Context, node: Node) !Node {
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 {
6341 if (!isBoolRes(node)) {4619 if (!isBoolRes(node)) {
6342 if (!nodeIsInfixOp(node.tag)) return node;4620 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;
6351 }4621 }
63524622
6353 const builtin_node = try c.createBuiltinCall("@boolToInt", 1);4623 return Tag.bool_to_int.create(c.arena, node);
6354 builtin_node.params()[0] = node;
6355 builtin_node.rparen_token = try appendToken(c, .RParen, ")");
6356 return &builtin_node.base;
6357}4624}
63584625
6359fn macroIntToBool(c: *Context, node: *ast.Node) !*ast.Node {4626fn macroIntToBool(c: *Context, node: Node) !Node {
6360 if (isBoolRes(node)) {4627 if (isBoolRes(node)) {
6361 if (!nodeIsInfixOp(node.tag)) return node;4628 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;
6370 }4629 }
63714630
6372 const op_token = try appendToken(c, .BangEqual, "!=");4631 return Tag.not_equal.create(c.arena, .{ .lhs = node, .rhs = Tag.zero_literal.init() });
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;
6400}4632}
64014633
6402fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4634fn parseCCondExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6403 const node = try parseCOrExpr(c, m, scope);4635 const node = try parseCOrExpr(c, m, scope);
6404 if (m.peek().? != .QuestionMark) {4636 if (m.peek().? != .QuestionMark) {
6405 return node;4637 return node;
6406 }4638 }
6407 _ = m.next();4639 _ = m.next();
64084640
6409 // must come immediately after expr4641 const then_body = try parseCOrExpr(c, m, scope);
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);
6414 if (m.next().? != .Colon) {4642 if (m.next().? != .Colon) {
6415 try m.fail(c, "unable to translate C expr: expected ':'", .{});4643 try m.fail(c, "unable to translate C expr: expected ':'", .{});
6416 return error.ParseError;4644 return error.ParseError;
6417 }4645 }
6418 if_node.@"else" = try transCreateNodeElse(c);4646 const else_body = try parseCCondExpr(c, m, scope);
6419 if_node.@"else".?.body = try parseCCondExpr(c, m, scope);4647 return Tag.@"if".create(c.arena, .{ .cond = node, .then = then_body, .@"else" = else_body });
6420 return &if_node.base;
6421}4648}
64224649
6423fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4650fn parseCOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6424 var node = try parseCAndExpr(c, m, scope);4651 var node = try parseCAndExpr(c, m, scope);
6425 while (m.next().? == .PipePipe) {4652 while (m.next().? == .PipePipe) {
6426 const lhs_node = try macroIntToBool(c, node);4653 const lhs = try macroIntToBool(c, node);
6427 const op_token = try appendToken(c, .Keyword_or, "or");4654 const rhs = try macroIntToBool(c, try parseCAndExpr(c, m, scope));
6428 const rhs_node = try parseCAndExpr(c, m, scope);4655 node = try Tag.@"or".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
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;
6437 }4656 }
6438 m.i -= 1;4657 m.i -= 1;
6439 return node;4658 return node;
6440}4659}
64414660
6442fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4661fn parseCAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6443 var node = try parseCBitOrExpr(c, m, scope);4662 var node = try parseCBitOrExpr(c, m, scope);
6444 while (m.next().? == .AmpersandAmpersand) {4663 while (m.next().? == .AmpersandAmpersand) {
6445 const lhs_node = try macroIntToBool(c, node);4664 const lhs = try macroIntToBool(c, node);
6446 const op_token = try appendToken(c, .Keyword_and, "and");4665 const rhs = try macroIntToBool(c, try parseCBitOrExpr(c, m, scope));
6447 const rhs_node = try parseCBitOrExpr(c, m, scope);4666 node = try Tag.@"and".create(c.arena, .{ .lhs = lhs, .rhs = rhs });
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;
6456 }4667 }
6457 m.i -= 1;4668 m.i -= 1;
6458 return node;4669 return node;
6459}4670}
64604671
6461fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4672fn parseCBitOrExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6462 var node = try parseCBitXorExpr(c, m, scope);4673 var node = try parseCBitXorExpr(c, m, scope);
6463 while (m.next().? == .Pipe) {4674 while (m.next().? == .Pipe) {
6464 const lhs_node = try macroBoolToInt(c, node);4675 const lhs = try macroBoolToInt(c, node);
6465 const op_token = try appendToken(c, .Pipe, "|");4676 const rhs = try macroBoolToInt(c, try parseCBitXorExpr(c, m, scope));
6466 const rhs_node = try parseCBitXorExpr(c, m, scope);4677 node = try Tag.bit_or.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
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;
6475 }4678 }
6476 m.i -= 1;4679 m.i -= 1;
6477 return node;4680 return node;
6478}4681}
64794682
6480fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4683fn parseCBitXorExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6481 var node = try parseCBitAndExpr(c, m, scope);4684 var node = try parseCBitAndExpr(c, m, scope);
6482 while (m.next().? == .Caret) {4685 while (m.next().? == .Caret) {
6483 const lhs_node = try macroBoolToInt(c, node);4686 const lhs = try macroBoolToInt(c, node);
6484 const op_token = try appendToken(c, .Caret, "^");4687 const rhs = try macroBoolToInt(c, try parseCBitAndExpr(c, m, scope));
6485 const rhs_node = try parseCBitAndExpr(c, m, scope);4688 node = try Tag.bit_xor.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
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;
6494 }4689 }
6495 m.i -= 1;4690 m.i -= 1;
6496 return node;4691 return node;
6497}4692}
64984693
6499fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4694fn parseCBitAndExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6500 var node = try parseCEqExpr(c, m, scope);4695 var node = try parseCEqExpr(c, m, scope);
6501 while (m.next().? == .Ampersand) {4696 while (m.next().? == .Ampersand) {
6502 const lhs_node = try macroBoolToInt(c, node);4697 const lhs = try macroBoolToInt(c, node);
6503 const op_token = try appendToken(c, .Ampersand, "&");4698 const rhs = try macroBoolToInt(c, try parseCEqExpr(c, m, scope));
6504 const rhs_node = try parseCEqExpr(c, m, scope);4699 node = try Tag.bit_and.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
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;
6513 }4700 }
6514 m.i -= 1;4701 m.i -= 1;
6515 return node;4702 return node;
6516}4703}
65174704
6518fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4705fn parseCEqExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6519 var node = try parseCRelExpr(c, m, scope);4706 var node = try parseCRelExpr(c, m, scope);
6520 while (true) {4707 while (true) {
6521 var op_token: ast.TokenIndex = undefined;
6522 var op_id: ast.Node.Tag = undefined;
6523 switch (m.peek().?) {4708 switch (m.peek().?) {
6524 .BangEqual => {4709 .BangEqual => {
6525 op_token = try appendToken(c, .BangEqual, "!=");4710 _ = m.next();
6526 op_id = .BangEqual;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 });
6527 },4714 },
6528 .EqualEqual => {4715 .EqualEqual => {
6529 op_token = try appendToken(c, .EqualEqual, "==");4716 _ = m.next();
6530 op_id = .EqualEqual;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 });
6531 },4720 },
6532 else => return node,4721 else => return node,
6533 }4722 }
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;
6545 }4723 }
6546}4724}
65474725
6548fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4726fn parseCRelExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6549 var node = try parseCShiftExpr(c, m, scope);4727 var node = try parseCShiftExpr(c, m, scope);
6550 while (true) {4728 while (true) {
6551 var op_token: ast.TokenIndex = undefined;
6552 var op_id: ast.Node.Tag = undefined;
6553 switch (m.peek().?) {4729 switch (m.peek().?) {
6554 .AngleBracketRight => {4730 .AngleBracketRight => {
6555 op_token = try appendToken(c, .AngleBracketRight, ">");4731 _ = m.next();
6556 op_id = .GreaterThan;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 });
6557 },4735 },
6558 .AngleBracketRightEqual => {4736 .AngleBracketRightEqual => {
6559 op_token = try appendToken(c, .AngleBracketRightEqual, ">=");4737 _ = m.next();
6560 op_id = .GreaterOrEqual;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 });
6561 },4741 },
6562 .AngleBracketLeft => {4742 .AngleBracketLeft => {
6563 op_token = try appendToken(c, .AngleBracketLeft, "<");4743 _ = m.next();
6564 op_id = .LessThan;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 });
6565 },4747 },
6566 .AngleBracketLeftEqual => {4748 .AngleBracketLeftEqual => {
6567 op_token = try appendToken(c, .AngleBracketLeftEqual, "<=");4749 _ = m.next();
6568 op_id = .LessOrEqual;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 });
6569 },4753 },
6570 else => return node,4754 else => return node,
6571 }4755 }
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;
6583 }4756 }
6584}4757}
65854758
6586fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4759fn parseCShiftExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6587 var node = try parseCAddSubExpr(c, m, scope);4760 var node = try parseCAddSubExpr(c, m, scope);
6588 while (true) {4761 while (true) {
6589 var op_token: ast.TokenIndex = undefined;
6590 var op_id: ast.Node.Tag = undefined;
6591 switch (m.peek().?) {4762 switch (m.peek().?) {
6592 .AngleBracketAngleBracketLeft => {4763 .AngleBracketAngleBracketLeft => {
6593 op_token = try appendToken(c, .AngleBracketAngleBracketLeft, "<<");4764 _ = m.next();
6594 op_id = .BitShiftLeft;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 });
6595 },4768 },
6596 .AngleBracketAngleBracketRight => {4769 .AngleBracketAngleBracketRight => {
6597 op_token = try appendToken(c, .AngleBracketAngleBracketRight, ">>");4770 _ = m.next();
6598 op_id = .BitShiftRight;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 });
6599 },4774 },
6600 else => return node,4775 else => return node,
6601 }4776 }
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;
6613 }4777 }
6614}4778}
66154779
6616fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4780fn parseCAddSubExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6617 var node = try parseCMulExpr(c, m, scope);4781 var node = try parseCMulExpr(c, m, scope);
6618 while (true) {4782 while (true) {
6619 var op_token: ast.TokenIndex = undefined;
6620 var op_id: ast.Node.Tag = undefined;
6621 switch (m.peek().?) {4783 switch (m.peek().?) {
6622 .Plus => {4784 .Plus => {
6623 op_token = try appendToken(c, .Plus, "+");4785 _ = m.next();
6624 op_id = .Add;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 });
6625 },4789 },
6626 .Minus => {4790 .Minus => {
6627 op_token = try appendToken(c, .Minus, "-");4791 _ = m.next();
6628 op_id = .Sub;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 });
6629 },4795 },
6630 else => return node,4796 else => return node,
6631 }4797 }
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;
6643 }4798 }
6644}4799}
66454800
6646fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4801fn parseCMulExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6647 var node = try parseCUnaryExpr(c, m, scope);4802 var node = try parseCUnaryExpr(c, m, scope);
6648 while (true) {4803 while (true) {
6649 var op_token: ast.TokenIndex = undefined;
6650 var op_id: ast.Node.Tag = undefined;
6651 switch (m.next().?) {4804 switch (m.next().?) {
6652 .Asterisk => {4805 .Asterisk => {
6653 if (m.peek().? == .RParen) {4806 const next = m.peek().?;
4807 if (next == .RParen or next == .Nl or next == .Eof) {
6654 // type *)4808 // type *)
66554809
6656 // hack to get zig fmt to render a comma in builtin calls
6657 _ = try appendToken(c, .Comma, ",");
6658
6659 // last token of `node`4810 // last token of `node`
6660 const prev_id = m.list[m.i - 1].id;4811 const prev_id = m.list[m.i - 1].id;
66614812
6662 if (prev_id == .Keyword_void) {4813 if (prev_id == .Keyword_void) {
6663 const ptr = try transCreateNodePtrType(c, false, false, .Asterisk);4814 const ptr = try Tag.single_pointer.create(c.arena, .{
6664 ptr.rhs = node;4815 .is_const = false,
6665 const optional_node = try transCreateNodeSimplePrefixOp(c, .OptionalType, .QuestionMark, "?");4816 .is_volatile = false,
6666 optional_node.rhs = &ptr.base;4817 .elem_type = node,
6667 return &optional_node.base;4818 });
4819 return Tag.optional_type.create(c.arena, ptr);
6668 } else {4820 } else {
6669 const ptr = try transCreateNodePtrType(c, false, false, Token.Id.Identifier);4821 return Tag.c_pointer.create(c.arena, .{
6670 ptr.rhs = node;4822 .is_const = false,
6671 return &ptr.base;4823 .is_volatile = false,
4824 .elem_type = node,
4825 });
6672 }4826 }
6673 } else {4827 } else {
6674 // expr * expr4828 // expr * expr
6675 op_token = try appendToken(c, .Asterisk, "*");4829 const lhs = try macroBoolToInt(c, node);
6676 op_id = .BitShiftLeft;4830 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4831 node = try Tag.mul.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6677 }4832 }
6678 },4833 },
6679 .Slash => {4834 .Slash => {
6680 op_id = .Div;4835 const lhs = try macroBoolToInt(c, node);
6681 op_token = try appendToken(c, .Slash, "/");4836 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4837 node = try Tag.div.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6682 },4838 },
6683 .Percent => {4839 .Percent => {
6684 op_id = .Mod;4840 const lhs = try macroBoolToInt(c, node);
6685 op_token = try appendToken(c, .Percent, "%");4841 const rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
4842 node = try Tag.mod.create(c.arena, .{ .lhs = lhs, .rhs = rhs });
6686 },4843 },
6687 else => {4844 else => {
6688 m.i -= 1;4845 m.i -= 1;
6689 return node;4846 return node;
6690 },4847 },
6691 }4848 }
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;
6702 }4849 }
6703}4850}
67044851
6705fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4852fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6706 var node = try parseCPrimaryExpr(c, m, scope);4853 var node = try parseCPrimaryExpr(c, m, scope);
6707 while (true) {4854 while (true) {
6708 switch (m.next().?) {4855 switch (m.next().?) {
...@@ -6712,38 +4859,33 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N...@@ -6712,38 +4859,33 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
6712 return error.ParseError;4859 return error.ParseError;
6713 }4860 }
67144861
6715 node = try transCreateNodeFieldAccess(c, node, m.slice());4862 node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
6716 continue;
6717 },4863 },
6718 .Arrow => {4864 .Arrow => {
6719 if (m.next().? != .Identifier) {4865 if (m.next().? != .Identifier) {
6720 try m.fail(c, "unable to translate C expr: expected identifier", .{});4866 try m.fail(c, "unable to translate C expr: expected identifier", .{});
6721 return error.ParseError;4867 return error.ParseError;
6722 }4868 }
6723 const deref = try transCreateNodePtrDeref(c, node);4869
6724 node = try transCreateNodeFieldAccess(c, deref, m.slice());4870 const deref = try Tag.deref.create(c.arena, node);
6725 continue;4871 node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
6726 },4872 },
6727 .LBracket => {4873 .LBracket => {
6728 const arr_node = try transCreateNodeArrayAccess(c, node);4874 const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
6729 arr_node.index_expr = try parseCExpr(c, m, scope);4875 node = try Tag.array_access.create(c.arena, .{ .lhs = node, .rhs = index });
6730 arr_node.rtoken = try appendToken(c, .RBracket, "]");
6731 node = &arr_node.base;
6732 if (m.next().? != .RBracket) {4876 if (m.next().? != .RBracket) {
6733 try m.fail(c, "unable to translate C expr: expected ']'", .{});4877 try m.fail(c, "unable to translate C expr: expected ']'", .{});
6734 return error.ParseError;4878 return error.ParseError;
6735 }4879 }
6736 continue;
6737 },4880 },
6738 .LParen => {4881 .LParen => {
6739 _ = try appendToken(c, .LParen, "(");4882 var args = std.ArrayList(Node).init(c.gpa);
6740 var call_params = std.ArrayList(*ast.Node).init(c.gpa);4883 defer args.deinit();
6741 defer call_params.deinit();
6742 while (true) {4884 while (true) {
6743 const arg = try parseCCondExpr(c, m, scope);4885 const arg = try parseCCondExpr(c, m, scope);
6744 try call_params.append(arg);4886 try args.append(arg);
6745 switch (m.next().?) {4887 switch (m.next().?) {
6746 .Comma => _ = try appendToken(c, .Comma, ","),4888 .Comma => {},
6747 .RParen => break,4889 .RParen => break,
6748 else => {4890 else => {
6749 try m.fail(c, "unable to translate C expr: expected ',' or ')'", .{});4891 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...@@ -6751,32 +4893,17 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
6751 },4893 },
6752 }4894 }
6753 }4895 }
6754 const call_node = try ast.Node.Call.alloc(c.arena, call_params.items.len);4896 node = try Tag.call.create(c.arena, .{ .lhs = node, .args = try c.arena.dupe(Node, args.items) });
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;
6764 },4897 },
6765 .LBrace => {4898 .LBrace => {
6766 // must come immediately after `node`4899 var init_vals = std.ArrayList(Node).init(c.gpa);
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);
6773 defer init_vals.deinit();4900 defer init_vals.deinit();
67744901
6775 while (true) {4902 while (true) {
6776 const val = try parseCCondExpr(c, m, scope);4903 const val = try parseCCondExpr(c, m, scope);
6777 try init_vals.append(val);4904 try init_vals.append(val);
6778 switch (m.next().?) {4905 switch (m.next().?) {
6779 .Comma => _ = try appendToken(c, .Comma, ","),4906 .Comma => {},
6780 .RBrace => break,4907 .RBrace => break,
6781 else => {4908 else => {
6782 try m.fail(c, "unable to translate C expr: expected ',' or '}}'", .{});4909 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...@@ -6784,29 +4911,8 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
6784 },4911 },
6785 }4912 }
6786 }4913 }
6787 const tuple_node = try ast.Node.StructInitializerDot.alloc(c.arena, init_vals.items.len);4914 const tuple_node = try Tag.tuple.create(c.arena, try c.arena.dupe(Node, init_vals.items));
6788 tuple_node.* = .{4915 node = try Tag.std_mem_zeroinit.create(c.arena, .{ .lhs = node, .rhs = 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;
6810 },4916 },
6811 .PlusPlus, .MinusMinus => {4917 .PlusPlus, .MinusMinus => {
6812 try m.fail(c, "TODO postfix inc/dec expr", .{});4918 try m.fail(c, "TODO postfix inc/dec expr", .{});
...@@ -6820,35 +4926,31 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N...@@ -6820,35 +4926,31 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
6820 }4926 }
6821}4927}
68224928
6823fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {4929fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
6824 switch (m.next().?) {4930 switch (m.next().?) {
6825 .Bang => {4931 .Bang => {
6826 const node = try transCreateNodeSimplePrefixOp(c, .BoolNot, .Bang, "!");4932 const operand = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));
6827 node.rhs = try macroIntToBool(c, try parseCUnaryExpr(c, m, scope));4933 return Tag.not.create(c.arena, operand);
6828 return &node.base;
6829 },4934 },
6830 .Minus => {4935 .Minus => {
6831 const node = try transCreateNodeSimplePrefixOp(c, .Negation, .Minus, "-");4936 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
6832 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));4937 return Tag.negate.create(c.arena, operand);
6833 return &node.base;
6834 },4938 },
6835 .Plus => return try parseCUnaryExpr(c, m, scope),4939 .Plus => return try parseCUnaryExpr(c, m, scope),
6836 .Tilde => {4940 .Tilde => {
6837 const node = try transCreateNodeSimplePrefixOp(c, .BitNot, .Tilde, "~");4941 const operand = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));
6838 node.rhs = try macroBoolToInt(c, try parseCUnaryExpr(c, m, scope));4942 return Tag.bit_not.create(c.arena, operand);
6839 return &node.base;
6840 },4943 },
6841 .Asterisk => {4944 .Asterisk => {
6842 const node = try macroGroup(c, try parseCUnaryExpr(c, m, scope));4945 const operand = try parseCUnaryExpr(c, m, scope);
6843 return try transCreateNodePtrDeref(c, node);4946 return Tag.deref.create(c.arena, operand);
6844 },4947 },
6845 .Ampersand => {4948 .Ampersand => {
6846 const node = try transCreateNodeSimplePrefixOp(c, .AddressOf, .Ampersand, "&");4949 const operand = try parseCUnaryExpr(c, m, scope);
6847 node.rhs = try macroGroup(c, try parseCUnaryExpr(c, m, scope));4950 return Tag.address_of.create(c.arena, operand);
6848 return &node.base;
6849 },4951 },
6850 .Keyword_sizeof => {4952 .Keyword_sizeof => {
6851 const inner = if (m.peek().? == .LParen) blk: {4953 const operand = if (m.peek().? == .LParen) blk: {
6852 _ = m.next();4954 _ = m.next();
6853 // C grammar says this should be 'type-name' but we have to4955 // C grammar says this should be 'type-name' but we have to
6854 // use parseCMulExpr to correctly handle pointer types.4956 // use parseCMulExpr to correctly handle pointer types.
...@@ -6860,18 +4962,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod...@@ -6860,18 +4962,7 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
6860 break :blk inner;4962 break :blk inner;
6861 } else try parseCUnaryExpr(c, m, scope);4963 } else try parseCUnaryExpr(c, m, scope);
68624964
6863 //(@import("std").meta.sizeof(dest, x))4965 return Tag.std_meta_sizeof.create(c.arena, operand);
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;
6875 },4966 },
6876 .Keyword_alignof => {4967 .Keyword_alignof => {
6877 // TODO this won't work if using <stdalign.h>'s4968 // 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...@@ -6882,16 +4973,13 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
6882 }4973 }
6883 // C grammar says this should be 'type-name' but we have to4974 // C grammar says this should be 'type-name' but we have to
6884 // use parseCMulExpr to correctly handle pointer types.4975 // use parseCMulExpr to correctly handle pointer types.
6885 const inner = try parseCMulExpr(c, m, scope);4976 const operand = try parseCMulExpr(c, m, scope);
6886 if (m.next().? != .RParen) {4977 if (m.next().? != .RParen) {
6887 try m.fail(c, "unable to translate C expr: expected ')'", .{});4978 try m.fail(c, "unable to translate C expr: expected ')'", .{});
6888 return error.ParseError;4979 return error.ParseError;
6889 }4980 }
68904981
6891 const builtin_call = try c.createBuiltinCall("@alignOf", 1);4982 return Tag.alignof.create(c.arena, operand);
6892 builtin_call.params()[0] = inner;
6893 builtin_call.rparen_token = try appendToken(c, .RParen, ")");
6894 return &builtin_call.base;
6895 },4983 },
6896 .PlusPlus, .MinusMinus => {4984 .PlusPlus, .MinusMinus => {
6897 try m.fail(c, "TODO unary inc/dec expr", .{});4985 try m.fail(c, "TODO unary inc/dec expr", .{});
...@@ -6904,51 +4992,40 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod...@@ -6904,51 +4992,40 @@ fn parseCUnaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Nod
6904 }4992 }
6905}4993}
69064994
6907fn tokenSlice(c: *Context, token: ast.TokenIndex) []u8 {4995fn getContainer(c: *Context, node: Node) ?Node {
6908 const tok = c.token_locs.items[token];4996 switch (node.tag()) {
6909 const slice = c.source_buffer.items[tok.start..tok.end];4997 .@"union",
6910 return if (mem.startsWith(u8, slice, "@\""))4998 .@"struct",
6911 slice[2 .. slice.len - 1]4999 .@"enum",
6912 else5000 .address_of,
6913 slice;5001 .bit_not,
6914}5002 .not,
69155003 .optional_type,
6916fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {5004 .negate,
6917 switch (node.tag) {5005 .negate_wrap,
6918 .ContainerDecl,5006 .array_type,
6919 .AddressOf,5007 .c_pointer,
6920 .Await,5008 .single_pointer,
6921 .BitNot,
6922 .BoolNot,
6923 .OptionalType,
6924 .Negation,
6925 .NegationWrap,
6926 .Resume,
6927 .Try,
6928 .ArrayType,
6929 .ArrayTypeSentinel,
6930 .PtrType,
6931 .SliceType,
6932 => return node,5009 => return node,
69335010
6934 .Identifier => {5011 .identifier => {
6935 const ident = node.castTag(.Identifier).?;5012 const ident = node.castTag(.identifier).?;
6936 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {5013 if (c.global_scope.sym_table.get(ident.data)) |value| {
6937 if (value.cast(ast.Node.VarDecl)) |var_decl|5014 if (value.castTag(.var_decl)) |var_decl|
6938 return getContainer(c, var_decl.getInitNode().?);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);
6939 }5018 }
6940 },5019 },
69415020
6942 .Period => {5021 .field_access => {
6943 const infix = node.castTag(.Period).?;5022 const field_access = node.castTag(.field_access).?;
69445023
6945 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {5024 if (getContainerTypeOf(c, field_access.data.lhs)) |ty_node| {
6946 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {5025 if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
6947 for (container.fieldsAndDecls()) |field_ref| {5026 for (container.data.fields) |field| {
6948 const field = field_ref.cast(ast.Node.ContainerField).?;5027 if (mem.eql(u8, field.name, field_access.data.field_name)) {
6949 const ident = infix.rhs.castTag(.Identifier).?;5028 return getContainer(c, field.type);
6950 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6951 return getContainer(c, field.type_expr.?);
6952 }5029 }
6953 }5030 }
6954 }5031 }
...@@ -6960,22 +5037,19 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {...@@ -6960,22 +5037,19 @@ fn getContainer(c: *Context, node: *ast.Node) ?*ast.Node {
6960 return null;5037 return null;
6961}5038}
69625039
6963fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {5040fn getContainerTypeOf(c: *Context, ref: Node) ?Node {
6964 if (ref.castTag(.Identifier)) |ident| {5041 if (ref.castTag(.identifier)) |ident| {
6965 if (c.global_scope.sym_table.get(tokenSlice(c, ident.token))) |value| {5042 if (c.global_scope.sym_table.get(ident.data)) |value| {
6966 if (value.cast(ast.Node.VarDecl)) |var_decl| {5043 if (value.castTag(.var_decl)) |var_decl| {
6967 if (var_decl.getTypeNode()) |ty|5044 return getContainer(c, var_decl.data.type);
6968 return getContainer(c, ty);
6969 }5045 }
6970 }5046 }
6971 } else if (ref.castTag(.Period)) |infix| {5047 } else if (ref.castTag(.field_access)) |field_access| {
6972 if (getContainerTypeOf(c, infix.lhs)) |ty_node| {5048 if (getContainerTypeOf(c, field_access.data.lhs)) |ty_node| {
6973 if (ty_node.cast(ast.Node.ContainerDecl)) |container| {5049 if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
6974 for (container.fieldsAndDecls()) |field_ref| {5050 for (container.data.fields) |field| {
6975 const field = field_ref.cast(ast.Node.ContainerField).?;5051 if (mem.eql(u8, field.name, field_access.data.field_name)) {
6976 const ident = infix.rhs.castTag(.Identifier).?;5052 return getContainer(c, field.type);
6977 if (mem.eql(u8, tokenSlice(c, field.name_token), tokenSlice(c, ident.token))) {
6978 return getContainer(c, field.type_expr.?);
6979 }5053 }
6980 }5054 }
6981 } else5055 } else
...@@ -6985,11 +5059,16 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {...@@ -6985,11 +5059,16 @@ fn getContainerTypeOf(c: *Context, ref: *ast.Node) ?*ast.Node {
6985 return null;5059 return null;
6986}5060}
69875061
6988fn getFnProto(c: *Context, ref: *ast.Node) ?*ast.Node.FnProto {5062fn getFnProto(c: *Context, ref: Node) ?*ast.Payload.Func {
6989 const init = if (ref.cast(ast.Node.VarDecl)) |v| v.getInitNode().? else return null;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;
6990 if (getContainerTypeOf(c, init)) |ty_node| {5069 if (getContainerTypeOf(c, init)) |ty_node| {
6991 if (ty_node.castTag(.OptionalType)) |prefix| {5070 if (ty_node.castTag(.optional_type)) |prefix| {
6992 if (prefix.rhs.cast(ast.Node.FnProto)) |fn_proto| {5071 if (prefix.data.castTag(.func)) |fn_proto| {
6993 return fn_proto;5072 return fn_proto;
6994 }5073 }
6995 }5074 }
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 {...@@ -28,6 +28,8 @@ pub const Type = extern union {
28 .i32,28 .i32,
29 .u64,29 .u64,
30 .i64,30 .i64,
31 .u128,
32 .i128,
31 .usize,33 .usize,
32 .isize,34 .isize,
33 .c_short,35 .c_short,
...@@ -357,6 +359,8 @@ pub const Type = extern union {...@@ -357,6 +359,8 @@ pub const Type = extern union {
357 .i32,359 .i32,
358 .u64,360 .u64,
359 .i64,361 .i64,
362 .u128,
363 .i128,
360 .usize,364 .usize,
361 .isize,365 .isize,
362 .c_short,366 .c_short,
...@@ -506,6 +510,8 @@ pub const Type = extern union {...@@ -506,6 +510,8 @@ pub const Type = extern union {
506 .i32,510 .i32,
507 .u64,511 .u64,
508 .i64,512 .i64,
513 .u128,
514 .i128,
509 .usize,515 .usize,
510 .isize,516 .isize,
511 .c_short,517 .c_short,
...@@ -772,6 +778,8 @@ pub const Type = extern union {...@@ -772,6 +778,8 @@ pub const Type = extern union {
772 .i32,778 .i32,
773 .u64,779 .u64,
774 .i64,780 .i64,
781 .u128,
782 .i128,
775 .usize,783 .usize,
776 .isize,784 .isize,
777 .c_short,785 .c_short,
...@@ -868,6 +876,7 @@ pub const Type = extern union {...@@ -868,6 +876,7 @@ pub const Type = extern union {
868 .i16, .u16 => return 2,876 .i16, .u16 => return 2,
869 .i32, .u32 => return 4,877 .i32, .u32 => return 4,
870 .i64, .u64 => return 8,878 .i64, .u64 => return 8,
879 .u128, .i128 => return 16,
871880
872 .isize,881 .isize,
873 .usize,882 .usize,
...@@ -1010,6 +1019,7 @@ pub const Type = extern union {...@@ -1010,6 +1019,7 @@ pub const Type = extern union {
1010 .i16, .u16 => return 2,1019 .i16, .u16 => return 2,
1011 .i32, .u32 => return 4,1020 .i32, .u32 => return 4,
1012 .i64, .u64 => return 8,1021 .i64, .u64 => return 8,
1022 .u128, .i128 => return 16,
10131023
1014 .@"anyframe", .anyframe_T, .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),1024 .@"anyframe", .anyframe_T, .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
10151025
...@@ -1109,6 +1119,8 @@ pub const Type = extern union {...@@ -1109,6 +1119,8 @@ pub const Type = extern union {
1109 .i32,1119 .i32,
1110 .u64,1120 .u64,
1111 .i64,1121 .i64,
1122 .u128,
1123 .i128,
1112 .usize,1124 .usize,
1113 .isize,1125 .isize,
1114 .c_short,1126 .c_short,
...@@ -1191,6 +1203,8 @@ pub const Type = extern union {...@@ -1191,6 +1203,8 @@ pub const Type = extern union {
1191 .i32,1203 .i32,
1192 .u64,1204 .u64,
1193 .i64,1205 .i64,
1206 .u128,
1207 .i128,
1194 .usize,1208 .usize,
1195 .isize,1209 .isize,
1196 .c_short,1210 .c_short,
...@@ -1278,6 +1292,8 @@ pub const Type = extern union {...@@ -1278,6 +1292,8 @@ pub const Type = extern union {
1278 .i32,1292 .i32,
1279 .u64,1293 .u64,
1280 .i64,1294 .i64,
1295 .u128,
1296 .i128,
1281 .usize,1297 .usize,
1282 .isize,1298 .isize,
1283 .c_short,1299 .c_short,
...@@ -1359,6 +1375,8 @@ pub const Type = extern union {...@@ -1359,6 +1375,8 @@ pub const Type = extern union {
1359 .i32,1375 .i32,
1360 .u64,1376 .u64,
1361 .i64,1377 .i64,
1378 .u128,
1379 .i128,
1362 .usize,1380 .usize,
1363 .isize,1381 .isize,
1364 .c_short,1382 .c_short,
...@@ -1440,6 +1458,8 @@ pub const Type = extern union {...@@ -1440,6 +1458,8 @@ pub const Type = extern union {
1440 .i32,1458 .i32,
1441 .u64,1459 .u64,
1442 .i64,1460 .i64,
1461 .u128,
1462 .i128,
1443 .usize,1463 .usize,
1444 .isize,1464 .isize,
1445 .c_short,1465 .c_short,
...@@ -1522,6 +1542,8 @@ pub const Type = extern union {...@@ -1522,6 +1542,8 @@ pub const Type = extern union {
1522 .i32,1542 .i32,
1523 .u64,1543 .u64,
1524 .i64,1544 .i64,
1545 .u128,
1546 .i128,
1525 .usize,1547 .usize,
1526 .isize,1548 .isize,
1527 .c_short,1549 .c_short,
...@@ -1660,6 +1682,8 @@ pub const Type = extern union {...@@ -1660,6 +1682,8 @@ pub const Type = extern union {
1660 .i32 => unreachable,1682 .i32 => unreachable,
1661 .u64 => unreachable,1683 .u64 => unreachable,
1662 .i64 => unreachable,1684 .i64 => unreachable,
1685 .u128 => unreachable,
1686 .i128 => unreachable,
1663 .usize => unreachable,1687 .usize => unreachable,
1664 .isize => unreachable,1688 .isize => unreachable,
1665 .c_short => unreachable,1689 .c_short => unreachable,
...@@ -1776,6 +1800,8 @@ pub const Type = extern union {...@@ -1776,6 +1800,8 @@ pub const Type = extern union {
1776 .i32,1800 .i32,
1777 .u64,1801 .u64,
1778 .i64,1802 .i64,
1803 .u128,
1804 .i128,
1779 .usize,1805 .usize,
1780 .isize,1806 .isize,
1781 .c_short,1807 .c_short,
...@@ -1856,6 +1882,8 @@ pub const Type = extern union {...@@ -1856,6 +1882,8 @@ pub const Type = extern union {
1856 .i32,1882 .i32,
1857 .u64,1883 .u64,
1858 .i64,1884 .i64,
1885 .u128,
1886 .i128,
1859 .usize,1887 .usize,
1860 .isize,1888 .isize,
1861 .c_short,1889 .c_short,
...@@ -2009,6 +2037,8 @@ pub const Type = extern union {...@@ -2009,6 +2037,8 @@ pub const Type = extern union {
2009 .i16,2037 .i16,
2010 .i32,2038 .i32,
2011 .i64,2039 .i64,
2040 .u128,
2041 .i128,
2012 => true,2042 => true,
2013 };2043 };
2014 }2044 }
...@@ -2061,6 +2091,8 @@ pub const Type = extern union {...@@ -2061,6 +2091,8 @@ pub const Type = extern union {
2061 .i16,2091 .i16,
2062 .i32,2092 .i32,
2063 .i64,2093 .i64,
2094 .u128,
2095 .i128,
2064 .optional,2096 .optional,
2065 .optional_single_mut_pointer,2097 .optional_single_mut_pointer,
2066 .optional_single_const_pointer,2098 .optional_single_const_pointer,
...@@ -2167,6 +2199,8 @@ pub const Type = extern union {...@@ -2167,6 +2199,8 @@ pub const Type = extern union {
2167 .i32 => .{ .signedness = .signed, .bits = 32 },2199 .i32 => .{ .signedness = .signed, .bits = 32 },
2168 .u64 => .{ .signedness = .unsigned, .bits = 64 },2200 .u64 => .{ .signedness = .unsigned, .bits = 64 },
2169 .i64 => .{ .signedness = .signed, .bits = 64 },2201 .i64 => .{ .signedness = .signed, .bits = 64 },
2202 .u128 => .{ .signedness = .unsigned, .bits = 128 },
2203 .i128 => .{ .signedness = .signed, .bits = 128 },
2170 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },2204 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
2171 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },2205 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
2172 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },2206 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
...@@ -2227,6 +2261,8 @@ pub const Type = extern union {...@@ -2227,6 +2261,8 @@ pub const Type = extern union {
2227 .i32,2261 .i32,
2228 .u64,2262 .u64,
2229 .i64,2263 .i64,
2264 .u128,
2265 .i128,
2230 .optional,2266 .optional,
2231 .optional_single_mut_pointer,2267 .optional_single_mut_pointer,
2232 .optional_single_const_pointer,2268 .optional_single_const_pointer,
...@@ -2333,6 +2369,8 @@ pub const Type = extern union {...@@ -2333,6 +2369,8 @@ pub const Type = extern union {
2333 .i32,2369 .i32,
2334 .u64,2370 .u64,
2335 .i64,2371 .i64,
2372 .u128,
2373 .i128,
2336 .usize,2374 .usize,
2337 .isize,2375 .isize,
2338 .c_short,2376 .c_short,
...@@ -2417,6 +2455,8 @@ pub const Type = extern union {...@@ -2417,6 +2455,8 @@ pub const Type = extern union {
2417 .i32,2455 .i32,
2418 .u64,2456 .u64,
2419 .i64,2457 .i64,
2458 .u128,
2459 .i128,
2420 .usize,2460 .usize,
2421 .isize,2461 .isize,
2422 .c_short,2462 .c_short,
...@@ -2500,6 +2540,8 @@ pub const Type = extern union {...@@ -2500,6 +2540,8 @@ pub const Type = extern union {
2500 .i32,2540 .i32,
2501 .u64,2541 .u64,
2502 .i64,2542 .i64,
2543 .u128,
2544 .i128,
2503 .usize,2545 .usize,
2504 .isize,2546 .isize,
2505 .c_short,2547 .c_short,
...@@ -2583,6 +2625,8 @@ pub const Type = extern union {...@@ -2583,6 +2625,8 @@ pub const Type = extern union {
2583 .i32,2625 .i32,
2584 .u64,2626 .u64,
2585 .i64,2627 .i64,
2628 .u128,
2629 .i128,
2586 .usize,2630 .usize,
2587 .isize,2631 .isize,
2588 .c_short,2632 .c_short,
...@@ -2663,6 +2707,8 @@ pub const Type = extern union {...@@ -2663,6 +2707,8 @@ pub const Type = extern union {
2663 .i32,2707 .i32,
2664 .u64,2708 .u64,
2665 .i64,2709 .i64,
2710 .u128,
2711 .i128,
2666 .usize,2712 .usize,
2667 .isize,2713 .isize,
2668 .c_short,2714 .c_short,
...@@ -2743,6 +2789,8 @@ pub const Type = extern union {...@@ -2743,6 +2789,8 @@ pub const Type = extern union {
2743 .i32,2789 .i32,
2744 .u64,2790 .u64,
2745 .i64,2791 .i64,
2792 .u128,
2793 .i128,
2746 .usize,2794 .usize,
2747 .isize,2795 .isize,
2748 .c_short,2796 .c_short,
...@@ -2793,6 +2841,8 @@ pub const Type = extern union {...@@ -2793,6 +2841,8 @@ pub const Type = extern union {
2793 .i32,2841 .i32,
2794 .u64,2842 .u64,
2795 .i64,2843 .i64,
2844 .u128,
2845 .i128,
2796 .usize,2846 .usize,
2797 .isize,2847 .isize,
2798 .c_short,2848 .c_short,
...@@ -2874,6 +2924,8 @@ pub const Type = extern union {...@@ -2874,6 +2924,8 @@ pub const Type = extern union {
2874 .i32,2924 .i32,
2875 .u64,2925 .u64,
2876 .i64,2926 .i64,
2927 .u128,
2928 .i128,
2877 .usize,2929 .usize,
2878 .isize,2930 .isize,
2879 .c_short,2931 .c_short,
...@@ -2971,6 +3023,8 @@ pub const Type = extern union {...@@ -2971,6 +3023,8 @@ pub const Type = extern union {
2971 .i32,3023 .i32,
2972 .u64,3024 .u64,
2973 .i64,3025 .i64,
3026 .u128,
3027 .i128,
2974 .usize,3028 .usize,
2975 .isize,3029 .isize,
2976 .c_short,3030 .c_short,
...@@ -3060,6 +3114,8 @@ pub const Type = extern union {...@@ -3060,6 +3114,8 @@ pub const Type = extern union {
3060 .i32,3114 .i32,
3061 .u64,3115 .u64,
3062 .i64,3116 .i64,
3117 .u128,
3118 .i128,
3063 .usize,3119 .usize,
3064 .isize,3120 .isize,
3065 .c_short,3121 .c_short,
...@@ -3193,6 +3249,8 @@ pub const Type = extern union {...@@ -3193,6 +3249,8 @@ pub const Type = extern union {
3193 i32,3249 i32,
3194 u64,3250 u64,
3195 i64,3251 i64,
3252 u128,
3253 i128,
3196 usize,3254 usize,
3197 isize,3255 isize,
3198 c_short,3256 c_short,
...@@ -3277,6 +3335,8 @@ pub const Type = extern union {...@@ -3277,6 +3335,8 @@ pub const Type = extern union {
3277 .i32,3335 .i32,
3278 .u64,3336 .u64,
3279 .i64,3337 .i64,
3338 .u128,
3339 .i128,
3280 .usize,3340 .usize,
3281 .isize,3341 .isize,
3282 .c_short,3342 .c_short,
...@@ -3352,6 +3412,11 @@ pub const Type = extern union {...@@ -3352,6 +3412,11 @@ pub const Type = extern union {
3352 };3412 };
3353 }3413 }
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
3355 pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Type {3420 pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Type {
3356 const ptr = try ally.create(t.Type());3421 const ptr = try ally.create(t.Type());
3357 ptr.* = .{3422 ptr.* = .{
src/zig_clang.cpp+5
...@@ -2244,6 +2244,11 @@ unsigned ZigClangAPSInt_getNumWords(const ZigClangAPSInt *self) {...@@ -2244,6 +2244,11 @@ unsigned ZigClangAPSInt_getNumWords(const ZigClangAPSInt *self) {
2244 return casted->getNumWords();2244 return casted->getNumWords();
2245}2245}
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
2247uint64_t ZigClangAPInt_getLimitedValue(const ZigClangAPInt *self, uint64_t limit) {2252uint64_t ZigClangAPInt_getLimitedValue(const ZigClangAPInt *self, uint64_t limit) {
2248 auto casted = reinterpret_cast<const llvm::APInt *>(self);2253 auto casted = reinterpret_cast<const llvm::APInt *>(self);
2249 return casted->getLimitedValue(limit);2254 return casted->getLimitedValue(limit);
src/zig_clang.h+1
...@@ -1097,6 +1097,7 @@ ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPSInt_negate(const struct Zig...@@ -1097,6 +1097,7 @@ ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangAPSInt_negate(const struct Zig
1097ZIG_EXTERN_C void ZigClangAPSInt_free(const struct ZigClangAPSInt *self);1097ZIG_EXTERN_C void ZigClangAPSInt_free(const struct ZigClangAPSInt *self);
1098ZIG_EXTERN_C const uint64_t *ZigClangAPSInt_getRawData(const struct ZigClangAPSInt *self);1098ZIG_EXTERN_C const uint64_t *ZigClangAPSInt_getRawData(const struct ZigClangAPSInt *self);
1099ZIG_EXTERN_C unsigned ZigClangAPSInt_getNumWords(const struct ZigClangAPSInt *self);1099ZIG_EXTERN_C unsigned ZigClangAPSInt_getNumWords(const struct ZigClangAPSInt *self);
1100ZIG_EXTERN_C bool ZigClangAPSInt_lessThanEqual(const struct ZigClangAPSInt *self, uint64_t rhs);
11001101
1101ZIG_EXTERN_C uint64_t ZigClangAPInt_getLimitedValue(const struct ZigClangAPInt *self, uint64_t limit);1102ZIG_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");...@@ -3,6 +3,14 @@ const tests = @import("tests.zig");
3const nl = std.cstr.line_sep;3const nl = std.cstr.line_sep;
44
5pub fn addCases(cases: *tests.RunTranslatedCContext) void {5pub 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
6 cases.add("parenthesized string literal",14 cases.add("parenthesized string literal",
7 \\void foo(const char *s) {}15 \\void foo(const char *s) {}
8 \\int main(void) {16 \\int main(void) {
...@@ -922,4 +930,13 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -922,4 +930,13 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
922 \\ return 0;930 \\ return 0;
923 \\}931 \\}
924 , "");932 , "");
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 , "");
925}942}
test/translate_c.zig+483-291
...@@ -3,12 +3,206 @@ const std = @import("std");...@@ -3,12 +3,206 @@ const std = @import("std");
3const CrossTarget = std.zig.CrossTarget;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub 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",
7 \\int foo(int bar, ...) {201 \\int foo(int bar, ...) {
8 \\ return 1;202 \\ return 1;
9 \\}203 \\}
10 , &[_][]const u8{204 , &[_][]const u8{
11 \\warning: TODO unable to translate variadic function, demoted to declaration205 \\warning: TODO unable to translate variadic function, demoted to extern
12 \\pub extern fn foo(bar: c_int, ...) c_int;206 \\pub extern fn foo(bar: c_int, ...) c_int;
13 });207 });
14208
...@@ -21,11 +215,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -21,11 +215,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
21 \\ Foo *bar;215 \\ Foo *bar;
22 \\} Bar;216 \\} Bar;
23 , &[_][]const u8{217 , &[_][]const u8{
24 \\const struct_unnamed_1 = //218 \\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo
25 ,219 \\const struct_unnamed_1 = opaque {};
26 \\warning: unsupported type: 'Atomic'
27 \\ opaque {}; //
28 ,
29 \\pub const Foo = struct_unnamed_1;220 \\pub const Foo = struct_unnamed_1;
30 \\const struct_unnamed_2 = extern struct {221 \\const struct_unnamed_2 = extern struct {
31 \\ bar: ?*Foo,222 \\ bar: ?*Foo,
...@@ -43,8 +234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -43,8 +234,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
43 ,234 ,
44 \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);235 \\pub const VALUE = ((((1 + (2 * 3)) + (4 * 5)) + 6) << 7) | @boolToInt(8 == 9);
45 ,236 ,
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)) {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)) {
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);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);
48 \\}239 \\}
49 });240 });
50241
...@@ -57,7 +248,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -57,7 +248,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
57 \\pub export var bar: f32 = @import("std").mem.zeroes(f32);248 \\pub export var bar: f32 = @import("std").mem.zeroes(f32);
58 \\threadlocal var bar_1: c_int = 2;249 \\threadlocal var bar_1: c_int = 2;
59 \\pub export fn foo() c_int {250 \\pub export fn foo() c_int {
60 \\ _ = bar_1;
61 \\ return 0;251 \\ return 0;
62 \\}252 \\}
63 });253 });
...@@ -107,7 +297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -107,7 +297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
107 \\ int i1;297 \\ int i1;
108 \\} boom_t;298 \\} boom_t;
109 \\#define FOO ((boom_t){1})299 \\#define FOO ((boom_t){1})
110 , &[_][]const u8{ // TODO properly translate this300 , &[_][]const u8{
111 \\pub const struct_Color = extern struct {301 \\pub const struct_Color = extern struct {
112 \\ r: u8,302 \\ r: u8,
113 \\ g: u8,303 \\ g: u8,
...@@ -127,7 +317,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -127,7 +317,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
127 \\};317 \\};
128 \\pub const boom_t = struct_boom_t;318 \\pub const boom_t = struct_boom_t;
129 ,319 ,
130 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{ 1 });320 \\pub const FOO = @import("std").mem.zeroInit(boom_t, .{1});
131 });321 });
132322
133 cases.add("complex switch",323 cases.add("complex switch",
...@@ -142,14 +332,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -142,14 +332,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
142 \\ }332 \\ }
143 \\}333 \\}
144 , &[_][]const u8{ // TODO properly translate this334 , &[_][]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;
146 });339 });
147340
148 cases.add("correct semicolon after infixop",341 cases.add("correct semicolon after infixop",
149 \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)342 \\#define __ferror_unlocked_body(_fp) (((_fp)->_flags & _IO_ERR_SEEN) != 0)
150 , &[_][]const u8{343 , &[_][]const u8{
151 \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf(((_fp.*._flags) & _IO_ERR_SEEN) != 0) {344 \\pub fn __ferror_unlocked_body(_fp: anytype) callconv(.Inline) @TypeOf((_fp.*._flags & _IO_ERR_SEEN) != 0) {
152 \\ return ((_fp.*._flags) & _IO_ERR_SEEN) != 0;345 \\ return (_fp.*._flags & _IO_ERR_SEEN) != 0;
153 \\}346 \\}
154 });347 });
155348
...@@ -193,9 +386,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -193,9 +386,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
193 \\pub export fn foo() void {386 \\pub export fn foo() void {
194 \\ while (false) while (false) {};387 \\ while (false) while (false) {};
195 \\ while (true) while (false) {};388 \\ while (true) while (false) {};
196 \\ while (true) while (true) {389 \\ while (true) {}
197 \\ if (!false) break;
198 \\ };
199 \\}390 \\}
200 });391 });
201392
...@@ -245,15 +436,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -245,15 +436,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
245 \\ volatile _Atomic int abufused[12];436 \\ volatile _Atomic int abufused[12];
246 \\};437 \\};
247 , &[_][]const u8{438 , &[_][]const u8{
248 \\pub const struct_arcan_shmif_page = //439 \\source.h:4:8: warning: struct demoted to opaque type - unable to translate type of field abufused
249 ,440 \\pub const struct_arcan_shmif_page = opaque {};
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`
255 \\pub const struct_arcan_shmif_cont = extern struct {441 \\pub const struct_arcan_shmif_cont = extern struct {
256 \\ addr: [*c]struct_arcan_shmif_page,442 \\ addr: ?*struct_arcan_shmif_page,
257 \\};443 \\};
258 });444 });
259445
...@@ -293,22 +479,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -293,22 +479,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
293 , &[_][]const u8{479 , &[_][]const u8{
294 \\pub const uuid_t = [16]u8;480 \\pub const uuid_t = [16]u8;
295 \\pub const UUID_NULL: uuid_t = [16]u8{481 \\pub const UUID_NULL: uuid_t = [16]u8{
296 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),482 \\ 0,
297 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),483 \\ 0,
298 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),484 \\ 0,
299 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),485 \\ 0,
300 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),486 \\ 0,
301 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),487 \\ 0,
302 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),488 \\ 0,
303 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),489 \\ 0,
304 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),490 \\ 0,
305 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),491 \\ 0,
306 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),492 \\ 0,
307 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),493 \\ 0,
308 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),494 \\ 0,
309 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),495 \\ 0,
310 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),496 \\ 0,
311 \\ @bitCast(u8, @truncate(i8, @as(c_int, 0))),497 \\ 0,
312 \\};498 \\};
313 });499 });
314500
...@@ -362,10 +548,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -362,10 +548,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
362 \\};548 \\};
363 \\pub export var ub: union_unnamed_1 = union_unnamed_1{549 \\pub export var ub: union_unnamed_1 = union_unnamed_1{
364 \\ .c = [4]u8{550 \\ .c = [4]u8{
365 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))),551 \\ 'a',
366 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))),552 \\ 'b',
367 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'b'))),553 \\ 'b',
368 \\ @bitCast(u8, @truncate(i8, @as(c_int, 'a'))),554 \\ 'a',
369 \\ },555 \\ },
370 \\};556 \\};
371 });557 });
...@@ -492,7 +678,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -492,7 +678,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
492 , &[_][]const u8{678 , &[_][]const u8{
493 \\pub export fn foo() void {679 \\pub export fn foo() void {
494 \\ var a: c_int = undefined;680 \\ var a: c_int = undefined;
495 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 123)));681 \\ var b: u8 = 123;
496 \\ const c: c_int = undefined;682 \\ const c: c_int = undefined;
497 \\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440));683 \\ const d: c_uint = @bitCast(c_uint, @as(c_int, 440));
498 \\ var e: c_int = 10;684 \\ var e: c_int = 10;
...@@ -514,8 +700,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -514,8 +700,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
514 \\ var a: c_int = undefined;700 \\ var a: c_int = undefined;
515 \\ _ = @as(c_int, 1);701 \\ _ = @as(c_int, 1);
516 \\ _ = "hey";702 \\ _ = "hey";
517 \\ _ = (@as(c_int, 1) + @as(c_int, 1));703 \\ _ = @as(c_int, 1) + @as(c_int, 1);
518 \\ _ = (@as(c_int, 1) - @as(c_int, 1));704 \\ _ = @as(c_int, 1) - @as(c_int, 1);
519 \\ a = 1;705 \\ a = 1;
520 \\}706 \\}
521 });707 });
...@@ -559,9 +745,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -559,9 +745,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
559 \\ '2',745 \\ '2',
560 \\ 0,746 \\ 0,
561 \\};747 \\};
562 \\pub export fn foo() void {748 \\pub export fn foo() void {}
563 \\ _ = v2;
564 \\}
565 });749 });
566750
567 cases.add("simple function definition",751 cases.add("simple function definition",
...@@ -634,9 +818,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -634,9 +818,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
634 \\ var a: c_int = undefined;818 \\ var a: c_int = undefined;
635 \\ var b: c_int = undefined;819 \\ var b: c_int = undefined;
636 \\ var c: c_int = undefined;820 \\ var c: c_int = undefined;
637 \\ c = (a + b);821 \\ c = a + b;
638 \\ c = (a - b);822 \\ c = a - b;
639 \\ c = (a * b);823 \\ c = a * b;
640 \\ c = @divTrunc(a, b);824 \\ c = @divTrunc(a, b);
641 \\ c = @rem(a, b);825 \\ c = @rem(a, b);
642 \\ return 0;826 \\ return 0;
...@@ -645,11 +829,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -645,11 +829,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
645 \\ var a: c_uint = undefined;829 \\ var a: c_uint = undefined;
646 \\ var b: c_uint = undefined;830 \\ var b: c_uint = undefined;
647 \\ var c: c_uint = undefined;831 \\ var c: c_uint = undefined;
648 \\ c = (a +% b);832 \\ c = a +% b;
649 \\ c = (a -% b);833 \\ c = a -% b;
650 \\ c = (a *% b);834 \\ c = a *% b;
651 \\ c = (a / b);835 \\ c = a / b;
652 \\ c = (a % b);836 \\ c = a % b;
653 \\ return 0;837 \\ return 0;
654 \\}838 \\}
655 });839 });
...@@ -914,13 +1098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -914,13 +1098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
914 \\ ;;;;;1098 \\ ;;;;;
915 \\}1099 \\}
916 , &[_][]const u8{1100 , &[_][]const u8{
917 \\pub export fn foo() void {1101 \\pub export fn foo() void {}
918 \\ {}
919 \\ {}
920 \\ {}
921 \\ {}
922 \\ {}
923 \\}
924 });1102 });
9251103
926 if (std.Target.current.os.tag != .windows) {1104 if (std.Target.current.os.tag != .windows) {
...@@ -1335,11 +1513,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1335,11 +1513,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1335 \\extern enum enum_ty my_enum;1513 \\extern enum enum_ty my_enum;
1336 \\enum enum_ty { FOO };1514 \\enum enum_ty { FOO };
1337 , &[_][]const u8{1515 , &[_][]const u8{
1338 \\pub const FOO = @enumToInt(enum_enum_ty.FOO);
1339 \\pub const enum_enum_ty = extern enum(c_int) {1516 \\pub const enum_enum_ty = extern enum(c_int) {
1340 \\ FOO,1517 \\ FOO,
1341 \\ _,1518 \\ _,
1342 \\};1519 \\};
1520 \\pub const FOO = @enumToInt(enum_enum_ty.FOO);
1343 \\pub extern var my_enum: enum_enum_ty;1521 \\pub extern var my_enum: enum_enum_ty;
1344 });1522 });
13451523
...@@ -1448,7 +1626,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1448,7 +1626,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1448 , &[_][]const u8{1626 , &[_][]const u8{
1449 \\pub fn foo() callconv(.C) void {1627 \\pub fn foo() callconv(.C) void {
1450 \\ var arr: [10]u8 = [1]u8{1628 \\ var arr: [10]u8 = [1]u8{
1451 \\ @bitCast(u8, @truncate(i8, @as(c_int, 1))),1629 \\ 1,
1452 \\ } ++ [1]u8{0} ** 9;1630 \\ } ++ [1]u8{0} ** 9;
1453 \\ var arr1: [10][*c]u8 = [1][*c]u8{1631 \\ var arr1: [10][*c]u8 = [1][*c]u8{
1454 \\ null,1632 \\ null,
...@@ -1481,48 +1659,48 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1481,48 +1659,48 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1481 \\ p,1659 \\ p,
1482 \\};1660 \\};
1483 , &[_][]const u8{1661 , &[_][]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);
1487 \\const enum_unnamed_1 = extern enum(c_int) {1662 \\const enum_unnamed_1 = extern enum(c_int) {
1488 \\ a,1663 \\ a,
1489 \\ b,1664 \\ b,
1490 \\ c,1665 \\ c,
1491 \\ _,1666 \\ _,
1492 \\};1667 \\};
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);
1493 \\pub const d = enum_unnamed_1;1671 \\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);
1497 \\const enum_unnamed_2 = extern enum(c_int) {1672 \\const enum_unnamed_2 = extern enum(c_int) {
1498 \\ e = 0,1673 \\ e = 0,
1499 \\ f = 4,1674 \\ f = 4,
1500 \\ g = 5,1675 \\ g = 5,
1501 \\ _,1676 \\ _,
1502 \\};1677 \\};
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);
1503 \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);1681 \\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);
1507 \\const enum_unnamed_3 = extern enum(c_int) {1682 \\const enum_unnamed_3 = extern enum(c_int) {
1508 \\ i,1683 \\ i,
1509 \\ j,1684 \\ j,
1510 \\ k,1685 \\ k,
1511 \\ _,1686 \\ _,
1512 \\};1687 \\};
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);
1513 \\pub const struct_Baz = extern struct {1691 \\pub const struct_Baz = extern struct {
1514 \\ l: enum_unnamed_3,1692 \\ l: enum_unnamed_3,
1515 \\ m: d,1693 \\ m: d,
1516 \\};1694 \\};
1517 \\pub const n = @enumToInt(enum_i.n);
1518 \\pub const o = @enumToInt(enum_i.o);
1519 \\pub const p = @enumToInt(enum_i.p);
1520 \\pub const enum_i = extern enum(c_int) {1695 \\pub const enum_i = extern enum(c_int) {
1521 \\ n,1696 \\ n,
1522 \\ o,1697 \\ o,
1523 \\ p,1698 \\ p,
1524 \\ _,1699 \\ _,
1525 \\};1700 \\};
1701 \\pub const n = @enumToInt(enum_i.n);
1702 \\pub const o = @enumToInt(enum_i.o);
1703 \\pub const p = @enumToInt(enum_i.p);
1526 ,1704 ,
1527 \\pub const Baz = struct_Baz;1705 \\pub const Baz = struct_Baz;
1528 });1706 });
...@@ -1639,7 +1817,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1639,7 +1817,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1639 cases.add("macro pointer cast",1817 cases.add("macro pointer cast",
1640 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)1818 \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
1641 , &[_][]const u8{1819 , &[_][]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);
1643 });1821 });
16441822
1645 cases.add("basic macro function",1823 cases.add("basic macro function",
...@@ -1701,13 +1879,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1701,13 +1879,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1701 \\ unsigned d = 440;1879 \\ unsigned d = 440;
1702 \\}1880 \\}
1703 , &[_][]const u8{1881 , &[_][]const u8{
1704 \\pub var a: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));1882 \\pub var a: c_long = 2;
1705 \\pub var b: c_long = @bitCast(c_long, @as(c_long, @as(c_int, 2)));1883 \\pub var b: c_long = 2;
1706 \\pub var c: c_int = 4;1884 \\pub var c: c_int = 4;
1707 \\pub export fn foo(arg_c_1: u8) void {1885 \\pub export fn foo(arg_c_1: u8) void {
1708 \\ var c_1 = arg_c_1;1886 \\ var c_1 = arg_c_1;
1709 \\ var a_2: c_int = undefined;1887 \\ 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;
1711 \\ b_3 = @bitCast(u8, @truncate(i8, a_2));1889 \\ b_3 = @bitCast(u8, @truncate(i8, a_2));
1712 \\ {1890 \\ {
1713 \\ var d: c_int = 5;1891 \\ var d: c_int = 5;
...@@ -1723,17 +1901,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1723,17 +1901,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1723 \\}1901 \\}
1724 , &[_][]const u8{1902 , &[_][]const u8{
1725 \\pub export fn foo() c_int {1903 \\pub export fn foo() c_int {
1726 \\ _ = (blk: {1904 \\ _ = blk: {
1727 \\ _ = @as(c_int, 2);1905 \\ _ = @as(c_int, 2);
1728 \\ break :blk @as(c_int, 4);1906 \\ break :blk @as(c_int, 4);
1729 \\ });1907 \\ };
1730 \\ return (blk: {1908 \\ return blk: {
1731 \\ _ = (blk_1: {1909 \\ _ = blk_1: {
1732 \\ _ = @as(c_int, 2);1910 \\ _ = @as(c_int, 2);
1733 \\ break :blk_1 @as(c_int, 4);1911 \\ break :blk_1 @as(c_int, 4);
1734 \\ });1912 \\ };
1735 \\ break :blk @as(c_int, 6);1913 \\ break :blk @as(c_int, 6);
1736 \\ });1914 \\ };
1737 \\}1915 \\}
1738 });1916 });
17391917
...@@ -1780,20 +1958,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1780,20 +1958,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1780 \\ while (true) {1958 \\ while (true) {
1781 \\ var a_1: c_int = 4;1959 \\ var a_1: c_int = 4;
1782 \\ a_1 = 9;1960 \\ a_1 = 9;
1783 \\ return (blk: {1961 \\ return blk: {
1784 \\ _ = @as(c_int, 6);1962 \\ _ = @as(c_int, 6);
1785 \\ break :blk a_1;1963 \\ break :blk a_1;
1786 \\ });1964 \\ };
1787 \\ }1965 \\ }
1788 \\ while (true) {1966 \\ while (true) {
1789 \\ var a_1: c_int = 2;1967 \\ var a_1: c_int = 2;
1790 \\ a_1 = 12;1968 \\ a_1 = 12;
1791 \\ if (!true) break;
1792 \\ }
1793 \\ while (true) {
1794 \\ a = 7;
1795 \\ if (!true) break;
1796 \\ }1969 \\ }
1970 \\ while (true) a = 7;
1797 \\ return 0;1971 \\ return 0;
1798 \\}1972 \\}
1799 });1973 });
...@@ -1813,16 +1987,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1813,16 +1987,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1813 \\ var b: c_int = 4;1987 \\ var b: c_int = 4;
1814 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {1988 \\ while ((i + @as(c_int, 2)) != 0) : (i = 2) {
1815 \\ var a: c_int = 2;1989 \\ var a: c_int = 2;
1816 \\ _ = (blk: {1990 \\ _ = blk: {
1817 \\ _ = (blk_1: {1991 \\ _ = blk_1: {
1818 \\ a = 6;1992 \\ a = 6;
1819 \\ break :blk_1 @as(c_int, 5);1993 \\ break :blk_1 @as(c_int, 5);
1820 \\ });1994 \\ };
1821 \\ break :blk @as(c_int, 7);1995 \\ break :blk @as(c_int, 7);
1822 \\ });1996 \\ };
1823 \\ }1997 \\ }
1824 \\ }1998 \\ }
1825 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, 2)));1999 \\ var i: u8 = 2;
1826 \\}2000 \\}
1827 });2001 });
18282002
...@@ -1830,7 +2004,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1830,7 +2004,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1830 \\unsigned anyerror = 2;2004 \\unsigned anyerror = 2;
1831 \\#define noreturn _Noreturn2005 \\#define noreturn _Noreturn
1832 , &[_][]const u8{2006 , &[_][]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;
1834 ,2008 ,
1835 \\pub const noreturn_2 = @compileError("unable to translate C expr: unexpected token .Keyword_noreturn");2009 \\pub const noreturn_2 = @compileError("unable to translate C expr: unexpected token .Keyword_noreturn");
1836 });2010 });
...@@ -1844,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1844,7 +2018,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1844 \\pub export var a: f32 = @floatCast(f32, 3.1415);2018 \\pub export var a: f32 = @floatCast(f32, 3.1415);
1845 \\pub export var b: f64 = 3.1415;2019 \\pub export var b: f64 = 3.1415;
1846 \\pub export var c: c_int = @floatToInt(c_int, 3.1415);2020 \\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;
1848 });2022 });
18492023
1850 cases.add("conditional operator",2024 cases.add("conditional operator",
...@@ -1854,7 +2028,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1854,7 +2028,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1854 \\}2028 \\}
1855 , &[_][]const u8{2029 , &[_][]const u8{
1856 \\pub export fn bar() c_int {2030 \\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);
1858 \\ return if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6);2032 \\ return if (true) @as(c_int, 5) else if (true) @as(c_int, 4) else @as(c_int, 6);
1859 \\}2033 \\}
1860 });2034 });
...@@ -1870,34 +2044,47 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1870,34 +2044,47 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1870 \\ default:2044 \\ default:
1871 \\ res = 3 * i;2045 \\ res = 3 * i;
1872 \\ break;2046 \\ break;
2047 \\ break;
1873 \\ case 4:2048 \\ case 4:
2049 \\ case 5:
2050 \\ res = 69;
2051 \\ {
1874 \\ res = 5;2052 \\ res = 5;
2053 \\ return;
2054 \\ }
2055 \\ case 6:
2056 \\ res = 1;
2057 \\ return;
1875 \\ }2058 \\ }
1876 \\}2059 \\}
1877 , &[_][]const u8{2060 , &[_][]const u8{
1878 \\pub export fn switch_fn(arg_i: c_int) void {2061 \\pub export fn switch_fn(arg_i: c_int) void {
1879 \\ var i = arg_i;2062 \\ var i = arg_i;
1880 \\ var res: c_int = 0;2063 \\ var res: c_int = 0;
1881 \\ @"switch": {2064 \\ switch (i) {
1882 \\ case_2: {2065 \\ @as(c_int, 0) => {
1883 \\ default: {2066 \\ res = 1;
1884 \\ case_1: {2067 \\ res = 2;
1885 \\ case: {2068 \\ res = @as(c_int, 3) * i;
1886 \\ switch (i) {2069 \\ },
1887 \\ @as(c_int, 0) => break :case,2070 \\ @as(c_int, 1)...@as(c_int, 3) => {
1888 \\ @as(c_int, 1)...@as(c_int, 3) => break :case_1,2071 \\ res = 2;
1889 \\ else => break :default,2072 \\ res = @as(c_int, 3) * i;
1890 \\ @as(c_int, 4) => break :case_2,2073 \\ },
1891 \\ }2074 \\ else => {
1892 \\ }2075 \\ res = @as(c_int, 3) * i;
1893 \\ res = 1;2076 \\ },
1894 \\ }2077 \\ @as(c_int, 4), @as(c_int, 5) => {
1895 \\ res = 2;2078 \\ res = 69;
2079 \\ {
2080 \\ res = 5;
2081 \\ return;
1896 \\ }2082 \\ }
1897 \\ res = (@as(c_int, 3) * i);2083 \\ },
1898 \\ break :@"switch";2084 \\ @as(c_int, 6) => {
1899 \\ }2085 \\ res = 1;
1900 \\ res = 5;2086 \\ return;
2087 \\ },
1901 \\ }2088 \\ }
1902 \\}2089 \\}
1903 });2090 });
...@@ -1973,13 +2160,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1973,13 +2160,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1973 \\ Two,2160 \\ Two,
1974 \\};2161 \\};
1975 , &[_][]const u8{2162 , &[_][]const u8{
1976 \\pub const One = @enumToInt(enum_unnamed_1.One);
1977 \\pub const Two = @enumToInt(enum_unnamed_1.Two);
1978 \\const enum_unnamed_1 = extern enum(c_int) {2163 \\const enum_unnamed_1 = extern enum(c_int) {
1979 \\ One,2164 \\ One,
1980 \\ Two,2165 \\ Two,
1981 \\ _,2166 \\ _,
1982 \\};2167 \\};
2168 \\pub const One = @enumToInt(enum_unnamed_1.One);
2169 \\pub const Two = @enumToInt(enum_unnamed_1.Two);
1983 });2170 });
19842171
1985 cases.add("c style cast",2172 cases.add("c style cast",
...@@ -1993,7 +2180,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1993,7 +2180,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1993 \\}2180 \\}
1994 });2181 });
19952182
1996 // TODO translate-c should in theory be able to figure out to drop all these casts
1997 cases.add("escape sequences",2183 cases.add("escape sequences",
1998 \\const char *escapes() {2184 \\const char *escapes() {
1999 \\char a = '\'',2185 \\char a = '\'',
...@@ -2012,17 +2198,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2012,17 +2198,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2012 \\2198 \\
2013 , &[_][]const u8{2199 , &[_][]const u8{
2014 \\pub export fn escapes() [*c]const u8 {2200 \\pub export fn escapes() [*c]const u8 {
2015 \\ var a: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\'')));2201 \\ var a: u8 = '\'';
2016 \\ var b: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\\')));2202 \\ var b: u8 = '\\';
2017 \\ var c: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x07')));2203 \\ var c: u8 = '\x07';
2018 \\ var d: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x08')));2204 \\ var d: u8 = '\x08';
2019 \\ var e: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0c')));2205 \\ var e: u8 = '\x0c';
2020 \\ var f: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\n')));2206 \\ var f: u8 = '\n';
2021 \\ var g: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\r')));2207 \\ var g: u8 = '\r';
2022 \\ var h: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\t')));2208 \\ var h: u8 = '\t';
2023 \\ var i: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x0b')));2209 \\ var i: u8 = '\x0b';
2024 \\ var j: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\x00')));2210 \\ var j: u8 = '\x00';
2025 \\ var k: u8 = @bitCast(u8, @truncate(i8, @as(c_int, '\"')));2211 \\ var k: u8 = '\"';
2026 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";2212 \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\"";
2027 \\}2213 \\}
2028 });2214 });
...@@ -2043,12 +2229,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2043,12 +2229,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2043 \\pub export fn foo() void {2229 \\pub export fn foo() void {
2044 \\ var a: c_int = 2;2230 \\ var a: c_int = 2;
2045 \\ while (true) {2231 \\ while (true) {
2046 \\ a = (a - @as(c_int, 1));2232 \\ a = a - @as(c_int, 1);
2047 \\ if (!(a != 0)) break;2233 \\ if (!(a != 0)) break;
2048 \\ }2234 \\ }
2049 \\ var b: c_int = 2;2235 \\ var b: c_int = 2;
2050 \\ while (true) {2236 \\ while (true) {
2051 \\ b = (b - @as(c_int, 1));2237 \\ b = b - @as(c_int, 1);
2052 \\ if (!(b != 0)) break;2238 \\ if (!(b != 0)) break;
2053 \\ }2239 \\ }
2054 \\}2240 \\}
...@@ -2084,25 +2270,28 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2084,25 +2270,28 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2084 \\ C,2270 \\ C,
2085 \\ _,2271 \\ _,
2086 \\};2272 \\};
2273 \\pub const FooA = @enumToInt(enum_Foo.A);
2274 \\pub const FooB = @enumToInt(enum_Foo.B);
2275 \\pub const FooC = @enumToInt(enum_Foo.C);
2087 \\pub const SomeTypedef = c_int;2276 \\pub const SomeTypedef = c_int;
2088 \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {2277 \\pub export fn and_or_non_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void) c_int {
2089 \\ var a = arg_a;2278 \\ var a = arg_a;
2090 \\ var b = arg_b;2279 \\ var b = arg_b;
2091 \\ var c = arg_c;2280 \\ var c = arg_c;
2092 \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);2281 \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);
2093 \\ var e: c_int = @boolToInt(((a != 0) and (b != 0)));2282 \\ var e: c_int = @boolToInt((a != 0) and (b != 0));
2094 \\ var f: c_int = @boolToInt(((b != 0) and (c != null)));2283 \\ var f: c_int = @boolToInt((b != 0) and (c != null));
2095 \\ var g: c_int = @boolToInt(((a != 0) and (c != null)));2284 \\ var g: c_int = @boolToInt((a != 0) and (c != null));
2096 \\ var h: c_int = @boolToInt(((a != 0) or (b != 0)));2285 \\ var h: c_int = @boolToInt((a != 0) or (b != 0));
2097 \\ var i: c_int = @boolToInt(((b != 0) or (c != null)));2286 \\ var i: c_int = @boolToInt((b != 0) or (c != null));
2098 \\ var j: c_int = @boolToInt(((a != 0) or (c != null)));2287 \\ 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)));2288 \\ 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)));2289 \\ 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)));2290 \\ var m: c_int = @boolToInt((c != null) or (@bitCast(c_uint, @enumToInt(d)) != 0));
2102 \\ var td: SomeTypedef = 44;2291 \\ var td: SomeTypedef = 44;
2103 \\ var o: c_int = @boolToInt(((td != 0) or (b != 0)));2292 \\ var o: c_int = @boolToInt((td != 0) or (b != 0));
2104 \\ var p: c_int = @boolToInt(((c != null) and (td != 0)));2293 \\ var p: c_int = @boolToInt((c != null) and (td != 0));
2105 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);2294 \\ return (((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p;
2106 \\}2295 \\}
2107 ,2296 ,
2108 \\pub const Foo = enum_Foo;2297 \\pub const Foo = enum_Foo;
...@@ -2129,6 +2318,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2129,6 +2318,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2129 \\ B,2318 \\ B,
2130 \\ _,2319 \\ _,
2131 \\};2320 \\};
2321 \\pub const BarA = @enumToInt(enum_Bar.A);
2322 \\pub const BarB = @enumToInt(enum_Bar.B);
2132 \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;2323 \\pub extern fn func(a: [*c]struct_Foo, b: [*c][*c]enum_Bar) void;
2133 ,2324 ,
2134 \\pub const Foo = struct_Foo;2325 \\pub const Foo = struct_Foo;
...@@ -2143,7 +2334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2143,7 +2334,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2143 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {2334 \\pub export fn max(arg_a: c_int, arg_b: c_int) c_int {
2144 \\ var a = arg_a;2335 \\ var a = arg_a;
2145 \\ var b = arg_b;2336 \\ var b = arg_b;
2146 \\ return ((a & b) ^ (a | b));2337 \\ return (a & b) ^ (a | b);
2147 \\}2338 \\}
2148 });2339 });
21492340
...@@ -2162,13 +2353,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2162,13 +2353,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2162 \\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int {2353 \\pub export fn test_comparisons(arg_a: c_int, arg_b: c_int) c_int {
2163 \\ var a = arg_a;2354 \\ var a = arg_a;
2164 \\ var b = arg_b;2355 \\ var b = arg_b;
2165 \\ var c: c_int = @boolToInt((a < b));2356 \\ var c: c_int = @boolToInt(a < b);
2166 \\ var d: c_int = @boolToInt((a > b));2357 \\ var d: c_int = @boolToInt(a > b);
2167 \\ var e: c_int = @boolToInt((a <= b));2358 \\ var e: c_int = @boolToInt(a <= b);
2168 \\ var f: c_int = @boolToInt((a >= b));2359 \\ var f: c_int = @boolToInt(a >= b);
2169 \\ var g: c_int = @boolToInt((c < d));2360 \\ var g: c_int = @boolToInt(c < d);
2170 \\ var h: c_int = @boolToInt((e < f));2361 \\ var h: c_int = @boolToInt(e < f);
2171 \\ var i: c_int = @boolToInt((g < h));2362 \\ var i: c_int = @boolToInt(g < h);
2172 \\ return i;2363 \\ return i;
2173 \\}2364 \\}
2174 });2365 });
...@@ -2215,11 +2406,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2215,11 +2406,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2215 \\}2406 \\}
2216 , &[_][]const u8{2407 , &[_][]const u8{
2217 \\pub export fn foo() c_int {2408 \\pub export fn foo() c_int {
2218 \\ return (blk: {2409 \\ return blk: {
2219 \\ var a: c_int = 1;2410 \\ var a: c_int = 1;
2220 \\ _ = a;2411 \\ _ = a;
2221 \\ break :blk a;2412 \\ break :blk a;
2222 \\ });2413 \\ };
2223 \\}2414 \\}
2224 });2415 });
22252416
...@@ -2289,8 +2480,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2289,8 +2480,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2289 , &[_][]const u8{2480 , &[_][]const u8{
2290 \\pub export fn foo() void {2481 \\pub export fn foo() void {
2291 \\ var a: [10]c_longlong = undefined;2482 \\ var a: [10]c_longlong = undefined;
2292 \\ var i: c_longlong = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));2483 \\ var i: c_longlong = 0;
2293 \\ a[@intCast(usize, i)] = @bitCast(c_longlong, @as(c_longlong, @as(c_int, 0)));2484 \\ a[@intCast(usize, i)] = 0;
2294 \\}2485 \\}
2295 });2486 });
22962487
...@@ -2302,8 +2493,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2302,8 +2493,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2302 , &[_][]const u8{2493 , &[_][]const u8{
2303 \\pub export fn foo() void {2494 \\pub export fn foo() void {
2304 \\ var a: [10]c_uint = undefined;2495 \\ var a: [10]c_uint = undefined;
2305 \\ var i: c_uint = @bitCast(c_uint, @as(c_int, 0));2496 \\ var i: c_uint = 0;
2306 \\ a[i] = @bitCast(c_uint, @as(c_int, 0));2497 \\ a[i] = 0;
2307 \\}2498 \\}
2308 });2499 });
23092500
...@@ -2371,9 +2562,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2371,9 +2562,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2371 \\ var a: c_int = 2;2562 \\ var a: c_int = 2;
2372 \\ }2563 \\ }
2373 \\ if ((blk: {2564 \\ if ((blk: {
2374 \\ _ = @as(c_int, 2);2565 \\ _ = @as(c_int, 2);
2375 \\ break :blk @as(c_int, 5);2566 \\ break :blk @as(c_int, 5);
2376 \\ }) != 0) {2567 \\ }) != 0) {
2377 \\ var a: c_int = 2;2568 \\ var a: c_int = 2;
2378 \\ }2569 \\ }
2379 \\}2570 \\}
...@@ -2395,6 +2586,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2395,6 +2586,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2395 \\ C,2586 \\ C,
2396 \\ _,2587 \\ _,
2397 \\};2588 \\};
2589 \\pub const A = @enumToInt(enum_SomeEnum.A);
2590 \\pub const B = @enumToInt(enum_SomeEnum.B);
2591 \\pub const C = @enumToInt(enum_SomeEnum.C);
2398 \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {2592 \\pub export fn if_none_bool(arg_a: c_int, arg_b: f32, arg_c: ?*c_void, arg_d: enum_SomeEnum) c_int {
2399 \\ var a = arg_a;2593 \\ var a = arg_a;
2400 \\ var b = arg_b;2594 \\ var b = arg_b;
...@@ -2484,10 +2678,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2484,10 +2678,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2484 \\ var f: ?fn () callconv(.C) void = foo;2678 \\ var f: ?fn () callconv(.C) void = foo;
2485 \\ var b: ?fn () callconv(.C) c_int = baz;2679 \\ var b: ?fn () callconv(.C) c_int = baz;
2486 \\ f.?();2680 \\ f.?();
2487 \\ (f).?();2681 \\ f.?();
2488 \\ foo();2682 \\ foo();
2489 \\ _ = b.?();2683 \\ _ = b.?();
2490 \\ _ = (b).?();2684 \\ _ = b.?();
2491 \\ _ = baz();2685 \\ _ = baz();
2492 \\}2686 \\}
2493 });2687 });
...@@ -2508,31 +2702,31 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2508,31 +2702,31 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2508 , &[_][]const u8{2702 , &[_][]const u8{
2509 \\pub export fn foo() void {2703 \\pub export fn foo() void {
2510 \\ var i: c_int = 0;2704 \\ var i: c_int = 0;
2511 \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));2705 \\ var u: c_uint = 0;
2512 \\ i += 1;2706 \\ i += 1;
2513 \\ i -= 1;2707 \\ i -= 1;
2514 \\ u +%= 1;2708 \\ u +%= 1;
2515 \\ u -%= 1;2709 \\ u -%= 1;
2516 \\ i = (blk: {2710 \\ i = blk: {
2517 \\ const ref = &i;2711 \\ const ref = &i;
2518 \\ ref.* += 1;2712 \\ ref.* += 1;
2519 \\ break :blk ref.*;2713 \\ break :blk ref.*;
2520 \\ });2714 \\ };
2521 \\ i = (blk: {2715 \\ i = blk: {
2522 \\ const ref = &i;2716 \\ const ref = &i;
2523 \\ ref.* -= 1;2717 \\ ref.* -= 1;
2524 \\ break :blk ref.*;2718 \\ break :blk ref.*;
2525 \\ });2719 \\ };
2526 \\ u = (blk: {2720 \\ u = blk: {
2527 \\ const ref = &u;2721 \\ const ref = &u;
2528 \\ ref.* +%= 1;2722 \\ ref.* +%= 1;
2529 \\ break :blk ref.*;2723 \\ break :blk ref.*;
2530 \\ });2724 \\ };
2531 \\ u = (blk: {2725 \\ u = blk: {
2532 \\ const ref = &u;2726 \\ const ref = &u;
2533 \\ ref.* -%= 1;2727 \\ ref.* -%= 1;
2534 \\ break :blk ref.*;2728 \\ break :blk ref.*;
2535 \\ });2729 \\ };
2536 \\}2730 \\}
2537 });2731 });
25382732
...@@ -2595,67 +2789,67 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2595,67 +2789,67 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2595 , &[_][]const u8{2789 , &[_][]const u8{
2596 \\pub export fn foo() void {2790 \\pub export fn foo() void {
2597 \\ var a: c_int = 0;2791 \\ var a: c_int = 0;
2598 \\ var b: c_uint = @bitCast(c_uint, @as(c_int, 0));2792 \\ var b: c_uint = 0;
2599 \\ a += (blk: {2793 \\ a += blk: {
2600 \\ const ref = &a;2794 \\ const ref = &a;
2601 \\ ref.* = ref.* + @as(c_int, 1);2795 \\ ref.* += @as(c_int, 1);
2602 \\ break :blk ref.*;2796 \\ break :blk ref.*;
2603 \\ });2797 \\ };
2604 \\ a -= (blk: {2798 \\ a -= blk: {
2605 \\ const ref = &a;2799 \\ const ref = &a;
2606 \\ ref.* = ref.* - @as(c_int, 1);2800 \\ ref.* -= @as(c_int, 1);
2607 \\ break :blk ref.*;2801 \\ break :blk ref.*;
2608 \\ });2802 \\ };
2609 \\ a *= (blk: {2803 \\ a *= blk: {
2610 \\ const ref = &a;2804 \\ const ref = &a;
2611 \\ ref.* = ref.* * @as(c_int, 1);2805 \\ ref.* *= @as(c_int, 1);
2612 \\ break :blk ref.*;2806 \\ break :blk ref.*;
2613 \\ });2807 \\ };
2614 \\ a &= (blk: {2808 \\ a &= blk: {
2615 \\ const ref = &a;2809 \\ const ref = &a;
2616 \\ ref.* = ref.* & @as(c_int, 1);2810 \\ ref.* &= @as(c_int, 1);
2617 \\ break :blk ref.*;2811 \\ break :blk ref.*;
2618 \\ });2812 \\ };
2619 \\ a |= (blk: {2813 \\ a |= blk: {
2620 \\ const ref = &a;2814 \\ const ref = &a;
2621 \\ ref.* = ref.* | @as(c_int, 1);2815 \\ ref.* |= @as(c_int, 1);
2622 \\ break :blk ref.*;2816 \\ break :blk ref.*;
2623 \\ });2817 \\ };
2624 \\ a ^= (blk: {2818 \\ a ^= blk: {
2625 \\ const ref = &a;2819 \\ const ref = &a;
2626 \\ ref.* = ref.* ^ @as(c_int, 1);2820 \\ ref.* ^= @as(c_int, 1);
2627 \\ break :blk ref.*;2821 \\ break :blk ref.*;
2628 \\ });2822 \\ };
2629 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), (blk: {2823 \\ a >>= @intCast(@import("std").math.Log2Int(c_int), blk: {
2630 \\ const ref = &a;2824 \\ 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));
2632 \\ break :blk ref.*;2826 \\ break :blk ref.*;
2633 \\ }));2827 \\ });
2634 \\ a <<= @intCast(@import("std").math.Log2Int(c_int), (blk: {2828 \\ a <<= @intCast(@import("std").math.Log2Int(c_int), blk: {
2635 \\ const ref = &a;2829 \\ 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));
2637 \\ break :blk ref.*;2831 \\ break :blk ref.*;
2638 \\ }));2832 \\ });
2639 \\ a = @divTrunc(a, (blk: {2833 \\ a = @divTrunc(a, blk: {
2640 \\ const ref = &a;2834 \\ const ref = &a;
2641 \\ ref.* = @divTrunc(ref.*, @as(c_int, 1));2835 \\ ref.* = @divTrunc(ref.*, @as(c_int, 1));
2642 \\ break :blk ref.*;2836 \\ break :blk ref.*;
2643 \\ }));2837 \\ });
2644 \\ a = @rem(a, (blk: {2838 \\ a = @rem(a, blk: {
2645 \\ const ref = &a;2839 \\ const ref = &a;
2646 \\ ref.* = @rem(ref.*, @as(c_int, 1));2840 \\ ref.* = @rem(ref.*, @as(c_int, 1));
2647 \\ break :blk ref.*;2841 \\ break :blk ref.*;
2648 \\ }));2842 \\ });
2649 \\ b /= (blk: {2843 \\ b /= blk: {
2650 \\ const ref = &b;2844 \\ const ref = &b;
2651 \\ ref.* = ref.* / @bitCast(c_uint, @as(c_int, 1));2845 \\ ref.* /= @bitCast(c_uint, @as(c_int, 1));
2652 \\ break :blk ref.*;2846 \\ break :blk ref.*;
2653 \\ });2847 \\ };
2654 \\ b %= (blk: {2848 \\ b %= blk: {
2655 \\ const ref = &b;2849 \\ const ref = &b;
2656 \\ ref.* = ref.* % @bitCast(c_uint, @as(c_int, 1));2850 \\ ref.* %= @bitCast(c_uint, @as(c_int, 1));
2657 \\ break :blk ref.*;2851 \\ break :blk ref.*;
2658 \\ });2852 \\ };
2659 \\}2853 \\}
2660 });2854 });
26612855
...@@ -2673,47 +2867,47 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2673,47 +2867,47 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2673 \\}2867 \\}
2674 , &[_][]const u8{2868 , &[_][]const u8{
2675 \\pub export fn foo() void {2869 \\pub export fn foo() void {
2676 \\ var a: c_uint = @bitCast(c_uint, @as(c_int, 0));2870 \\ var a: c_uint = 0;
2677 \\ a +%= (blk: {2871 \\ a +%= blk: {
2678 \\ const ref = &a;2872 \\ const ref = &a;
2679 \\ ref.* = ref.* +% @bitCast(c_uint, @as(c_int, 1));2873 \\ ref.* +%= @bitCast(c_uint, @as(c_int, 1));
2680 \\ break :blk ref.*;2874 \\ break :blk ref.*;
2681 \\ });2875 \\ };
2682 \\ a -%= (blk: {2876 \\ a -%= blk: {
2683 \\ const ref = &a;2877 \\ const ref = &a;
2684 \\ ref.* = ref.* -% @bitCast(c_uint, @as(c_int, 1));2878 \\ ref.* -%= @bitCast(c_uint, @as(c_int, 1));
2685 \\ break :blk ref.*;2879 \\ break :blk ref.*;
2686 \\ });2880 \\ };
2687 \\ a *%= (blk: {2881 \\ a *%= blk: {
2688 \\ const ref = &a;2882 \\ const ref = &a;
2689 \\ ref.* = ref.* *% @bitCast(c_uint, @as(c_int, 1));2883 \\ ref.* *%= @bitCast(c_uint, @as(c_int, 1));
2690 \\ break :blk ref.*;2884 \\ break :blk ref.*;
2691 \\ });2885 \\ };
2692 \\ a &= (blk: {2886 \\ a &= blk: {
2693 \\ const ref = &a;2887 \\ const ref = &a;
2694 \\ ref.* = ref.* & @bitCast(c_uint, @as(c_int, 1));2888 \\ ref.* &= @bitCast(c_uint, @as(c_int, 1));
2695 \\ break :blk ref.*;2889 \\ break :blk ref.*;
2696 \\ });2890 \\ };
2697 \\ a |= (blk: {2891 \\ a |= blk: {
2698 \\ const ref = &a;2892 \\ const ref = &a;
2699 \\ ref.* = ref.* | @bitCast(c_uint, @as(c_int, 1));2893 \\ ref.* |= @bitCast(c_uint, @as(c_int, 1));
2700 \\ break :blk ref.*;2894 \\ break :blk ref.*;
2701 \\ });2895 \\ };
2702 \\ a ^= (blk: {2896 \\ a ^= blk: {
2703 \\ const ref = &a;2897 \\ const ref = &a;
2704 \\ ref.* = ref.* ^ @bitCast(c_uint, @as(c_int, 1));2898 \\ ref.* ^= @bitCast(c_uint, @as(c_int, 1));
2705 \\ break :blk ref.*;2899 \\ break :blk ref.*;
2706 \\ });2900 \\ };
2707 \\ a >>= @intCast(@import("std").math.Log2Int(c_uint), (blk: {2901 \\ a >>= @intCast(@import("std").math.Log2Int(c_uint), blk: {
2708 \\ const ref = &a;2902 \\ 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));
2710 \\ break :blk ref.*;2904 \\ break :blk ref.*;
2711 \\ }));2905 \\ });
2712 \\ a <<= @intCast(@import("std").math.Log2Int(c_uint), (blk: {2906 \\ a <<= @intCast(@import("std").math.Log2Int(c_uint), blk: {
2713 \\ const ref = &a;2907 \\ 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));
2715 \\ break :blk ref.*;2909 \\ break :blk ref.*;
2716 \\ }));2910 \\ });
2717 \\}2911 \\}
2718 });2912 });
27192913
...@@ -2733,35 +2927,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2733,35 +2927,35 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2733 , &[_][]const u8{2927 , &[_][]const u8{
2734 \\pub export fn foo() void {2928 \\pub export fn foo() void {
2735 \\ var i: c_int = 0;2929 \\ var i: c_int = 0;
2736 \\ var u: c_uint = @bitCast(c_uint, @as(c_int, 0));2930 \\ var u: c_uint = 0;
2737 \\ i += 1;2931 \\ i += 1;
2738 \\ i -= 1;2932 \\ i -= 1;
2739 \\ u +%= 1;2933 \\ u +%= 1;
2740 \\ u -%= 1;2934 \\ u -%= 1;
2741 \\ i = (blk: {2935 \\ i = blk: {
2742 \\ const ref = &i;2936 \\ const ref = &i;
2743 \\ const tmp = ref.*;2937 \\ const tmp = ref.*;
2744 \\ ref.* += 1;2938 \\ ref.* += 1;
2745 \\ break :blk tmp;2939 \\ break :blk tmp;
2746 \\ });2940 \\ };
2747 \\ i = (blk: {2941 \\ i = blk: {
2748 \\ const ref = &i;2942 \\ const ref = &i;
2749 \\ const tmp = ref.*;2943 \\ const tmp = ref.*;
2750 \\ ref.* -= 1;2944 \\ ref.* -= 1;
2751 \\ break :blk tmp;2945 \\ break :blk tmp;
2752 \\ });2946 \\ };
2753 \\ u = (blk: {2947 \\ u = blk: {
2754 \\ const ref = &u;2948 \\ const ref = &u;
2755 \\ const tmp = ref.*;2949 \\ const tmp = ref.*;
2756 \\ ref.* +%= 1;2950 \\ ref.* +%= 1;
2757 \\ break :blk tmp;2951 \\ break :blk tmp;
2758 \\ });2952 \\ };
2759 \\ u = (blk: {2953 \\ u = blk: {
2760 \\ const ref = &u;2954 \\ const ref = &u;
2761 \\ const tmp = ref.*;2955 \\ const tmp = ref.*;
2762 \\ ref.* -%= 1;2956 \\ ref.* -%= 1;
2763 \\ break :blk tmp;2957 \\ break :blk tmp;
2764 \\ });2958 \\ };
2765 \\}2959 \\}
2766 });2960 });
27672961
...@@ -2854,15 +3048,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2854,15 +3048,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2854 \\ Foo1,3048 \\ Foo1,
2855 \\};3049 \\};
2856 , &[_][]const u8{3050 , &[_][]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");
2860 \\pub const enum_Foo = extern enum(c_int) {3051 \\pub const enum_Foo = extern enum(c_int) {
2861 \\ A = 2,3052 \\ A = 2,
2862 \\ B = 5,3053 \\ B = 5,
2863 \\ @"1" = 6,3054 \\ @"1" = 6,
2864 \\ _,3055 \\ _,
2865 \\};3056 \\};
3057 \\pub const FooA = @enumToInt(enum_Foo.A);
3058 \\pub const FooB = @enumToInt(enum_Foo.B);
3059 \\pub const Foo1 = @enumToInt(enum_Foo.@"1");
2866 ,3060 ,
2867 \\pub const Foo = enum_Foo;3061 \\pub const Foo = enum_Foo;
2868 });3062 });
...@@ -2872,13 +3066,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2872,13 +3066,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2872 \\#define BAR (void*) a3066 \\#define BAR (void*) a
2873 \\#define BAZ (uint32_t)(2)3067 \\#define BAZ (uint32_t)(2)
2874 , &[_][]const u8{3068 , &[_][]const u8{
2875 \\pub fn FOO(bar: anytype) callconv(.Inline) @TypeOf(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))) {
2876 \\ return baz((@import("std").meta.cast(?*c_void, baz)));3070 \\ return baz(@import("std").meta.cast(?*c_void, baz));
2877 \\}3071 \\}
2878 ,3072 ,
2879 \\pub const BAR = (@import("std").meta.cast(?*c_void, a));3073 \\pub const BAR = @import("std").meta.cast(?*c_void, a);
2880 ,3074 ,
2881 \\pub const BAZ = (@import("std").meta.cast(u32, 2));3075 \\pub const BAZ = @import("std").meta.cast(u32, 2);
2882 });3076 });
28833077
2884 cases.add("macro with cast to unsigned short, long, and long long",3078 cases.add("macro with cast to unsigned short, long, and long long",
...@@ -2886,9 +3080,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2886,9 +3080,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2886 \\#define CURLAUTH_BASIC ((unsigned long) 1)3080 \\#define CURLAUTH_BASIC ((unsigned long) 1)
2887 \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1)3081 \\#define CURLAUTH_BASIC_BUT_ULONGLONG ((unsigned long long) 1)
2888 , &[_][]const u8{3082 , &[_][]const u8{
2889 \\pub const CURLAUTH_BASIC_BUT_USHORT = (@import("std").meta.cast(c_ushort, 1));3083 \\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));3084 \\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));3085 \\pub const CURLAUTH_BASIC_BUT_ULONGLONG = @import("std").meta.cast(c_ulonglong, 1);
2892 });3086 });
28933087
2894 cases.add("macro conditional operator",3088 cases.add("macro conditional operator",
...@@ -2904,9 +3098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2904,9 +3098,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2904 \\}3098 \\}
2905 , &[_][]const u8{3099 , &[_][]const u8{
2906 \\pub fn foo() callconv(.C) void {3100 \\pub fn foo() callconv(.C) void {
2907 \\ if (true) while (true) {3101 \\ if (true) {}
2908 \\ if (!false) break;
2909 \\ };
2910 \\}3102 \\}
2911 });3103 });
29123104
...@@ -2923,27 +3115,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -2923,27 +3115,27 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
2923 \\}3115 \\}
2924 });3116 });
29253117
2926 // TODO: detect to use different block labels here3118 // TODO fix zig fmt here
2927 cases.add("nested assignment",3119 // cases.add("nested assignment",
2928 \\int foo(int *p, int x) {3120 // \\int foo(int *p, int x) {
2929 \\ return *p++ = x;3121 // \\ return *p++ = x;
2930 \\}3122 // \\}
2931 , &[_][]const u8{3123 // , &[_][]const u8{
2932 \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {3124 // \\pub export fn foo(arg_p: [*c]c_int, arg_x: c_int) c_int {
2933 \\ var p = arg_p;3125 // \\ var p = arg_p;
2934 \\ var x = arg_x;3126 // \\ var x = arg_x;
2935 \\ return blk: {3127 // \\ return blk: {
2936 \\ const tmp = x;3128 // \\ const tmp = x;
2937 \\ (blk_1: {3129 // \\ (blk_1: {
2938 \\ const ref = &p;3130 // \\ const ref = &p;
2939 \\ const tmp_2 = ref.*;3131 // \\ const tmp_2 = ref.*;
2940 \\ ref.* += 1;3132 // \\ ref.* += 1;
2941 \\ break :blk_1 tmp_2;3133 // \\ break :blk_1 tmp_2;
2942 \\ }).?.* = tmp;3134 // \\ }).?.* = tmp;
2943 \\ break :blk tmp;3135 // \\ break :blk tmp;
2944 \\ };3136 // \\ };
2945 \\}3137 // \\}
2946 });3138 // });
29473139
2948 cases.add("widening and truncating integer casting to different signedness",3140 cases.add("widening and truncating integer casting to different signedness",
2949 \\unsigned long foo(void) {3141 \\unsigned long foo(void) {
...@@ -3033,10 +3225,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3033,10 +3225,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3033 , &[_][]const u8{3225 , &[_][]const u8{
3034 \\pub export fn foo(arg_x: bool) bool {3226 \\pub export fn foo(arg_x: bool) bool {
3035 \\ var x = arg_x;3227 \\ var x = arg_x;
3036 \\ var a: bool = (@as(c_int, @boolToInt(x)) != @as(c_int, 1));3228 \\ 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));3229 \\ var b: bool = @as(c_int, @boolToInt(a)) != @as(c_int, 0);
3038 \\ var c: bool = @ptrToInt(foo) != 0;3230 \\ 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)));
3040 \\}3232 \\}
3041 });3233 });
30423234
...@@ -3106,8 +3298,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3106,8 +3298,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3106 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)3298 \\#define DefaultScreen(dpy) (((_XPrivDisplay)(dpy))->default_screen)
3107 \\3299 \\
3108 , &[_][]const u8{3300 , &[_][]const u8{
3109 \\pub fn DefaultScreen(dpy: anytype) callconv(.Inline) @TypeOf((@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) {
3110 \\ return (@import("std").meta.cast(_XPrivDisplay, dpy)).*.default_screen;3302 \\ return @import("std").meta.cast(_XPrivDisplay, dpy).*.default_screen;
3111 \\}3303 \\}
3112 });3304 });
31133305
...@@ -3115,9 +3307,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3115,9 +3307,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3115 \\#define NULL ((void*)0)3307 \\#define NULL ((void*)0)
3116 \\#define FOO ((int)0x8000)3308 \\#define FOO ((int)0x8000)
3117 , &[_][]const u8{3309 , &[_][]const u8{
3118 \\pub const NULL = (@import("std").meta.cast(?*c_void, 0));3310 \\pub const NULL = @import("std").meta.cast(?*c_void, 0);
3119 ,3311 ,
3120 \\pub const FOO = (@import("std").meta.cast(c_int, 0x8000));3312 \\pub const FOO = @import("std").meta.cast(c_int, 0x8000);
3121 });3313 });
31223314
3123 if (std.Target.current.abi == .msvc) {3315 if (std.Target.current.abi == .msvc) {