mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 08:14:48 +00:00
Translate C now correctly converts ints, floats, ptrs and enums to bools
* Boolean "and" and "or" should also work with these types. * This new method also simplifies to output code.
This commit is contained in:
parent
b2887620f3
commit
2e010c60ae
@ -119,7 +119,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
|
||||
static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node);
|
||||
static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
|
||||
static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
|
||||
static AstNode *trans_to_bool_expr(Context *c, TransScope *scope, AstNode *expr);
|
||||
static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
|
||||
|
||||
ATTRIBUTE_PRINTF(3, 4)
|
||||
static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) {
|
||||
@ -467,6 +467,14 @@ static QualType get_expr_qual_type(Context *c, const Expr *expr) {
|
||||
return expr->getType();
|
||||
}
|
||||
|
||||
static QualType get_expr_qual_type_before_implicit_cast(Context *c, const Expr *expr) {
|
||||
if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
|
||||
const ImplicitCastExpr *cast_expr = static_cast<const ImplicitCastExpr *>(expr);
|
||||
return get_expr_qual_type(c, cast_expr->getSubExpr());
|
||||
}
|
||||
return expr->getType();
|
||||
}
|
||||
|
||||
static AstNode *get_expr_type(Context *c, const Expr *expr) {
|
||||
return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart());
|
||||
}
|
||||
@ -1152,6 +1160,22 @@ static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, Bi
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) {
|
||||
assert(bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeBoolOr);
|
||||
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
|
||||
node->data.bin_op_expr.bin_op = bin_op;
|
||||
|
||||
node->data.bin_op_expr.op1 = trans_bool_expr(c, ResultUsedYes, scope, lhs, TransRValue);
|
||||
if (node->data.bin_op_expr.op1 == nullptr)
|
||||
return nullptr;
|
||||
|
||||
node->data.bin_op_expr.op2 = trans_bool_expr(c, ResultUsedYes, scope, rhs, TransRValue);
|
||||
if (node->data.bin_op_expr.op2 == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, Expr *lhs, Expr *rhs) {
|
||||
if (result_used == ResultUsedNo) {
|
||||
// common case
|
||||
@ -1293,10 +1317,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
|
||||
case BO_Or:
|
||||
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS());
|
||||
case BO_LAnd:
|
||||
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
|
||||
return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
|
||||
case BO_LOr:
|
||||
// TODO: int vs bool
|
||||
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
|
||||
return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
|
||||
case BO_Assign:
|
||||
return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS());
|
||||
case BO_Comma:
|
||||
@ -1924,7 +1947,6 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
case UO_LNot:
|
||||
case UO_Not:
|
||||
{
|
||||
Expr *op_expr = stmt->getSubExpr();
|
||||
@ -1932,14 +1954,16 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
||||
if (sub_node == nullptr)
|
||||
return nullptr;
|
||||
|
||||
switch (stmt->getOpcode()) {
|
||||
case UO_LNot:
|
||||
return trans_create_node_prefix_op(c, PrefixOpBoolNot, trans_to_bool_expr(c, scope, sub_node));
|
||||
case UO_Not:
|
||||
return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node);
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node);
|
||||
}
|
||||
case UO_LNot:
|
||||
{
|
||||
Expr *op_expr = stmt->getSubExpr();
|
||||
AstNode *sub_node = trans_bool_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
|
||||
if (sub_node == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node);
|
||||
}
|
||||
case UO_Real:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real");
|
||||
@ -2220,10 +2244,30 @@ 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) {
|
||||
static AstNode *to_enum_zero_cmp(Context *c, AstNode *expr, AstNode *enum_type) {
|
||||
AstNode *tag_type = trans_create_node_builtin_fn_call_str(c, "TagType");
|
||||
tag_type->data.fn_call_expr.params.append(enum_type);
|
||||
|
||||
// @TagType(Enum)(0)
|
||||
AstNode *zero = trans_create_node_unsigned_negative(c, 0, false);
|
||||
AstNode *casted_zero = trans_create_node_fn_call_1(c, tag_type, zero);
|
||||
|
||||
// @bitCast(Enum, @TagType(Enum)(0))
|
||||
AstNode *bitcast = trans_create_node_builtin_fn_call_str(c, "bitCast");
|
||||
bitcast->data.fn_call_expr.params.append(enum_type);
|
||||
bitcast->data.fn_call_expr.params.append(casted_zero);
|
||||
|
||||
return trans_create_node_bin_op(c, expr, BinOpTypeCmpNotEq, bitcast);
|
||||
}
|
||||
|
||||
static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval) {
|
||||
AstNode *res = trans_expr(c, result_used, scope, expr, lrval);
|
||||
if (res == nullptr)
|
||||
return nullptr;
|
||||
|
||||
switch (res->type) {
|
||||
case NodeTypeBinOpExpr:
|
||||
switch (expr->data.bin_op_expr.bin_op) {
|
||||
switch (res->data.bin_op_expr.bin_op) {
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
case BinOpTypeCmpEq:
|
||||
@ -2232,76 +2276,208 @@ static AstNode *trans_to_bool_expr(Context *c, TransScope *scope, AstNode *expr)
|
||||
case BinOpTypeCmpGreaterThan:
|
||||
case BinOpTypeCmpLessOrEq:
|
||||
case BinOpTypeCmpGreaterOrEq:
|
||||
return expr;
|
||||
return res;
|
||||
default:
|
||||
goto convert_to_bitcast;
|
||||
break;
|
||||
}
|
||||
|
||||
case NodeTypePrefixOpExpr:
|
||||
switch (expr->data.prefix_op_expr.prefix_op) {
|
||||
switch (res->data.prefix_op_expr.prefix_op) {
|
||||
case PrefixOpBoolNot:
|
||||
return expr;
|
||||
return res;
|
||||
default:
|
||||
goto convert_to_bitcast;
|
||||
break;
|
||||
}
|
||||
|
||||
case NodeTypeBoolLiteral:
|
||||
return expr;
|
||||
return res;
|
||||
|
||||
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;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
const Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr();
|
||||
auto classs = ty->getTypeClass();
|
||||
switch (classs) {
|
||||
case Type::Builtin:
|
||||
{
|
||||
const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
|
||||
switch (builtin_ty->getKind()) {
|
||||
case BuiltinType::Bool:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UShort:
|
||||
case BuiltinType::UInt:
|
||||
case BuiltinType::ULong:
|
||||
case BuiltinType::ULongLong:
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::Int:
|
||||
case BuiltinType::Long:
|
||||
case BuiltinType::LongLong:
|
||||
case BuiltinType::UInt128:
|
||||
case BuiltinType::Int128:
|
||||
case BuiltinType::Float:
|
||||
case BuiltinType::Double:
|
||||
case BuiltinType::Float128:
|
||||
case BuiltinType::LongDouble:
|
||||
case BuiltinType::WChar_U:
|
||||
case BuiltinType::Char16:
|
||||
case BuiltinType::Char32:
|
||||
case BuiltinType::WChar_S:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
|
||||
case BuiltinType::NullPtr:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
|
||||
|
||||
case BuiltinType::Void:
|
||||
case BuiltinType::Half:
|
||||
case BuiltinType::ObjCId:
|
||||
case BuiltinType::ObjCClass:
|
||||
case BuiltinType::ObjCSel:
|
||||
case BuiltinType::OMPArraySection:
|
||||
case BuiltinType::Dependent:
|
||||
case BuiltinType::Overload:
|
||||
case BuiltinType::BoundMember:
|
||||
case BuiltinType::PseudoObject:
|
||||
case BuiltinType::UnknownAny:
|
||||
case BuiltinType::BuiltinFn:
|
||||
case BuiltinType::ARCUnbridgedCast:
|
||||
case BuiltinType::OCLImage1dRO:
|
||||
case BuiltinType::OCLImage1dArrayRO:
|
||||
case BuiltinType::OCLImage1dBufferRO:
|
||||
case BuiltinType::OCLImage2dRO:
|
||||
case BuiltinType::OCLImage2dArrayRO:
|
||||
case BuiltinType::OCLImage2dDepthRO:
|
||||
case BuiltinType::OCLImage2dArrayDepthRO:
|
||||
case BuiltinType::OCLImage2dMSAARO:
|
||||
case BuiltinType::OCLImage2dArrayMSAARO:
|
||||
case BuiltinType::OCLImage2dMSAADepthRO:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepthRO:
|
||||
case BuiltinType::OCLImage3dRO:
|
||||
case BuiltinType::OCLImage1dWO:
|
||||
case BuiltinType::OCLImage1dArrayWO:
|
||||
case BuiltinType::OCLImage1dBufferWO:
|
||||
case BuiltinType::OCLImage2dWO:
|
||||
case BuiltinType::OCLImage2dArrayWO:
|
||||
case BuiltinType::OCLImage2dDepthWO:
|
||||
case BuiltinType::OCLImage2dArrayDepthWO:
|
||||
case BuiltinType::OCLImage2dMSAAWO:
|
||||
case BuiltinType::OCLImage2dArrayMSAAWO:
|
||||
case BuiltinType::OCLImage2dMSAADepthWO:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepthWO:
|
||||
case BuiltinType::OCLImage3dWO:
|
||||
case BuiltinType::OCLImage1dRW:
|
||||
case BuiltinType::OCLImage1dArrayRW:
|
||||
case BuiltinType::OCLImage1dBufferRW:
|
||||
case BuiltinType::OCLImage2dRW:
|
||||
case BuiltinType::OCLImage2dArrayRW:
|
||||
case BuiltinType::OCLImage2dDepthRW:
|
||||
case BuiltinType::OCLImage2dArrayDepthRW:
|
||||
case BuiltinType::OCLImage2dMSAARW:
|
||||
case BuiltinType::OCLImage2dArrayMSAARW:
|
||||
case BuiltinType::OCLImage2dMSAADepthRW:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepthRW:
|
||||
case BuiltinType::OCLImage3dRW:
|
||||
case BuiltinType::OCLSampler:
|
||||
case BuiltinType::OCLEvent:
|
||||
case BuiltinType::OCLClkEvent:
|
||||
case BuiltinType::OCLQueue:
|
||||
case BuiltinType::OCLReserveID:
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::Pointer:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
|
||||
|
||||
case Type::Typedef:
|
||||
{
|
||||
const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
|
||||
const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
|
||||
auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl());
|
||||
if (existing_entry) {
|
||||
return existing_entry->value;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
case Type::Enum:
|
||||
{
|
||||
const EnumType *enum_ty = static_cast<const EnumType*>(ty);
|
||||
AstNode *enum_type = resolve_enum_decl(c, enum_ty->getDecl());
|
||||
return to_enum_zero_cmp(c, res, enum_type);
|
||||
}
|
||||
|
||||
case Type::Elaborated:
|
||||
{
|
||||
const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
|
||||
switch (elaborated_ty->getKeyword()) {
|
||||
case ETK_Enum: {
|
||||
AstNode *enum_type = trans_qual_type(c, elaborated_ty->getNamedType(), expr->getLocStart());
|
||||
return to_enum_zero_cmp(c, res, enum_type);
|
||||
}
|
||||
case ETK_Struct:
|
||||
case ETK_Union:
|
||||
case ETK_Interface:
|
||||
case ETK_Class:
|
||||
case ETK_Typename:
|
||||
case ETK_None:
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
case Type::FunctionProto:
|
||||
case Type::Record:
|
||||
case Type::ConstantArray:
|
||||
case Type::Paren:
|
||||
case Type::Decayed:
|
||||
case Type::Attributed:
|
||||
case Type::IncompleteArray:
|
||||
case Type::BlockPointer:
|
||||
case Type::LValueReference:
|
||||
case Type::RValueReference:
|
||||
case Type::MemberPointer:
|
||||
case Type::VariableArray:
|
||||
case Type::DependentSizedArray:
|
||||
case Type::DependentSizedExtVector:
|
||||
case Type::Vector:
|
||||
case Type::ExtVector:
|
||||
case Type::FunctionNoProto:
|
||||
case Type::UnresolvedUsing:
|
||||
case Type::Adjusted:
|
||||
case Type::TypeOfExpr:
|
||||
case Type::TypeOf:
|
||||
case Type::Decltype:
|
||||
case Type::UnaryTransform:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::TemplateSpecialization:
|
||||
case Type::Auto:
|
||||
case Type::InjectedClassName:
|
||||
case Type::DependentName:
|
||||
case Type::DependentTemplateSpecialization:
|
||||
case Type::PackExpansion:
|
||||
case Type::ObjCObject:
|
||||
case Type::ObjCInterface:
|
||||
case Type::Complex:
|
||||
case Type::ObjCObjectPointer:
|
||||
case Type::Atomic:
|
||||
case Type::Pipe:
|
||||
case Type::ObjCTypeParam:
|
||||
case Type::DeducedTemplateSpecialization:
|
||||
return res;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
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));
|
||||
while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
if (while_scope->node->data.while_expr.condition == nullptr)
|
||||
return nullptr;
|
||||
|
||||
@ -2328,11 +2504,10 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
if (condition_node == nullptr)
|
||||
if_node->data.if_bool_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
if (if_node->data.if_bool_expr.condition == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if_node->data.if_bool_expr.condition = trans_to_bool_expr(c, scope, condition_node);
|
||||
return if_node;
|
||||
}
|
||||
|
||||
@ -2524,12 +2699,18 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
|
||||
if (cond_stmt == nullptr) {
|
||||
while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
|
||||
} else {
|
||||
TransScope *end_cond_scope = trans_stmt(c, cond_scope, cond_stmt,
|
||||
&while_scope->node->data.while_expr.condition);
|
||||
if (end_cond_scope == nullptr)
|
||||
return nullptr;
|
||||
if (Expr::classof(cond_stmt)) {
|
||||
const Expr *cond_expr = static_cast<const Expr*>(cond_stmt);
|
||||
while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, cond_expr, TransRValue);
|
||||
|
||||
while_scope->node->data.while_expr.condition = trans_to_bool_expr(c, cond_scope, while_scope->node->data.while_expr.condition);
|
||||
if (while_scope->node->data.while_expr.condition == nullptr)
|
||||
return nullptr;
|
||||
} else {
|
||||
TransScope *end_cond_scope = trans_stmt(c, cond_scope, cond_stmt,
|
||||
&while_scope->node->data.while_expr.condition);
|
||||
if (end_cond_scope == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const Stmt *inc_stmt = stmt->getInc();
|
||||
|
||||
@ -451,6 +451,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addC("logical and, logical or on none bool values",
|
||||
\\int and_or_none_bool(int a, float b, void *c) {
|
||||
\\ if (a && b) return 0;
|
||||
\\ if (b && c) return 1;
|
||||
\\ if (a && c) return 2;
|
||||
\\ if (a || b) return 3;
|
||||
\\ if (b || c) return 4;
|
||||
\\ if (a || c) return 5;
|
||||
\\ return 6;
|
||||
\\}
|
||||
,
|
||||
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ if ((a != 0) and (b != 0)) return 0;
|
||||
\\ if ((b != 0) and (c != null)) return 1;
|
||||
\\ if ((a != 0) and (c != null)) return 2;
|
||||
\\ if ((a != 0) or (b != 0)) return 3;
|
||||
\\ if ((b != 0) or (c != null)) return 4;
|
||||
\\ if ((a != 0) or (c != null)) return 5;
|
||||
\\ return 6;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addC("assign",
|
||||
\\int max(int a) {
|
||||
\\ int tmp;
|
||||
@ -1102,17 +1124,18 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
);
|
||||
|
||||
cases.add("bool not",
|
||||
\\int foo(int x) {
|
||||
\\ return !(x == 0);
|
||||
\\ return !x;
|
||||
\\int foo(int a, float b, void *c) {
|
||||
\\ return !(a == 0);
|
||||
\\ return !a;
|
||||
\\ return !b;
|
||||
\\ return !c;
|
||||
\\}
|
||||
,
|
||||
\\pub fn foo(x: c_int) c_int {
|
||||
\\ return !(x == 0);
|
||||
\\ return !__to_bool_expr: {
|
||||
\\ const _tmp = x;
|
||||
\\ break :__to_bool_expr @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0;
|
||||
\\ };
|
||||
\\pub fn foo(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ return !(a == 0);
|
||||
\\ return !(a != 0);
|
||||
\\ return !(b != 0);
|
||||
\\ return !(c != null);
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -1148,75 +1171,66 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE);
|
||||
);
|
||||
|
||||
cases.add("if on int",
|
||||
\\int if_int(int i) {
|
||||
\\ if (i) {
|
||||
\\ return 0;
|
||||
\\ } else {
|
||||
\\ return 1;
|
||||
\\ }
|
||||
cases.add("if on none bool",
|
||||
\\enum SomeEnum { A, B, C };
|
||||
\\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
|
||||
\\ if (a) return 0;
|
||||
\\ if (b) return 1;
|
||||
\\ if (c) return 2;
|
||||
\\ if (d) return 3;
|
||||
\\ return 4;
|
||||
\\}
|
||||
,
|
||||
\\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;
|
||||
\\ }
|
||||
\\}
|
||||
\\pub const A = enum_SomeEnum.A;
|
||||
\\pub const B = enum_SomeEnum.B;
|
||||
\\pub const C = enum_SomeEnum.C;
|
||||
\\pub const enum_SomeEnum = extern enum {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\};
|
||||
\\pub fn if_none_bool(a: c_int, b: f32, c: ?&c_void, d: enum_SomeEnum) c_int {
|
||||
\\ if (a != 0) return 0;
|
||||
\\ if (b != 0) return 1;
|
||||
\\ if (c != null) return 2;
|
||||
\\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
|
||||
\\ return 4;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("while on int",
|
||||
\\int while_int(int i) {
|
||||
\\ while (i) {
|
||||
\\ return 0;
|
||||
\\ }
|
||||
cases.add("while on none bool",
|
||||
\\int while_none_bool(int a, float b, void *c) {
|
||||
\\ while (a) return 0;
|
||||
\\ while (b) return 1;
|
||||
\\ while (c) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
,
|
||||
\\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;
|
||||
\\ }
|
||||
\\}
|
||||
\\pub fn while_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ while (a != 0) return 0;
|
||||
\\ while (b != 0) return 1;
|
||||
\\ while (c != null) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("for on int",
|
||||
\\int for_int(int i) {
|
||||
\\ for (;i;) {
|
||||
\\ return 0;
|
||||
\\ }
|
||||
\\
|
||||
\\ for (int j = 4;j;j--) {
|
||||
\\ return 0;
|
||||
\\ }
|
||||
cases.add("for on none bool",
|
||||
\\int for_none_bool(int a, float b, void *c) {
|
||||
\\ for (;a;) return 0;
|
||||
\\ for (;b;) return 1;
|
||||
\\ for (;c;) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
,
|
||||
\\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;
|
||||
\\ }
|
||||
\\ }
|
||||
\\}
|
||||
\\pub fn for_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ while (a != 0) return 0;
|
||||
\\ while (b != 0) return 1;
|
||||
\\ while (c != null) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("for on int",
|
||||
cases.add("switch on int",
|
||||
\\int switch_fn(int i) {
|
||||
\\ int res = 0;
|
||||
\\ switch (i) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user