From ab6fe57462374d59b20ac46eeb4eefbf2f6938a0 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 17 Dec 2019 01:08:08 +0200 Subject: [PATCH] translate-c-2 for loops --- src-self-hosted/clang.zig | 6 ++- src-self-hosted/translate_c.zig | 73 +++++++++++++++++++++++++++++---- test/translate_c.zig | 24 +++++++++++ 3 files changed, 92 insertions(+), 11 deletions(-) diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index a3db8f7c2b..80d8cd2c06 100644 --- a/src-self-hosted/clang.zig +++ b/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; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 91c96756e0..9f74ce72e1 100644 --- a/src-self-hosted/translate_c.zig +++ b/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; } diff --git a/test/translate_c.zig b/test/translate_c.zig index 6b2014db9b..b4164297ea 100644 --- a/test/translate_c.zig +++ b/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) {