| ... | @@ -987,59 +987,75 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast | ... | @@ -987,59 +987,75 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast |
| 987 | return nullptr; | 987 | return nullptr; |
| 988 | case BO_ShrAssign: { | 988 | case BO_ShrAssign: { |
| 989 | BinOpType bin_op = BinOpTypeBitShiftRight; | 989 | BinOpType bin_op = BinOpTypeBitShiftRight; |
| 990 | // c: lhs >>= rhs; | 990 | |
| 991 | // zig: { | | |
| 992 | // zig: const _ref = &lhs; | | |
| 993 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | | |
| 994 | // zig: *_ref | | |
| 995 | // zig: }; | | |
| 996 | // where u5 is the appropriate type | | |
| 997 | | | |
| 998 | // TODO: avoid mess when we don't need the assignment value for chained assignments or anything. | | |
| 999 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | | |
| 1000 | | | |
| 1001 | // const _ref = &lhs; | | |
| 1002 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | | |
| 1003 | if (lhs == nullptr) return nullptr; | | |
| 1004 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | | |
| 1005 | // TODO: avoid name collisions with generated variable names | | |
| 1006 | Buf* tmp_var_name = buf_create_from_str("_ref"); | | |
| 1007 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | | |
| 1008 | child_block->data.block.statements.append(tmp_var_decl); | | |
| 1009 | | | |
| 1010 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | | |
| 1011 | | | |
| 1012 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | | |
| 1013 | if (rhs == nullptr) return nullptr; | | |
| 1014 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); | 991 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); |
| 1015 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); | 992 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); |
| 1016 | | 993 | |
| 1017 | AstNode *assign_statement = trans_create_node_bin_op(c, | 994 | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); |
| 1018 | trans_create_node_prefix_op(c, PrefixOpDereference, | 995 | if (!use_intermediate_casts && !result_used) { |
| 1019 | trans_create_node_symbol(c, tmp_var_name)), | 996 | // simple common case, where the C and Zig are identical: |
| 1020 | BinOpTypeAssign, | 997 | // lhs >>= rh* s |
| 1021 | trans_c_cast(c, rhs_location, | 998 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); |
| 1022 | stmt->getComputationResultType(), | 999 | if (lhs == nullptr) return nullptr; |
| 1023 | trans_create_node_bin_op(c, | 1000 | |
| 1024 | trans_c_cast(c, rhs_location, | 1001 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); |
| 1025 | stmt->getComputationLHSType(), | 1002 | if (rhs == nullptr) return nullptr; |
| 1026 | trans_create_node_prefix_op(c, PrefixOpDereference, | 1003 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| 1027 | trans_create_node_symbol(c, tmp_var_name))), | 1004 | |
| 1028 | bin_op, | 1005 | return trans_create_node_bin_op(c, lhs, BinOpTypeAssignBitShiftRight, coerced_rhs); |
| 1029 | trans_create_node_fn_call_1(c, | 1006 | } else { |
| 1030 | rhs_type, | 1007 | // need more complexity. worst case, this looks like this: |
| 1031 | rhs)))); | 1008 | // c: lhs >>= rhs |
| 1032 | child_block->data.block.statements.append(assign_statement); | 1009 | // zig: { |
| 1033 | | 1010 | // zig: const _ref = &lhs; |
| 1034 | if (result_used) { | 1011 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| 1035 | // *_ref | 1012 | // zig: *_ref |
| 1036 | child_block->data.block.statements.append( | 1013 | // zig: } |
| | 1014 | // where u5 is the appropriate type |
| | 1015 | |
| | 1016 | // TODO: avoid mess when we don't need the assignment value for chained assignments or anything. |
| | 1017 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); |
| | 1018 | |
| | 1019 | // const _ref = &lhs; |
| | 1020 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); |
| | 1021 | if (lhs == nullptr) return nullptr; |
| | 1022 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); |
| | 1023 | // TODO: avoid name collisions with generated variable names |
| | 1024 | Buf* tmp_var_name = buf_create_from_str("_ref"); |
| | 1025 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); |
| | 1026 | child_block->data.block.statements.append(tmp_var_decl); |
| | 1027 | |
| | 1028 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); |
| | 1029 | |
| | 1030 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); |
| | 1031 | if (rhs == nullptr) return nullptr; |
| | 1032 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); |
| | 1033 | |
| | 1034 | AstNode *assign_statement = trans_create_node_bin_op(c, |
| 1037 | trans_create_node_prefix_op(c, PrefixOpDereference, | 1035 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| 1038 | trans_create_node_symbol(c, tmp_var_name))); | 1036 | trans_create_node_symbol(c, tmp_var_name)), |
| 1039 | child_block->data.block.last_statement_is_result_expression = true; | 1037 | BinOpTypeAssign, |
| 1040 | } | 1038 | trans_c_cast(c, rhs_location, |
| | 1039 | stmt->getComputationResultType(), |
| | 1040 | trans_create_node_bin_op(c, |
| | 1041 | trans_c_cast(c, rhs_location, |
| | 1042 | stmt->getComputationLHSType(), |
| | 1043 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| | 1044 | trans_create_node_symbol(c, tmp_var_name))), |
| | 1045 | bin_op, |
| | 1046 | coerced_rhs))); |
| | 1047 | child_block->data.block.statements.append(assign_statement); |
| | 1048 | |
| | 1049 | if (result_used) { |
| | 1050 | // *_ref |
| | 1051 | child_block->data.block.statements.append( |
| | 1052 | trans_create_node_prefix_op(c, PrefixOpDereference, |
| | 1053 | trans_create_node_symbol(c, tmp_var_name))); |
| | 1054 | child_block->data.block.last_statement_is_result_expression = true; |
| | 1055 | } |
| 1041 | | 1056 | |
| 1042 | return child_block; | 1057 | return child_block; |
| | 1058 | } |
| 1043 | } | 1059 | } |
| 1044 | case BO_AndAssign: | 1060 | case BO_AndAssign: |
| 1045 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign"); | 1061 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign"); |