| ... | @@ -8,7 +8,6 @@ const ctok = std.c.tokenizer; | ... | @@ -8,7 +8,6 @@ const ctok = std.c.tokenizer; |
| 8 | const CToken = std.c.Token; | 8 | const CToken = std.c.Token; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const math = std.math; | 10 | const math = std.math; |
| 11 | const Type = @import("type.zig").Type; | | |
| 12 | const ast = @import("translate_c/ast.zig"); | 11 | const ast = @import("translate_c/ast.zig"); |
| 13 | const Node = ast.Node; | 12 | const Node = ast.Node; |
| 14 | | 13 | |
| ... | @@ -20,7 +19,7 @@ pub const Error = error{OutOfMemory}; | ... | @@ -20,7 +19,7 @@ pub const Error = error{OutOfMemory}; |
| 20 | const TypeError = Error || error{UnsupportedType}; | 19 | const TypeError = Error || error{UnsupportedType}; |
| 21 | const TransError = TypeError || error{UnsupportedTranslation}; | 20 | const TransError = TypeError || error{UnsupportedTranslation}; |
| 22 | | 21 | |
| 23 | const SymbolTable = std.StringArrayHashMap(*ast.Node); | 22 | const SymbolTable = std.StringArrayHashMap(Node); |
| 24 | const AliasList = std.ArrayList(struct { | 23 | const 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 | }; |
| 40 | | 39 | |
| 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 allocated | 41 | /// 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), |
| 159 | | 159 | |
| 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 | } |
| 171 | | 172 | |
| | 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 | } |
| 197 | | 204 | |
| 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 | }; |
| 252 | | 277 | |
| 253 | pub const Context = struct { | 278 | pub 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) = .{}, |
| 269 | | 288 | |
| 270 | /// This one is different than the root scope's name table. This contains | 289 | /// 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 | }; |
| 331 | | 316 | |
| 332 | pub fn translate( | 317 | pub 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(); |
| 350 | | 335 | |
| 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 return | 336 | // 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 | } |
| 388 | | 365 | |
| 389 | _ = try Node.usingnamespace_builtins.init(); | 366 | try context.global_scope.nodes.append(try Node.usingnamespace_builtins.init()); |
| 390 | | 367 | |
| 391 | try prepopulateGlobalNameTable(ast_unit, &context); | 368 | try prepopulateGlobalNameTable(ast_unit, &context); |
| 392 | | 369 | |
| ... | @@ -403,29 +380,7 @@ pub fn translate( | ... | @@ -403,29 +380,7 @@ pub fn translate( |
| 403 | } | 380 | } |
| 404 | } | 381 | } |
| 405 | | 382 | |
| 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 | } |
| 430 | | 385 | |
| 431 | fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { | 386 | fn 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 | }; |
| 1882 | fn transIntegerLiteral( | 1837 | fn 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 | } |
| 1894 | | 1849 | |
| 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 | } |
| 1899 | | 1854 | |
| 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. |
| 1909 | | 1864 | |
| 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 | | |
| 1925 | fn 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 | } |
| 1929 | | 1871 | |
| 1930 | fn transReturnStmt( | 1872 | fn 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, ")"); | | |
| 1945 | | 1879 | |
| 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 | } |
| 1957 | | 1887 | |
| 1958 | fn transStringLiteral( | 1888 | fn 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 | } |
| 2253 | | 2183 | |
| | 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. |
| | 2186 | fn 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 | |
| 2254 | fn transInitListExprRecord( | 2211 | fn 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 | } |
| 3259 | | 3216 | |
| 3260 | fn transUnaryOperator(rp: RestorePoint, scope: *Scope, stmt: *const clang.UnaryOperator, used: ResultUsed) TransError!*ast.Node { | 3217 | fn 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 | else | 3222 | 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 | else | 3226 | 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 | else | 3230 | 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 | else | 3234 | 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 -% x | 3255 | // 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 | } else | 3257 | } 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 | } |
| 3327 | | 3272 | |
| ... | @@ -3910,8 +3855,7 @@ fn maybeSuppressResult( | ... | @@ -3910,8 +3855,7 @@ fn maybeSuppressResult( |
| 3910 | return &op_node.base; | 3855 | return &op_node.base; |
| 3911 | } | 3856 | } |
| 3912 | | 3857 | |
| 3913 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { | 3858 | fn 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 | } |
| 3917 | | 3861 | |
| ... | @@ -4356,7 +4300,7 @@ fn transCreateNodePtrType( | ... | @@ -4356,7 +4300,7 @@ fn transCreateNodePtrType( |
| 4356 | return node; | 4300 | return node; |
| 4357 | } | 4301 | } |
| 4358 | | 4302 | |
| 4359 | fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node { | 4303 | fn 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 | } |
| 4408 | | 4345 | |
| 4409 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { | 4346 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |