From bf47cf418af785550f298a519b0dbfa2efcdd3cb Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 6 Mar 2018 11:57:51 +0100 Subject: [PATCH] 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 --- src/translate_c.cpp | 161 ++++++++++++++++++++++--------------------- test/translate_c.zig | 65 ++++++++++++++--- 2 files changed, 139 insertions(+), 87 deletions(-) diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 9a1ef7ffd6..bee867c4ab 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -2204,10 +2204,88 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt return ErrorNone; } +static AstNode *trans_to_bool_expr(Context *c, TransScope *scope, AstNode *expr) { + switch (expr->type) { + case NodeTypeBinOpExpr: + switch (expr->data.bin_op_expr.bin_op) { + case BinOpTypeBoolOr: + case BinOpTypeBoolAnd: + case BinOpTypeCmpEq: + case BinOpTypeCmpNotEq: + case BinOpTypeCmpLessThan: + case BinOpTypeCmpGreaterThan: + case BinOpTypeCmpLessOrEq: + case BinOpTypeCmpGreaterOrEq: + return expr; + default: + goto convert_to_bitcast; + } + + case NodeTypePrefixOpExpr: + switch (expr->data.prefix_op_expr.prefix_op) { + case PrefixOpBoolNot: + return expr; + default: + goto convert_to_bitcast; + } + + case NodeTypeBoolLiteral: + return expr; + + default: { + // 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, expr); + child_scope->node->data.block.statements.append(tmp_var_decl); + + // @sizeOf(@typeOf(_tmp)) * 8 + AstNode *typeof_tmp = trans_create_node_builtin_fn_call_str(c, "typeOf"); + typeof_tmp->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name)); + 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)); + + // @IntType(false, @sizeOf(@typeOf(_tmp)) * 8) + AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType"); + int_type->data.fn_call_expr.params.append(trans_create_node_bool(c, false)); + int_type->data.fn_call_expr.params.append(sizeof_tmp_in_bits); + + // @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) + AstNode *bit_cast = trans_create_node_builtin_fn_call_str(c, "bitCast"); + 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)); + + // 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)); + 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_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue); + 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; @@ -2238,83 +2316,8 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt * if (condition_node == nullptr) return nullptr; - switch (condition_node->type) { - case NodeTypeBinOpExpr: - switch (condition_node->data.bin_op_expr.bin_op) { - case BinOpTypeBoolOr: - case BinOpTypeBoolAnd: - case BinOpTypeCmpEq: - case BinOpTypeCmpNotEq: - case BinOpTypeCmpLessThan: - case BinOpTypeCmpGreaterThan: - case BinOpTypeCmpLessOrEq: - case BinOpTypeCmpGreaterOrEq: - if_node->data.if_bool_expr.condition = condition_node; - return if_node; - default: - goto convert_to_bitcast; - } - - case NodeTypePrefixOpExpr: - switch (condition_node->data.prefix_op_expr.prefix_op) { - case PrefixOpBoolNot: - if_node->data.if_bool_expr.condition = condition_node; - return if_node; - default: - goto convert_to_bitcast; - } - - case NodeTypeBoolLiteral: - if_node->data.if_bool_expr.condition = condition_node; - return if_node; - - 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: - TransScopeBlock *child_scope = trans_scope_block_create(c, scope); - - // 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); - child_scope->node->data.block.statements.append(tmp_var_decl); - - // @sizeOf(@typeOf(_tmp)) * 8 - AstNode *typeof_tmp = trans_create_node_builtin_fn_call_str(c, "typeOf"); - typeof_tmp->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name)); - 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)); - - // @IntType(false, @sizeOf(@typeOf(_tmp)) * 8) - AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType"); - int_type->data.fn_call_expr.params.append(trans_create_node_bool(c, false)); - int_type->data.fn_call_expr.params.append(sizeof_tmp_in_bits); - - // @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) - AstNode *bit_cast = trans_create_node_builtin_fn_call_str(c, "bitCast"); - 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) { } - 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); - - return child_scope->node; - } - } + 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) { @@ -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(); diff --git a/test/translate_c.zig b/test/translate_c.zig index e6270842b1..23bb1759c0 100644 --- a/test/translate_c.zig +++ b/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; + \\ }; + \\ }; + \\} ); }