| ... | ... | @@ -8,7 +8,6 @@ const ctok = std.c.tokenizer; |
| 8 | 8 | const CToken = std.c.Token; |
| 9 | 9 | const mem = std.mem; |
| 10 | 10 | const math = std.math; |
| 11 | | const Type = @import("type.zig").Type; |
| 12 | 11 | const ast = @import("translate_c/ast.zig"); |
| 13 | 12 | const Node = ast.Node; |
| 14 | 13 | |
| ... | ... | @@ -20,7 +19,7 @@ pub const Error = error{OutOfMemory}; |
| 20 | 19 | const TypeError = Error || error{UnsupportedType}; |
| 21 | 20 | const TransError = TypeError || error{UnsupportedTranslation}; |
| 22 | 21 | |
| 23 | | const SymbolTable = std.StringArrayHashMap(*ast.Node); |
| 22 | const SymbolTable = std.StringArrayHashMap(Node); |
| 24 | 23 | const AliasList = std.ArrayList(struct { |
| 25 | 24 | alias: []const u8, |
| 26 | 25 | name: []const u8, |
| ... | ... | @@ -38,13 +37,13 @@ const Scope = struct { |
| 38 | 37 | Loop, |
| 39 | 38 | }; |
| 40 | 39 | |
| 41 | | /// Represents an in-progress ast.Node.Switch. This struct is stack-allocated. |
| 42 | | /// When it is deinitialized, it produces an ast.Node.Switch which is allocated |
| 40 | /// Represents an in-progress Node.Switch. This struct is stack-allocated. |
| 41 | /// When it is deinitialized, it produces an Node.Switch which is allocated |
| 43 | 42 | /// into the main arena. |
| 44 | 43 | const Switch = struct { |
| 45 | 44 | base: Scope, |
| 46 | 45 | pending_block: Block, |
| 47 | | cases: []*ast.Node, |
| 46 | cases: []Node, |
| 48 | 47 | case_index: usize, |
| 49 | 48 | switch_label: ?[]const u8, |
| 50 | 49 | default_label: ?[]const u8, |
| ... | ... | @@ -156,6 +155,7 @@ const Scope = struct { |
| 156 | 155 | sym_table: SymbolTable, |
| 157 | 156 | macro_table: SymbolTable, |
| 158 | 157 | context: *Context, |
| 158 | nodes: std.ArrayList(Node), |
| 159 | 159 | |
| 160 | 160 | fn init(c: *Context) Root { |
| 161 | 161 | return .{ |
| ... | ... | @@ -163,12 +163,19 @@ const Scope = struct { |
| 163 | 163 | .id = .Root, |
| 164 | 164 | .parent = null, |
| 165 | 165 | }, |
| 166 | | .sym_table = SymbolTable.init(c.arena), |
| 167 | | .macro_table = SymbolTable.init(c.arena), |
| 166 | .sym_table = SymbolTable.init(c.gpa), |
| 167 | .macro_table = SymbolTable.init(c.gpa), |
| 168 | 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 | 179 | /// Check if the global scope contains this name, without looking into the "future", e.g. |
| 173 | 180 | /// ignore the preprocessed decl and macro names. |
| 174 | 181 | fn containsNow(scope: *Root, name: []const u8) bool { |
| ... | ... | @@ -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 | 206 | var scope = inner; |
| 200 | 207 | while (true) { |
| 201 | 208 | switch (scope.id) { |
| 202 | | .Root => return null, |
| 209 | .Root => unreachable, |
| 203 | 210 | .Block => { |
| 204 | 211 | const block = @fieldParentPtr(Block, "base", scope); |
| 205 | 212 | if (block.return_type) |qt| return qt; |
| ... | ... | @@ -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 | 278 | pub const Context = struct { |
| 254 | 279 | gpa: *mem.Allocator, |
| 255 | 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 | 281 | source_manager: *clang.SourceManager, |
| 262 | 282 | decl_table: std.AutoArrayHashMapUnmanaged(usize, []const u8) = .{}, |
| 263 | 283 | alias_list: AliasList, |
| 264 | 284 | global_scope: *Scope.Root, |
| 265 | 285 | clang_context: *clang.ASTContext, |
| 266 | 286 | mangle_count: u32 = 0, |
| 267 | | root_decls: std.ArrayListUnmanaged(*ast.Node) = .{}, |
| 268 | 287 | opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{}, |
| 269 | 288 | |
| 270 | 289 | /// This one is different than the root scope's name table. This contains |
| ... | ... | @@ -293,40 +312,6 @@ pub const Context = struct { |
| 293 | 312 | const column = c.source_manager.getSpellingColumnNumber(spelling_loc); |
| 294 | 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 | 317 | pub fn translate( |
| ... | ... | @@ -348,9 +333,6 @@ pub fn translate( |
| 348 | 333 | }; |
| 349 | 334 | defer ast_unit.delete(); |
| 350 | 335 | |
| 351 | | var source_buffer = std.ArrayList(u8).init(gpa); |
| 352 | | defer source_buffer.deinit(); |
| 353 | | |
| 354 | 336 | // For memory that has the same lifetime as the Tree that we return |
| 355 | 337 | // from this function. |
| 356 | 338 | var arena = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -367,9 +349,7 @@ pub fn translate( |
| 367 | 349 | var context = Context{ |
| 368 | 350 | .gpa = gpa, |
| 369 | 351 | .arena = &arena.allocator, |
| 370 | | .source_buffer = &source_buffer, |
| 371 | 352 | .source_manager = ast_unit.getSourceManager(), |
| 372 | | .err = undefined, |
| 373 | 353 | .alias_list = AliasList.init(gpa), |
| 374 | 354 | .global_scope = try arena.allocator.create(Scope.Root), |
| 375 | 355 | .clang_context = ast_unit.getASTContext(), |
| ... | ... | @@ -378,15 +358,12 @@ pub fn translate( |
| 378 | 358 | defer { |
| 379 | 359 | context.decl_table.deinit(gpa); |
| 380 | 360 | context.alias_list.deinit(); |
| 381 | | context.token_ids.deinit(gpa); |
| 382 | | context.token_locs.deinit(gpa); |
| 383 | | context.errors.deinit(gpa); |
| 384 | 361 | context.global_names.deinit(gpa); |
| 385 | | context.root_decls.deinit(gpa); |
| 386 | 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 | 368 | try prepopulateGlobalNameTable(ast_unit, &context); |
| 392 | 369 | |
| ... | ... | @@ -403,29 +380,7 @@ pub fn translate( |
| 403 | 380 | } |
| 404 | 381 | } |
| 405 | 382 | |
| 406 | | const eof_token = try appendToken(&context, .Eof, ""); |
| 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; |
| 383 | return ast.render(context.global_scope.nodes.items); |
| 429 | 384 | } |
| 430 | 385 | |
| 431 | 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 | 453 | }, |
| 499 | 454 | else => { |
| 500 | 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 | 1835 | no_as, |
| 1881 | 1836 | }; |
| 1882 | 1837 | fn transIntegerLiteral( |
| 1883 | | rp: RestorePoint, |
| 1838 | c: *Context, |
| 1884 | 1839 | scope: *Scope, |
| 1885 | 1840 | expr: *const clang.IntegerLiteral, |
| 1886 | 1841 | result_used: ResultUsed, |
| 1887 | 1842 | suppress_as: SuppressCast, |
| 1888 | | ) TransError!*ast.Node { |
| 1843 | ) TransError!Node { |
| 1889 | 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 | 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 | 1850 | if (suppress_as == .no_as) { |
| 1896 | | const int_lit_node = try transCreateNodeAPInt(rp.c, eval_result.Val.getInt()); |
| 1897 | | return maybeSuppressResult(rp, scope, result_used, int_lit_node); |
| 1851 | const int_lit_node = try transCreateNodeAPInt(c, eval_result.Val.getInt()); |
| 1852 | return maybeSuppressResult(c, scope, result_used, int_lit_node); |
| 1898 | 1853 | } |
| 1899 | 1854 | |
| 1900 | 1855 | // Integer literals in C have types, and this can matter for several reasons. |
| ... | ... | @@ -1908,51 +1863,26 @@ fn transIntegerLiteral( |
| 1908 | 1863 | // But the first step is to be correct, and the next step is to make the output more elegant. |
| 1909 | 1864 | |
| 1910 | 1865 | // @as(T, x) |
| 1911 | | const expr_base = @ptrCast(*const clang.Expr, expr); |
| 1912 | | const as_node = try rp.c.createBuiltinCall("@as", 2); |
| 1913 | | const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc()); |
| 1914 | | as_node.params()[0] = ty_node; |
| 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.?); |
| 1866 | const ty_node = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()); |
| 1867 | const rhs = try transCreateNodeAPInt(c, eval_result.Val.getInt()); |
| 1868 | const as = try Node.as.create(c.arena, .{ .lhs = ty_node, .rhs = rhs }); |
| 1869 | return maybeSuppressResult(c, scope, result_used, as); |
| 1928 | 1870 | } |
| 1929 | 1871 | |
| 1930 | 1872 | fn transReturnStmt( |
| 1931 | | rp: RestorePoint, |
| 1873 | c: *Context, |
| 1932 | 1874 | scope: *Scope, |
| 1933 | 1875 | expr: *const clang.ReturnStmt, |
| 1934 | 1876 | ) TransError!*ast.Node { |
| 1935 | | const return_kw = try appendToken(rp.c, .Keyword_return, "return"); |
| 1936 | | var rhs: ?*ast.Node = if (expr.getRetValue()) |val_expr| |
| 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, ")"); |
| 1877 | const val_expr = expr.getRetValue() orelse |
| 1878 | return Node.return_void.init(); |
| 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, .{ |
| 1949 | | .ltoken = return_kw, |
| 1950 | | .tag = .Return, |
| 1951 | | }, .{ |
| 1952 | | .rhs = rhs, |
| 1953 | | }); |
| 1954 | | _ = try appendToken(rp.c, .Semicolon, ";"); |
| 1955 | | return &return_expr.base; |
| 1885 | return Node.@"return".create(c.arena, rhs); |
| 1956 | 1886 | } |
| 1957 | 1887 | |
| 1958 | 1888 | fn transStringLiteral( |
| ... | ... | @@ -2251,6 +2181,33 @@ fn transExpr( |
| 2251 | 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 | 2211 | fn transInitListExprRecord( |
| 2255 | 2212 | rp: RestorePoint, |
| 2256 | 2213 | scope: *Scope, |
| ... | ... | @@ -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 | 3218 | const op_expr = stmt.getSubExpr(); |
| 3262 | 3219 | switch (stmt.getOpcode()) { |
| 3263 | 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 | 3222 | else |
| 3266 | | return transCreatePostCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used), |
| 3223 | return transCreatePostCrement(c, scope, stmt, .AssignAdd, .PlusEqual, "+=", used), |
| 3267 | 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 | 3226 | else |
| 3270 | | return transCreatePostCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3227 | return transCreatePostCrement(c, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3271 | 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 | 3230 | else |
| 3274 | | return transCreatePreCrement(rp, scope, stmt, .AssignAdd, .PlusEqual, "+=", used), |
| 3231 | return transCreatePreCrement(c, scope, stmt, .AssignAdd, .PlusEqual, "+=", used), |
| 3275 | 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 | 3234 | else |
| 3278 | | return transCreatePreCrement(rp, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3235 | return transCreatePreCrement(c, scope, stmt, .AssignSub, .MinusEqual, "-=", used), |
| 3279 | 3236 | .AddrOf => { |
| 3280 | 3237 | if (cIsFunctionDeclRef(op_expr)) { |
| 3281 | 3238 | return transExpr(rp, scope, op_expr, used, .r_value); |
| 3282 | 3239 | } |
| 3283 | | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .AddressOf, .Ampersand, "&"); |
| 3284 | | op_node.rhs = try transExpr(rp, scope, op_expr, used, .r_value); |
| 3285 | | return &op_node.base; |
| 3240 | return Node.address_of.create(c.arena, try transExpr(c, scope, op_expr, used, .r_value)); |
| 3286 | 3241 | }, |
| 3287 | 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 | 3244 | var is_ptr = false; |
| 3290 | 3245 | const fn_ty = qualTypeGetFnProto(op_expr.getType(), &is_ptr); |
| 3291 | 3246 | if (fn_ty != null and is_ptr) |
| 3292 | | return value_node; |
| 3293 | | const unwrapped = try transCreateNodeUnwrapNull(rp.c, value_node); |
| 3294 | | return transCreateNodePtrDeref(rp.c, unwrapped); |
| 3247 | return node; |
| 3248 | return Node.unwrap_deref.create(c.arena, node); |
| 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 | 3251 | .Minus => { |
| 3298 | 3252 | if (!qualTypeHasWrappingOverflow(op_expr.getType())) { |
| 3299 | | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .Negation, .Minus, "-"); |
| 3300 | | op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3301 | | return &op_node.base; |
| 3253 | return Node.negate.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); |
| 3302 | 3254 | } else if (cIsUnsignedInteger(op_expr.getType())) { |
| 3303 | | // we gotta emit 0 -% x |
| 3304 | | const zero = try transCreateNodeInt(rp.c, 0); |
| 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); |
| 3255 | // use -% x for unsigned integers |
| 3256 | return Node.negate_wrap.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); |
| 3308 | 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 | 3260 | .Not => { |
| 3312 | | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BitNot, .Tilde, "~"); |
| 3313 | | op_node.rhs = try transExpr(rp, scope, op_expr, .used, .r_value); |
| 3314 | | return &op_node.base; |
| 3261 | return Node.bit_not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); |
| 3315 | 3262 | }, |
| 3316 | 3263 | .LNot => { |
| 3317 | | const op_node = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!"); |
| 3318 | | op_node.rhs = try transBoolExpr(rp, scope, op_expr, .used, .r_value, true); |
| 3319 | | return &op_node.base; |
| 3264 | return Node.not.create(c.arena, try transExpr(c, scope, op_expr, .used, .r_value)); |
| 3320 | 3265 | }, |
| 3321 | 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 | 3855 | return &op_node.base; |
| 3911 | 3856 | } |
| 3912 | 3857 | |
| 3913 | | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { |
| 3914 | | try c.root_decls.append(c.gpa, decl_node); |
| 3858 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void { |
| 3915 | 3859 | _ = try c.global_scope.sym_table.put(name, decl_node); |
| 3916 | 3860 | } |
| 3917 | 3861 | |
| ... | ... | @@ -4356,7 +4300,7 @@ fn transCreateNodePtrType( |
| 4356 | 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 | 4304 | const num_limbs = math.cast(usize, int.getNumWords()) catch |err| switch (err) { |
| 4361 | 4305 | error.Overflow => return error.OutOfMemory, |
| 4362 | 4306 | }; |
| ... | ... | @@ -4396,14 +4340,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !*ast.Node { |
| 4396 | 4340 | const str = big.toStringAlloc(c.arena, 10, false) catch |err| switch (err) { |
| 4397 | 4341 | error.OutOfMemory => return error.OutOfMemory, |
| 4398 | 4342 | }; |
| 4399 | | defer c.arena.free(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; |
| 4343 | return Node.int_literal.create(c.arena, str); |
| 4407 | 4344 | } |
| 4408 | 4345 | |
| 4409 | 4346 | fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { |