Commit bf47cf418a

Jimmi Holst Christensen <jhc@liab.dk>
2018-03-06 11:57:51
expr to bool is now it's own function. * Now while and for loops work on ints and floats, like if statements * This fixes the loop problem in #813
1 parent 61ecc48
Changed files (2)
src/translate_c.cpp
@@ -2204,43 +2204,10 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt
     return ErrorNone;
 }
 
-static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) {
-    TransScopeWhile *while_scope = trans_scope_while_create(c, scope);
-
-    while_scope->node->data.while_expr.condition = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
-    if (while_scope->node->data.while_expr.condition == nullptr)
-        return nullptr;
-
-    TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(),
-            &while_scope->node->data.while_expr.body);
-    if (body_scope == nullptr) 
-        return nullptr;
-
-    return while_scope->node;
-}
-
-static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) {
-    // if (c) t
-    // if (c) t else e
-    AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);
-
-    TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block);
-    if (then_scope == nullptr)
-        return nullptr;
-
-    if (stmt->getElse() != nullptr) {
-        TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node);
-        if (else_scope == nullptr)
-            return nullptr;
-    }
-
-    AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
-    if (condition_node == nullptr)
-        return nullptr;
-
-    switch (condition_node->type) {
+static AstNode *trans_to_bool_expr(Context *c, TransScope *scope, AstNode *expr) {
+    switch (expr->type) {
         case NodeTypeBinOpExpr:
-            switch (condition_node->data.bin_op_expr.bin_op) {
+            switch (expr->data.bin_op_expr.bin_op) {
                 case BinOpTypeBoolOr:
                 case BinOpTypeBoolAnd:
                 case BinOpTypeCmpEq:
@@ -2249,43 +2216,42 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
                 case BinOpTypeCmpGreaterThan:
                 case BinOpTypeCmpLessOrEq:
                 case BinOpTypeCmpGreaterOrEq:
-                    if_node->data.if_bool_expr.condition = condition_node;
-                    return if_node;
+                    return expr;
                 default:
                     goto convert_to_bitcast;
             }
 
         case NodeTypePrefixOpExpr:
-            switch (condition_node->data.prefix_op_expr.prefix_op) {
+            switch (expr->data.prefix_op_expr.prefix_op) {
                 case PrefixOpBoolNot:
-                    if_node->data.if_bool_expr.condition = condition_node;
-                    return if_node;
+                    return expr;
                 default:
                     goto convert_to_bitcast;
             }
 
         case NodeTypeBoolLiteral:
-            if_node->data.if_bool_expr.condition = condition_node;
-            return if_node;
+            return expr;
 
         default: {
-        // In Zig, float, int and pointer does not work in if statements.
-        // To make it work, we bitcast any value we get to an int of the right size
-        // and comp it to 0
-        // TODO: This doesn't work for pointers, as they become nullable on
-        //       translate
-        // c: if (cond) { }
-        // zig: {
-        // zig:     const _tmp = cond;
-        // zig:     if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
-        // zig: }
-        convert_to_bitcast:
+            // In Zig, float, int and pointer does not implicitly cast to bool.
+            // To make it work, we bitcast any value we get to an int of the right size
+            // and comp it to 0
+            // TODO: This doesn't work for pointers, as they become nullable on
+            //       translate
+            // c: expr
+            // zig: __to_bool_expr: {
+            // zig:     const _tmp = cond;
+            // zig:     break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0;
+            // zig: }
+            convert_to_bitcast:
             TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
+            Buf *label_name = buf_create_from_str("__to_bool_expr");
+            child_scope->node->data.block.name = label_name;
 
             // const _tmp = cond;
             // TODO: avoid name collisions with generated variable names
-            Buf* tmp_var_name = buf_create_from_str("_tmp");
-            AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, condition_node);
+            Buf *tmp_var_name = buf_create_from_str("_tmp");
+            AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, expr);
             child_scope->node->data.block.statements.append(tmp_var_decl);
 
             // @sizeOf(@typeOf(_tmp)) * 8
@@ -2294,8 +2260,8 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
             AstNode *sizeof_tmp = trans_create_node_builtin_fn_call_str(c, "sizeOf");
             sizeof_tmp->data.fn_call_expr.params.append(typeof_tmp);
             AstNode *sizeof_tmp_in_bits = trans_create_node_bin_op(
-                c, sizeof_tmp, BinOpTypeMult,
-                trans_create_node_unsigned_negative(c, 8, false));
+                    c, sizeof_tmp, BinOpTypeMult,
+                    trans_create_node_unsigned_negative(c, 8, false));
 
             // @IntType(false, @sizeOf(@typeOf(_tmp)) * 8)
             AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType");
@@ -2307,16 +2273,53 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
             bit_cast->data.fn_call_expr.params.append(int_type);
             bit_cast->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
 
-            // if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
+            // break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0
             AstNode *not_eql_zero = trans_create_node_bin_op(c, bit_cast, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
-            if_node->data.if_bool_expr.condition = not_eql_zero;
-            child_scope->node->data.block.statements.append(if_node);
+            child_scope->node->data.block.statements.append(trans_create_node_break(c, label_name, not_eql_zero));
 
             return child_scope->node;
         }
     }
 }
 
+static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) {
+    TransScopeWhile *while_scope = trans_scope_while_create(c, scope);
+
+    while_scope->node->data.while_expr.condition = trans_to_bool_expr(c, scope, trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue));
+    if (while_scope->node->data.while_expr.condition == nullptr)
+        return nullptr;
+
+    TransScope *body_scope = trans_stmt(c, &while_scope->base, stmt->getBody(),
+            &while_scope->node->data.while_expr.body);
+    if (body_scope == nullptr) 
+        return nullptr;
+
+    return while_scope->node;
+}
+
+static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *stmt) {
+    // if (c) t
+    // if (c) t else e
+    AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr);
+
+    TransScope *then_scope = trans_stmt(c, scope, stmt->getThen(), &if_node->data.if_bool_expr.then_block);
+    if (then_scope == nullptr)
+        return nullptr;
+
+    if (stmt->getElse() != nullptr) {
+        TransScope *else_scope = trans_stmt(c, scope, stmt->getElse(), &if_node->data.if_bool_expr.else_node);
+        if (else_scope == nullptr)
+            return nullptr;
+    }
+
+    AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
+    if (condition_node == nullptr)
+        return nullptr;
+
+    if_node->data.if_bool_expr.condition = trans_to_bool_expr(c, scope, condition_node);
+    return if_node;
+}
+
 static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {
     AstNode *node = trans_create_node(c, NodeTypeFnCallExpr);
 
@@ -2503,6 +2506,8 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
                 &while_scope->node->data.while_expr.condition);
         if (end_cond_scope == nullptr)
             return nullptr;
+
+        while_scope->node->data.while_expr.condition = trans_to_bool_expr(c, cond_scope, while_scope->node->data.while_expr.condition);
     }
 
     const Stmt *inc_stmt = stmt->getInc();
test/translate_c.zig
@@ -1124,15 +1124,62 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
         \\    }
         \\}
     ,
-        \\pub fn if_int(i: c_int) c_int {
-        \\    {
-        \\        const _tmp = i;
-        \\        if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) {
-        \\            return 0;
-        \\        } else {
-        \\            return 1;
-        \\        };
-        \\    };
+       \\pub fn if_int(i: c_int) c_int {
+       \\    if (__to_bool_expr: {
+       \\        const _tmp = i;
+       \\        break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0;
+       \\    }) {
+       \\        return 0;
+       \\    } else {
+       \\        return 1;
+       \\    };
+       \\}
+    );
+
+    cases.add("while on int",
+        \\int while_int(int i) {
+        \\    while (i) {
+        \\        return 0;
+        \\    }
+        \\}
+    ,
+       \\pub fn while_int(i: c_int) c_int {
+       \\    while (__to_bool_expr: {
+       \\        const _tmp = i;
+       \\        break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0;
+       \\    }) {
+       \\        return 0;
+       \\    };
+       \\}
+    );
+
+    cases.add("for on int",
+        \\int for_int(int i) {
+        \\    for (;i;) {
+        \\        return 0;
+        \\    }
+        \\
+        \\    for (int j = 4;j;j--) {
+        \\        return 0;
+        \\    }
         \\}
+    ,
+       \\pub fn for_int(i: c_int) c_int {
+       \\    while (__to_bool_expr: {
+       \\        const _tmp = i;
+       \\        break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0;
+       \\    }) {
+       \\        return 0;
+       \\    };
+       \\    {
+       \\        var j: c_int = 4;
+       \\        while (__to_bool_expr: {
+       \\            const _tmp = j;
+       \\            break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0;
+       \\        }) : (j -= 1) {
+       \\            return 0;
+       \\        };
+       \\    };
+       \\}
     );
 }