From 4bd23aefe7c96063b31433d26b7135b890996b02 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Sep 2017 22:58:06 -0400 Subject: local var --- src/parsec.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 32462407ee..47f45dc9b6 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -188,11 +188,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 +200,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); @@ -268,7 +280,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; } @@ -1166,7 +1178,7 @@ 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(), + AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), buf_create_from_str(decl_name(var_decl)), type_node, init_node); block->data.block.statements.append(node); continue; @@ -2396,13 +2408,13 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { init_node = trans_create_node_symbol_str(c, "undefined"); } - 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; -- cgit v1.2.3 From 6f50457b61b076bee8378c083e01425f7c81c76b Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Mon, 11 Sep 2017 19:58:14 -0700 Subject: wip c to zig stuff --- src/parsec.cpp | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 175 insertions(+), 14 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 32462407ee..09afc02369 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -126,6 +126,13 @@ 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); node->data.field_access_expr.struct_expr = container; @@ -133,6 +140,10 @@ static AstNode *trans_create_node_field_access(Context *c, AstNode *container, B 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 +151,14 @@ 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 *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 +174,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(1); @@ -286,10 +312,45 @@ 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 AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, + const SourceLocation &source_loc) +{ + 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(qt.getTypePtr()); @@ -361,7 +422,6 @@ 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 AstNode *const skip_add_to_block_node = (AstNode *) 0x2; static AstNode *trans_expr(Context *c, AstNode *block, Expr *expr) { @@ -877,25 +937,127 @@ static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator zig_unreachable(); } +static AstNode *trans_compound_assign_operator(Context *c, 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; + // 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, child_block, stmt->getLHS()); + 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(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, child_block, stmt->getRHS()); + if (rhs == nullptr) return nullptr; + const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); + AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); + + 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, + trans_create_node_fn_call_1(c, + rhs_type, + rhs)))); + child_block->data.block.statements.append(assign_statement); + + // *_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()); 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) - return nullptr; - AstNode *target_node = trans_expr(c, block, stmt->getSubExpr()); if (target_node == nullptr) return nullptr; - - node->data.fn_call_expr.params.append(result_type_node); - node->data.fn_call_expr.params.append(target_node); - return node; + return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); } case CK_Dependent: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); @@ -1422,6 +1584,8 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { return trans_conditional_operator(c, block, (ConditionalOperator *)stmt); case Stmt::BinaryOperatorClass: return trans_binary_operator(c, block, (BinaryOperator *)stmt); + case Stmt::CompoundAssignOperatorClass: + return trans_compound_assign_operator(c, block, (CompoundAssignOperator *)stmt); case Stmt::ImplicitCastExprClass: return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt); case Stmt::DeclRefExprClass: @@ -1504,9 +1668,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; -- cgit v1.2.3 From e52418097d908f6f0b96513395752405329caf4e Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Mon, 11 Sep 2017 20:08:45 -0700 Subject: not my segfault --- src/parsec.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index cc9da96ed4..9d1d892c2d 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -988,7 +988,7 @@ static AstNode *trans_compound_assign_operator(Context *c, AstNode *block, Compo 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(c, true, tmp_var_name, nullptr, addr_of_lhs); + 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)); @@ -2194,10 +2194,13 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { return; } + ZigList fake_names; 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); const ParmVarDecl *param = fn_decl->getParamDecl(i); const char *name = decl_name(param); + fake_names.append(buf_create_from_str(name)); + buf_append_char(fake_names.at(i), '_'); if (strlen(name) == 0) { Buf *proto_param_name = param_node->data.param_decl.name; if (proto_param_name == nullptr) { -- cgit v1.2.3 From 99cb6e955a4a044a19f98abd1d486560ee9c9729 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Mon, 11 Sep 2017 20:39:42 -0700 Subject: oh, actually it was --- src/parsec.cpp | 66 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 23 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 9d1d892c2d..b508f0f622 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -2194,43 +2194,63 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { return; } - ZigList fake_names; 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); const ParmVarDecl *param = fn_decl->getParamDecl(i); const char *name = decl_name(param); - fake_names.append(buf_create_from_str(name)); - buf_append_char(fake_names.at(i), '_'); - 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()) { - Stmt *body = fn_decl->getBody(); + if (!fn_decl->hasBody()) { + // just a prototype + c->root->data.root.top_level_decls.append(proto_node); + 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; - } + // actual function definition with body - proto_node->data.fn_proto.fn_def_node = fn_def_node; - c->root->data.root.top_level_decls.append(fn_def_node); + Stmt *body = fn_decl->getBody(); + AstNode *actual_body_node = trans_stmt(c, nullptr, body); + 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; } - c->root->data.root.top_level_decls.append(proto_node); + // it worked + + AstNode *parameter_init_block = 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; + // 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)); + + parameter_init_block->data.block.statements.append(parameter_init); + } + + parameter_init_block->data.block.statements.append(actual_body_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 = parameter_init_block; + + 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) { -- cgit v1.2.3 From 4adffea8d03f63650263e5ea984ecd47b0b3a903 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Mon, 11 Sep 2017 21:37:11 -0700 Subject: analysis of result used --- src/parsec.cpp | 79 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 33 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index b508f0f622..4070fb4186 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -159,6 +159,14 @@ static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpTyp 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; @@ -433,11 +441,11 @@ static bool c_is_float(Context *c, QualType qt) { } } -static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt); +static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt); 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) { + return trans_stmt(c, result_used, block, expr); } static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { @@ -781,7 +789,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); if (child_node == nullptr) return nullptr; if (child_node != skip_add_to_block_node) @@ -797,7 +805,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); if (return_node->data.return_expr.expr == nullptr) return nullptr; return return_node; @@ -813,44 +821,44 @@ 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); 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); 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); 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); 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); 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_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"); @@ -909,6 +917,7 @@ static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_LOr"); return nullptr; case BO_Assign: + (void)result_used; emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign"); return nullptr; case BO_MulAssign: @@ -949,7 +958,7 @@ static AstNode *trans_binary_operator(Context *c, AstNode *block, BinaryOperator zig_unreachable(); } -static AstNode *trans_compound_assign_operator(Context *c, AstNode *block, CompoundAssignOperator *stmt) { +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"); @@ -983,7 +992,7 @@ static AstNode *trans_compound_assign_operator(Context *c, AstNode *block, Compo AstNode *child_block = trans_create_node(c, NodeTypeBlock); // const _ref = &lhs; - AstNode *lhs = trans_expr(c, child_block, stmt->getLHS()); + AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS()); 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 @@ -993,7 +1002,7 @@ static AstNode *trans_compound_assign_operator(Context *c, AstNode *block, Compo // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); - AstNode *rhs = trans_expr(c, child_block, stmt->getRHS()); + AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS()); if (rhs == nullptr) return nullptr; const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); @@ -1015,11 +1024,13 @@ static AstNode *trans_compound_assign_operator(Context *c, AstNode *block, Compo rhs)))); child_block->data.block.statements.append(assign_statement); - // *_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; + 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; } @@ -1063,10 +1074,10 @@ static AstNode *trans_compound_assign_operator(Context *c, AstNode *block, Compo 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()); case CK_IntegralCast: { - AstNode *target_node = trans_expr(c, block, stmt->getSubExpr()); + AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr()); if (target_node == nullptr) return nullptr; return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); @@ -1279,7 +1290,7 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * 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); if (node->data.prefix_op_expr.primary_expr == nullptr) return nullptr; @@ -1289,7 +1300,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); if (node->data.bin_op_expr.op2 == nullptr) return nullptr; @@ -1331,7 +1342,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()); if (init_node == nullptr) return nullptr; @@ -1572,18 +1583,18 @@ 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()); 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()); 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_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { case Stmt::ReturnStmtClass: @@ -1593,11 +1604,11 @@ 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, block, (CompoundAssignOperator *)stmt); + 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: @@ -1747,12 +1758,14 @@ static AstNode *trans_stmt(Context *c, AstNode *block, Stmt *stmt) { emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); return nullptr; case Stmt::CallExprClass: + (void)result_used; 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: @@ -2219,7 +2232,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { // actual function definition with body Stmt *body = fn_decl->getBody(); - AstNode *actual_body_node = trans_stmt(c, nullptr, body); + AstNode *actual_body_node = trans_stmt(c, false, nullptr, body); assert(actual_body_node != skip_add_to_block_node); if (actual_body_node == nullptr) { emit_warning(c, fn_decl->getLocation(), "unable to translate function"); -- cgit v1.2.3 From b1e04865cc2313886238e4361dcf2c849b9ecd7b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Sep 2017 13:08:02 -0400 Subject: parsec: don't make pointless block in fn body --- src/parsec.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index d1d9791ab8..a7b4f79196 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -2241,7 +2241,8 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { // it worked - AstNode *parameter_init_block = trans_create_node(c, NodeTypeBlock); + 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); @@ -2253,14 +2254,16 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { // 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)); - parameter_init_block->data.block.statements.append(parameter_init); + body_node_with_param_inits->data.block.statements.append(parameter_init); } - parameter_init_block->data.block.statements.append(actual_body_node); + 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)); + } 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 = parameter_init_block; + 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); -- cgit v1.2.3 From 0228f8c9fd848ec86aa188229ee82dfb0698ae0d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Sep 2017 21:16:26 -0400 Subject: all parsec tests passing --- src/parsec.cpp | 82 ++++++++++++++++++++++++++++++++++----------------------- test/parsec.zig | 23 ++++++++++++++++ 2 files changed, 72 insertions(+), 33 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index a7b4f79196..94ef135f44 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -49,6 +49,8 @@ struct Context { CodeGen *codegen; ASTContext *ctx; + + HashMap ptr_params; }; static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); @@ -441,11 +443,16 @@ static bool c_is_float(Context *c, QualType qt) { } } -static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt); +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, bool result_used, AstNode *block, Expr *expr) { - return trans_stmt(c, result_used, 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) { @@ -789,7 +796,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, false, 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) @@ -805,7 +812,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, true, 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; @@ -828,15 +835,15 @@ static AstNode *trans_conditional_operator(Context *c, bool result_used, AstNode Expr *true_expr = stmt->getTrueExpr(); Expr *false_expr = stmt->getFalseExpr(); - node->data.if_bool_expr.condition = trans_expr(c, true, 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, result_used, 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, result_used, 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; @@ -847,11 +854,11 @@ static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOp 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, true, 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, true, 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; @@ -992,7 +999,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast AstNode *child_block = trans_create_node(c, NodeTypeBlock); // const _ref = &lhs; - AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS()); + 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 @@ -1002,7 +1009,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); - AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS()); + AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); if (rhs == nullptr) return nullptr; const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); @@ -1074,10 +1081,10 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) { switch (stmt->getCastKind()) { case CK_LValueToRValue: - return trans_expr(c, true, block, stmt->getSubExpr()); + return trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); case CK_IntegralCast: { - AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr()); + AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); if (target_node == nullptr) return nullptr; return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); @@ -1254,10 +1261,13 @@ 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) { @@ -1290,7 +1300,7 @@ static AstNode *trans_unary_operator(Context *c, AstNode *block, UnaryOperator * 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, true, 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; @@ -1300,7 +1310,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, true, 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; @@ -1342,7 +1352,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, true, block, var_decl->getInit()); + init_node = trans_expr(c, true, block, var_decl->getInit(), TransRValue); if (init_node == nullptr) return nullptr; @@ -1351,8 +1361,10 @@ static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *st if (type_node == nullptr) return nullptr; + Buf *symbol_name = buf_create_from_str(decl_name(var_decl)); + AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), - buf_create_from_str(decl_name(var_decl)), type_node, init_node); + symbol_name, type_node, init_node); block->data.block.statements.append(node); continue; } @@ -1583,18 +1595,18 @@ 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, true, 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, false, 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, bool result_used, AstNode *block, Stmt *stmt) { +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: @@ -1612,7 +1624,7 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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); case Stmt::DeclStmtClass: @@ -2230,9 +2242,9 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { } // actual function definition with body - + c->ptr_params.clear(); Stmt *body = fn_decl->getBody(); - AstNode *actual_body_node = trans_stmt(c, false, nullptr, body); + 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"); @@ -2247,14 +2259,17 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { 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; - // 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)); + 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; - body_node_with_param_inits->data.block.statements.append(parameter_init); + // 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); + } } for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { @@ -2875,6 +2890,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *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/test/parsec.zig b/test/parsec.zig index 9b1bffcb55..8f5a2a8f8a 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -314,4 +314,27 @@ pub fn addCases(cases: &tests.ParseCContext) { , \\pub const LUA_GLOBALSINDEX = -10002; ); + + cases.add("sift right assign", + \\int log2(unsigned a) { + \\ int i = 0; + \\ while (a > 0) { + \\ a >>= 100; + \\ //i++; + \\ } + \\ return i; + \\} + , + \\export fn log2(_arg_a: c_uint) -> c_int { + \\ var a = _arg_a; + \\ var i: c_int = 0; + \\ while (a > c_uint(0)) { + \\ { + \\ const _ref = &a; + \\ *_ref = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(100)); + \\ }; + \\ }; + \\ return i; + \\} + ); } -- cgit v1.2.3 From e2f8bec7ac1834c6d6db73f0089483295298c8af Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 18:37:36 -0700 Subject: optimize >>= operator for common case --- src/parsec.cpp | 112 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 48 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 94ef135f44..fcffaf7a88 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -987,59 +987,75 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast return nullptr; case BO_ShrAssign: { BinOpType bin_op = BinOpTypeBitShiftRight; - // 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; + const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); - 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, - trans_create_node_fn_call_1(c, - rhs_type, - rhs)))); - child_block->data.block.statements.append(assign_statement); - - if (result_used) { - // *_ref - child_block->data.block.statements.append( + 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))); - child_block->data.block.last_statement_is_result_expression = true; - } + 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; + return child_block; + } } case BO_AndAssign: emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign"); -- cgit v1.2.3 From 9cdb5dec7aed4a1f692f4ddac034d1f944c0a837 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Sep 2017 22:44:24 -0400 Subject: parsec: cleaner shifting code for fixed size types --- src/analyze.cpp | 4 ---- src/parsec.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/util.hpp | 4 ++++ test/parsec.zig | 23 +++++++++++++++++++++-- 4 files changed, 76 insertions(+), 6 deletions(-) (limited to 'src/parsec.cpp') 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/parsec.cpp b/src/parsec.cpp index fcffaf7a88..9307ba6733 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -347,9 +347,60 @@ static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, 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(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(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); 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 diff --git a/test/parsec.zig b/test/parsec.zig index 16650d24a1..f408066d24 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -315,12 +315,11 @@ pub fn addCases(cases: &tests.ParseCContext) { \\pub const LUA_GLOBALSINDEX = -10002; ); - cases.add("sift right assign", + cases.add("shift right assign", \\int log2(unsigned a) { \\ int i = 0; \\ while (a > 0) { \\ a >>= 1; - \\ //i++; \\ } \\ return i; \\} @@ -334,4 +333,24 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ return i; \\} ); + + cases.add("shift right assign with a fixed size type", + \\#include + \\int log2(uint32_t a) { + \\ int i = 0; + \\ while (a > 0) { + \\ a >>= 1; + \\ } + \\ return i; + \\} + , + \\export fn log2(_arg_a: u32) -> c_int { + \\ var a = _arg_a; + \\ var i: c_int = 0; + \\ while (a > c_uint(0)) { + \\ a >>= u5(1); + \\ }; + \\ return i; + \\} + ); } -- cgit v1.2.3 From c10b052ceec96b0e927a3365708798a860696cbf Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 19:49:41 -0700 Subject: translate expr++ from c to zig --- src/parsec.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 8 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index fcffaf7a88..5b2c860bf5 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -386,8 +386,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(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(c_type); @@ -406,7 +415,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(c_type); @@ -443,6 +452,16 @@ static bool c_is_float(Context *c, QualType qt) { } } +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, @@ -1286,11 +1305,35 @@ static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue 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; @@ -1312,7 +1355,7 @@ 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; @@ -1642,7 +1685,7 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s case Stmt::DeclRefExprClass: 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: -- cgit v1.2.3 From 38059e6f97ae62aab9d3ca2f386eca1a1186a930 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 20 Sep 2017 23:16:44 -0400 Subject: parse-c: fix anonymous enums --- src/parsec.cpp | 14 +++++++++++--- test/parsec.zig | 10 ++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index d2f5731e22..2895ccdb1b 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -137,6 +137,9 @@ static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, As 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; @@ -2527,9 +2530,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) { diff --git a/test/parsec.zig b/test/parsec.zig index f408066d24..0952d2debf 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -353,4 +353,14 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ return i; \\} ); + + cases.add("anonymous enum", + \\enum { + \\ One, + \\ Two, + \\}; + , + \\pub const One = 0; + \\pub const Two = 1; + ); } -- cgit v1.2.3 From f68d724647b33028310471b5e7a32dd5898ac961 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 00:02:18 -0400 Subject: parse-c: support function calls --- src/parsec.cpp | 35 ++++++++++++++++++++++++++++------- test/parsec.zig | 10 ++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 2895ccdb1b..8cc0945e48 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1178,6 +1178,13 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas return nullptr; return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); } + case CK_FunctionToPointerDecay: + { + AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); + if (target_node == nullptr) + return nullptr; + return target_node; + } case CK_Dependent: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); return nullptr; @@ -1208,9 +1215,6 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas 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; @@ -1719,6 +1723,25 @@ static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { return while_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_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -1744,6 +1767,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s return trans_local_declaration(c, block, (DeclStmt *)stmt); case Stmt::WhileStmtClass: return trans_while_loop(c, block, (WhileStmt *)stmt); + case Stmt::CallExprClass: + return trans_call_expr(c, result_used, block, (CallExpr *)stmt); case Stmt::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -1882,10 +1907,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s case Stmt::CXXUuidofExprClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); return nullptr; - case Stmt::CallExprClass: - (void)result_used; - 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; diff --git a/test/parsec.zig b/test/parsec.zig index 0952d2debf..5df16aabac 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -363,4 +363,14 @@ pub fn addCases(cases: &tests.ParseCContext) { \\pub const One = 0; \\pub const Two = 1; ); + + cases.add("function call", + \\static void bar(void) { } + \\void foo(void) { bar(); } + , + \\pub fn bar() {} + \\export fn foo() { + \\ bar(); + \\} + ); } -- cgit v1.2.3 From 46fef543f945bb2ddce32073c16b93a153a47754 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 21:16:49 -0700 Subject: if statement --- src/parsec.cpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index d2f5731e22..bd9d8db822 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1716,6 +1716,30 @@ static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { return while_node; } +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_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -1741,6 +1765,9 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -2106,9 +2133,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; -- cgit v1.2.3 From 4c8443d96db4a441b393ea0c3c8d76a7493f46d0 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 21:37:56 -0700 Subject: logical and, logical or --- src/ast_render.cpp | 4 ++-- src/parsec.cpp | 10 ++++------ test/parsec.zig | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 1ac9d8de79..a68e1efc58 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 "<"; diff --git a/src/parsec.cpp b/src/parsec.cpp index da1d9dd3c4..342b519b19 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -976,8 +976,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo 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; @@ -991,11 +990,10 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Or"); return nullptr; 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: (void)result_used; emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign"); diff --git a/test/parsec.zig b/test/parsec.zig index b4f91a984f..a30cb067b1 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -373,6 +373,22 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + cases.add("logical and, logical or", + \\int max(int a, int b) { + \\ if (a < b || a == b) + \\ return b; + \\ if (a >= b && a == b) + \\ return a; + \\ return a; + \\} + , + \\export fn max(a: c_int, b: c_int) -> c_int { + \\ if ((a < b) or (a == b)) return b; + \\ if ((a >= b) and (a == b)) return a; + \\ return a; + \\} + ); + cases.add("shift right assign with a fixed size type", \\#include \\int log2(uint32_t a) { -- cgit v1.2.3 From 0827a8f36bd0b99b876586b8c7ee099fbc903535 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 21:47:43 -0700 Subject: ==, != --- src/parsec.cpp | 3 +-- test/parsec.zig | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 342b519b19..0c49cf30ef 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -978,8 +978,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo case BO_EQ: 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; diff --git a/test/parsec.zig b/test/parsec.zig index a30cb067b1..0027903f36 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -373,6 +373,22 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + cases.add("==, !=", + \\int max(int a, int b) { + \\ if (a == b) + \\ return a; + \\ if (a != b) + \\ return b; + \\ return a; + \\} + , + \\export fn max(a: c_int, b: c_int) -> c_int { + \\ if (a == b) return a; + \\ if (a != b) return b; + \\ return a; + \\} + ); + cases.add("logical and, logical or", \\int max(int a, int b) { \\ if (a < b || a == b) -- cgit v1.2.3 From eba45b0013bf06849ac55d99b4a20d44624c7016 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 00:54:08 -0400 Subject: parse-c: field access expressions --- src/ast_render.cpp | 2 ++ src/parsec.cpp | 24 +++++++++++++++++++++--- test/parsec.zig | 18 +++++++++++++++++- 3 files changed, 40 insertions(+), 4 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/ast_render.cpp b/src/ast_render.cpp index a68e1efc58..599d4b2659 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -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/parsec.cpp b/src/parsec.cpp index 0c49cf30ef..f559773497 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -291,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]; @@ -1763,6 +1767,21 @@ static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, Ca 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_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -1793,6 +1812,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s case Stmt::CallExprClass: return trans_call_expr(c, result_used, block, (CallExpr *)stmt); + case Stmt::MemberExprClass: + return trans_member_expr(c, block, (MemberExpr *)stmt); case Stmt::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -2037,9 +2058,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; diff --git a/test/parsec.zig b/test/parsec.zig index 0027903f36..45282e793a 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -98,7 +98,7 @@ pub fn addCases(cases: &tests.ParseCContext) { , \\pub const BarB = enum_Bar.B; , - \\pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar); + \\pub extern fn func(a: ?&struct_Foo, b: ?&(?&enum_Bar)); , \\pub const Foo = struct_Foo; , @@ -444,4 +444,20 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ bar(); \\} ); + + cases.add("field access expression", + \\struct Foo { + \\ int field; + \\}; + \\int read_field(struct Foo *foo) { + \\ return foo->field; + \\} + , + \\pub const struct_Foo = extern struct { + \\ field: c_int, + \\}; + \\export fn read_field(foo: ?&struct_Foo) -> c_int { + \\ return (??foo).field; + \\} + ); } -- cgit v1.2.3 From 0d9174750298574cd293869d255ae59e540d0ebb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 01:04:43 -0400 Subject: parse-c: null statements --- src/parsec.cpp | 6 ++---- test/parsec.zig | 8 ++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index f559773497..af84ff3953 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1811,7 +1811,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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::CaseStmtClass: @@ -2181,9 +2182,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; diff --git a/test/parsec.zig b/test/parsec.zig index 45282e793a..aed5abada7 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -460,4 +460,12 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ return (??foo).field; \\} ); + + cases.add("null statements", + \\void foo(void) { + \\ ;;;;; + \\} + , + \\export fn foo() {} + ); } -- cgit v1.2.3 From 2ae789d27cec716c104a9e817a66f59b2ed53f47 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 22:04:51 -0700 Subject: bitwise binary operators --- src/parsec.cpp | 12 ++++-------- test/parsec.zig | 10 ++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 0c49cf30ef..e074c3138f 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -980,14 +980,11 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo case BO_NE: 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: return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); case BO_LOr: @@ -2107,8 +2104,7 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; diff --git a/test/parsec.zig b/test/parsec.zig index 0027903f36..7bae7ce259 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -389,6 +389,16 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + cases.add("bitwise binary operators", + \\int max(int a, int b) { + \\ return (a & b) ^ (a | b); + \\} + , + \\export fn max(a: c_int, b: c_int) -> c_int { + \\ return (a & b) ^ (a | b); + \\} + ); + cases.add("logical and, logical or", \\int max(int a, int b) { \\ if (a < b || a == b) -- cgit v1.2.3 From 33784871ec8d809d513193f5e24865059231b1f3 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 22:14:39 -0700 Subject: assign --- src/parsec.cpp | 8 +++++--- test/parsec.zig | 12 ++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 1c452ff28b..5997564c0a 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -995,9 +995,11 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo // TODO: int vs bool return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); case BO_Assign: - (void)result_used; - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign"); - return nullptr; + if (result_used) { + emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign with result_used"); + return nullptr; + } + return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeAssign, stmt->getRHS()); case BO_MulAssign: emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign"); return nullptr; diff --git a/test/parsec.zig b/test/parsec.zig index 71b6f6906e..4cb77ffe2a 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -415,6 +415,18 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + cases.add("assign", + \\int max(int a) { + \\ int tmp; + \\ tmp = a; + \\} + , + \\export fn max(a: c_int) -> c_int { + \\ var tmp: c_int; + \\ tmp = a; + \\} + ); + cases.add("shift right assign with a fixed size type", \\#include \\int log2(uint32_t a) { -- cgit v1.2.3 From 0d1f64b08cf1dc20c733391c6639af0ba88755e9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 01:22:50 -0400 Subject: parse-c: fix undefined array literals --- src/parsec.cpp | 4 ++-- test/parsec.zig | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 5997564c0a..89a133c872 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -2777,7 +2777,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: @@ -2794,7 +2794,7 @@ 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_global(c, is_const, name, var_type, init_node); diff --git a/test/parsec.zig b/test/parsec.zig index 4cb77ffe2a..58b545eb28 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -490,4 +490,10 @@ pub fn addCases(cases: &tests.ParseCContext) { , \\export fn foo() {} ); + + cases.add("undefined array global", + \\int array[100]; + , + \\pub var array: [100]c_int = undefined; + ); } -- cgit v1.2.3 From 67a5a3f3d74c4ca6f241fc67590dbc94210c2948 Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 22:36:33 -0700 Subject: add sub mul div rem --- src/parsec.cpp | 47 +++++++++++++++++++++++++++++++++++++---------- test/parsec.zig | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 10 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 89a133c872..7626812fa3 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -951,20 +951,47 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo 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; diff --git a/test/parsec.zig b/test/parsec.zig index 58b545eb28..e2b0c6f225 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -389,6 +389,42 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + cases.add("add, sub, mul, div, rem", + \\int s(int a, int b) { + \\ int c; + \\ c = a + b; + \\ c = a - b; + \\ c = a * b; + \\ c = a / b; + \\ c = a % b; + \\} + \\unsigned u(unsigned a, unsigned b) { + \\ unsigned c; + \\ c = a + b; + \\ c = a - b; + \\ c = a * b; + \\ c = a / b; + \\ c = a % b; + \\} + , + \\export fn s(a: c_int, b: c_int) -> c_int { + \\ var c: c_int; + \\ c = (a + b); + \\ c = (a - b); + \\ c = (a * b); + \\ c = @divTrunc(a, b); + \\ c = @rem(a, b); + \\} + \\export fn u(a: c_uint, b: c_uint) -> c_uint { + \\ var c: c_uint; + \\ c = (a +% b); + \\ c = (a -% b); + \\ c = (a *% b); + \\ c = (a / b); + \\ c = (a % b); + \\} + ); + cases.add("bitwise binary operators", \\int max(int a, int b) { \\ return (a & b) ^ (a | b); -- cgit v1.2.3 From 1360af847e5cdc8f4dc279cf64e9acd4a32d0b86 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 01:38:16 -0400 Subject: parse-c: array access expression --- src/parsec.cpp | 25 +++++++++++++++++++------ test/parsec.zig | 13 +++++++++++++ 2 files changed, 32 insertions(+), 6 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 7626812fa3..bfe7181955 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1206,6 +1206,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas 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) @@ -1239,9 +1240,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_NullToPointer: emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToPointer"); return nullptr; @@ -1808,6 +1806,22 @@ static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt) 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_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -1841,6 +1855,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -1901,9 +1917,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; diff --git a/test/parsec.zig b/test/parsec.zig index e2b0c6f225..482736713d 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -532,4 +532,17 @@ pub fn addCases(cases: &tests.ParseCContext) { , \\pub var array: [100]c_int = undefined; ); + + cases.add("array access", + \\int array[100]; + \\int foo(int index) { + \\ return array[index]; + \\} + , + \\pub var array: [100]c_int = undefined; + \\export fn foo(index: c_int) -> c_int { + \\ return array[index]; + \\} + ); + } -- cgit v1.2.3 From 5ac2cf9c28253a7b6144c9f5b19f68df1e26527c Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 22:41:07 -0700 Subject: fix assignment needing an lvalue --- src/parsec.cpp | 17 ++++++++++++++++- test/parsec.zig | 5 ++++- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index bfe7181955..f1ca4c9f5f 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -942,6 +942,21 @@ static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOp return node; } +static AstNode *trans_create_assign(Context *c, AstNode *block, Expr *lhs, Expr *rhs) { + 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; +} + static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { switch (stmt->getOpcode()) { case BO_PtrMemD: @@ -1026,7 +1041,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign with result_used"); return nullptr; } - return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeAssign, stmt->getRHS()); + return trans_create_assign(c, block, stmt->getLHS(), stmt->getRHS()); case BO_MulAssign: emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign"); return nullptr; diff --git a/test/parsec.zig b/test/parsec.zig index 482736713d..78b4c8b782 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -455,11 +455,14 @@ pub fn addCases(cases: &tests.ParseCContext) { \\int max(int a) { \\ int tmp; \\ tmp = a; + \\ a = tmp; \\} , - \\export fn max(a: c_int) -> c_int { + \\export fn max(_arg_a: c_int) -> c_int { + \\ var a = _arg_a; \\ var tmp: c_int; \\ tmp = a; + \\ a = tmp; \\} ); -- cgit v1.2.3 From 2655cf1bf7fc57d57572405f6e21b0b9a7986451 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 01:54:51 -0400 Subject: parse-c: support c style cast --- src/parsec.cpp | 15 ++++++++++++--- test/parsec.zig | 10 ++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index f1ca4c9f5f..88afc8b0ed 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1837,6 +1837,16 @@ static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubs 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_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { Stmt::StmtClass sc = stmt->getStmtClass(); switch (sc) { @@ -1872,6 +1882,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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::CaseStmtClass: emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); return nullptr; @@ -2020,9 +2032,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; diff --git a/test/parsec.zig b/test/parsec.zig index 78b4c8b782..725fc47abd 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -548,4 +548,14 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + + cases.add("c style cast", + \\int float_to_int(float a) { + \\ return (int)a; + \\} + , + \\export fn float_to_int(a: f32) -> c_int { + \\ return c_int(a); + \\} + ); } -- cgit v1.2.3 From c01ae69cdbb84a3c154df635afd01675a6a7a616 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 02:31:52 -0400 Subject: parse-c: support implicit cast to void * --- src/parsec.cpp | 16 +++++++++++++--- test/parsec.zig | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 88afc8b0ed..30d256ecc6 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1228,12 +1228,22 @@ static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCas 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()); + + 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; diff --git a/test/parsec.zig b/test/parsec.zig index 725fc47abd..77a63a8798 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -558,4 +558,26 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ return c_int(a); \\} ); + + cases.add("implicit cast to void *", + \\void *foo(unsigned short *x) { + \\ return x; + \\} + , + \\export fn foo(x: ?&c_ushort) -> ?&c_void { + \\ return @ptrCast(?&c_void, x); + \\} + ); } + + + + +// TODO +//float *ptrcast(int *a) { +// return (float *)a; +//} +// should translate to +// fn ptrcast(a: ?&c_int) -> ?&f32 { +// return @ptrCast(?&f32, a); +// } -- cgit v1.2.3 From be37b03f4c841ea4e309008885e1831fa86ff085 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 21 Sep 2017 02:37:42 -0400 Subject: parse-c: support sizeof --- src/parsec.cpp | 15 ++++++++++++--- test/parsec.zig | 11 +++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 30d256ecc6..b9328a8ba0 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -1857,6 +1857,16 @@ static AstNode *trans_c_style_cast_expr(Context *c, bool result_used, AstNode *b 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) { @@ -1894,6 +1904,8 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; @@ -2233,9 +2245,6 @@ static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *s 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; diff --git a/test/parsec.zig b/test/parsec.zig index 77a63a8798..814abbd52e 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -568,6 +568,17 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ return @ptrCast(?&c_void, x); \\} ); + + cases.add("sizeof", + \\#include + \\size_t size_of(void) { + \\ return sizeof(int); + \\} + , + \\export fn size_of() -> usize { + \\ return @sizeOf(c_int); + \\} + ); } -- cgit v1.2.3 From d7775e3dca054003acaf500fcf018f9cf582b78d Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 23:45:46 -0700 Subject: chain assignment --- src/parsec.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++--------------- test/parsec.zig | 17 +++++++++++++++++ 2 files changed, 61 insertions(+), 15 deletions(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index b9328a8ba0..988bf351ee 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -942,19 +942,52 @@ static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOp return node; } -static AstNode *trans_create_assign(Context *c, AstNode *block, Expr *lhs, Expr *rhs) { - AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); - node->data.bin_op_expr.bin_op = BinOpTypeAssign; +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.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; + 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; + 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)); + + return child_block; + } } static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { @@ -1037,11 +1070,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo // TODO: int vs bool return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); case BO_Assign: - if (result_used) { - emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_Assign with result_used"); - return nullptr; - } - return trans_create_assign(c, block, stmt->getLHS(), stmt->getRHS()); + 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; diff --git a/test/parsec.zig b/test/parsec.zig index 814abbd52e..54fd1c4c5d 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -466,6 +466,23 @@ pub fn addCases(cases: &tests.ParseCContext) { \\} ); + cases.add("chaining assign", + \\void max(int a) { + \\ int b, c; + \\ c = b = a; + \\} + , + \\export fn max(a: c_int) { + \\ var b: c_int; + \\ var c: c_int; + \\ c = { + \\ const _tmp = a; + \\ b = _tmp; + \\ _tmp; + \\ }; + \\} + ); + cases.add("shift right assign with a fixed size type", \\#include \\int log2(uint32_t a) { -- cgit v1.2.3 From ee42caee0e6a24aa252845a72733007ed384d2bf Mon Sep 17 00:00:00 2001 From: Josh Wolfe Date: Wed, 20 Sep 2017 23:49:46 -0700 Subject: fix chain assignment semicolon --- src/parsec.cpp | 1 + test/parsec.zig | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/parsec.cpp') diff --git a/src/parsec.cpp b/src/parsec.cpp index 988bf351ee..b389400f58 100644 --- a/src/parsec.cpp +++ b/src/parsec.cpp @@ -985,6 +985,7 @@ static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block // _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; } diff --git a/test/parsec.zig b/test/parsec.zig index 54fd1c4c5d..23707ab9da 100644 --- a/test/parsec.zig +++ b/test/parsec.zig @@ -478,7 +478,7 @@ pub fn addCases(cases: &tests.ParseCContext) { \\ c = { \\ const _tmp = a; \\ b = _tmp; - \\ _tmp; + \\ _tmp \\ }; \\} ); -- cgit v1.2.3