translate-c-2 for loops

This commit is contained in:
Vexu 2019-12-17 01:08:08 +02:00
parent d54bcb2b62
commit ab6fe57462
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 92 additions and 11 deletions

View File

@ -1047,5 +1047,7 @@ pub extern fn ZigClangWhileStmt_getBody(*const ZigClangWhileStmt) *const ZigClan
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;
pub extern fn ZigClangForStmt_getInit(*const ZigClangForStmt) ?*const ZigClangStmt;
pub extern fn ZigClangForStmt_getCond(*const ZigClangForStmt) ?*const ZigClangExpr;
pub extern fn ZigClangForStmt_getInc(*const ZigClangForStmt) ?*const ZigClangExpr;
pub extern fn ZigClangForStmt_getBody(*const ZigClangForStmt) *const ZigClangStmt;

View File

@ -207,9 +207,10 @@ const Scope = struct {
};
}
fn getBreakableScope(scope: *Scope) *Scope {
fn getBreakableScope(inner: *Scope) *Scope {
var scope = inner;
while (scope.id != .Switch and scope.id != .Root) : (scope = scope.parent.?) {}
return scope;
}
};
@ -626,8 +627,9 @@ fn transStmt(
block.rbrace = try appendToken(rp.c, .RBrace, "}");
return &block.base;
},
.ContinueStmtClass => return transCreateNodeContinue(rp.c),
.ContinueStmtClass => return try transCreateNodeContinue(rp.c),
.BreakStmtClass => return transBreak(rp, scope),
.ForStmtClass => return transForLoop(rp, scope, @ptrCast(*const ZigClangForStmt, stmt)),
else => {
return revertAndWarn(
rp,
@ -795,7 +797,7 @@ fn transCompoundStmtInline(
fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
const block_scope = try Scope.Block.init(rp.c, scope, false);
block_scope.block_node = try transCreateNodeBlock(rp.c, block_scope.label);
block_scope.block_node = try transCreateNodeBlock(rp.c, null);
try transCompoundStmtInline(rp, &block_scope.base, stmt, block_scope.block_node);
block_scope.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
return &block_scope.block_node.base;
@ -1267,7 +1269,7 @@ fn transDoWhileLoop(
// zig: b;
// zig: if (!cond) break;
// zig: }
break :blk (try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?
break :blk (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
@ -1305,6 +1307,50 @@ fn transDoWhileLoop(
return &while_node.base;
}
fn transForLoop(
rp: RestorePoint,
scope: *Scope,
stmt: *const ZigClangForStmt,
) TransError!*ast.Node {
var inner = scope;
var block = false;
var block_scope: ?*Scope.Block = null;
if (ZigClangForStmt_getInit(stmt)) |init| {
block_scope = try Scope.Block.init(rp.c, scope, false);
block_scope.?.block_node = try transCreateNodeBlock(rp.c, null);
inner = &block_scope.?.base;
_ = try transStmt(rp, inner, init, .unused, .r_value);
}
var cond_scope = Scope.Condition{
.base = .{
.parent = inner,
.id = .Condition,
},
};
const while_node = try transCreateNodeWhile(rp.c);
while_node.condition = if (ZigClangForStmt_getCond(stmt)) |cond|
try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
else
try transCreateNodeBoolLiteral(rp.c, true);
_ = try appendToken(rp.c, .RParen, ")");
if (ZigClangForStmt_getInc(stmt)) |incr| {
_ = try appendToken(rp.c, .Colon, ":");
_ = try appendToken(rp.c, .LParen, "(");
while_node.continue_expr = try transExpr(rp, &cond_scope.base, incr, .unused, .r_value);
_ = try appendToken(rp.c, .RParen, ")");
}
while_node.body = try transStmt(rp, inner, ZigClangForStmt_getBody(stmt), .unused, .r_value);
if (block_scope != null) {
try block_scope.?.block_node.statements.push(&while_node.base);
block_scope.?.block_node.rbrace = try appendToken(rp.c, .RBrace, "}");
return &block_scope.?.block_node.base;
} else
return &while_node.base;
}
fn transCPtrCast(
rp: RestorePoint,
loc: ZigClangSourceLocation,
@ -1358,12 +1404,20 @@ fn maybeSuppressResult(
result: *ast.Node,
) TransError!*ast.Node {
if (used == .used) return result;
// NOTE: This is backwards, but the semicolon must immediately follow the node.
_ = try appendToken(rp.c, .Semicolon, ";");
if (scope.id != .Condition) {
// NOTE: This is backwards, but the semicolon must immediately follow the node.
_ = try appendToken(rp.c, .Semicolon, ";");
} else { // TODO is there a way to avoid this hack?
// this parenthesis must come immediately following the node
_ = try appendToken(rp.c, .RParen, ")");
// these need to come before _
_ = try appendToken(rp.c, .Colon, ":");
_ = try appendToken(rp.c, .LParen, "(");
}
const lhs = try transCreateNodeIdentifier(rp.c, "_");
const op_token = try appendToken(rp.c, .Equal, "=");
const op_node = try rp.c.a().create(ast.Node.InfixOp);
op_node.* = ast.Node.InfixOp{
op_node.* = .{
.op_token = op_token,
.lhs = lhs,
.op = .Assign,
@ -1728,7 +1782,8 @@ fn transCreateNodeAssign(
const lhs_node = try transExpr(rp, scope, lhs, .used, .l_value);
const eq_token = try appendToken(rp.c, .Equal, "=");
const rhs_node = try transExpr(rp, scope, rhs, .used, .r_value);
_ = try appendToken(rp.c, .Semicolon, ";");
if (scope.id != .Condition)
_ = try appendToken(rp.c, .Semicolon, ";");
const node = try rp.c.a().create(ast.Node.InfixOp);
node.* = .{
@ -2196,7 +2251,7 @@ fn transCreateNodeContinue(c: *Context) !*ast.Node {
.kind = .{ .Continue = null },
.rhs = null,
};
_ = try appendToken(rp.c, .Semicolon, ";");
_ = try appendToken(c, .Semicolon, ";");
return &node.base;
}

View File

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