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