Commit ab6fe57462

Vexu <git@vexu.eu>
2019-12-17 00:08:08
translate-c-2 for loops
1 parent d54bcb2
Changed files (3)
src-self-hosted/clang.zig
@@ -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;
src-self-hosted/translate_c.zig
@@ -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;
 }
 
test/translate_c.zig
@@ -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) {