Commit 66dd64ec15

Veikka Tuominen <git@vexu.eu>
2021-02-10 21:30:19
translate-c: convert most control flow
1 parent d8b9fca
Changed files (2)
src
src/translate_c/ast.zig
@@ -29,7 +29,11 @@ pub const Node = extern union {
         char_literal,
         identifier,
         @"if",
+        /// if (!operand) break;
+        if_not_break,
         @"while",
+        /// while (true) operand
+        while_true,
         @"switch",
         @"continue",
         @"break",
@@ -211,6 +215,8 @@ pub const Node = extern union {
                 .ptr_to_int,
                 .enum_to_int,
                 .empty_array,
+                .while_true,
+                .if_not_break,
                 => Payload.UnOp,
 
                 .add,
@@ -399,6 +405,7 @@ pub const Payload = struct {
         data: struct {
             cond: Node,
             body: Node,
+            cont_expr: ?Node
         },
     };
 
src/translate_c.zig
@@ -107,6 +107,7 @@ const Scope = struct {
             // do while, we want to put `if (cond) break;` at the end.
             const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop);
             const stmts = try c.arena.alloc(Node, alloc_len);
+            stmts.len -= 1;
             mem.copy(Node, stmts, self.statements.items);
             return Node.block.create(c.arena, .{
                 .lable = self.label,
@@ -1748,7 +1749,7 @@ fn transCCast(
     if (dst_type.eq(src_type)) return expr;
     if (qualTypeIsPtr(dst_type) and qualTypeIsPtr(src_type))
         return transCPtrCast(c, loc, dst_type, src_type, expr);
-    
+
     const dst_node = try transQualType(c, dst_type, loc);
     if (cIsInteger(dst_type) and (cIsInteger(src_type) or cIsEnum(src_type))) {
         // 1. If src_type is an enum, determine the underlying signed int type
@@ -1931,7 +1932,7 @@ fn transInitListExprArray(
     if (all_count == 0) {
         return Node.empty_array.create(c.arena, try transQualType(c, child_qt, source_loc));
     }
-    
+
     const ty_node = try transType(ty);
     const init_node = if (init_count != 0) blk: {
         const init_list = try c.arena.alloc(Node, init_count);
@@ -2058,14 +2059,12 @@ fn transImplicitValueInitExpr(
 }
 
 fn transIfStmt(
-    rp: RestorePoint,
+    c: *Context,
     scope: *Scope,
     stmt: *const clang.IfStmt,
-) TransError!*ast.Node {
+) TransError!Node {
     // if (c) t
     // if (c) t else e
-    const if_node = try transCreateNodeIf(rp.c);
-
     var cond_scope = Scope.Condition{
         .base = .{
             .parent = scope,
@@ -2074,26 +2073,21 @@ fn transIfStmt(
     };
     defer cond_scope.deinit();
     const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
-    if_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
-    _ = try appendToken(rp.c, .RParen, ")");
-
-    if_node.body = try transStmt(rp, scope, stmt.getThen(), .unused, .r_value);
+    const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value);
 
-    if (stmt.getElse()) |expr| {
-        if_node.@"else" = try transCreateNodeElse(rp.c);
-        if_node.@"else".?.body = try transStmt(rp, scope, expr, .unused, .r_value);
-    }
-    _ = try appendToken(rp.c, .Semicolon, ";");
-    return &if_node.base;
+    const then_body = try transStmt(c, scope, stmt.getThen(), .unused, .r_value);
+    const else_body = if (stmt.getElse()) |expr|
+        try transStmt(c, scope, expr, .unused, .r_value)
+    else
+        null;
+    return Node.@"if".create(c.arena, .{ .cond = cond, .then = then_body, .@"else" = else_body });
 }
 
 fn transWhileLoop(
-    rp: RestorePoint,
+    c: *Context,
     scope: *Scope,
     stmt: *const clang.WhileStmt,
-) TransError!*ast.Node {
-    const while_node = try transCreateNodeWhile(rp.c);
-
+) TransError!Node {
     var cond_scope = Scope.Condition{
         .base = .{
             .parent = scope,
@@ -2102,35 +2096,28 @@ fn transWhileLoop(
     };
     defer cond_scope.deinit();
     const cond_expr = @ptrCast(*const clang.Expr, stmt.getCond());
-    while_node.condition = try transBoolExpr(rp, &cond_scope.base, cond_expr, .used, .r_value, false);
-    _ = try appendToken(rp.c, .RParen, ")");
+    const cond = try transBoolExpr(c, &cond_scope.base, cond_expr, .used, .r_value);
 
     var loop_scope = Scope{
         .parent = scope,
         .id = .Loop,
     };
-    while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
-    _ = try appendToken(rp.c, .Semicolon, ";");
-    return &while_node.base;
+    const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
+    return Node.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = null });
 }
 
 fn transDoWhileLoop(
-    rp: RestorePoint,
+    c: *Context,
     scope: *Scope,
     stmt: *const clang.DoStmt,
-) 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;
+) TransError!Node {
     var loop_scope = Scope{
         .parent = scope,
         .id = .Loop,
     };
 
     // if (!cond) break;
-    const if_node = try transCreateNodeIf(rp.c);
+    const if_node = try transCreateNodeIf(c);
     var cond_scope = Scope.Condition{
         .base = .{
             .parent = scope,
@@ -2138,12 +2125,8 @@ fn transDoWhileLoop(
         },
     };
     defer cond_scope.deinit();
-    const prefix_op = try transCreateNodeSimplePrefixOp(rp.c, .BoolNot, .Bang, "!");
-    prefix_op.rhs = try transBoolExpr(rp, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value, true);
-    _ = try appendToken(rp.c, .RParen, ")");
-    if_node.condition = &prefix_op.base;
-    if_node.body = &(try transCreateNodeBreak(rp.c, null, null)).base;
-    _ = try appendToken(rp.c, .Semicolon, ";");
+    const cond = try transBoolExpr(c, &cond_scope.base, @ptrCast(*const clang.Expr, stmt.getCond()), .used, .r_value);
+    const if_not_break = try Node.if_not_break.create(c.arena, cond);
 
     const body_node = if (stmt.getBody().getStmtClass() == .CompoundStmtClass) blk: {
         // there's already a block in C, so we'll append our condition to it.
@@ -2156,8 +2139,12 @@ fn transDoWhileLoop(
         // zig:   b;
         // zig:   if (!cond) break;
         // zig: }
-        const node = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
-        break :blk node.castTag(.Block).?;
+        const node = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
+        const block = node.castTag(.block);
+        block.data.stmts.len += 1; // This is safe since we reserve one extra space in Scope.Block.complete.
+        block.data.stmts[block.data.stmts.len - 1] = if_not_break;
+        break :blk node;
+        
     } else blk: {
         // the C statement is without a block, so we need to create a block to contain it.
         // c: do
@@ -2167,27 +2154,19 @@ fn transDoWhileLoop(
         // zig:   a;
         // zig:   if (!cond) break;
         // zig: }
-        new = true;
-        const block = try rp.c.createBlock(2);
-        block.statements_len = 1; // over-allocated so we can add another below
-        block.statements()[0] = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
-        break :blk block;
+        const statements = try c.arena.create(Node, 2);
+        statements[0] = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
+        statements[1] = if_not_break;
+        break :blk try Node.block.create(c.arena, .{ .label = null, .stmts = statements });
     };
-
-    // In both cases above, we reserved 1 extra statement.
-    body_node.statements_len += 1;
-    body_node.statements()[body_node.statements_len - 1] = &if_node.base;
-    if (new)
-        body_node.rbrace = try appendToken(rp.c, .RBrace, "}");
-    while_node.body = &body_node.base;
-    return &while_node.base;
+    return Node.while_true.create(c.arena, body_node);
 }
 
 fn transForLoop(
-    rp: RestorePoint,
+    c: *Context,
     scope: *Scope,
     stmt: *const clang.ForStmt,
-) TransError!*ast.Node {
+) TransError!Node {
     var loop_scope = Scope{
         .parent = scope,
         .id = .Loop,
@@ -2197,9 +2176,9 @@ fn transForLoop(
     defer if (block_scope) |*bs| bs.deinit();
 
     if (stmt.getInit()) |init| {
-        block_scope = try Scope.Block.init(rp.c, scope, false);
+        block_scope = try Scope.Block.init(c, scope, false);
         loop_scope.parent = &block_scope.?.base;
-        const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);
+        const init_node = try transStmt(c, &block_scope.?.base, init, .unused, .r_value);
         try block_scope.?.statements.append(init_node);
     }
     var cond_scope = Scope.Condition{
@@ -2210,27 +2189,23 @@ fn transForLoop(
     };
     defer cond_scope.deinit();
 
-    const while_node = try transCreateNodeWhile(rp.c);
-    while_node.condition = if (stmt.getCond()) |cond|
-        try transBoolExpr(rp, &cond_scope.base, cond, .used, .r_value, false)
+    const cond = if (stmt.getCond()) |cond|
+        try transBoolExpr(c, &cond_scope.base, cond, .used, .r_value)
     else
-        try transCreateNodeBoolLiteral(rp.c, true);
-    _ = try appendToken(rp.c, .RParen, ")");
+        Node.true_literal.init();
 
-    if (stmt.getInc()) |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, ")");
-    }
+    const cont_expr = if (stmt.getInc()) |incr|
+        try transExpr(c, &cond_scope.base, incr, .unused, .r_value)
+    else
+        null;
 
-    while_node.body = try transStmt(rp, &loop_scope, stmt.getBody(), .unused, .r_value);
+    const body = try transStmt(c, &loop_scope, stmt.getBody(), .unused, .r_value);
+    const while_node = try Node.@"while".create(c.arena, .{ .cond = cond, .body = body, .cont_expr = cont_expr });
     if (block_scope) |*bs| {
-        try bs.statements.append(&while_node.base);
-        return try bs.complete(rp.c);
+        try bs.statements.append(while_node);
+        return try bs.complete(c);
     } else {
-        _ = try appendToken(rp.c, .Semicolon, ";");
-        return &while_node.base;
+        return while_node;
     }
 }