authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-10 23:02:38+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-02-16 16:40:05+02:00
logcadd4483be80f73f192621f79eea41117183129c
treeec365d44270e50ab71670dc037b081436f5bd3a3
parent66dd64ec15d787bb43cb0ab1169e8bac6cfe762e
signature Commit is signed but in an unrecognized format.

translate-c: convert switch


2 files changed, 118 insertions(+), 195 deletions(-)

src/translate_c.zig+101-181
...@@ -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 }
16101610
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: do2149 // c: do
...@@ -2209,27 +2208,11 @@ fn transForLoop(...@@ -2209,27 +2208,11 @@ fn transForLoop(
2209 }2208 }
2210}2209}
22112210
2212fn 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
2223fn transSwitch(2211fn 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 };
22512231
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 }
22632247
2264 // tmp block that all statements will go before being picked up by a case or default2248 // 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();
22672251
2268 // Note that we do not defer a deinit here; the switch_scope.pending_block field2252 // 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` and2253 // 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 with2254 // 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));
22742258
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, ";");
22772260
2278 // take all pending statements2261 // 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 }
22862269
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;
23102283
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}
23152288
2316fn transCase(2289fn 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, ";");
23252297
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);
23412301
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, ",");
23482305
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);
23532311
2354 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);2312 switch_scope.pending_block.label = label;
2355 _ = try appendToken(rp.c, .Colon, ":");
23562313
2357 // take all pending statements2314 // 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);
23602317
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);
23642321
2365 try switch_scope.pending_block.statements.append(pending_node);2322 try switch_scope.pending_block.statements.append(pending_node);
23662323
2367 return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value);2324 return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value);
2368}2325}
23692326
2370fn transDefault(2327fn 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, ",");
23862335
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 );
23912340 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, ":");
23942342
2395 // take all pending statements2343 // 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);
23982346
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);
24032351
2404 return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value);2352 return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value);
2405}2353}
24062354
2407fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!*ast.Node {2355fn 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", .{});
24112359
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 });
24222369 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}
24352376
2436fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!*ast.Node {2377fn 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}
24392380
2440fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!*ast.Node {2381fn 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}
24542387
2455fn transCharLiteral(2388fn 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 constant2398 // 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 else2402 else
2470 try transCreateCharLitNode(rp.c, narrow, val);2403 try transCreateCharLitNode(c, narrow, val);
24712404
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}
24872417
2488fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!*ast.Node {2418fn 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();
24962425
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}
25202440
2521fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node {2441fn 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}
45874507
src/translate_c/ast.zig+17-14
...@@ -35,8 +35,13 @@ pub const Node = extern union {...@@ -35,8 +35,13 @@ pub const Node = extern union {
35 /// while (true) operand35 /// while (true) operand
36 while_true,36 while_true,
37 @"switch",37 @"switch",
38 /// else => operand,
39 switch_else,
40 /// lhs => rhs,
41 switch_prong,
38 @"continue",42 @"continue",
39 @"break",43 @"break",
44 break_val,
40 @"return",45 @"return",
41 field_access,46 field_access,
42 field_access_arrow,47 field_access_arrow,
...@@ -109,6 +114,7 @@ pub const Node = extern union {...@@ -109,6 +114,7 @@ pub const Node = extern union {
109 bit_or,114 bit_or,
110 bit_xor,115 bit_xor,
111 array_cat,116 array_cat,
117 ellipsis3,
112118
113 log2_int_type,119 log2_int_type,
114 /// @import("std").math.Log2Int(operand)120 /// @import("std").math.Log2Int(operand)
...@@ -217,6 +223,7 @@ pub const Node = extern union {...@@ -217,6 +223,7 @@ pub const Node = extern union {
217 .empty_array,223 .empty_array,
218 .while_true,224 .while_true,
219 .if_not_break,225 .if_not_break,
226 .switch_else,
220 => Payload.UnOp,227 => Payload.UnOp,
221228
222 .add,229 .add,
...@@ -280,6 +287,8 @@ pub const Node = extern union {...@@ -280,6 +287,8 @@ pub const Node = extern union {
280 .int_to_enum,287 .int_to_enum,
281 .int_to_ptr,288 .int_to_ptr,
282 .array_cat,289 .array_cat,
290 .ellipsis3,
291 .switch_prong,
283 => Payload.BinOp,292 => Payload.BinOp,
284293
285 .int,294 .int,
...@@ -300,6 +309,7 @@ pub const Node = extern union {...@@ -300,6 +309,7 @@ pub const Node = extern union {
300 .@"while" => Payload.While,309 .@"while" => Payload.While,
301 .@"switch" => Payload.Switch,310 .@"switch" => Payload.Switch,
302 .@"break" => Payload.Break,311 .@"break" => Payload.Break,
312 .break_val => Payload.BreakVal,
303 .call => Payload.Call,313 .call => Payload.Call,
304 .var_decl => Payload.VarDecl,314 .var_decl => Payload.VarDecl,
305 .func => Payload.Func,315 .func => Payload.Func,
...@@ -413,22 +423,20 @@ pub const Payload = struct {...@@ -413,22 +423,20 @@ pub const Payload = struct {
413 base: Node = .{ .tag = .@"switch" },423 base: Node = .{ .tag = .@"switch" },
414 data: struct {424 data: struct {
415 cond: Node,425 cond: Node,
416 cases: []Prong,426 cases: []Node,
417 default: ?[]const u8,
418
419 pub const Prong = struct {
420 lhs: Node,
421 rhs: ?Node,
422 label: []const u8,
423 };
424 },427 },
425 };428 };
426429
427 pub const Break = struct {430 pub const Break = struct {
428 base: Node = .{ .tag = .@"break" },431 base: Node = .{ .tag = .@"break" },
432 data: ?[]const u8,
433 };
434
435 pub const BreakVal = struct {
436 base: Node = .{ .tag = .break_val },
429 data: struct {437 data: struct {
430 label: ?[]const u8,438 label: ?[]const u8,
431 rhs: ?Node,439 val: Node,
432 },440 },
433 };441 };
434442
...@@ -525,11 +533,6 @@ pub const Payload = struct {...@@ -525,11 +533,6 @@ pub const Payload = struct {
525 },533 },
526 };534 };
527535
528 pub const Break = struct {
529 base: Node = .{ .tag = .@"break" },
530 data: *Block
531 };
532
533 pub const Array = struct {536 pub const Array = struct {
534 base: Node,537 base: Node,
535 data: struct {538 data: struct {