diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-09-21 02:56:06 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-09-21 02:56:06 -0400 |
| commit | c2f3dc94eba85a32f3b7ab5857b33636a0a2e4df (patch) | |
| tree | bb809f8eb6a1d7fb709607dcadce511b2a58dd8f /src | |
| parent | c4a54377e3f07bbd2f9c54c1962c7941792c2c1f (diff) | |
| parent | ee42caee0e6a24aa252845a72733007ed384d2bf (diff) | |
| download | zig-c2f3dc94eba85a32f3b7ab5857b33636a0a2e4df.tar.gz zig-c2f3dc94eba85a32f3b7ab5857b33636a0a2e4df.zip | |
Merge branch 'c-to-zig'
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.cpp | 4 | ||||
| -rw-r--r-- | src/ast_render.cpp | 6 | ||||
| -rw-r--r-- | src/codegen.cpp | 2 | ||||
| -rw-r--r-- | src/ir.cpp | 2 | ||||
| -rw-r--r-- | src/parsec.cpp | 787 | ||||
| -rw-r--r-- | src/util.hpp | 4 |
6 files changed, 661 insertions, 144 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index f20d155e4f..e0d34be281 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -163,10 +163,6 @@ static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *so return entry; } -static uint8_t log2_u64(uint64_t x) { - return (63 - clzll(x)); -} - static uint8_t bits_needed_for_unsigned(uint64_t x) { if (x == 0) { return 0; diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 1ac9d8de79..599d4b2659 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -14,8 +14,8 @@ static const char *bin_op_str(BinOpType bin_op) { switch (bin_op) { case BinOpTypeInvalid: return "(invalid)"; - case BinOpTypeBoolOr: return "||"; - case BinOpTypeBoolAnd: return "&&"; + case BinOpTypeBoolOr: return "or"; + case BinOpTypeBoolAnd: return "and"; case BinOpTypeCmpEq: return "=="; case BinOpTypeCmpNotEq: return "!="; case BinOpTypeCmpLessThan: return "<"; @@ -580,10 +580,12 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { break; case NodeTypePrefixOpExpr: { + if (!grouped) fprintf(ar->f, "("); PrefixOp op = node->data.prefix_op_expr.prefix_op; fprintf(ar->f, "%s", prefix_op_str(op)); render_node_ungrouped(ar, node->data.prefix_op_expr.primary_expr); + if (!grouped) fprintf(ar->f, ")"); break; } case NodeTypeAddrOfExpr: diff --git a/src/codegen.cpp b/src/codegen.cpp index e559a5de74..ab4bf4ebf4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5037,7 +5037,7 @@ void codegen_parsec(CodeGen *g, Buf *full_path) { ZigList<ErrorMsg *> errors = {0}; int err = parse_h_file(import, &errors, buf_ptr(full_path), g, nullptr); if (err) { - fprintf(stderr, "unable to parse .h file: %s\n", err_str(err)); + fprintf(stderr, "unable to parse C file: %s\n", err_str(err)); exit(1); } diff --git a/src/ir.cpp b/src/ir.cpp index e6e6345831..422c40b678 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13459,7 +13459,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc int err; if ((err = parse_h_buf(child_import, &errors, &cimport_scope->buf, ira->codegen, node))) { - zig_panic("unable to parse h file: %s\n", err_str(err)); + zig_panic("unable to parse C file: %s\n", err_str(err)); } if (errors.length > 0) { diff --git a/src/parsec.cpp b/src/parsec.cpp index 22f6136138..b389400f58 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -49,6 +49,8 @@ struct Context { CodeGen *codegen; ASTContext *ctx; + + HashMap<Buf *, bool, buf_hash, buf_eql_buf> ptr_params; }; static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); @@ -126,13 +128,27 @@ static AstNode *trans_create_node_opaque(Context *c) { return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); } +static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, AstNode *arg1) { + AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); + node->data.fn_call_expr.fn_ref_expr = fn_ref_expr; + node->data.fn_call_expr.params.append(arg1); + return node; +} + static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); + if (container->type == NodeTypeSymbol) { + assert(container->data.symbol_expr.symbol != nullptr); + } node->data.field_access_expr.struct_expr = container; node->data.field_access_expr.field_name = field_name; return node; } +static AstNode *trans_create_node_field_access_str(Context *c, AstNode *container, const char *field_name) { + return trans_create_node_field_access(c, container, buf_create_from_str(field_name)); +} + static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); node->data.prefix_op_expr.prefix_op = op; @@ -140,6 +156,22 @@ static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *ch return node; } +static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) { + AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); + node->data.bin_op_expr.op1 = lhs_node; + node->data.bin_op_expr.bin_op = op; + node->data.bin_op_expr.op2 = rhs_node; + return node; +} + +static AstNode *maybe_suppress_result(Context *c, bool result_used, AstNode *node) { + if (result_used) return node; + return trans_create_node_bin_op(c, + trans_create_node_symbol_str(c, "_"), + BinOpTypeAssign, + node); +} + static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) { AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr); node->data.addr_of_expr.is_const = is_const; @@ -155,6 +187,13 @@ static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { return node; } +static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) { + AstNode *node = trans_create_node(c, NodeTypeStringLiteral); + node->data.string_literal.buf = buf; + node->data.string_literal.c = false; + return node; +} + static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { AstNode *node = trans_create_node(c, NodeTypeIntLiteral); node->data.int_literal.bigint = allocate<BigInt>(1); @@ -188,11 +227,11 @@ static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, Ast return node; } -static AstNode *trans_create_node_var_decl(Context *c, bool is_const, Buf *var_name, AstNode *type_node, - AstNode *init_node) +static AstNode *trans_create_node_var_decl(Context *c, VisibMod visib_mod, bool is_const, Buf *var_name, + AstNode *type_node, AstNode *init_node) { AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); - node->data.variable_declaration.visib_mod = c->visib_mod; + node->data.variable_declaration.visib_mod = visib_mod; node->data.variable_declaration.symbol = var_name; node->data.variable_declaration.is_const = is_const; node->data.variable_declaration.type = type_node; @@ -200,6 +239,18 @@ static AstNode *trans_create_node_var_decl(Context *c, bool is_const, Buf *var_n return node; } +static AstNode *trans_create_node_var_decl_global(Context *c, bool is_const, Buf *var_name, AstNode *type_node, + AstNode *init_node) +{ + return trans_create_node_var_decl(c, c->visib_mod, is_const, var_name, type_node, init_node); +} + +static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf *var_name, AstNode *type_node, + AstNode *init_node) +{ + return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node); +} + static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) { AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); @@ -240,6 +291,10 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_n return fn_def; } +static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) { + return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child); +} + static AstNode *get_global(Context *c, Buf *name) { for (size_t i = 0; i < c->root->data.root.top_level_decls.length; i += 1) { AstNode *decl_node = c->root->data.root.top_level_decls.items[i]; @@ -268,7 +323,7 @@ static AstNode *get_global(Context *c, Buf *name) { static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { bool is_const = true; AstNode *type_node = nullptr; - AstNode *node = trans_create_node_var_decl(c, is_const, var_name, type_node, value_node); + AstNode *node = trans_create_node_var_decl_global(c, is_const, var_name, type_node, value_node); c->root->data.root.top_level_decls.append(node); return node; } @@ -286,10 +341,96 @@ static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) } +static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); + static bool is_c_void_type(AstNode *node) { return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); } +static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, const QualType &qt, AstNode *expr) { + // TODO: maybe widen to increase size + // TODO: maybe bitcast to change sign + // TODO: maybe truncate to reduce size + return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr); +} + +static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { + const Type *ty = qt.getTypePtr(); + switch (ty->getTypeClass()) { + case Type::Builtin: + { + const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); + switch (builtin_ty->getKind()) { + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + case BuiltinType::SChar: + return 8; + case BuiltinType::UInt128: + case BuiltinType::Int128: + return 128; + default: + return 0; + } + zig_unreachable(); + } + case Type::Typedef: + { + const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + const char *type_name = decl_name(typedef_decl); + if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { + return 8; + } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { + return 16; + } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { + return 32; + } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { + return 64; + } else { + return 0; + } + } + default: + return 0; + } + zig_unreachable(); +} + + +static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, + const SourceLocation &source_loc) +{ + uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); + if (int_bit_width != 0) { + // we can perform the log2 now. + uint64_t cast_bit_width = log2_u64(int_bit_width); + return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); + } + + AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); + +// @import("std").math.Log2Int(c_long); +// +// FnCall +// FieldAccess +// FieldAccess +// FnCall (.builtin = true) +// Symbol "import" +// StringLiteral "std" +// Symbol "math" +// Symbol "Log2Int" +// zig_type_node + + AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); + import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std"))); + AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); + AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); + AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); + + return log2int_fn_call; +} + static bool qual_type_child_is_fn_proto(const QualType &qt) { if (qt.getTypePtr()->getTypeClass() == Type::Paren) { const ParenType *paren_type = static_cast<const ParenType *>(qt.getTypePtr()); @@ -303,8 +444,17 @@ static bool qual_type_child_is_fn_proto(const QualType &qt) { return false; } +static QualType resolve_any_typedef(Context *c, QualType qt) { + const Type * ty = qt.getTypePtr(); + if (ty->getTypeClass() != Type::Typedef) + return qt; + const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); + const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); + return typedef_decl->getUnderlyingType(); +} + static bool c_is_signed_integer(Context *c, QualType qt) { - const Type *c_type = qt.getTypePtr(); + const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); if (c_type->getTypeClass() != Type::Builtin) return false; const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); @@ -323,7 +473,7 @@ static bool c_is_signed_integer(Context *c, QualType qt) { } static bool c_is_unsigned_integer(Context *c, QualType qt) { - const Type *c_type = qt.getTypePtr(); + const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); if (c_type->getTypeClass() != Type::Builtin) return false; const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); @@ -360,12 +510,26 @@ static bool c_is_float(Context *c, QualType qt) { } } -static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt); -static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); +static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { + if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { + // float and signed integer overflow is undefined behavior. + return false; + } else { + // unsigned integer overflow wraps around. + return true; + } +} + +enum TransLRValue { + TransLValue, + TransRValue, +}; + +static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrval); static AstNode *const skip_add_to_block_node = (AstNode *) 0x2; -static AstNode *trans_expr(Context *c, AstNode *block, Expr *expr) { - return trans_stmt(c, block, expr); +static AstNode *trans_expr(Context *c, bool result_used, AstNode *block, Expr *expr, TransLRValue lrval) { + return trans_stmt(c, result_used, block, expr, lrval); } static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { @@ -709,7 +873,7 @@ static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &s static AstNode *trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { AstNode *child_block = trans_create_node(c, NodeTypeBlock); for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { - AstNode *child_node = trans_stmt(c, child_block, *it); + AstNode *child_node = trans_stmt(c, false, child_block, *it, TransRValue); if (child_node == nullptr) return nullptr; if (child_node != skip_add_to_block_node) @@ -725,7 +889,7 @@ static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) return nullptr; } else { AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); - return_node->data.return_expr.expr = trans_expr(c, block, value_expr); + return_node->data.return_expr.expr = trans_expr(c, true, block, value_expr, TransRValue); if (return_node->data.return_expr.expr == nullptr) return nullptr; return return_node; @@ -741,44 +905,93 @@ static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) { return trans_create_node_apint(c, result); } -static AstNode *trans_conditional_operator(Context *c, AstNode *block, ConditionalOperator *stmt) { +static AstNode *trans_conditional_operator(Context *c, bool result_used, AstNode *block, ConditionalOperator *stmt) { AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); Expr *cond_expr = stmt->getCond(); Expr *true_expr = stmt->getTrueExpr(); Expr *false_expr = stmt->getFalseExpr(); - node->data.if_bool_expr.condition = trans_expr(c, block, cond_expr); + node->data.if_bool_expr.condition = trans_expr(c, true, block, cond_expr, TransRValue); if (node->data.if_bool_expr.condition == nullptr) return nullptr; - node->data.if_bool_expr.then_block = trans_expr(c, block, true_expr); + node->data.if_bool_expr.then_block = trans_expr(c, result_used, block, true_expr, TransRValue); if (node->data.if_bool_expr.then_block == nullptr) return nullptr; - node->data.if_bool_expr.else_node = trans_expr(c, block, false_expr); + node->data.if_bool_expr.else_node = trans_expr(c, result_used, block, false_expr, TransRValue); if (node->data.if_bool_expr.else_node == nullptr) return nullptr; - return node; + return maybe_suppress_result(c, result_used, node); } static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOpType bin_op, Expr *rhs) { AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.bin_op = bin_op; - node->data.bin_op_expr.op1 = trans_expr(c, block, lhs); + node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransRValue); if (node->data.bin_op_expr.op1 == nullptr) return nullptr; - node->data.bin_op_expr.op2 = trans_expr(c, block, rhs); + node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); if (node->data.bin_op_expr.op2 == nullptr) return nullptr; return node; } -static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator *stmt) { +static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block, Expr *lhs, Expr *rhs) { + if (!result_used) { + // common case + AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); + node->data.bin_op_expr.bin_op = BinOpTypeAssign; + + node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransLValue); + if (node->data.bin_op_expr.op1 == nullptr) + return nullptr; + + node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); + if (node->data.bin_op_expr.op2 == nullptr) + return nullptr; + + return node; + } else { + // worst case + // c: lhs = rhs + // zig: { + // zig: const _tmp = rhs; + // zig: lhs = _tmp; + // zig: _tmp + // zig: } + + AstNode *child_block = trans_create_node(c, NodeTypeBlock); + + // const _tmp = rhs; + AstNode *rhs_node = trans_expr(c, true, child_block, rhs, TransRValue); + if (rhs_node == nullptr) return nullptr; + // 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, rhs_node); + child_block->data.block.statements.append(tmp_var_decl); + + // lhs = _tmp; + AstNode *lhs_node = trans_expr(c, true, child_block, lhs, TransLValue); + if (lhs_node == nullptr) return nullptr; + child_block->data.block.statements.append( + trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, + trans_create_node_symbol(c, tmp_var_name))); + + // _tmp + child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); + child_block->data.block.last_statement_is_result_expression = true; + + return child_block; + } +} + +static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { switch (stmt->getOpcode()) { case BO_PtrMemD: emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD"); @@ -787,20 +1000,47 @@ static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI"); return nullptr; case BO_Mul: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Mul"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), + qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, + stmt->getRHS()); case BO_Div: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Div"); - return nullptr; + if (qual_type_has_wrapping_overflow(c, stmt->getType())) { + // unsigned/float division uses the operator + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); + } else { + // signed integer division uses @divTrunc + AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); + AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); + if (lhs == nullptr) return nullptr; + fn_call->data.fn_call_expr.params.append(lhs); + AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); + if (rhs == nullptr) return nullptr; + fn_call->data.fn_call_expr.params.append(rhs); + return fn_call; + } case BO_Rem: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Rem"); - return nullptr; + if (qual_type_has_wrapping_overflow(c, stmt->getType())) { + // unsigned/float division uses the operator + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); + } else { + // signed integer division uses @divTrunc + AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); + AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); + if (lhs == nullptr) return nullptr; + fn_call->data.fn_call_expr.params.append(lhs); + AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); + if (rhs == nullptr) return nullptr; + fn_call->data.fn_call_expr.params.append(rhs); + return fn_call; + } case BO_Add: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Add"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), + qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, + stmt->getRHS()); case BO_Sub: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Sub"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), + qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, + stmt->getRHS()); case BO_Shl: emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Shl"); return nullptr; @@ -816,29 +1056,22 @@ static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator case BO_GE: return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); case BO_EQ: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_EQ"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); case BO_NE: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_NE"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); case BO_And: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_And"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); case BO_Xor: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Xor"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); case BO_Or: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Or"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); case BO_LAnd: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_LAnd"); - return nullptr; + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); case BO_LOr: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_LOr"); - return nullptr; + // TODO: int vs bool + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); case BO_Assign: - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign"); - return nullptr; + return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS()); case BO_MulAssign: emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign"); return nullptr; @@ -877,32 +1110,170 @@ static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator zig_unreachable(); } +static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) { + switch (stmt->getOpcode()) { + case BO_MulAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_MulAssign"); + return nullptr; + case BO_DivAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); + return nullptr; + case BO_RemAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); + return nullptr; + case BO_AddAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AddAssign"); + return nullptr; + case BO_SubAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_SubAssign"); + return nullptr; + case BO_ShlAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_ShlAssign"); + return nullptr; + case BO_ShrAssign: { + BinOpType bin_op = BinOpTypeBitShiftRight; + + const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); + AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); + + bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); + if (!use_intermediate_casts && !result_used) { + // simple common case, where the C and Zig are identical: + // lhs >>= rh* s + AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); + if (lhs == nullptr) return nullptr; + + AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); + if (rhs == nullptr) return nullptr; + AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); + + return trans_create_node_bin_op(c, lhs, BinOpTypeAssignBitShiftRight, coerced_rhs); + } else { + // need more complexity. worst case, this looks like this: + // c: lhs >>= rhs + // zig: { + // zig: const _ref = &lhs; + // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); + // zig: *_ref + // zig: } + // where u5 is the appropriate type + + // TODO: avoid mess when we don't need the assignment value for chained assignments or anything. + AstNode *child_block = trans_create_node(c, NodeTypeBlock); + + // const _ref = &lhs; + AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); + if (lhs == nullptr) return nullptr; + AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); + // TODO: avoid name collisions with generated variable names + Buf* tmp_var_name = buf_create_from_str("_ref"); + AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); + child_block->data.block.statements.append(tmp_var_decl); + + // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); + + AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); + if (rhs == nullptr) return nullptr; + AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); + + AstNode *assign_statement = trans_create_node_bin_op(c, + trans_create_node_prefix_op(c, PrefixOpDereference, + trans_create_node_symbol(c, tmp_var_name)), + BinOpTypeAssign, + trans_c_cast(c, rhs_location, + stmt->getComputationResultType(), + trans_create_node_bin_op(c, + trans_c_cast(c, rhs_location, + stmt->getComputationLHSType(), + trans_create_node_prefix_op(c, PrefixOpDereference, + trans_create_node_symbol(c, tmp_var_name))), + bin_op, + coerced_rhs))); + child_block->data.block.statements.append(assign_statement); + + if (result_used) { + // *_ref + child_block->data.block.statements.append( + trans_create_node_prefix_op(c, PrefixOpDereference, + trans_create_node_symbol(c, tmp_var_name))); + child_block->data.block.last_statement_is_result_expression = true; + } + + return child_block; + } + } + case BO_AndAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign"); + return nullptr; + case BO_XorAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_XorAssign"); + return nullptr; + case BO_OrAssign: + emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_OrAssign"); + return nullptr; + case BO_PtrMemD: + case BO_PtrMemI: + case BO_Assign: + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Add: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_And: + case BO_Xor: + case BO_Or: + case BO_LAnd: + case BO_LOr: + case BO_Comma: + zig_panic("compound assign expected to be handled by binary operator"); + } + + zig_unreachable(); +} + static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) { switch (stmt->getCastKind()) { case CK_LValueToRValue: - return trans_expr(c, block, stmt->getSubExpr()); + return trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); case CK_IntegralCast: { - AstNode *node = trans_create_node_builtin_fn_call_str(c, "bitCast"); - - AstNode *result_type_node = trans_qual_type(c, stmt->getType(), stmt->getExprLoc()); - if (result_type_node == nullptr) + AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); + if (target_node == nullptr) return nullptr; - - AstNode *target_node = trans_expr(c, block, stmt->getSubExpr()); + return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); + } + case CK_FunctionToPointerDecay: + case CK_ArrayToPointerDecay: + { + AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) return nullptr; + return target_node; + } + case CK_BitCast: + { + AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); + if (target_node == nullptr) + return nullptr; + + AstNode *dest_type_node = trans_qual_type(c, stmt->getType(), stmt->getLocStart()); - node->data.fn_call_expr.params.append(result_type_node); + AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); + node->data.fn_call_expr.params.append(dest_type_node); node->data.fn_call_expr.params.append(target_node); return node; } case CK_Dependent: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); return nullptr; - case CK_BitCast: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BitCast"); - return nullptr; case CK_LValueBitCast: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_LValueBitCast"); return nullptr; @@ -924,12 +1295,6 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas case CK_ToUnion: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); return nullptr; - case CK_ArrayToPointerDecay: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ArrayToPointerDecay"); - return nullptr; - case CK_FunctionToPointerDecay: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FunctionToPointerDecay"); - return nullptr; case CK_NullToPointer: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToPointer"); return nullptr; @@ -1069,17 +1434,44 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas zig_unreachable(); } -static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt) { +static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue lrval) { ValueDecl *value_decl = stmt->getDecl(); - const char *name = decl_name(value_decl); - return trans_create_node_symbol_str(c, name); + Buf *symbol_name = buf_create_from_str(decl_name(value_decl)); + if (lrval == TransLValue) { + c->ptr_params.put(symbol_name, true); + } + return trans_create_node_symbol(c, symbol_name); } -static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator *stmt) { +static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { switch (stmt->getOpcode()) { - case UO_PostInc: - emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc"); - return nullptr; + case UO_PostInc: { + Expr *op_expr = stmt->getSubExpr(); + BinOpType bin_op = qual_type_has_wrapping_overflow(c, op_expr->getType()) + ? BinOpTypeAssignPlusWrap + : BinOpTypeAssignPlus; + + if (!result_used) { + // common case + // c: expr++ + // zig: expr += 1 + return trans_create_node_bin_op(c, + trans_expr(c, true, block, op_expr, TransLValue), + bin_op, + trans_create_node_unsigned(c, 1)); + } else { + // worst case + // c: expr++ + // zig: { + // zig: const _ref = &expr; + // zig: const _tmp = *_ref; + // zig: *_ref += 1; + // zig: _tmp + // zig: } + emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostInc with result_used"); + return nullptr; + } + } case UO_PostDec: emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PostDec"); return nullptr; @@ -1101,11 +1493,11 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * case UO_Minus: { Expr *op_expr = stmt->getSubExpr(); - if (c_is_signed_integer(c, op_expr->getType()) || c_is_float(c, op_expr->getType())) { + if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); node->data.prefix_op_expr.prefix_op = PrefixOpNegation; - node->data.prefix_op_expr.primary_expr = trans_expr(c, block, op_expr); + node->data.prefix_op_expr.primary_expr = trans_expr(c, true, block, op_expr, TransRValue); if (node->data.prefix_op_expr.primary_expr == nullptr) return nullptr; @@ -1115,7 +1507,7 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); - node->data.bin_op_expr.op2 = trans_expr(c, block, op_expr); + node->data.bin_op_expr.op2 = trans_expr(c, true, block, op_expr, TransRValue); if (node->data.bin_op_expr.op2 == nullptr) return nullptr; @@ -1157,7 +1549,7 @@ static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *st QualType qual_type = var_decl->getTypeSourceInfo()->getType(); AstNode *init_node = nullptr; if (var_decl->hasInit()) { - init_node = trans_expr(c, block, var_decl->getInit()); + init_node = trans_expr(c, true, block, var_decl->getInit(), TransRValue); if (init_node == nullptr) return nullptr; @@ -1166,8 +1558,10 @@ static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *st if (type_node == nullptr) return nullptr; - AstNode *node = trans_create_node_var_decl(c, qual_type.isConstQualified(), - buf_create_from_str(decl_name(var_decl)), type_node, init_node); + Buf *symbol_name = buf_create_from_str(decl_name(var_decl)); + + AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), + symbol_name, type_node, init_node); block->data.block.statements.append(node); continue; } @@ -1398,18 +1792,112 @@ static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *st static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); - while_node->data.while_expr.condition = trans_expr(c, block, stmt->getCond()); + while_node->data.while_expr.condition = trans_expr(c, true, block, stmt->getCond(), TransRValue); if (while_node->data.while_expr.condition == nullptr) return nullptr; - while_node->data.while_expr.body = trans_stmt(c, block, stmt->getBody()); + while_node->data.while_expr.body = trans_stmt(c, false, block, stmt->getBody(), TransRValue); if (while_node->data.while_expr.body == nullptr) return nullptr; return while_node; } -static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { +static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) { + // if (c) t + // if (c) t else e + AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); + + // TODO: condition != 0 + AstNode *condition_node = trans_expr(c, true, block, stmt->getCond(), TransRValue); + if (condition_node == nullptr) + return nullptr; + if_node->data.if_bool_expr.condition = condition_node; + + if_node->data.if_bool_expr.then_block = trans_stmt(c, false, block, stmt->getThen(), TransRValue); + if (if_node->data.if_bool_expr.then_block == nullptr) + return nullptr; + + if (stmt->getElse() != nullptr) { + if_node->data.if_bool_expr.else_node = trans_stmt(c, false, block, stmt->getElse(), TransRValue); + if (if_node->data.if_bool_expr.else_node == nullptr) + return nullptr; + } + + return if_node; +} + +static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) { + AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); + node->data.fn_call_expr.fn_ref_expr = trans_expr(c, true, block, stmt->getCallee(), TransRValue); + if (node->data.fn_call_expr.fn_ref_expr == nullptr) + return nullptr; + + unsigned num_args = stmt->getNumArgs(); + Expr **args = stmt->getArgs(); + for (unsigned i = 0; i < num_args; i += 1) { + AstNode *arg_node = trans_expr(c, true, block, args[i], TransRValue); + if (arg_node == nullptr) + return nullptr; + + node->data.fn_call_expr.params.append(arg_node); + } + + return node; +} + +static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt) { + AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); + if (container_node == nullptr) + return nullptr; + + if (stmt->isArrow()) { + container_node = trans_create_node_unwrap_null(c, container_node); + } + + const char *name = decl_name(stmt->getMemberDecl()); + + AstNode *node = trans_create_node_field_access_str(c, container_node, name); + return node; +} + +static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubscriptExpr *stmt) { + AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); + if (container_node == nullptr) + return nullptr; + + AstNode *idx_node = trans_expr(c, true, block, stmt->getIdx(), TransRValue); + if (idx_node == nullptr) + return nullptr; + + + AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); + node->data.array_access_expr.array_ref_expr = container_node; + node->data.array_access_expr.subscript = idx_node; + return node; +} + +static AstNode *trans_c_style_cast_expr(Context *c, bool result_used, AstNode *block, + CStyleCastExpr *stmt, TransLRValue lrvalue) +{ + AstNode *sub_expr_node = trans_expr(c, result_used, block, stmt->getSubExpr(), lrvalue); + if (sub_expr_node == nullptr) + return nullptr; + + return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), sub_expr_node); +} + +static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, UnaryExprOrTypeTraitExpr *stmt) { + AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); + if (type_node == nullptr) + return nullptr; + + AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); + node->data.fn_call_expr.params.append(type_node); + return node; +} + +static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { case Stmt::ReturnStmtClass: @@ -1419,19 +1907,35 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::IntegerLiteralClass: return trans_integer_literal(c, (IntegerLiteral *)stmt); case Stmt::ConditionalOperatorClass: - return trans_conditional_operator(c, block, (ConditionalOperator *)stmt); + return trans_conditional_operator(c, result_used, block, (ConditionalOperator *)stmt); case Stmt::BinaryOperatorClass: - return trans_binary_operator(c, block, (BinaryOperator *)stmt); + return trans_binary_operator(c, result_used, block, (BinaryOperator *)stmt); + case Stmt::CompoundAssignOperatorClass: + return trans_compound_assign_operator(c, result_used, block, (CompoundAssignOperator *)stmt); case Stmt::ImplicitCastExprClass: return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt); case Stmt::DeclRefExprClass: - return trans_decl_ref_expr(c, (DeclRefExpr *)stmt); + return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); case Stmt::UnaryOperatorClass: - return trans_unary_operator(c, block, (UnaryOperator *)stmt); + return trans_unary_operator(c, result_used, block, (UnaryOperator *)stmt); case Stmt::DeclStmtClass: return trans_local_declaration(c, block, (DeclStmt *)stmt); case Stmt::WhileStmtClass: return trans_while_loop(c, block, (WhileStmt *)stmt); + case Stmt::IfStmtClass: + return trans_if_statement(c, block, (IfStmt *)stmt); + case Stmt::CallExprClass: + return trans_call_expr(c, result_used, block, (CallExpr *)stmt); + case Stmt::NullStmtClass: + return skip_add_to_block_node; + case Stmt::MemberExprClass: + return trans_member_expr(c, block, (MemberExpr *)stmt); + case Stmt::ArraySubscriptExprClass: + return trans_array_subscript_expr(c, block, (ArraySubscriptExpr *)stmt); + case Stmt::CStyleCastExprClass: + return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue); + case Stmt::UnaryExprOrTypeTraitExprClass: + return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt); case Stmt::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -1492,9 +1996,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::ArrayInitLoopExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass"); return nullptr; - case Stmt::ArraySubscriptExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C ArraySubscriptExprClass"); - return nullptr; case Stmt::ArrayTypeTraitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass"); return nullptr; @@ -1504,9 +2005,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::AtomicExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass"); return nullptr; - case Stmt::CompoundAssignOperatorClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundAssignOperatorClass"); - return nullptr; case Stmt::BlockExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass"); return nullptr; @@ -1573,13 +2071,11 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::CXXUuidofExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); return nullptr; - case Stmt::CallExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C CallExprClass"); - return nullptr; case Stmt::CUDAKernelCallExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass"); return nullptr; case Stmt::CXXMemberCallExprClass: + (void)result_used; emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass"); return nullptr; case Stmt::CXXOperatorCallExprClass: @@ -1588,9 +2084,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::UserDefinedLiteralClass: emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass"); return nullptr; - case Stmt::CStyleCastExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C CStyleCastExprClass"); - return nullptr; case Stmt::CXXFunctionalCastExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass"); return nullptr; @@ -1681,9 +2174,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::MaterializeTemporaryExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass"); return nullptr; - case Stmt::MemberExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C MemberExprClass"); - return nullptr; case Stmt::NoInitExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass"); return nullptr; @@ -1751,8 +2241,7 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass"); return nullptr; case Stmt::ParenExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C ParenExprClass"); - return nullptr; + return trans_expr(c, result_used, block, ((ParenExpr*)stmt)->getSubExpr(), lrvalue); case Stmt::ParenListExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); return nullptr; @@ -1786,9 +2275,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::TypoExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass"); return nullptr; - case Stmt::UnaryExprOrTypeTraitExprClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C UnaryExprOrTypeTraitExprClass"); - return nullptr; case Stmt::VAArgExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass"); return nullptr; @@ -1798,9 +2284,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::GotoStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass"); return nullptr; - case Stmt::IfStmtClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C IfStmtClass"); - return nullptr; case Stmt::IndirectGotoStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass"); return nullptr; @@ -1810,9 +2293,6 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { case Stmt::MSDependentExistsStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass"); return nullptr; - case Stmt::NullStmtClass: - emit_warning(c, stmt->getLocStart(), "TODO handle C NullStmtClass"); - return nullptr; case Stmt::OMPAtomicDirectiveClass: emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass"); return nullptr; @@ -2025,36 +2505,65 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { AstNode *param_node = proto_node->data.fn_proto.params.at(i); const ParmVarDecl *param = fn_decl->getParamDecl(i); const char *name = decl_name(param); - if (strlen(name) == 0) { - Buf *proto_param_name = param_node->data.param_decl.name; + Buf *proto_param_name; + if (strlen(name) != 0) { + proto_param_name = buf_create_from_str(name); + } else { + proto_param_name = param_node->data.param_decl.name; if (proto_param_name == nullptr) { - param_node->data.param_decl.name = buf_sprintf("arg%" ZIG_PRI_usize "", i); - } else { - param_node->data.param_decl.name = proto_param_name; + proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); } - } else { - param_node->data.param_decl.name = buf_create_from_str(name); } + param_node->data.param_decl.name = proto_param_name; + } + + if (!fn_decl->hasBody()) { + // just a prototype + c->root->data.root.top_level_decls.append(proto_node); + return; } - if (fn_decl->hasBody()) { - Stmt *body = fn_decl->getBody(); + // actual function definition with body + c->ptr_params.clear(); + Stmt *body = fn_decl->getBody(); + AstNode *actual_body_node = trans_stmt(c, false, nullptr, body, TransRValue); + assert(actual_body_node != skip_add_to_block_node); + if (actual_body_node == nullptr) { + emit_warning(c, fn_decl->getLocation(), "unable to translate function"); + return; + } - AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); - fn_def_node->data.fn_def.fn_proto = proto_node; - fn_def_node->data.fn_def.body = trans_stmt(c, nullptr, body); - assert(fn_def_node->data.fn_def.body != skip_add_to_block_node); - if (fn_def_node->data.fn_def.body == nullptr) { - emit_warning(c, fn_decl->getLocation(), "unable to translate function"); - return; + // it worked + + assert(actual_body_node->type == NodeTypeBlock); + AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock); + + for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { + AstNode *param_node = proto_node->data.fn_proto.params.at(i); + Buf *good_name = param_node->data.param_decl.name; + + if (c->ptr_params.maybe_get(good_name) != nullptr) { + // TODO: avoid name collisions + Buf *mangled_name = buf_sprintf("_arg_%s", buf_ptr(good_name)); + param_node->data.param_decl.name = mangled_name; + + // var c_name = _mangled_name; + AstNode *parameter_init = trans_create_node_var_decl_local(c, false, good_name, nullptr, trans_create_node_symbol(c, mangled_name)); + + body_node_with_param_inits->data.block.statements.append(parameter_init); } + } - proto_node->data.fn_proto.fn_def_node = fn_def_node; - c->root->data.root.top_level_decls.append(fn_def_node); - return; + for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { + body_node_with_param_inits->data.block.statements.append(actual_body_node->data.block.statements.at(i)); } - c->root->data.root.top_level_decls.append(proto_node); + AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); + fn_def_node->data.fn_def.fn_proto = proto_node; + fn_def_node->data.fn_def.body = body_node_with_param_inits; + + proto_node->data.fn_proto.fn_def_node = fn_def_node; + c->root->data.root.top_level_decls.append(fn_def_node); } static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { @@ -2190,9 +2699,14 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { // in C each enum value is in the global namespace. so we put them there too. // at this point we can rely on the enum emitting successfully - AstNode *field_access_node = trans_create_node_field_access(c, - trans_create_node_symbol(c, full_type_name), field_name); - add_global_var(c, enum_val_name, field_access_node); + if (is_anonymous) { + AstNode *lit_node = trans_create_node_unsigned(c, i); + add_global_var(c, enum_val_name, lit_node); + } else { + AstNode *field_access_node = trans_create_node_field_access(c, + trans_create_node_symbol(c, full_type_name), field_name); + add_global_var(c, enum_val_name, field_access_node); + } } if (is_anonymous) { @@ -2376,7 +2890,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { init_node = trans_create_node_apint(c, ap_value->getInt()); break; case APValue::Uninitialized: - init_node = trans_create_node_symbol_str(c, "undefined"); + init_node = trans_create_node(c, NodeTypeUndefinedLiteral); break; case APValue::Float: case APValue::ComplexInt: @@ -2393,16 +2907,16 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { return; } } else { - init_node = trans_create_node_symbol_str(c, "undefined"); + init_node = trans_create_node(c, NodeTypeUndefinedLiteral); } - AstNode *var_node = trans_create_node_var_decl(c, is_const, name, var_type, init_node); + AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, init_node); c->root->data.root.top_level_decls.append(var_node); return; } if (is_extern) { - AstNode *var_node = trans_create_node_var_decl(c, is_const, name, var_type, nullptr); + AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, nullptr); var_node->data.variable_declaration.is_extern = true; c->root->data.root.top_level_decls.append(var_node); return; @@ -2663,6 +3177,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch c->visib_mod = VisibModPub; c->decl_table.init(8); c->macro_table.init(8); + c->ptr_params.init(8); c->codegen = codegen; c->source_node = source_node; diff --git a/src/util.hpp b/src/util.hpp index b4f90bc79a..bf997bb08a 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -147,4 +147,8 @@ bool uint64_eq(uint64_t a, uint64_t b); uint32_t ptr_hash(const void *ptr); bool ptr_eq(const void *a, const void *b); +static inline uint8_t log2_u64(uint64_t x) { + return (63 - clzll(x)); +} + #endif |
