authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-07 22:28:41+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:37:08+02:00
log7514c0ad0d327d2427009c26e5930540297e396e
tree1c696f87661d4139cd40b65fdba2f3deab2a3304
parentf5041caa2e9d1e891bd93aa2721a4a283123f0d9
signature Commit is signed but in an unrecognized format.

translate-c: unary operator, integers and misc


2 files changed, 138 insertions(+), 176 deletions(-)

src/translate_c.zig+108-171
...@@ -8,7 +8,6 @@ const ctok = std.c.tokenizer;...@@ -8,7 +8,6 @@ const ctok = std.c.tokenizer;
8const CToken = std.c.Token;8const CToken = std.c.Token;
9const mem = std.mem;9const mem = std.mem;
10const math = std.math;10const math = std.math;
11const Type = @import("type.zig").Type;
12const ast = @import("translate_c/ast.zig");11const ast = @import("translate_c/ast.zig");
13const Node = ast.Node;12const Node = ast.Node;
1413
...@@ -20,7 +19,7 @@ pub const Error = error{OutOfMemory};...@@ -20,7 +19,7 @@ pub const Error = error{OutOfMemory};
20const TypeError = Error || error{UnsupportedType};19const TypeError = Error || error{UnsupportedType};
21const TransError = TypeError || error{UnsupportedTranslation};20const TransError = TypeError || error{UnsupportedTranslation};
2221
23const SymbolTable = std.StringArrayHashMap(*ast.Node);22const SymbolTable = std.StringArrayHashMap(Node);
24const AliasList = std.ArrayList(struct {23const AliasList = std.ArrayList(struct {
25 alias: []const u8,24 alias: []const u8,
26 name: []const u8,25 name: []const u8,
...@@ -38,13 +37,13 @@ const Scope = struct {...@@ -38,13 +37,13 @@ const Scope = struct {
38 Loop,37 Loop,
39 };38 };
4039
41 /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated.40 /// Represents an in-progress Node.Switch. This struct is stack-allocated.
42 /// When it is deinitialized, it produces an ast.Node.Switch which is allocated41 /// When it is deinitialized, it produces an Node.Switch which is allocated
43 /// into the main arena.42 /// into the main arena.
44 const Switch = struct {43 const Switch = struct {
45 base: Scope,44 base: Scope,
46 pending_block: Block,45 pending_block: Block,
47 cases: []*ast.Node,46 cases: []Node,
48 case_index: usize,47 case_index: usize,
49 switch_label: ?[]const u8,48 switch_label: ?[]const u8,
50 default_label: ?[]const u8,49 default_label: ?[]const u8,
...@@ -156,6 +155,7 @@ const Scope = struct {...@@ -156,6 +155,7 @@ const Scope = struct {
156 sym_table: SymbolTable,155 sym_table: SymbolTable,
157 macro_table: SymbolTable,156 macro_table: SymbolTable,
158 context: *Context,157 context: *Context,
158 nodes: std.ArrayList(Node),
159159
160 fn init(c: *Context) Root {160 fn init(c: *Context) Root {
161 return .{161 return .{
...@@ -163,12 +163,19 @@ const Scope = struct {...@@ -163,12 +163,19 @@ const Scope = struct {
163 .id = .Root,163 .id = .Root,
164 .parent = null,164 .parent = null,
165 },165 },
166 .sym_table = SymbolTable.init(c.arena),166 .sym_table = SymbolTable.init(c.gpa),
167 .macro_table = SymbolTable.init(c.arena),167 .macro_table = SymbolTable.init(c.gpa),
168 .context = c,168 .context = c,
169 .nodes = std.ArrayList(Node).init(c.gpa),
169 };170 };
170 }171 }
171172
173 fn deinit(scope: *Root) void {
174 scope.sym_table.deinit();
175 scope.macro_table.deinit();
176 scope.nodes.deinit();
177 }
178
172 /// Check if the global scope contains this name, without looking into the "future", e.g.179 /// Check if the global scope contains this name, without looking into the "future", e.g.
173 /// ignore the preprocessed decl and macro names.180 /// ignore the preprocessed decl and macro names.
174 fn containsNow(scope: *Root, name: []const u8) bool {181 fn containsNow(scope: *Root, name: []const u8) bool {
...@@ -195,11 +202,11 @@ const Scope = struct {...@@ -195,11 +202,11 @@ const Scope = struct {
195 }202 }
196 }203 }
197204
198 fn findBlockReturnType(inner: *Scope, c: *Context) ?clang.QualType {205 fn findBlockReturnType(inner: *Scope, c: *Context) clang.QualType {
199 var scope = inner;206 var scope = inner;
200 while (true) {207 while (true) {
201 switch (scope.id) {208 switch (scope.id) {
202 .Root => return null,209 .Root => unreachable,
203 .Block => {210 .Block => {
204 const block = @fieldParentPtr(Block, "base", scope);211 const block = @fieldParentPtr(Block, "base", scope);
205 if (block.return_type) |qt| return qt;212 if (block.return_type) |qt| return qt;
...@@ -248,23 +255,35 @@ const Scope = struct {...@@ -248,23 +255,35 @@ const Scope = struct {
248 }255 }
249 }256 }
250 }257 }
258
259 /// Appends a node to the first block scope if inside a function, or to the root tree if not.
260 fn appendNode(scope: *Scope, node: Node) !void {
261 var scope = inner;
262 while (true) {
263 switch (scope.id) {
264 .Root => {
265 const root = @fieldParentPtr(Root, "base", scope).contains(name);
266 return root.nodes.append(node);
267 },
268 .Block => {
269 const block = @fieldParentPtr(Block, "base", scope).contains(name);
270 return block.statements.append(node);
271 },
272 else => scope = scope.parent.?,
273 }
274 }
275 }
251};276};
252277
253pub const Context = struct {278pub const Context = struct {
254 gpa: *mem.Allocator,279 gpa: *mem.Allocator,
255 arena: *mem.Allocator,280 arena: *mem.Allocator,
256 token_ids: std.ArrayListUnmanaged(Token.Id) = .{},
257 token_locs: std.ArrayListUnmanaged(Token.Loc) = .{},
258 errors: std.ArrayListUnmanaged(ast.Error) = .{},
259 source_buffer: *std.ArrayList(u8),
260 err: Error,
261 source_manager: *clang.SourceManager,281 source_manager: *clang.SourceManager,
262 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},282 decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{},
263 alias_list: AliasList,283 alias_list: AliasList,
264 global_scope: *Scope.Root,284 global_scope: *Scope.Root,
265 clang_context: *clang.ASTContext,285 clang_context: *clang.ASTContext,
266 mangle_count: u32 = 0,286 mangle_count: u32 = 0,
267 root_decls: std.ArrayListUnmanaged(*ast.Node) = .{},
268 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},287 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
269288
270 /// This one is different than the root scope's name table. This contains289 /// This one is different than the root scope's name table. This contains
...@@ -293,40 +312,6 @@ pub const Context = struct {...@@ -293,40 +312,6 @@ pub const Context = struct {
293 const column = c.source_manager.getSpellingColumnNumber(spelling_loc);312 const column = c.source_manager.getSpellingColumnNumber(spelling_loc);
294 return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });313 return std.fmt.allocPrint(c.arena, "{s}:{d}:{d}", .{ filename, line, column });
295 }314 }
296
297 fn createCall(c: *Context, fn_expr: *ast.Node, params_len: ast.NodeIndex) !*ast.Node.Call {
298 _ = try appendToken(c, .LParen, "(");
299 const node = try ast.Node.Call.alloc(c.arena, params_len);
300 node.* = .{
301 .lhs = fn_expr,
302 .params_len = params_len,
303 .async_token = null,
304 .rtoken = undefined, // set after appending args
305 };
306 return node;
307 }
308
309 fn createBuiltinCall(c: *Context, name: []const u8, params_len: ast.NodeIndex) !*ast.Node.BuiltinCall {
310 const builtin_token = try appendToken(c, .Builtin, name);
311 _ = try appendToken(c, .LParen, "(");
312 const node = try ast.Node.BuiltinCall.alloc(c.arena, params_len);
313 node.* = .{
314 .builtin_token = builtin_token,
315 .params_len = params_len,
316 .rparen_token = undefined, // set after appending args
317 };
318 return node;
319 }
320
321 fn createBlock(c: *Context, statements_len: ast.NodeIndex) !*ast.Node.Block {
322 const block_node = try ast.Node.Block.alloc(c.arena, statements_len);
323 block_node.* = .{
324 .lbrace = try appendToken(c, .LBrace, "{"),
325 .statements_len = statements_len,
326 .rbrace = undefined,
327 };
328 return block_node;
329 }
330};315};
331316
332pub fn translate(317pub fn translate(
...@@ -348,9 +333,6 @@ pub fn translate(...@@ -348,9 +333,6 @@ pub fn translate(
348 };333 };
349 defer ast_unit.delete();334 defer ast_unit.delete();
350335
351 var source_buffer = std.ArrayList(u8).init(gpa);
352 defer source_buffer.deinit();
353
354 // For memory that has the same lifetime as the Tree that we return336 // For memory that has the same lifetime as the Tree that we return
355 // from this function.337 // from this function.
356 var arena = std.heap.ArenaAllocator.init(gpa);338 var arena = std.heap.ArenaAllocator.init(gpa);
...@@ -367,9 +349,7 @@ pub fn translate(...@@ -367,9 +349,7 @@ pub fn translate(
367 var context = Context{349 var context = Context{
368 .gpa = gpa,350 .gpa = gpa,
369 .arena = &arena.allocator,351 .arena = &arena.allocator,
370 .source_buffer = &source_buffer,
371 .source_manager = ast_unit.getSourceManager(),352 .source_manager = ast_unit.getSourceManager(),
372 .err = undefined,
373 .alias_list = AliasList.init(gpa),353 .alias_list = AliasList.init(gpa),
374 .global_scope = try arena.allocator.create(Scope.Root),354 .global_scope = try arena.allocator.create(Scope.Root),
375 .clang_context = ast_unit.getASTContext(),355 .clang_context = ast_unit.getASTContext(),
...@@ -378,15 +358,12 @@ pub fn translate(...@@ -378,15 +358,12 @@ pub fn translate(
378 defer {358 defer {
379 context.decl_table.deinit(gpa);359 context.decl_table.deinit(gpa);
380 context.alias_list.deinit();360 context.alias_list.deinit();
381 context.token_ids.deinit(gpa);
382 context.token_locs.deinit(gpa);
383 context.errors.deinit(gpa);
384 context.global_names.deinit(gpa);361 context.global_names.deinit(gpa);
385 context.root_decls.deinit(gpa);
386 context.opaque_demotes.deinit(gpa);362 context.opaque_demotes.deinit(gpa);
363 context.global_scope.deini();
387 }364 }
388365
389 _ = try Node.usingnamespace_builtins.init();366 try context.global_scope.nodes.append(try Node.usingnamespace_builtins.init());
390367
391 try prepopulateGlobalNameTable(ast_unit, &context);368 try prepopulateGlobalNameTable(ast_unit, &context);
392369
...@@ -403,29 +380,7 @@ pub fn translate(...@@ -403,29 +380,7 @@ pub fn translate(
403 }380 }
404 }381 }
405382
406 const eof_token = try appendToken(&context, .Eof, "");383 return ast.render(context.global_scope.nodes.items);
407 const root_node = try ast.Node.Root.create(&arena.allocator, context.root_decls.items.len, eof_token);
408 mem.copy(*ast.Node, root_node.decls(), context.root_decls.items);
409
410 if (false) {
411 std.debug.warn("debug source:\n{s}\n==EOF==\ntokens:\n", .{source_buffer.items});
412 for (context.token_ids.items) |token| {
413 std.debug.warn("{}\n", .{token});
414 }
415 }
416
417 const tree = try arena.allocator.create(ast.Tree);
418 tree.* = .{
419 .gpa = gpa,
420 .source = try arena.allocator.dupe(u8, source_buffer.items),
421 .token_ids = context.token_ids.toOwnedSlice(gpa),
422 .token_locs = context.token_locs.toOwnedSlice(gpa),
423 .errors = context.errors.toOwnedSlice(gpa),
424 .root_node = root_node,
425 .arena = arena.state,
426 .generated = true,
427 };
428 return tree;
429}384}
430385
431fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {386fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
...@@ -498,7 +453,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {...@@ -498,7 +453,7 @@ fn declVisitor(c: *Context, decl: *const clang.Decl) Error!void {
498 },453 },
499 else => {454 else => {
500 const decl_name = try c.str(decl.getDeclKindName());455 const decl_name = try c.str(decl.getDeclKindName());
501 try emitWarning(c, decl.getLocation(), "ignoring {s} declaration", .{decl_name});456 try warn(c, decl.getLocation(), "ignoring {s} declaration", .{decl_name});
502 },457 },
503 }458 }
504}459}
...@@ -1880,21 +1835,21 @@ const SuppressCast = enum {...@@ -1880,21 +1835,21 @@ const SuppressCast = enum {
1880 no_as,1835 no_as,
1881};1836};
1882fn transIntegerLiteral(1837fn transIntegerLiteral(
1883 rp: RestorePoint,1838 c: *Context,
1884 scope: *Scope,1839 scope: *Scope,
1885 expr: *const clang.IntegerLiteral,1840 expr: *const clang.IntegerLiteral,
1886 result_used: ResultUsed,1841 result_used: ResultUsed,
1887 suppress_as: SuppressCast,1842 suppress_as: SuppressCast,
1888) TransError!*ast.Node {1843) TransError!Node {
1889 var eval_result: clang.ExprEvalResult = undefined;1844 var eval_result: clang.ExprEvalResult = undefined;
1890 if (!expr.EvaluateAsInt(&eval_result, rp.c.clang_context)) {1845 if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) {
1891 const loc = expr.getBeginLoc();1846 const loc = expr.getBeginLoc();
1892 return revertAndWarn(rp, error.UnsupportedTranslation, loc, "invalid integer literal", .{});1847 return revertAndWarn(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
1893 }1848 }
18941849
1895 if (suppress_as == .no_as) {1850 if (suppress_as == .no_as) {
1896 const int_lit_node = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());1851 const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt());
1897 return maybeSuppressResult(rp, scope, result_used, int_lit_node);1852 return maybeSuppressResult(c, scope, result_used, int_lit_node);
1898 }1853 }
18991854
1900 // Integer literals in C have types, and this can matter for several reasons.1855 // Integer literals in C have types, and this can matter for several reasons.
...@@ -1908,51 +1863,26 @@ fn transIntegerLiteral(...@@ -1908,51 +1863,26 @@ fn transIntegerLiteral(
1908 // But the first step is to be correct, and the next step is to make the output more elegant.1863 // But the first step is to be correct, and the next step is to make the output more elegant.
19091864
1910 // @as(T, x)1865 // @as(T, x)
1911 const expr_base = @ptrCast(*const clang.Expr, expr);1866 const ty_node = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc());
1912 const as_node = try rp.c.createBuiltinCall("@as", 2);1867 const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt());
1913 const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc());1868 const as = try Node.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs });
1914 as_node.params()[0] = ty_node;1869 return maybeSuppressResult(c, scope, result_used, as);
1915 _ = try appendToken(rp.c, .Comma, ",");
1916 as_node.params()[1] = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt());
1917
1918 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1919 return maybeSuppressResult(rp, scope, result_used, &as_node.base);
1920}
1921
1922/// In C if a function has return type `int` and the return value is a boolean
1923/// expression, there is no implicit cast. So the translated Zig will need to
1924/// call @boolToInt
1925fn zigShouldCastBooleanReturnToInt(node: ?*ast.Node, qt: ?clang.QualType) bool {
1926 if (node == null or qt == null) return false;
1927 return isBoolRes(node.?) and cIsNativeInt(qt.?);
1928}1870}
19291871
1930fn transReturnStmt(1872fn transReturnStmt(
1931 rp: RestorePoint,1873 c: *Context,
1932 scope: *Scope,1874 scope: *Scope,
1933 expr: *const clang.ReturnStmt,1875 expr: *const clang.ReturnStmt,
1934) TransError!*ast.Node {1876) TransError!*ast.Node {
1935 const return_kw = try appendToken(rp.c, .Keyword_return, "return");1877 const val_expr = expr.getRetValue() orelse
1936 var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr|1878 return Node.return_void.init();
1937 try transExprCoercing(rp, scope, val_expr, .used, .r_value)
1938 else
1939 null;
1940 const return_qt = scope.findBlockReturnType(rp.c);
1941 if (zigShouldCastBooleanReturnToInt(rhs, return_qt)) {
1942 const bool_to_int_node = try rp.c.createBuiltinCall("@boolToInt", 1);
1943 bool_to_int_node.params()[0] = rhs.?;
1944 bool_to_int_node.rparen_token = try appendToken(rp.c, .RParen, ")");
19451879
1946 rhs = &bool_to_int_node.base;1880 var rhs = try transExprCoercing(c, scope, val_expr, .used, .r_value);
1881 const return_qt = scope.findBlockReturnType(c);
1882 if (isBoolRes(rhs) and !qualTypeIsBoolean(return_qt)) {
1883 rhs = try Node.bool_to_int.create(c.arena, rhs);
1947 }1884 }
1948 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{1885 return Node.@"return".create(c.arena, rhs);
1949 .ltoken = return_kw,
1950 .tag = .Return,
1951 }, .{
1952 .rhs = rhs,
1953 });
1954 _ = try appendToken(rp.c, .Semicolon, ";");
1955 return &return_expr.base;
1956}1886}
19571887
1958fn transStringLiteral(1888fn transStringLiteral(
...@@ -2251,6 +2181,33 @@ fn transExpr(...@@ -2251,6 +2181,33 @@ fn transExpr(
2251 return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue);2181 return transStmt(c, scope, @ptrCast(*const clang.Stmt, expr), used, lrvalue);
2252}2182}
22532183
2184/// Same as `transExpr` but with the knowledge that the operand will be type coerced, and therefore
2185/// an `@as` would be redundant. This is used to prevent redundant `@as` in integer literals.
2186fn transExprCoercing(
2187 c: *Context,
2188 scope: *Scope,
2189 expr: *const clang.Expr,
2190 used: ResultUsed,
2191 lrvalue: LRValue,
2192) TransError!Node {
2193 switch (@ptrCast(*const clang.Stmt, expr).getStmtClass()) {
2194 .IntegerLiteralClass => {
2195 return transIntegerLiteral(c, scope, @ptrCast(*const clang.IntegerLiteral, expr), .used, .no_as);
2196 },
2197 .CharacterLiteralClass => {
2198 return transCharLiteral(c, scope, @ptrCast(*const clang.CharacterLiteral, expr), .used, .no_as);
2199 },
2200 .UnaryOperatorClass => {
2201 const un_expr = @ptrCast(*const clang.UnaryOperator, expr);
2202 if (un_expr.getOpcode() == .Extension) {
2203 return transExprCoercing(c, scope, un_expr.getSubExpr(), used, lrvalue);
2204 }
2205 },
2206 else => {},
2207 }
2208 return transExpr(c, scope, expr, .used, .r_value);
2209}
2210
2254fn transInitListExprRecord(2211fn transInitListExprRecord(
2255 rp: RestorePoint,2212 rp: RestorePoint,
2256 scope: *Scope,2213 scope: *Scope,
...@@ -3257,71 +3214,59 @@ fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {...@@ -3257,71 +3214,59 @@ fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool {
3257 }3214 }
3258}3215}
32593216
3260fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!*ast.Node {3217fn transUnaryOperator(c: *Context, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!Node {
3261 const op_expr = stmt.getSubExpr();3218 const op_expr = stmt.getSubExpr();
3262 switch (stmt.getOpcode()) {3219 switch (stmt.getOpcode()) {
3263 .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType()))3220 .PostInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3264 return transCreatePostCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)3221 return transCreatePostCrement(c, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
3265 else3222 else
3266 return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),3223 return transCreatePostCrement(c, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
3267 .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType()))3224 .PostDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3268 return transCreatePostCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)3225 return transCreatePostCrement(c, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
3269 else3226 else
3270 return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),3227 return transCreatePostCrement(c, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
3271 .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType()))3228 .PreInc => if (qualTypeHasWrappingOverflow(stmt.getType()))
3272 return transCreatePreCrement(rp, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)3229 return transCreatePreCrement(c, scope, stmt, .AssignAddWrap, .PlusPercentEqual, "+%=", used)
3273 else3230 else
3274 return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),3231 return transCreatePreCrement(c, scope, stmt, .AssignAdd, .PlusEqual, "+=", used),
3275 .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType()))3232 .PreDec => if (qualTypeHasWrappingOverflow(stmt.getType()))
3276 return transCreatePreCrement(rp, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)3233 return transCreatePreCrement(c, scope, stmt, .AssignSubWrap, .MinusPercentEqual, "-%=", used)
3277 else3234 else
3278 return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used),3235 return transCreatePreCrement(c, scope, stmt, .AssignSub, .MinusEqual, "-=", used),
3279 .AddrOf => {3236 .AddrOf => {
3280 if (cIsFunctionDeclRef(op_expr)) {3237 if (cIsFunctionDeclRef(op_expr)) {
3281 return transExpr(rp, scope, op_expr, used, .r_value);3238 return transExpr(rp, scope, op_expr, used, .r_value);
3282 }3239 }
3283 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&");3240 return Node.address_of.create(c.arena, try transExpr(c, scope, op_expr, used, .r_value));
3284 op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value);
3285 return &op_node.base;
3286 },3241 },
3287 .Deref => {3242 .Deref => {
3288 const value_node = try transExpr(rp, scope, op_expr, used, .r_value);3243 const node = try transExpr(c, scope, op_expr, used, .r_value);
3289 var is_ptr = false;3244 var is_ptr = false;
3290 const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);3245 const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr);
3291 if (fn_ty != null and is_ptr)3246 if (fn_ty != null and is_ptr)
3292 return value_node;3247 return node;
3293 const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node);3248 return Node.unwrap_deref.create(c.arena, node);
3294 return transCreateNodePtrDeref(rp.c, unwrapped);
3295 },3249 },
3296 .Plus => return transExpr(rp, scope, op_expr, used, .r_value),3250 .Plus => return transExpr(c, scope, op_expr, used, .r_value),
3297 .Minus => {3251 .Minus => {
3298 if (!qualTypeHasWrappingOverflow(op_expr.getType())) {3252 if (!qualTypeHasWrappingOverflow(op_expr.getType())) {
3299 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-");3253 return Node.negate.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
3300 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3301 return &op_node.base;
3302 } else if (cIsUnsignedInteger(op_expr.getType())) {3254 } else if (cIsUnsignedInteger(op_expr.getType())) {
3303 // we gotta emit 0 -% x3255 // use -% x for unsigned integers
3304 const zero = try transCreateNodeInt(rp.c, 0);3256 return Node.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
3305 const token = try appendToken(rp.c, .MinusPercent, "-%");
3306 const expr = try transExpr(rp, scope, op_expr, .used, .r_value);
3307 return transCreateNodeInfixOp(rp, scope, zero, .SubWrap, token, expr, used, true);
3308 } else3257 } else
3309 return revertAndWarn(rp, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{});3258 return revertAndWarn(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "C negation with non float non integer", .{});
3310 },3259 },
3311 .Not => {3260 .Not => {
3312 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~");3261 return Node.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
3313 op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value);
3314 return &op_node.base;
3315 },3262 },
3316 .LNot => {3263 .LNot => {
3317 const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");3264 return Node.not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value));
3318 op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true);
3319 return &op_node.base;
3320 },3265 },
3321 .Extension => {3266 .Extension => {
3322 return transExpr(rp, scope, stmt.getSubExpr(), used, .l_value);3267 return transExpr(c, scope, stmt.getSubExpr(), used, .l_value);
3323 },3268 },
3324 else => return revertAndWarn(rp, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}),3269 else => return revertAndWarn(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "unsupported C translation {}", .{stmt.getOpcode()}),
3325 }3270 }
3326}3271}
33273272
...@@ -3910,8 +3855,7 @@ fn maybeSuppressResult(...@@ -3910,8 +3855,7 @@ fn maybeSuppressResult(
3910 return &op_node.base;3855 return &op_node.base;
3911}3856}
39123857
3913fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void {3858fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
3914 try c.root_decls.append(c.gpa, decl_node);
3915 _ = try c.global_scope.sym_table.put(name, decl_node);3859 _ = try c.global_scope.sym_table.put(name, decl_node);
3916}3860}
39173861
...@@ -4356,7 +4300,7 @@ fn transCreateNodePtrType(...@@ -4356,7 +4300,7 @@ fn transCreateNodePtrType(
4356 return node;4300 return node;
4357}4301}
43584302
4359fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {4303fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node {
4360 const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) {4304 const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) {
4361 error.Overflow => return error.OutOfMemory,4305 error.Overflow => return error.OutOfMemory,
4362 };4306 };
...@@ -4396,14 +4340,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {...@@ -4396,14 +4340,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node {
4396 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {4340 const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) {
4397 error.OutOfMemory => return error.OutOfMemory,4341 error.OutOfMemory => return error.OutOfMemory,
4398 };4342 };
4399 defer c.arena.free(str);4343 return Node.int_literal.create(c.arena, str);
4400 const token = try appendToken(c, .IntegerLiteral, str);
4401 const node = try c.arena.create(ast.Node.OneToken);
4402 node.* = .{
4403 .base = .{ .tag = .IntegerLiteral },
4404 .token = token,
4405 };
4406 return &node.base;
4407}4344}
44084345
4409fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {4346fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
src/translate_c/ast.zig+30-5
...@@ -109,11 +109,16 @@ pub const Node = extern union {...@@ -109,11 +109,16 @@ pub const Node = extern union {
109 div_trunc,109 div_trunc,
110 /// @boolToInt(lhs, rhs)110 /// @boolToInt(lhs, rhs)
111 bool_to_int,111 bool_to_int,
112 /// @as(lhs, rhs)
113 as,
112114
113 negate,115 negate,
114 negate_wrap,116 negate_wrap,
115 bit_not,117 bit_not,
116 not,118 not,
119 address_of,
120 // operand.?.*
121 unwrap_deref,
117122
118 block,123 block,
119 @"break",124 @"break",
...@@ -151,9 +156,8 @@ pub const Node = extern union {...@@ -151,9 +156,8 @@ pub const Node = extern union {
151 .bit_not,156 .bit_not,
152 .not,157 .not,
153 .optional_type,158 .optional_type,
154 .c_pointer,159 .address_of,
155 .single_pointer,160 .unwrap_deref,
156 .array_type,
157 => Payload.UnOp,161 => Payload.UnOp,
158162
159 .add,163 .add,
...@@ -208,6 +212,7 @@ pub const Node = extern union {...@@ -208,6 +212,7 @@ pub const Node = extern union {
208 .rem,212 .rem,
209 .int_cast,213 .int_cast,
210 .bool_to_int,214 .bool_to_int,
215 .as,
211 => Payload.BinOp,216 => Payload.BinOp,
212217
213 .int,218 .int,
...@@ -236,6 +241,9 @@ pub const Node = extern union {...@@ -236,6 +241,9 @@ pub const Node = extern union {
236 .container_init => Payload.ContainerInit,241 .container_init => Payload.ContainerInit,
237 .std_meta_cast => Payload.Infix,242 .std_meta_cast => Payload.Infix,
238 .block => Payload.Block,243 .block => Payload.Block,
244 .c_pointer => Payload.Pointer,
245 .single_pointer => Payload.Pointer,
246 .array_type => Payload.Array,
239 };247 };
240 }248 }
241249
...@@ -424,9 +432,26 @@ pub const Payload = struct {...@@ -424,9 +432,26 @@ pub const Payload = struct {
424 base: Node = .{ .tag = .@"break" },432 base: Node = .{ .tag = .@"break" },
425 data: *Block433 data: *Block
426 };434 };
435
436 pub const Array = struct {
437 base: Node,
438 data: struct {
439 elem_type: Node,
440 len: Node,
441 },
442 };
443
444 pub const Pointer = struct {
445 base: Node,
446 data: struct {
447 elem_type: Node,
448 is_const: bool,
449 is_volatile: bool,
450 },
451 };
427};452};
428453
429/// Converts the nodes into a Zig ast and then renders it.454/// Converts the nodes into a Zig ast.
430pub fn render(allocator: *Allocator, nodes: []const Node) !void {455pub fn render(allocator: *Allocator, nodes: []const Node) !*ast.Tree {
431 @panic("TODO");456 @panic("TODO");
432}457}