| ... | @@ -43,7 +43,7 @@ const Scope = struct { | ... | @@ -43,7 +43,7 @@ const Scope = struct { |
| 43 | const Switch = struct { | 43 | const Switch = struct { |
| 44 | base: Scope, | 44 | base: Scope, |
| 45 | pending_block: Block, | 45 | pending_block: Block, |
| 46 | cases: []Node, | 46 | cases: std.ArrayList(Node), |
| 47 | case_index: usize, | 47 | case_index: usize, |
| 48 | switch_label: ?[]const u8, | 48 | switch_label: ?[]const u8, |
| 49 | default_label: ?[]const u8, | 49 | default_label: ?[]const u8, |
| ... | @@ -1087,7 +1087,7 @@ fn transStmt( | ... | @@ -1087,7 +1087,7 @@ fn transStmt( |
| 1087 | return maybeSuppressResult(c, scope, result_used, expr); | 1087 | return maybeSuppressResult(c, scope, result_used, expr); |
| 1088 | }, | 1088 | }, |
| 1089 | else => { | 1089 | else => { |
| 1090 | return revertAndWarn( | 1090 | return fail( |
| 1091 | rp, | 1091 | rp, |
| 1092 | error.UnsupportedTranslation, | 1092 | error.UnsupportedTranslation, |
| 1093 | stmt.getBeginLoc(), | 1093 | stmt.getBeginLoc(), |
| ... | @@ -1348,7 +1348,7 @@ fn transDeclStmtOne( | ... | @@ -1348,7 +1348,7 @@ fn transDeclStmtOne( |
| 1348 | return error.UnsupportedTranslation; | 1348 | return error.UnsupportedTranslation; |
| 1349 | return node; | 1349 | return node; |
| 1350 | }, | 1350 | }, |
| 1351 | else => |kind| return revertAndWarn( | 1351 | else => |kind| return fail( |
| 1352 | rp, | 1352 | rp, |
| 1353 | error.UnsupportedTranslation, | 1353 | error.UnsupportedTranslation, |
| 1354 | decl.getLocation(), | 1354 | decl.getLocation(), |
| ... | @@ -1440,7 +1440,7 @@ fn transImplicitCastExpr( | ... | @@ -1440,7 +1440,7 @@ fn transImplicitCastExpr( |
| 1440 | .BuiltinFnToFnPtr => { | 1440 | .BuiltinFnToFnPtr => { |
| 1441 | return transExpr(rp, scope, sub_expr, result_used, .r_value); | 1441 | return transExpr(rp, scope, sub_expr, result_used, .r_value); |
| 1442 | }, | 1442 | }, |
| 1443 | else => |kind| return revertAndWarn( | 1443 | else => |kind| return fail( |
| 1444 | rp, | 1444 | rp, |
| 1445 | error.UnsupportedTranslation, | 1445 | error.UnsupportedTranslation, |
| 1446 | @ptrCast(*const clang.Stmt, expr).getBeginLoc(), | 1446 | @ptrCast(*const clang.Stmt, expr).getBeginLoc(), |
| ... | @@ -1460,7 +1460,7 @@ fn transBoolExpr( | ... | @@ -1460,7 +1460,7 @@ fn transBoolExpr( |
| 1460 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { | 1460 | if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { |
| 1461 | var is_zero: bool = undefined; | 1461 | var is_zero: bool = undefined; |
| 1462 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { | 1462 | if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { |
| 1463 | return revertAndWarn(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); | 1463 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); |
| 1464 | } | 1464 | } |
| 1465 | return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)] }; | 1465 | return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)] }; |
| 1466 | } | 1466 | } |
| ... | @@ -1605,7 +1605,7 @@ fn transIntegerLiteral( | ... | @@ -1605,7 +1605,7 @@ fn transIntegerLiteral( |
| 1605 | var eval_result: clang.ExprEvalResult = undefined; | 1605 | var eval_result: clang.ExprEvalResult = undefined; |
| 1606 | if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) { | 1606 | if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) { |
| 1607 | const loc = expr.getBeginLoc(); | 1607 | const loc = expr.getBeginLoc(); |
| 1608 | return revertAndWarn(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); | 1608 | return fail(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); |
| 1609 | } | 1609 | } |
| 1610 | | 1610 | |
| 1611 | if (suppress_as == .no_as) { | 1611 | if (suppress_as == .no_as) { |
| ... | @@ -2144,7 +2144,6 @@ fn transDoWhileLoop( | ... | @@ -2144,7 +2144,6 @@ fn transDoWhileLoop( |
| 2144 | block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete. | 2144 | block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete. |
| 2145 | block.data.stmts[block.data.stmts.len - 1] = if_not_break; | 2145 | block.data.stmts[block.data.stmts.len - 1] = if_not_break; |
| 2146 | break :blk node; | 2146 | break :blk node; |
| 2147 | | | |
| 2148 | } else blk: { | 2147 | } else blk: { |
| 2149 | // the C statement is without a block, so we need to create a block to contain it. | 2148 | // the C statement is without a block, so we need to create a block to contain it. |
| 2150 | // c: do | 2149 | // c: do |
| ... | @@ -2209,27 +2208,11 @@ fn transForLoop( | ... | @@ -2209,27 +2208,11 @@ fn transForLoop( |
| 2209 | } | 2208 | } |
| 2210 | } | 2209 | } |
| 2211 | | 2210 | |
| 2212 | fn getSwitchCaseCount(stmt: *const clang.SwitchStmt) usize { | | |
| 2213 | const body = stmt.getBody(); | | |
| 2214 | assert(body.getStmtClass() == .CompoundStmtClass); | | |
| 2215 | const comp = @ptrCast(*const clang.CompoundStmt, body); | | |
| 2216 | // TODO https://github.com/ziglang/zig/issues/1738 | | |
| 2217 | // return comp.body_end() - comp.body_begin(); | | |
| 2218 | const start_addr = @ptrToInt(comp.body_begin()); | | |
| 2219 | const end_addr = @ptrToInt(comp.body_end()); | | |
| 2220 | return (end_addr - start_addr) / @sizeOf(*clang.Stmt); | | |
| 2221 | } | | |
| 2222 | | | |
| 2223 | fn transSwitch( | 2211 | fn transSwitch( |
| 2224 | rp: RestorePoint, | 2212 | c: *Context, |
| 2225 | scope: *Scope, | 2213 | scope: *Scope, |
| 2226 | stmt: *const clang.SwitchStmt, | 2214 | stmt: *const clang.SwitchStmt, |
| 2227 | ) TransError!*ast.Node { | 2215 | ) TransError!Node { |
| 2228 | const switch_tok = try appendToken(rp.c, .Keyword_switch, "switch"); | | |
| 2229 | _ = try appendToken(rp.c, .LParen, "("); | | |
| 2230 | | | |
| 2231 | const cases_len = getSwitchCaseCount(stmt); | | |
| 2232 | | | |
| 2233 | var cond_scope = Scope.Condition{ | 2216 | var cond_scope = Scope.Condition{ |
| 2234 | .base = .{ | 2217 | .base = .{ |
| 2235 | .parent = scope, | 2218 | .parent = scope, |
| ... | @@ -2237,16 +2220,13 @@ fn transSwitch( | ... | @@ -2237,16 +2220,13 @@ fn transSwitch( |
| 2237 | }, | 2220 | }, |
| 2238 | }; | 2221 | }; |
| 2239 | defer cond_scope.deinit(); | 2222 | defer cond_scope.deinit(); |
| 2240 | const switch_expr = try transExpr(rp, &cond_scope.base, stmt.getCond(), .used, .r_value); | 2223 | const switch_expr = try transExpr(c, &cond_scope.base, stmt.getCond(), .used, .r_value); |
| 2241 | _ = try appendToken(rp.c, .RParen, ")"); | 2224 | const switch_node = try c.arena.create(ast.Payload.Switch); |
| 2242 | _ = try appendToken(rp.c, .LBrace, "{"); | | |
| 2243 | // reserve +1 case in case there is no default case | | |
| 2244 | const switch_node = try ast.Node.Switch.alloc(rp.c.arena, cases_len + 1); | | |
| 2245 | switch_node.* = .{ | 2225 | switch_node.* = .{ |
| 2246 | .switch_token = switch_tok, | 2226 | .data = .{ |
| 2247 | .expr = switch_expr, | 2227 | .cond = switch_expr, |
| 2248 | .cases_len = cases_len + 1, | 2228 | .cases = undefined, // set later |
| 2249 | .rbrace = try appendToken(rp.c, .RBrace, "}"), | 2229 | }, |
| 2250 | }; | 2230 | }; |
| 2251 | | 2231 | |
| 2252 | var switch_scope = Scope.Switch{ | 2232 | var switch_scope = Scope.Switch{ |
| ... | @@ -2254,29 +2234,32 @@ fn transSwitch( | ... | @@ -2254,29 +2234,32 @@ fn transSwitch( |
| 2254 | .id = .Switch, | 2234 | .id = .Switch, |
| 2255 | .parent = scope, | 2235 | .parent = scope, |
| 2256 | }, | 2236 | }, |
| 2257 | .cases = switch_node.cases(), | 2237 | .cases = std.ArrayList(Node).init(c.gpa), |
| 2258 | .case_index = 0, | | |
| 2259 | .pending_block = undefined, | 2238 | .pending_block = undefined, |
| 2260 | .default_label = null, | 2239 | .default_label = null, |
| 2261 | .switch_label = null, | 2240 | .switch_label = null, |
| 2262 | }; | 2241 | }; |
| | 2242 | defer { |
| | 2243 | switch_node.data.cases = try c.arena.dupe(Node, switch_scope.cases.items); |
| | 2244 | switch_node.data.default = switch_scope.switch_label; |
| | 2245 | switch_scope.cases.deinit(); |
| | 2246 | } |
| 2263 | | 2247 | |
| 2264 | // tmp block that all statements will go before being picked up by a case or default | 2248 | // tmp block that all statements will go before being picked up by a case or default |
| 2265 | var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, false); | 2249 | var block_scope = try Scope.Block.init(c, &switch_scope.base, false); |
| 2266 | defer block_scope.deinit(); | 2250 | defer block_scope.deinit(); |
| 2267 | | 2251 | |
| 2268 | // Note that we do not defer a deinit here; the switch_scope.pending_block field | 2252 | // Note that we do not defer a deinit here; the switch_scope.pending_block field |
| 2269 | // has its own memory management. This resource is freed inside `transCase` and | 2253 | // has its own memory management. This resource is freed inside `transCase` and |
| 2270 | // then the final pending_block is freed at the bottom of this function with | 2254 | // then the final pending_block is freed at the bottom of this function with |
| 2271 | // pending_block.deinit(). | 2255 | // pending_block.deinit(). |
| 2272 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); | 2256 | switch_scope.pending_block = try Scope.Block.init(c, scope, false); |
| 2273 | try switch_scope.pending_block.statements.append(&switch_node.base); | 2257 | try switch_scope.pending_block.statements.append(Node.initPayload(&switch_node.base)); |
| 2274 | | 2258 | |
| 2275 | const last = try transStmt(rp, &block_scope.base, stmt.getBody(), .unused, .r_value); | 2259 | const last = try transStmt(c, &block_scope.base, stmt.getBody(), .unused, .r_value); |
| 2276 | _ = try appendToken(rp.c, .Semicolon, ";"); | | |
| 2277 | | 2260 | |
| 2278 | // take all pending statements | 2261 | // take all pending statements |
| 2279 | const last_block_stmts = last.cast(ast.Node.Block).?.statements(); | 2262 | const last_block_stmts = last.castTag(.block).?.data.stmts; |
| 2280 | try switch_scope.pending_block.statements.ensureCapacity( | 2263 | try switch_scope.pending_block.statements.ensureCapacity( |
| 2281 | switch_scope.pending_block.statements.items.len + last_block_stmts.len, | 2264 | switch_scope.pending_block.statements.items.len + last_block_stmts.len, |
| 2282 | ); | 2265 | ); |
| ... | @@ -2285,213 +2268,159 @@ fn transSwitch( | ... | @@ -2285,213 +2268,159 @@ fn transSwitch( |
| 2285 | } | 2268 | } |
| 2286 | | 2269 | |
| 2287 | if (switch_scope.default_label == null) { | 2270 | if (switch_scope.default_label == null) { |
| 2288 | switch_scope.switch_label = try block_scope.makeMangledName(rp.c, "switch"); | 2271 | switch_scope.switch_label = try block_scope.makeMangledName(c, "switch"); |
| 2289 | } | 2272 | } |
| 2290 | if (switch_scope.switch_label) |l| { | 2273 | if (switch_scope.switch_label) |l| { |
| 2291 | switch_scope.pending_block.label = try appendIdentifier(rp.c, l); | 2274 | switch_scope.pending_block.label = l; |
| 2292 | _ = try appendToken(rp.c, .Colon, ":"); | | |
| 2293 | } | 2275 | } |
| 2294 | if (switch_scope.default_label == null) { | 2276 | if (switch_scope.default_label == null) { |
| 2295 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | 2277 | const else_prong = try Node.switch_else.create( |
| 2296 | else_prong.expr = blk: { | 2278 | c.arena, |
| 2297 | var br = try CtrlFlow.init(rp.c, .Break, switch_scope.switch_label.?); | 2279 | try Node.@"break".create(c.arena, switch_scope.switch_label.?), |
| 2298 | break :blk &(try br.finish(null)).base; | 2280 | ); |
| 2299 | }; | 2281 | switch_scope.cases.append(else_prong); |
| 2300 | _ = try appendToken(rp.c, .Comma, ","); | | |
| 2301 | | | |
| 2302 | if (switch_scope.case_index >= switch_scope.cases.len) | | |
| 2303 | return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{}); | | |
| 2304 | switch_scope.cases[switch_scope.case_index] = &else_prong.base; | | |
| 2305 | switch_scope.case_index += 1; | | |
| 2306 | } | 2282 | } |
| 2307 | // We overallocated in case there was no default, so now we correct | | |
| 2308 | // the number of cases in the AST node. | | |
| 2309 | switch_node.cases_len = switch_scope.case_index; | | |
| 2310 | | 2283 | |
| 2311 | const result_node = try switch_scope.pending_block.complete(rp.c); | 2284 | const result_node = try switch_scope.pending_block.complete(c); |
| 2312 | switch_scope.pending_block.deinit(); | 2285 | switch_scope.pending_block.deinit(); |
| 2313 | return result_node; | 2286 | return result_node; |
| 2314 | } | 2287 | } |
| 2315 | | 2288 | |
| 2316 | fn transCase( | 2289 | fn transCase( |
| 2317 | rp: RestorePoint, | 2290 | c: *Context, |
| 2318 | scope: *Scope, | 2291 | scope: *Scope, |
| 2319 | stmt: *const clang.CaseStmt, | 2292 | stmt: *const clang.CaseStmt, |
| 2320 | ) TransError!*ast.Node { | 2293 | ) TransError!Node { |
| 2321 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | 2294 | const block_scope = scope.findBlockScope(c) catch unreachable; |
| 2322 | const switch_scope = scope.getSwitch(); | 2295 | const switch_scope = scope.getSwitch(); |
| 2323 | const label = try block_scope.makeMangledName(rp.c, "case"); | 2296 | const label = try block_scope.makeMangledName(c, "case"); |
| 2324 | _ = try appendToken(rp.c, .Semicolon, ";"); | | |
| 2325 | | 2297 | |
| 2326 | const expr = if (stmt.getRHS()) |rhs| blk: { | 2298 | const expr = if (stmt.getRHS()) |rhs| blk: { |
| 2327 | const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .r_value); | 2299 | const lhs_node = try transExpr(c, scope, stmt.getLHS(), .used, .r_value); |
| 2328 | const ellips = try appendToken(rp.c, .Ellipsis3, "..."); | 2300 | const rhs_node = try transExpr(c, scope, rhs, .used, .r_value); |
| 2329 | const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value); | | |
| 2330 | | | |
| 2331 | const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); | | |
| 2332 | node.* = .{ | | |
| 2333 | .base = .{ .tag = .Range }, | | |
| 2334 | .op_token = ellips, | | |
| 2335 | .lhs = lhs_node, | | |
| 2336 | .rhs = rhs_node, | | |
| 2337 | }; | | |
| 2338 | break :blk &node.base; | | |
| 2339 | } else | | |
| 2340 | try transExpr(rp, scope, stmt.getLHS(), .used, .r_value); | | |
| 2341 | | 2301 | |
| 2342 | const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); | 2302 | break :blk Node.ellipsis3.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node }); |
| 2343 | switch_prong.expr = blk: { | 2303 | } else |
| 2344 | var br = try CtrlFlow.init(rp.c, .Break, label); | 2304 | try transExpr(c, scope, stmt.getLHS(), .used, .r_value); |
| 2345 | break :blk &(try br.finish(null)).base; | | |
| 2346 | }; | | |
| 2347 | _ = try appendToken(rp.c, .Comma, ","); | | |
| 2348 | | 2305 | |
| 2349 | if (switch_scope.case_index >= switch_scope.cases.len) | 2306 | const switch_prong = try Node.switch_prong.create( |
| 2350 | return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{}); | 2307 | c.arena, |
| 2351 | switch_scope.cases[switch_scope.case_index] = &switch_prong.base; | 2308 | try Node.@"break".create(c.arena, label), |
| 2352 | switch_scope.case_index += 1; | 2309 | ); |
| | 2310 | switch_scope.cases.append(switch_prong); |
| 2353 | | 2311 | |
| 2354 | switch_scope.pending_block.label = try appendIdentifier(rp.c, label); | 2312 | switch_scope.pending_block.label = label; |
| 2355 | _ = try appendToken(rp.c, .Colon, ":"); | | |
| 2356 | | 2313 | |
| 2357 | // take all pending statements | 2314 | // take all pending statements |
| 2358 | try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); | 2315 | try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); |
| 2359 | block_scope.statements.shrinkAndFree(0); | 2316 | block_scope.statements.shrinkAndFree(0); |
| 2360 | | 2317 | |
| 2361 | const pending_node = try switch_scope.pending_block.complete(rp.c); | 2318 | const pending_node = try switch_scope.pending_block.complete(c); |
| 2362 | switch_scope.pending_block.deinit(); | 2319 | switch_scope.pending_block.deinit(); |
| 2363 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); | 2320 | switch_scope.pending_block = try Scope.Block.init(c, scope, false); |
| 2364 | | 2321 | |
| 2365 | try switch_scope.pending_block.statements.append(pending_node); | 2322 | try switch_scope.pending_block.statements.append(pending_node); |
| 2366 | | 2323 | |
| 2367 | return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value); | 2324 | return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value); |
| 2368 | } | 2325 | } |
| 2369 | | 2326 | |
| 2370 | fn transDefault( | 2327 | fn transDefault( |
| 2371 | rp: RestorePoint, | 2328 | c: *Context, |
| 2372 | scope: *Scope, | 2329 | scope: *Scope, |
| 2373 | stmt: *const clang.DefaultStmt, | 2330 | stmt: *const clang.DefaultStmt, |
| 2374 | ) TransError!*ast.Node { | 2331 | ) TransError!Node { |
| 2375 | const block_scope = scope.findBlockScope(rp.c) catch unreachable; | 2332 | const block_scope = scope.findBlockScope(c) catch unreachable; |
| 2376 | const switch_scope = scope.getSwitch(); | 2333 | const switch_scope = scope.getSwitch(); |
| 2377 | switch_scope.default_label = try block_scope.makeMangledName(rp.c, "default"); | 2334 | switch_scope.default_label = try block_scope.makeMangledName(c, "default"); |
| 2378 | _ = try appendToken(rp.c, .Semicolon, ";"); | | |
| 2379 | | | |
| 2380 | const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); | | |
| 2381 | else_prong.expr = blk: { | | |
| 2382 | var br = try CtrlFlow.init(rp.c, .Break, switch_scope.default_label.?); | | |
| 2383 | break :blk &(try br.finish(null)).base; | | |
| 2384 | }; | | |
| 2385 | _ = try appendToken(rp.c, .Comma, ","); | | |
| 2386 | | 2335 | |
| 2387 | if (switch_scope.case_index >= switch_scope.cases.len) | 2336 | const else_prong = try Node.switch_else.create( |
| 2388 | return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{}); | 2337 | c.arena, |
| 2389 | switch_scope.cases[switch_scope.case_index] = &else_prong.base; | 2338 | try Node.@"break".create(c.arena, switch_scope.default_label.?), |
| 2390 | switch_scope.case_index += 1; | 2339 | ); |
| 2391 | | 2340 | switch_scope.cases.append(else_prong); |
| 2392 | switch_scope.pending_block.label = try appendIdentifier(rp.c, switch_scope.default_label.?); | 2341 | switch_scope.pending_block.label = try appendIdentifier(c, switch_scope.default_label.?); |
| 2393 | _ = try appendToken(rp.c, .Colon, ":"); | | |
| 2394 | | 2342 | |
| 2395 | // take all pending statements | 2343 | // take all pending statements |
| 2396 | try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); | 2344 | try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); |
| 2397 | block_scope.statements.shrinkAndFree(0); | 2345 | block_scope.statements.shrinkAndFree(0); |
| 2398 | | 2346 | |
| 2399 | const pending_node = try switch_scope.pending_block.complete(rp.c); | 2347 | const pending_node = try switch_scope.pending_block.complete(c); |
| 2400 | switch_scope.pending_block.deinit(); | 2348 | switch_scope.pending_block.deinit(); |
| 2401 | switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); | 2349 | switch_scope.pending_block = try Scope.Block.init(c, scope, false); |
| 2402 | try switch_scope.pending_block.statements.append(pending_node); | 2350 | try switch_scope.pending_block.statements.append(pending_node); |
| 2403 | | 2351 | |
| 2404 | return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value); | 2352 | return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value); |
| 2405 | } | 2353 | } |
| 2406 | | 2354 | |
| 2407 | fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!*ast.Node { | 2355 | fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node { |
| 2408 | var result: clang.ExprEvalResult = undefined; | 2356 | var result: clang.ExprEvalResult = undefined; |
| 2409 | if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, rp.c.clang_context)) | 2357 | if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context)) |
| 2410 | return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{}); | 2358 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{}); |
| 2411 | | 2359 | |
| 2412 | var val_node: ?*ast.Node = null; | | |
| 2413 | switch (result.Val.getKind()) { | 2360 | switch (result.Val.getKind()) { |
| 2414 | .Int => { | 2361 | .Int => { |
| 2415 | // See comment in `transIntegerLiteral` for why this code is here. | 2362 | // See comment in `transIntegerLiteral` for why this code is here. |
| 2416 | // @as(T, x) | 2363 | // @as(T, x) |
| 2417 | const expr_base = @ptrCast(*const clang.Expr, expr); | 2364 | const expr_base = @ptrCast(*const clang.Expr, expr); |
| 2418 | const as_node = try rp.c.createBuiltinCall("@as", 2); | 2365 | const as_node = try Node.as.create(c.arena, .{ |
| 2419 | const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc()); | 2366 | .lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()), |
| 2420 | as_node.params()[0] = ty_node; | 2367 | .rhs = try transCreateNodeAPInt(c, result.Val.getInt()), |
| 2421 | _ = try appendToken(rp.c, .Comma, ","); | 2368 | }); |
| 2422 | | 2369 | return maybeSuppressResult(c, scope, used, as_node); |
| 2423 | const int_lit_node = try transCreateNodeAPInt(rp.c, result.Val.getInt()); | | |
| 2424 | as_node.params()[1] = int_lit_node; | | |
| 2425 | | | |
| 2426 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | | |
| 2427 | | | |
| 2428 | return maybeSuppressResult(rp, scope, used, &as_node.base); | | |
| 2429 | }, | 2370 | }, |
| 2430 | else => { | 2371 | else => { |
| 2431 | return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind", .{}); | 2372 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind", .{}); |
| 2432 | }, | 2373 | }, |
| 2433 | } | 2374 | } |
| 2434 | } | 2375 | } |
| 2435 | | 2376 | |
| 2436 | fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!*ast.Node { | 2377 | fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!Node { |
| 2437 | return transStringLiteral(rp, scope, expr.getFunctionName(), used); | 2378 | return transStringLiteral(c, scope, expr.getFunctionName(), used); |
| 2438 | } | 2379 | } |
| 2439 | | 2380 | |
| 2440 | fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!*ast.Node { | 2381 | fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node { |
| 2441 | const node = try c.arena.create(ast.Node.OneToken); | 2382 | return Node.char_literal.create(c.arena, if (narrow) |
| 2442 | node.* = .{ | 2383 | try std.fmt.bufPrint(c.arena, "'{}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})}) |
| 2443 | .base = .{ .tag = .CharLiteral }, | 2384 | else |
| 2444 | .token = undefined, | 2385 | try std.fmt.bufPrint(c.arena, "'\\u{{{x}}}'", .{val})); |
| 2445 | }; | | |
| 2446 | if (narrow) { | | |
| 2447 | const val_array = [_]u8{@intCast(u8, val)}; | | |
| 2448 | node.token = try appendTokenFmt(c, .CharLiteral, "'{}'", .{std.zig.fmtEscapes(&val_array)}); | | |
| 2449 | } else { | | |
| 2450 | node.token = try appendTokenFmt(c, .CharLiteral, "'\\u{{{x}}}'", .{val}); | | |
| 2451 | } | | |
| 2452 | return &node.base; | | |
| 2453 | } | 2386 | } |
| 2454 | | 2387 | |
| 2455 | fn transCharLiteral( | 2388 | fn transCharLiteral( |
| 2456 | rp: RestorePoint, | 2389 | c: *Context, |
| 2457 | scope: *Scope, | 2390 | scope: *Scope, |
| 2458 | stmt: *const clang.CharacterLiteral, | 2391 | stmt: *const clang.CharacterLiteral, |
| 2459 | result_used: ResultUsed, | 2392 | result_used: ResultUsed, |
| 2460 | suppress_as: SuppressCast, | 2393 | suppress_as: SuppressCast, |
| 2461 | ) TransError!*ast.Node { | 2394 | ) TransError!Node { |
| 2462 | const kind = stmt.getKind(); | 2395 | const kind = stmt.getKind(); |
| 2463 | const val = stmt.getValue(); | 2396 | const val = stmt.getValue(); |
| 2464 | const narrow = kind == .Ascii or kind == .UTF8; | 2397 | const narrow = kind == .Ascii or kind == .UTF8; |
| 2465 | // C has a somewhat obscure feature called multi-character character constant | 2398 | // C has a somewhat obscure feature called multi-character character constant |
| 2466 | // e.g. 'abcd' | 2399 | // e.g. 'abcd' |
| 2467 | const int_lit_node = if (kind == .Ascii and val > 255) | 2400 | const int_lit_node = if (kind == .Ascii and val > 255) |
| 2468 | try transCreateNodeInt(rp.c, val) | 2401 | try transCreateNodeInt(c, val) |
| 2469 | else | 2402 | else |
| 2470 | try transCreateCharLitNode(rp.c, narrow, val); | 2403 | try transCreateCharLitNode(c, narrow, val); |
| 2471 | | 2404 | |
| 2472 | if (suppress_as == .no_as) { | 2405 | if (suppress_as == .no_as) { |
| 2473 | return maybeSuppressResult(rp, scope, result_used, int_lit_node); | 2406 | return maybeSuppressResult(c, scope, result_used, int_lit_node); |
| 2474 | } | 2407 | } |
| 2475 | // See comment in `transIntegerLiteral` for why this code is here. | 2408 | // See comment in `transIntegerLiteral` for why this code is here. |
| 2476 | // @as(T, x) | 2409 | // @as(T, x) |
| 2477 | const expr_base = @ptrCast(*const clang.Expr, stmt); | 2410 | const expr_base = @ptrCast(*const clang.Expr, stmt); |
| 2478 | const as_node = try rp.c.createBuiltinCall("@as", 2); | 2411 | const as_node = Node.as.create(c.arena, .{ |
| 2479 | const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc()); | 2412 | .lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()), |
| 2480 | as_node.params()[0] = ty_node; | 2413 | .rhs = int_lit_node, |
| 2481 | _ = try appendToken(rp.c, .Comma, ","); | 2414 | }); |
| 2482 | as_node.params()[1] = int_lit_node; | 2415 | return maybeSuppressResult(c, scope, result_used, as_node); |
| 2483 | | | |
| 2484 | as_node.rparen_token = try appendToken(rp.c, .RParen, ")"); | | |
| 2485 | return maybeSuppressResult(rp, scope, result_used, &as_node.base); | | |
| 2486 | } | 2416 | } |
| 2487 | | 2417 | |
| 2488 | fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!*ast.Node { | 2418 | fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!Node { |
| 2489 | const comp = stmt.getSubStmt(); | 2419 | const comp = stmt.getSubStmt(); |
| 2490 | if (used == .unused) { | 2420 | if (used == .unused) { |
| 2491 | return transCompoundStmt(rp, scope, comp); | 2421 | return transCompoundStmt(c, scope, comp); |
| 2492 | } | 2422 | } |
| 2493 | const lparen = try appendToken(rp.c, .LParen, "("); | 2423 | var block_scope = try Scope.Block.init(c, scope, true); |
| 2494 | var block_scope = try Scope.Block.init(rp.c, scope, true); | | |
| 2495 | defer block_scope.deinit(); | 2424 | defer block_scope.deinit(); |
| 2496 | | 2425 | |
| 2497 | var it = comp.body_begin(); | 2426 | var it = comp.body_begin(); |
| ... | @@ -2500,22 +2429,13 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, u | ... | @@ -2500,22 +2429,13 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, u |
| 2500 | const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); | 2429 | const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); |
| 2501 | try block_scope.statements.append(result); | 2430 | try block_scope.statements.append(result); |
| 2502 | } | 2431 | } |
| 2503 | const break_node = blk: { | 2432 | const break_node = try Node.break_val.create(c.arena, .{ |
| 2504 | var tmp = try CtrlFlow.init(rp.c, .Break, "blk"); | 2433 | .label = block_scope.label, |
| 2505 | const rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value); | 2434 | .val = try transStmt(c, &block_scope.base, it[0], .used, .r_value), |
| 2506 | break :blk try tmp.finish(rhs); | 2435 | }); |
| 2507 | }; | 2436 | try block_scope.statements.append(break_node); |
| 2508 | _ = try appendToken(rp.c, .Semicolon, ";"); | 2437 | |
| 2509 | try block_scope.statements.append(&break_node.base); | 2438 | return block_scope.complete(c); |
| 2510 | const block_node = try block_scope.complete(rp.c); | | |
| 2511 | const rparen = try appendToken(rp.c, .RParen, ")"); | | |
| 2512 | const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression); | | |
| 2513 | grouped_expr.* = .{ | | |
| 2514 | .lparen = lparen, | | |
| 2515 | .expr = block_node, | | |
| 2516 | .rparen = rparen, | | |
| 2517 | }; | | |
| 2518 | return maybeSuppressResult(rp, scope, used, &grouped_expr.base); | | |
| 2519 | } | 2439 | } |
| 2520 | | 2440 | |
| 2521 | fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node { | 2441 | fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node { |
| ... | @@ -4581,7 +4501,7 @@ fn fail( | ... | @@ -4581,7 +4501,7 @@ fn fail( |
| 4581 | comptime format: []const u8, | 4501 | comptime format: []const u8, |
| 4582 | args: anytype, | 4502 | args: anytype, |
| 4583 | ) (@TypeOf(err) || error{OutOfMemory}) { | 4503 | ) (@TypeOf(err) || error{OutOfMemory}) { |
| 4584 | try emitWarning(c, source_loc, format, args); | 4504 | try warn(c, source_loc, format, args); |
| 4585 | return err; | 4505 | return err; |
| 4586 | } | 4506 | } |
| 4587 | | 4507 | |