mirror of
https://github.com/ziglang/zig.git
synced 2025-12-23 22:53:06 +00:00
translate-c: convert switch
This commit is contained in:
parent
66dd64ec15
commit
cadd4483be
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user