Commit d54bcb2b62

Vexu <git@vexu.eu>
2019-12-16 22:54:16
translate-c-2 break and continue
1 parent 6a3d483
Changed files (1)
src-self-hosted
src-self-hosted/translate_c.zig
@@ -54,6 +54,7 @@ const Scope = struct {
 
     const Switch = struct {
         base: Scope,
+        label: []const u8,
     };
 
     /// used when getting a member `a.b`
@@ -190,6 +191,7 @@ const Scope = struct {
             .Ref => null,
             .FnDef => @fieldParentPtr(FnDef, "base", scope).getAlias(name),
             .Block => @fieldParentPtr(Block, "base", scope).getAlias(name),
+            .Condition => scope.parent.?.getAlias(name),
             else => @panic("TODO Scope.getAlias"),
         };
     }
@@ -200,9 +202,15 @@ const Scope = struct {
             .Root => @fieldParentPtr(Root, "base", scope).contains(name),
             .FnDef => @fieldParentPtr(FnDef, "base", scope).contains(name),
             .Block => @fieldParentPtr(Block, "base", scope).contains(name),
+            .Condition => scope.parent.?.contains(name),
             else => @panic("TODO Scope.contains"),
         };
     }
+
+    fn getBreakableScope(scope: *Scope) *Scope {
+        var scope = inner;
+        while (scope.id != .Switch and scope.id != .Root) : (scope = scope.parent.?) {}
+    }
 };
 
 const Context = struct {
@@ -613,6 +621,13 @@ fn transStmt(
         .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)),
+        .NullStmtClass => {
+            const block = try transCreateNodeBlock(rp.c, null);
+            block.rbrace = try appendToken(rp.c, .RBrace, "}");
+            return &block.base;
+        },
+        .ContinueStmtClass => return transCreateNodeContinue(rp.c),
+        .BreakStmtClass => return transBreak(rp, scope),
         else => {
             return revertAndWarn(
                 rp,
@@ -1241,7 +1256,7 @@ fn transDoWhileLoop(
     _ = try appendToken(rp.c, .RParen, ")");
     var new = false;
 
-    const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass)
+    const body_node = if (ZigClangStmt_getStmtClass(ZigClangDoStmt_getBody(stmt)) == .CompoundStmtClass) blk: {
         // there's already a block in C, so we'll append our condition to it.
         // c: do {
         // c:   a;
@@ -1252,8 +1267,8 @@ fn transDoWhileLoop(
         // zig:   b;
         // zig:   if (!cond) break;
         // zig: }
-        (try transStmt(rp, scope, ZigClangDoStmt_getBody(stmt), .unused, .r_value)).cast(ast.Node.Block).?
-    else blk: {
+        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
         // c:   a;
@@ -1262,7 +1277,6 @@ fn transDoWhileLoop(
         // 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));
@@ -1328,6 +1342,15 @@ fn transCPtrCast(
     return &ptrcast_node.base;
 }
 
+fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
+    const break_scope = scope.getBreakableScope();
+    const br = try transCreateNodeBreak(rp.c, if (break_scope.id == .Switch)
+        @fieldParentPtr(Scope.Switch, "base", break_scope).label
+    else
+        null);
+    return &br.base;
+}
+
 fn maybeSuppressResult(
     rp: RestorePoint,
     scope: *Scope,
@@ -2165,6 +2188,18 @@ fn transCreateNodeWhile(c: *Context) !*ast.Node.While {
     return node;
 }
 
+fn transCreateNodeContinue(c: *Context) !*ast.Node {
+    const ltoken = try appendToken(c, .Keyword_continue, "continue");
+    const node = try c.a().create(ast.Node.ControlFlowExpression);
+    node.* = .{
+        .ltoken = ltoken,
+        .kind = .{ .Continue = null },
+        .rhs = null,
+    };
+    _ = try appendToken(rp.c, .Semicolon, ";");
+    return &node.base;
+}
+
 const RestorePoint = struct {
     c: *Context,
     token_index: ast.TokenIndex,