translate-c-2 while loops

This commit is contained in:
Vexu 2019-12-16 21:45:38 +02:00
parent e3f1bfe483
commit 6a3d48353b
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 166 additions and 17 deletions

View File

@ -1040,3 +1040,12 @@ pub extern fn ZigClangMacroDefinitionRecord_getSourceRange_getEnd(*const ZigClan
pub extern fn ZigClangIfStmt_getThen(*const ZigClangIfStmt) *const ZigClangStmt;
pub extern fn ZigClangIfStmt_getElse(*const ZigClangIfStmt) ?*const ZigClangStmt;
pub extern fn ZigClangIfStmt_getCond(*const ZigClangIfStmt) *const ZigClangStmt;
pub extern fn ZigClangWhileStmt_getCond(*const ZigClangWhileStmt) *const ZigClangExpr;
pub extern fn ZigClangWhileStmt_getBody(*const ZigClangWhileStmt) *const ZigClangStmt;
pub extern fn ZigClangDoStmt_getCond(*const ZigClangDoStmt) *const ZigClangExpr;
pub extern fn ZigClangDoStmt_getBody(*const ZigClangDoStmt) *const ZigClangStmt;
pub extern fn ZigClangDoStmt_getCond(*const ZigClangDoStmt) *const ZigClangExpr;
pub extern fn ZigClangDoStmt_getBody(*const ZigClangDoStmt) *const ZigClangStmt;

View File

@ -172,7 +172,7 @@ const Scope = struct {
// comma operator used
return try Block.init(c, scope, true);
},
else => scope = inner,
else => scope = scope.parent.?,
}
}
}
@ -610,7 +610,9 @@ fn transStmt(
.ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue),
.InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used),
.ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used),
.IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt), result_used),
.IfStmtClass => return transIfStmt(rp, scope, @ptrCast(*const ZigClangIfStmt, stmt)),
.WhileStmtClass => return transWhileLoop(rp, scope, @ptrCast(*const ZigClangWhileStmt, stmt)),
.DoStmtClass => return transDoWhileLoop(rp, scope, @ptrCast(*const ZigClangDoStmt, stmt)),
else => {
return revertAndWarn(
rp,
@ -1184,7 +1186,6 @@ fn transIfStmt(
rp: RestorePoint,
scope: *Scope,
stmt: *const ZigClangIfStmt,
used: ResultUsed,
) TransError!*ast.Node {
// if (c) t
// if (c) t else e
@ -1196,7 +1197,7 @@ fn transIfStmt(
.id = .Condition,
},
};
if_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value);
if_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangIfStmt_getCond(stmt)), .used, .r_value, false);
_ = try appendToken(rp.c, .RParen, ")");
if_node.body = try transStmt(rp, scope, ZigClangIfStmt_getThen(stmt), .used, .r_value);
@ -1209,6 +1210,87 @@ fn transIfStmt(
return &if_node.base;
}
fn transWhileLoop(
rp: RestorePoint,
scope: *Scope,
stmt: *const ZigClangWhileStmt,
) TransError!*ast.Node {
const while_node = try transCreateNodeWhile(rp.c);
var cond_scope = Scope.Condition{
.base = .{
.parent = scope,
.id = .Condition,
},
};
while_node.condition = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangWhileStmt_getCond(stmt)), .used, .r_value, false);
_ = try appendToken(rp.c, .RParen, ")");
while_node.body = try transStmt(rp, scope, ZigClangWhileStmt_getBody(stmt), .unused, .r_value);
return &while_node.base;
}
fn transDoWhileLoop(
rp: RestorePoint,
scope: *Scope,
stmt: *const ZigClangDoStmt,
) TransError!*ast.Node {
const while_node = try transCreateNodeWhile(rp.c);
while_node.condition = try transCreateNodeBoolLiteral(rp.c, true);
_ = try appendToken(rp.c, .RParen, ")");
var new = false;
const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass)
// there's already a block in C, so we'll append our condition to it.
// c: do {
// c: a;
// c: b;
// c: } while(c);
// zig: while (true) {
// zig: a;
// zig: b;
// zig: if (!cond) break;
// zig: }
(try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?
else blk: {
// the C statement is without a block, so we need to create a block to contain it.
// c: do
// c: a;
// c: while(c);
// zig: while (true) {
// zig: a;
// zig: if (!cond) break;
// zig: }
new = true;
const block = try transCreateNodeBlock(rp.c, null);
try block.statements.push(try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value));
break :blk block;
};
// if (!cond) break;
const if_node = try transCreateNodeIf(rp.c);
var cond_scope = Scope.Condition{
.base = .{
.parent = scope,
.id = .Condition,
},
};
const prefix_op = try transCreateNodePrefixOp(rp.c, .BoolNot, .Bang, "!");
prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const ZigClangExpr, ZigClangDoStmt_getCond(stmt)), .used, .r_value, false);
_ = try appendToken(rp.c, .RParen, ")");
if_node.condition = &prefix_op.base;
if_node.body = &(try transCreateNodeBreak(rp.c, null)).base;
_ = try appendToken(rp.c, .Semicolon, ";");
try body_node.statements.push(&if_node.base);
if (new)
body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
while_node.body = &body_node.base;
return &while_node.base;
}
fn transCPtrCast(
rp: RestorePoint,
loc: ZigClangSourceLocation,
@ -1682,7 +1764,7 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti
const builtin_token = try appendToken(c, .Builtin, name);
_ = try appendToken(c, .LParen, "(");
const node = try c.a().create(ast.Node.BuiltinCall);
node.* = ast.Node.BuiltinCall{
node.* = .{
.builtin_token = builtin_token,
.params = ast.Node.BuiltinCall.ParamList.init(c.a()),
.rparen_token = undefined, // set after appending args
@ -1693,10 +1775,10 @@ fn transCreateNodeBuiltinFnCall(c: *Context, name: []const u8) !*ast.Node.Builti
fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
_ = try appendToken(c, .LParen, "(");
const node = try c.a().create(ast.Node.SuffixOp);
node.* = ast.Node.SuffixOp{
node.* = .{
.lhs = .{ .node = fn_expr },
.op = ast.Node.SuffixOp.Op{
.Call = ast.Node.SuffixOp.Op.Call{
.op = .{
.Call = .{
.params = ast.Node.SuffixOp.Op.Call.ParamList.init(c.a()),
.async_token = null,
},
@ -1744,7 +1826,7 @@ fn transCreateNodeInfixOp(
if (!grouped) return &node.base;
const rparen = try appendToken(rp.c, .RParen, ")");
const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
grouped_expr.* = ast.Node.GroupedExpression{
grouped_expr.* = .{
.lparen = lparen,
.expr = &node.base,
.rparen = rparen,
@ -1776,9 +1858,9 @@ fn transCreateNodePtrType(
.Asterisk => try appendToken(c, .Asterisk, "*"),
else => unreachable,
};
node.* = ast.Node.PrefixOp{
node.* = .{
.op_token = op_token,
.op = ast.Node.PrefixOp.Op{
.op = .{
.PtrType = .{
.const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null,
.volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null,
@ -1811,7 +1893,7 @@ fn transCreateNodeAPInt(c: *Context, int: ?*const ZigClangAPSInt) !*ast.Node {
fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
const ltoken = try appendToken(c, .Keyword_return, "return");
const node = try c.a().create(ast.Node.ControlFlowExpression);
node.* = ast.Node.ControlFlowExpression{
node.* = .{
.ltoken = ltoken,
.kind = .Return,
.rhs = null,
@ -1822,7 +1904,7 @@ fn transCreateNodeReturnExpr(c: *Context) !*ast.Node.ControlFlowExpression {
fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
const token = try appendToken(c, .Keyword_undefined, "undefined");
const node = try c.a().create(ast.Node.UndefinedLiteral);
node.* = ast.Node.UndefinedLiteral{
node.* = .{
.token = token,
};
return &node.base;
@ -1831,7 +1913,7 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node {
fn transCreateNodeNullLiteral(c: *Context) !*ast.Node {
const token = try appendToken(c, .Keyword_null, "null");
const node = try c.a().create(ast.Node.NullLiteral);
node.* = ast.Node.NullLiteral{
node.* = .{
.token = token,
};
return &node.base;
@ -1843,7 +1925,7 @@ fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node {
else
try appendToken(c, .Keyword_false, "false");
const node = try c.a().create(ast.Node.BoolLiteral);
node.* = ast.Node.BoolLiteral{
node.* = .{
.token = token,
};
return &node.base;
@ -2032,7 +2114,7 @@ fn transCreateNodeBreak(c: *Context, label: ?[]const u8) !*ast.Node.ControlFlowE
break :blk try transCreateNodeIdentifier(c, l);
} else null;
const node = try c.a().create(ast.Node.ControlFlowExpression);
node.* = ast.Node.ControlFlowExpression{
node.* = .{
.ltoken = ltoken,
.kind = .{ .Break = label_node },
.rhs = null,
@ -2046,7 +2128,7 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con
const name_tok = try appendIdentifier(c, name);
const node = try c.a().create(ast.Node.VarDecl);
node.* = ast.Node.VarDecl{
node.* = .{
.doc_comments = null,
.visib_token = visib_tok,
.thread_local_token = null,
@ -2065,6 +2147,24 @@ fn transCreateNodeVarDecl(c: *Context, is_pub: bool, is_const: bool, name: []con
return node;
}
fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
const while_tok = try appendToken(c, .Keyword_while, "while");
_ = try appendToken(c, .LParen, "(");
const node = try c.a().create(ast.Node.While);
node.* = .{
.label = null,
.inline_token = null,
.while_token = while_tok,
.condition = undefined,
.payload = null,
.continue_expr = null,
.body = undefined,
.@"else" = null,
};
return node;
}
const RestorePoint = struct {
c: *Context,
token_index: ast.TokenIndex,

View File

@ -755,6 +755,46 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.add_2("while loops",
\\int foo() {
\\ int a = 5;
\\ while (2)
\\ a = 2;
\\ while (4) {
\\ int a = 4;
\\ a = 9;
\\ return 6, a;
\\ }
\\ do {
\\ int a = 2;
\\ a = 12;
\\ } while (4);
\\ do
\\ a = 7;
\\ while (4);
\\}
, &[_][]const u8{
\\pub export fn foo() c_int {
\\ var a: c_int = 5;
\\ while (2 != 0) a = 2;
\\ while (4 != 0) {
\\ var a: c_int = 4;
\\ a = 9;
\\ _ = 6;
\\ return a;
\\ }
\\ while (true) {
\\ var a: c_int = 2;
\\ a = 12;
\\ if (!4 != 0) break;
\\ }
\\ while (true) {
\\ a = 7;
\\ if (!4 != 0) break;
\\ }
\\}
});
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
if (builtin.os != builtin.Os.windows) {