translate-c: convert switch

This commit is contained in:
Veikka Tuominen 2021-02-10 23:02:38 +02:00
parent 66dd64ec15
commit cadd4483be
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 117 additions and 194 deletions

View File

@ -43,7 +43,7 @@ const Scope = struct {
const Switch = struct { const Switch = struct {
base: Scope, base: Scope,
pending_block: Block, pending_block: Block,
cases: []Node, cases: std.ArrayList(Node),
case_index: usize, case_index: usize,
switch_label: ?[]const u8, switch_label: ?[]const u8,
default_label: ?[]const u8, default_label: ?[]const u8,
@ -1087,7 +1087,7 @@ fn transStmt(
return maybeSuppressResult(c, scope, result_used, expr); return maybeSuppressResult(c, scope, result_used, expr);
}, },
else => { else => {
return revertAndWarn( return fail(
rp, rp,
error.UnsupportedTranslation, error.UnsupportedTranslation,
stmt.getBeginLoc(), stmt.getBeginLoc(),
@ -1348,7 +1348,7 @@ fn transDeclStmtOne(
return error.UnsupportedTranslation; return error.UnsupportedTranslation;
return node; return node;
}, },
else => |kind| return revertAndWarn( else => |kind| return fail(
rp, rp,
error.UnsupportedTranslation, error.UnsupportedTranslation,
decl.getLocation(), decl.getLocation(),
@ -1440,7 +1440,7 @@ fn transImplicitCastExpr(
.BuiltinFnToFnPtr => { .BuiltinFnToFnPtr => {
return transExpr(rp, scope, sub_expr, result_used, .r_value); return transExpr(rp, scope, sub_expr, result_used, .r_value);
}, },
else => |kind| return revertAndWarn( else => |kind| return fail(
rp, rp,
error.UnsupportedTranslation, error.UnsupportedTranslation,
@ptrCast(*const clang.Stmt, expr).getBeginLoc(), @ptrCast(*const clang.Stmt, expr).getBeginLoc(),
@ -1460,7 +1460,7 @@ fn transBoolExpr(
if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) { if (@ptrCast(*const clang.Stmt, expr).getStmtClass() == .IntegerLiteralClass) {
var is_zero: bool = undefined; var is_zero: bool = undefined;
if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) { if (!(@ptrCast(*const clang.IntegerLiteral, expr).isZero(&is_zero, c.clang_context))) {
return revertAndWarn(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{}); return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid integer literal", .{});
} }
return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)] }; return Node{ .tag = ([2]ast.Node.Tag{ .true_literal, .false_literal })[@boolToInt(is_zero)] };
} }
@ -1605,7 +1605,7 @@ fn transIntegerLiteral(
var eval_result: clang.ExprEvalResult = undefined; var eval_result: clang.ExprEvalResult = undefined;
if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) { if (!expr.EvaluateAsInt(&eval_result, c.clang_context)) {
const loc = expr.getBeginLoc(); const loc = expr.getBeginLoc();
return revertAndWarn(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{}); return fail(c, error.UnsupportedTranslation, loc, "invalid integer literal", .{});
} }
if (suppress_as == .no_as) { if (suppress_as == .no_as) {
@ -2144,7 +2144,6 @@ fn transDoWhileLoop(
block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete. block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete.
block.data.stmts[block.data.stmts.len - 1] = if_not_break; block.data.stmts[block.data.stmts.len - 1] = if_not_break;
break :blk node; break :blk node;
} else blk: { } else blk: {
// the C statement is without a block, so we need to create a block to contain it. // the C statement is without a block, so we need to create a block to contain it.
// c: do // c: do
@ -2209,27 +2208,11 @@ fn transForLoop(
} }
} }
fn getSwitchCaseCount(stmt: *const clang.SwitchStmt) usize {
const body = stmt.getBody();
assert(body.getStmtClass() == .CompoundStmtClass);
const comp = @ptrCast(*const clang.CompoundStmt, body);
// TODO https://github.com/ziglang/zig/issues/1738
// return comp.body_end() - comp.body_begin();
const start_addr = @ptrToInt(comp.body_begin());
const end_addr = @ptrToInt(comp.body_end());
return (end_addr - start_addr) / @sizeOf(*clang.Stmt);
}
fn transSwitch( fn transSwitch(
rp: RestorePoint, c: *Context,
scope: *Scope, scope: *Scope,
stmt: *const clang.SwitchStmt, stmt: *const clang.SwitchStmt,
) TransError!*ast.Node { ) TransError!Node {
const switch_tok = try appendToken(rp.c, .Keyword_switch, "switch");
_ = try appendToken(rp.c, .LParen, "(");
const cases_len = getSwitchCaseCount(stmt);
var cond_scope = Scope.Condition{ var cond_scope = Scope.Condition{
.base = .{ .base = .{
.parent = scope, .parent = scope,
@ -2237,16 +2220,13 @@ fn transSwitch(
}, },
}; };
defer cond_scope.deinit(); defer cond_scope.deinit();
const switch_expr = try transExpr(rp, &cond_scope.base, stmt.getCond(), .used, .r_value); const switch_expr = try transExpr(c, &cond_scope.base, stmt.getCond(), .used, .r_value);
_ = try appendToken(rp.c, .RParen, ")"); const switch_node = try c.arena.create(ast.Payload.Switch);
_ = try appendToken(rp.c, .LBrace, "{");
// reserve +1 case in case there is no default case
const switch_node = try ast.Node.Switch.alloc(rp.c.arena, cases_len + 1);
switch_node.* = .{ switch_node.* = .{
.switch_token = switch_tok, .data = .{
.expr = switch_expr, .cond = switch_expr,
.cases_len = cases_len + 1, .cases = undefined, // set later
.rbrace = try appendToken(rp.c, .RBrace, "}"), },
}; };
var switch_scope = Scope.Switch{ var switch_scope = Scope.Switch{
@ -2254,29 +2234,32 @@ fn transSwitch(
.id = .Switch, .id = .Switch,
.parent = scope, .parent = scope,
}, },
.cases = switch_node.cases(), .cases = std.ArrayList(Node).init(c.gpa),
.case_index = 0,
.pending_block = undefined, .pending_block = undefined,
.default_label = null, .default_label = null,
.switch_label = null, .switch_label = null,
}; };
defer {
switch_node.data.cases = try c.arena.dupe(Node, switch_scope.cases.items);
switch_node.data.default = switch_scope.switch_label;
switch_scope.cases.deinit();
}
// tmp block that all statements will go before being picked up by a case or default // tmp block that all statements will go before being picked up by a case or default
var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, false); var block_scope = try Scope.Block.init(c, &switch_scope.base, false);
defer block_scope.deinit(); defer block_scope.deinit();
// Note that we do not defer a deinit here; the switch_scope.pending_block field // Note that we do not defer a deinit here; the switch_scope.pending_block field
// has its own memory management. This resource is freed inside `transCase` and // has its own memory management. This resource is freed inside `transCase` and
// then the final pending_block is freed at the bottom of this function with // then the final pending_block is freed at the bottom of this function with
// pending_block.deinit(). // pending_block.deinit().
switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); switch_scope.pending_block = try Scope.Block.init(c, scope, false);
try switch_scope.pending_block.statements.append(&switch_node.base); try switch_scope.pending_block.statements.append(Node.initPayload(&switch_node.base));
const last = try transStmt(rp, &block_scope.base, stmt.getBody(), .unused, .r_value); const last = try transStmt(c, &block_scope.base, stmt.getBody(), .unused, .r_value);
_ = try appendToken(rp.c, .Semicolon, ";");
// take all pending statements // take all pending statements
const last_block_stmts = last.cast(ast.Node.Block).?.statements(); const last_block_stmts = last.castTag(.block).?.data.stmts;
try switch_scope.pending_block.statements.ensureCapacity( try switch_scope.pending_block.statements.ensureCapacity(
switch_scope.pending_block.statements.items.len + last_block_stmts.len, switch_scope.pending_block.statements.items.len + last_block_stmts.len,
); );
@ -2285,213 +2268,159 @@ fn transSwitch(
} }
if (switch_scope.default_label == null) { if (switch_scope.default_label == null) {
switch_scope.switch_label = try block_scope.makeMangledName(rp.c, "switch"); switch_scope.switch_label = try block_scope.makeMangledName(c, "switch");
} }
if (switch_scope.switch_label) |l| { if (switch_scope.switch_label) |l| {
switch_scope.pending_block.label = try appendIdentifier(rp.c, l); switch_scope.pending_block.label = l;
_ = try appendToken(rp.c, .Colon, ":");
} }
if (switch_scope.default_label == null) { if (switch_scope.default_label == null) {
const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); const else_prong = try Node.switch_else.create(
else_prong.expr = blk: { c.arena,
var br = try CtrlFlow.init(rp.c, .Break, switch_scope.switch_label.?); try Node.@"break".create(c.arena, switch_scope.switch_label.?),
break :blk &(try br.finish(null)).base; );
}; switch_scope.cases.append(else_prong);
_ = try appendToken(rp.c, .Comma, ",");
if (switch_scope.case_index >= switch_scope.cases.len)
return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});
switch_scope.cases[switch_scope.case_index] = &else_prong.base;
switch_scope.case_index += 1;
} }
// We overallocated in case there was no default, so now we correct
// the number of cases in the AST node.
switch_node.cases_len = switch_scope.case_index;
const result_node = try switch_scope.pending_block.complete(rp.c); const result_node = try switch_scope.pending_block.complete(c);
switch_scope.pending_block.deinit(); switch_scope.pending_block.deinit();
return result_node; return result_node;
} }
fn transCase( fn transCase(
rp: RestorePoint, c: *Context,
scope: *Scope, scope: *Scope,
stmt: *const clang.CaseStmt, stmt: *const clang.CaseStmt,
) TransError!*ast.Node { ) TransError!Node {
const block_scope = scope.findBlockScope(rp.c) catch unreachable; const block_scope = scope.findBlockScope(c) catch unreachable;
const switch_scope = scope.getSwitch(); const switch_scope = scope.getSwitch();
const label = try block_scope.makeMangledName(rp.c, "case"); const label = try block_scope.makeMangledName(c, "case");
_ = try appendToken(rp.c, .Semicolon, ";");
const expr = if (stmt.getRHS()) |rhs| blk: { const expr = if (stmt.getRHS()) |rhs| blk: {
const lhs_node = try transExpr(rp, scope, stmt.getLHS(), .used, .r_value); const lhs_node = try transExpr(c, scope, stmt.getLHS(), .used, .r_value);
const ellips = try appendToken(rp.c, .Ellipsis3, "..."); const rhs_node = try transExpr(c, scope, rhs, .used, .r_value);
const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
const node = try rp.c.arena.create(ast.Node.SimpleInfixOp); break :blk Node.ellipsis3.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
node.* = .{
.base = .{ .tag = .Range },
.op_token = ellips,
.lhs = lhs_node,
.rhs = rhs_node,
};
break :blk &node.base;
} else } else
try transExpr(rp, scope, stmt.getLHS(), .used, .r_value); try transExpr(c, scope, stmt.getLHS(), .used, .r_value);
const switch_prong = try transCreateNodeSwitchCase(rp.c, expr); const switch_prong = try Node.switch_prong.create(
switch_prong.expr = blk: { c.arena,
var br = try CtrlFlow.init(rp.c, .Break, label); try Node.@"break".create(c.arena, label),
break :blk &(try br.finish(null)).base; );
}; switch_scope.cases.append(switch_prong);
_ = try appendToken(rp.c, .Comma, ",");
if (switch_scope.case_index >= switch_scope.cases.len) switch_scope.pending_block.label = label;
return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});
switch_scope.cases[switch_scope.case_index] = &switch_prong.base;
switch_scope.case_index += 1;
switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
_ = try appendToken(rp.c, .Colon, ":");
// take all pending statements // take all pending statements
try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
block_scope.statements.shrinkAndFree(0); block_scope.statements.shrinkAndFree(0);
const pending_node = try switch_scope.pending_block.complete(rp.c); const pending_node = try switch_scope.pending_block.complete(c);
switch_scope.pending_block.deinit(); switch_scope.pending_block.deinit();
switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); switch_scope.pending_block = try Scope.Block.init(c, scope, false);
try switch_scope.pending_block.statements.append(pending_node); try switch_scope.pending_block.statements.append(pending_node);
return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value); return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value);
} }
fn transDefault( fn transDefault(
rp: RestorePoint, c: *Context,
scope: *Scope, scope: *Scope,
stmt: *const clang.DefaultStmt, stmt: *const clang.DefaultStmt,
) TransError!*ast.Node { ) TransError!Node {
const block_scope = scope.findBlockScope(rp.c) catch unreachable; const block_scope = scope.findBlockScope(c) catch unreachable;
const switch_scope = scope.getSwitch(); const switch_scope = scope.getSwitch();
switch_scope.default_label = try block_scope.makeMangledName(rp.c, "default"); switch_scope.default_label = try block_scope.makeMangledName(c, "default");
_ = try appendToken(rp.c, .Semicolon, ";");
const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c)); const else_prong = try Node.switch_else.create(
else_prong.expr = blk: { c.arena,
var br = try CtrlFlow.init(rp.c, .Break, switch_scope.default_label.?); try Node.@"break".create(c.arena, switch_scope.default_label.?),
break :blk &(try br.finish(null)).base; );
}; switch_scope.cases.append(else_prong);
_ = try appendToken(rp.c, .Comma, ","); switch_scope.pending_block.label = try appendIdentifier(c, switch_scope.default_label.?);
if (switch_scope.case_index >= switch_scope.cases.len)
return revertAndWarn(rp, error.UnsupportedTranslation, @ptrCast(*const clang.Stmt, stmt).getBeginLoc(), "TODO complex switch cases", .{});
switch_scope.cases[switch_scope.case_index] = &else_prong.base;
switch_scope.case_index += 1;
switch_scope.pending_block.label = try appendIdentifier(rp.c, switch_scope.default_label.?);
_ = try appendToken(rp.c, .Colon, ":");
// take all pending statements // take all pending statements
try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items); try switch_scope.pending_block.statements.appendSlice(block_scope.statements.items);
block_scope.statements.shrinkAndFree(0); block_scope.statements.shrinkAndFree(0);
const pending_node = try switch_scope.pending_block.complete(rp.c); const pending_node = try switch_scope.pending_block.complete(c);
switch_scope.pending_block.deinit(); switch_scope.pending_block.deinit();
switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false); switch_scope.pending_block = try Scope.Block.init(c, scope, false);
try switch_scope.pending_block.statements.append(pending_node); try switch_scope.pending_block.statements.append(pending_node);
return transStmt(rp, scope, stmt.getSubStmt(), .unused, .r_value); return transStmt(c, scope, stmt.getSubStmt(), .unused, .r_value);
} }
fn transConstantExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!*ast.Node { fn transConstantExpr(c: *Context, scope: *Scope, expr: *const clang.Expr, used: ResultUsed) TransError!Node {
var result: clang.ExprEvalResult = undefined; var result: clang.ExprEvalResult = undefined;
if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, rp.c.clang_context)) if (!expr.EvaluateAsConstantExpr(&result, .EvaluateForCodeGen, c.clang_context))
return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{}); return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "invalid constant expression", .{});
var val_node: ?*ast.Node = null;
switch (result.Val.getKind()) { switch (result.Val.getKind()) {
.Int => { .Int => {
// See comment in `transIntegerLiteral` for why this code is here. // See comment in `transIntegerLiteral` for why this code is here.
// @as(T, x) // @as(T, x)
const expr_base = @ptrCast(*const clang.Expr, expr); const expr_base = @ptrCast(*const clang.Expr, expr);
const as_node = try rp.c.createBuiltinCall("@as", 2); const as_node = try Node.as.create(c.arena, .{
const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc()); .lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()),
as_node.params()[0] = ty_node; .rhs = try transCreateNodeAPInt(c, result.Val.getInt()),
_ = try appendToken(rp.c, .Comma, ","); });
return maybeSuppressResult(c, scope, used, as_node);
const int_lit_node = try transCreateNodeAPInt(rp.c, result.Val.getInt());
as_node.params()[1] = int_lit_node;
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return maybeSuppressResult(rp, scope, used, &as_node.base);
}, },
else => { else => {
return revertAndWarn(rp, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind", .{}); return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "unsupported constant expression kind", .{});
}, },
} }
} }
fn transPredefinedExpr(rp: RestorePoint, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!*ast.Node { fn transPredefinedExpr(c: *Context, scope: *Scope, expr: *const clang.PredefinedExpr, used: ResultUsed) TransError!Node {
return transStringLiteral(rp, scope, expr.getFunctionName(), used); return transStringLiteral(c, scope, expr.getFunctionName(), used);
} }
fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!*ast.Node { fn transCreateCharLitNode(c: *Context, narrow: bool, val: u32) TransError!Node {
const node = try c.arena.create(ast.Node.OneToken); return Node.char_literal.create(c.arena, if (narrow)
node.* = .{ try std.fmt.bufPrint(c.arena, "'{}'", .{std.zig.fmtEscapes(&.{@intCast(u8, val)})})
.base = .{ .tag = .CharLiteral }, else
.token = undefined, try std.fmt.bufPrint(c.arena, "'\\u{{{x}}}'", .{val}));
};
if (narrow) {
const val_array = [_]u8{@intCast(u8, val)};
node.token = try appendTokenFmt(c, .CharLiteral, "'{}'", .{std.zig.fmtEscapes(&val_array)});
} else {
node.token = try appendTokenFmt(c, .CharLiteral, "'\\u{{{x}}}'", .{val});
}
return &node.base;
} }
fn transCharLiteral( fn transCharLiteral(
rp: RestorePoint, c: *Context,
scope: *Scope, scope: *Scope,
stmt: *const clang.CharacterLiteral, stmt: *const clang.CharacterLiteral,
result_used: ResultUsed, result_used: ResultUsed,
suppress_as: SuppressCast, suppress_as: SuppressCast,
) TransError!*ast.Node { ) TransError!Node {
const kind = stmt.getKind(); const kind = stmt.getKind();
const val = stmt.getValue(); const val = stmt.getValue();
const narrow = kind == .Ascii or kind == .UTF8; const narrow = kind == .Ascii or kind == .UTF8;
// C has a somewhat obscure feature called multi-character character constant // C has a somewhat obscure feature called multi-character character constant
// e.g. 'abcd' // e.g. 'abcd'
const int_lit_node = if (kind == .Ascii and val > 255) const int_lit_node = if (kind == .Ascii and val > 255)
try transCreateNodeInt(rp.c, val) try transCreateNodeInt(c, val)
else else
try transCreateCharLitNode(rp.c, narrow, val); try transCreateCharLitNode(c, narrow, val);
if (suppress_as == .no_as) { if (suppress_as == .no_as) {
return maybeSuppressResult(rp, scope, result_used, int_lit_node); return maybeSuppressResult(c, scope, result_used, int_lit_node);
} }
// See comment in `transIntegerLiteral` for why this code is here. // See comment in `transIntegerLiteral` for why this code is here.
// @as(T, x) // @as(T, x)
const expr_base = @ptrCast(*const clang.Expr, stmt); const expr_base = @ptrCast(*const clang.Expr, stmt);
const as_node = try rp.c.createBuiltinCall("@as", 2); const as_node = Node.as.create(c.arena, .{
const ty_node = try transQualType(rp, expr_base.getType(), expr_base.getBeginLoc()); .lhs = try transQualType(c, expr_base.getType(), expr_base.getBeginLoc()),
as_node.params()[0] = ty_node; .rhs = int_lit_node,
_ = try appendToken(rp.c, .Comma, ","); });
as_node.params()[1] = int_lit_node; return maybeSuppressResult(c, scope, result_used, as_node);
as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
return maybeSuppressResult(rp, scope, result_used, &as_node.base);
} }
fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!*ast.Node { fn transStmtExpr(c: *Context, scope: *Scope, stmt: *const clang.StmtExpr, used: ResultUsed) TransError!Node {
const comp = stmt.getSubStmt(); const comp = stmt.getSubStmt();
if (used == .unused) { if (used == .unused) {
return transCompoundStmt(rp, scope, comp); return transCompoundStmt(c, scope, comp);
} }
const lparen = try appendToken(rp.c, .LParen, "("); var block_scope = try Scope.Block.init(c, scope, true);
var block_scope = try Scope.Block.init(rp.c, scope, true);
defer block_scope.deinit(); defer block_scope.deinit();
var it = comp.body_begin(); var it = comp.body_begin();
@ -2500,22 +2429,13 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.StmtExpr, u
const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value); const result = try transStmt(rp, &block_scope.base, it[0], .unused, .r_value);
try block_scope.statements.append(result); try block_scope.statements.append(result);
} }
const break_node = blk: { const break_node = try Node.break_val.create(c.arena, .{
var tmp = try CtrlFlow.init(rp.c, .Break, "blk"); .label = block_scope.label,
const rhs = try transStmt(rp, &block_scope.base, it[0], .used, .r_value); .val = try transStmt(c, &block_scope.base, it[0], .used, .r_value),
break :blk try tmp.finish(rhs); });
}; try block_scope.statements.append(break_node);
_ = try appendToken(rp.c, .Semicolon, ";");
try block_scope.statements.append(&break_node.base); return block_scope.complete(c);
const block_node = try block_scope.complete(rp.c);
const rparen = try appendToken(rp.c, .RParen, ")");
const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
grouped_expr.* = .{
.lparen = lparen,
.expr = block_node,
.rparen = rparen,
};
return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
} }
fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node { fn transMemberExpr(rp: RestorePoint, scope: *Scope, stmt: *const clang.MemberExpr, result_used: ResultUsed) TransError!*ast.Node {
@ -4581,7 +4501,7 @@ fn fail(
comptime format: []const u8, comptime format: []const u8,
args: anytype, args: anytype,
) (@TypeOf(err) || error{OutOfMemory}) { ) (@TypeOf(err) || error{OutOfMemory}) {
try emitWarning(c, source_loc, format, args); try warn(c, source_loc, format, args);
return err; return err;
} }

View File

@ -35,8 +35,13 @@ pub const Node = extern union {
/// while (true) operand /// while (true) operand
while_true, while_true,
@"switch", @"switch",
/// else => operand,
switch_else,
/// lhs => rhs,
switch_prong,
@"continue", @"continue",
@"break", @"break",
break_val,
@"return", @"return",
field_access, field_access,
field_access_arrow, field_access_arrow,
@ -109,6 +114,7 @@ pub const Node = extern union {
bit_or, bit_or,
bit_xor, bit_xor,
array_cat, array_cat,
ellipsis3,
log2_int_type, log2_int_type,
/// @import("std").math.Log2Int(operand) /// @import("std").math.Log2Int(operand)
@ -217,6 +223,7 @@ pub const Node = extern union {
.empty_array, .empty_array,
.while_true, .while_true,
.if_not_break, .if_not_break,
.switch_else,
=> Payload.UnOp, => Payload.UnOp,
.add, .add,
@ -280,6 +287,8 @@ pub const Node = extern union {
.int_to_enum, .int_to_enum,
.int_to_ptr, .int_to_ptr,
.array_cat, .array_cat,
.ellipsis3,
.switch_prong,
=> Payload.BinOp, => Payload.BinOp,
.int, .int,
@ -300,6 +309,7 @@ pub const Node = extern union {
.@"while" => Payload.While, .@"while" => Payload.While,
.@"switch" => Payload.Switch, .@"switch" => Payload.Switch,
.@"break" => Payload.Break, .@"break" => Payload.Break,
.break_val => Payload.BreakVal,
.call => Payload.Call, .call => Payload.Call,
.var_decl => Payload.VarDecl, .var_decl => Payload.VarDecl,
.func => Payload.Func, .func => Payload.Func,
@ -413,22 +423,20 @@ pub const Payload = struct {
base: Node = .{ .tag = .@"switch" }, base: Node = .{ .tag = .@"switch" },
data: struct { data: struct {
cond: Node, cond: Node,
cases: []Prong, cases: []Node,
default: ?[]const u8,
pub const Prong = struct {
lhs: Node,
rhs: ?Node,
label: []const u8,
};
}, },
}; };
pub const Break = struct { pub const Break = struct {
base: Node = .{ .tag = .@"break" }, base: Node = .{ .tag = .@"break" },
data: ?[]const u8,
};
pub const BreakVal = struct {
base: Node = .{ .tag = .break_val },
data: struct { data: struct {
label: ?[]const u8, label: ?[]const u8,
rhs: ?Node, val: Node,
}, },
}; };
@ -525,11 +533,6 @@ pub const Payload = struct {
}, },
}; };
pub const Break = struct {
base: Node = .{ .tag = .@"break" },
data: *Block
};
pub const Array = struct { pub const Array = struct {
base: Node, base: Node,
data: struct { data: struct {