authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-11-13 21:37:30-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2017-11-13 21:37:30-07:00
log4c2cdf6f4da09e2986aa7a574455995168bcab8f
tree936ce1f8ee8868e78800cff17a3c4ec9b0b5b6b1
parentc1fde0e8c45e4ba20fbc3306238c5e7627c2dfd9

parsec supports more compound assign operators


2 files changed, 213 insertions(+), 117 deletions(-)

src/parsec.cpp+156-117
...@@ -1034,7 +1034,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo...@@ -1034,7 +1034,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
1034 // unsigned/float division uses the operator1034 // unsigned/float division uses the operator
1035 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());1035 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
1036 } else {1036 } else {
1037 // signed integer division uses @divTrunc1037 // signed integer division uses @rem
1038 AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");1038 AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");
1039 AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);1039 AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
1040 if (lhs == nullptr) return nullptr;1040 if (lhs == nullptr) return nullptr;
...@@ -1081,36 +1081,6 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo...@@ -1081,36 +1081,6 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
1081 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());1081 return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
1082 case BO_Assign:1082 case BO_Assign:
1083 return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS());1083 return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS());
1084 case BO_MulAssign:
1085 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_MulAssign");
1086 return nullptr;
1087 case BO_DivAssign:
1088 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_DivAssign");
1089 return nullptr;
1090 case BO_RemAssign:
1091 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_RemAssign");
1092 return nullptr;
1093 case BO_AddAssign:
1094 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AddAssign");
1095 return nullptr;
1096 case BO_SubAssign:
1097 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_SubAssign");
1098 return nullptr;
1099 case BO_ShlAssign:
1100 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShlAssign");
1101 return nullptr;
1102 case BO_ShrAssign:
1103 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_ShrAssign");
1104 return nullptr;
1105 case BO_AndAssign:
1106 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_AndAssign");
1107 return nullptr;
1108 case BO_XorAssign:
1109 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_XorAssign");
1110 return nullptr;
1111 case BO_OrAssign:
1112 emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_OrAssign");
1113 return nullptr;
1114 case BO_Comma:1084 case BO_Comma:
1115 {1085 {
1116 block = trans_create_node(c, NodeTypeBlock);1086 block = trans_create_node(c, NodeTypeBlock);
...@@ -1123,112 +1093,181 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo...@@ -1123,112 +1093,181 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
1123 block->data.block.last_statement_is_result_expression = true;1093 block->data.block.last_statement_is_result_expression = true;
1124 return block;1094 return block;
1125 }1095 }
1126 }
1127
1128 zig_unreachable();
1129}
1130
1131static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
1132 switch (stmt->getOpcode()) {
1133 case BO_MulAssign:1096 case BO_MulAssign:
1134 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_MulAssign");
1135 return nullptr;
1136 case BO_DivAssign:1097 case BO_DivAssign:
1137 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
1138 return nullptr;
1139 case BO_RemAssign:1098 case BO_RemAssign:
1140 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
1141 return nullptr;
1142 case BO_AddAssign:1099 case BO_AddAssign:
1143 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AddAssign");
1144 return nullptr;
1145 case BO_SubAssign:1100 case BO_SubAssign:
1146 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_SubAssign");
1147 return nullptr;
1148 case BO_ShlAssign:1101 case BO_ShlAssign:
1149 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_ShlAssign");1102 case BO_ShrAssign:
1150 return nullptr;1103 case BO_AndAssign:
1151 case BO_ShrAssign: {1104 case BO_XorAssign:
1152 BinOpType bin_op = BinOpTypeBitShiftRight;1105 case BO_OrAssign:
1106 zig_unreachable();
1107 }
11531108
1154 const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();1109 zig_unreachable();
1155 AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);1110}
11561111
1157 bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();1112static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
1158 if (!use_intermediate_casts && !result_used) {1113 const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
1159 // simple common case, where the C and Zig are identical:1114 AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
1160 // lhs >>= rh* s
1161 AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
1162 if (lhs == nullptr) return nullptr;
11631115
1164 AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);1116 bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
1165 if (rhs == nullptr) return nullptr;1117 if (!use_intermediate_casts && !result_used) {
1166 AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);1118 // simple common case, where the C and Zig are identical:
1119 // lhs >>= rhs
1120 AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
1121 if (lhs == nullptr) return nullptr;
11671122
1168 return trans_create_node_bin_op(c, lhs, BinOpTypeAssignBitShiftRight, coerced_rhs);1123 AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
1169 } else {1124 if (rhs == nullptr) return nullptr;
1170 // need more complexity. worst case, this looks like this:1125 AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
1171 // c: lhs >>= rhs
1172 // zig: {
1173 // zig: const _ref = &lhs;
1174 // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
1175 // zig: *_ref
1176 // zig: }
1177 // where u5 is the appropriate type
11781126
1179 // TODO: avoid mess when we don't need the assignment value for chained assignments or anything.1127 return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs);
1180 AstNode *child_block = trans_create_node(c, NodeTypeBlock);1128 } else {
1129 // need more complexity. worst case, this looks like this:
1130 // c: lhs >>= rhs
1131 // zig: {
1132 // zig: const _ref = &lhs;
1133 // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs));
1134 // zig: *_ref
1135 // zig: }
1136 // where u5 is the appropriate type
11811137
1182 // const _ref = &lhs;1138 AstNode *child_block = trans_create_node(c, NodeTypeBlock);
1183 AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
1184 if (lhs == nullptr) return nullptr;
1185 AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
1186 // TODO: avoid name collisions with generated variable names
1187 Buf* tmp_var_name = buf_create_from_str("_ref");
1188 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
1189 child_block->data.block.statements.append(tmp_var_decl);
11901139
1191 // *_ref = result_type(operation_type(*_ref) >> u5(rhs));1140 // const _ref = &lhs;
1141 AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
1142 if (lhs == nullptr) return nullptr;
1143 AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
1144 // TODO: avoid name collisions with generated variable names
1145 Buf* tmp_var_name = buf_create_from_str("_ref");
1146 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
1147 child_block->data.block.statements.append(tmp_var_decl);
11921148
1193 AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);1149 // *_ref = result_type(operation_type(*_ref) >> u5(rhs));
1194 if (rhs == nullptr) return nullptr;
1195 AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
11961150
1197 AstNode *assign_statement = trans_create_node_bin_op(c,1151 AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
1198 trans_create_node_prefix_op(c, PrefixOpDereference,1152 if (rhs == nullptr) return nullptr;
1199 trans_create_node_symbol(c, tmp_var_name)),1153 AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
1200 BinOpTypeAssign,1154
1155 AstNode *assign_statement = trans_create_node_bin_op(c,
1156 trans_create_node_prefix_op(c, PrefixOpDereference,
1157 trans_create_node_symbol(c, tmp_var_name)),
1158 BinOpTypeAssign,
1159 trans_c_cast(c, rhs_location,
1160 stmt->getComputationResultType(),
1161 trans_create_node_bin_op(c,
1201 trans_c_cast(c, rhs_location,1162 trans_c_cast(c, rhs_location,
1202 stmt->getComputationResultType(),1163 stmt->getComputationLHSType(),
1203 trans_create_node_bin_op(c,
1204 trans_c_cast(c, rhs_location,
1205 stmt->getComputationLHSType(),
1206 trans_create_node_prefix_op(c, PrefixOpDereference,
1207 trans_create_node_symbol(c, tmp_var_name))),
1208 bin_op,
1209 coerced_rhs)));
1210 child_block->data.block.statements.append(assign_statement);
1211
1212 if (result_used) {
1213 // *_ref
1214 child_block->data.block.statements.append(
1215 trans_create_node_prefix_op(c, PrefixOpDereference,1164 trans_create_node_prefix_op(c, PrefixOpDereference,
1216 trans_create_node_symbol(c, tmp_var_name)));1165 trans_create_node_symbol(c, tmp_var_name))),
1217 child_block->data.block.last_statement_is_result_expression = true;1166 bin_op,
1218 }1167 coerced_rhs)));
12191168 child_block->data.block.statements.append(assign_statement);
1220 return child_block;1169
1221 }1170 if (result_used) {
1171 // *_ref
1172 child_block->data.block.statements.append(
1173 trans_create_node_prefix_op(c, PrefixOpDereference,
1174 trans_create_node_symbol(c, tmp_var_name)));
1175 child_block->data.block.last_statement_is_result_expression = true;
1222 }1176 }
1223 case BO_AndAssign:1177
1224 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign");1178 return child_block;
1179 }
1180}
1181
1182static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
1183 if (!result_used) {
1184 // simple common case, where the C and Zig are identical:
1185 // lhs += rhs
1186 AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
1187 if (lhs == nullptr) return nullptr;
1188 AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
1189 if (rhs == nullptr) return nullptr;
1190 return trans_create_node_bin_op(c, lhs, assign_op, rhs);
1191 } else {
1192 // need more complexity. worst case, this looks like this:
1193 // c: lhs += rhs
1194 // zig: {
1195 // zig: const _ref = &lhs;
1196 // zig: *_ref = *_ref + rhs;
1197 // zig: *_ref
1198 // zig: }
1199
1200 AstNode *child_block = trans_create_node(c, NodeTypeBlock);
1201
1202 // const _ref = &lhs;
1203 AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue);
1204 if (lhs == nullptr) return nullptr;
1205 AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs);
1206 // TODO: avoid name collisions with generated variable names
1207 Buf* tmp_var_name = buf_create_from_str("_ref");
1208 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs);
1209 child_block->data.block.statements.append(tmp_var_decl);
1210
1211 // *_ref = *_ref + rhs;
1212
1213 AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
1214 if (rhs == nullptr) return nullptr;
1215
1216 AstNode *assign_statement = trans_create_node_bin_op(c,
1217 trans_create_node_prefix_op(c, PrefixOpDereference,
1218 trans_create_node_symbol(c, tmp_var_name)),
1219 BinOpTypeAssign,
1220 trans_create_node_bin_op(c,
1221 trans_create_node_prefix_op(c, PrefixOpDereference,
1222 trans_create_node_symbol(c, tmp_var_name)),
1223 bin_op,
1224 rhs));
1225 child_block->data.block.statements.append(assign_statement);
1226
1227 // *_ref
1228 child_block->data.block.statements.append(
1229 trans_create_node_prefix_op(c, PrefixOpDereference,
1230 trans_create_node_symbol(c, tmp_var_name)));
1231 child_block->data.block.last_statement_is_result_expression = true;
1232
1233 return child_block;
1234 }
1235}
1236
1237
1238static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
1239 switch (stmt->getOpcode()) {
1240 case BO_MulAssign:
1241 if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1242 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap);
1243 else
1244 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult);
1245 case BO_DivAssign:
1246 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
1225 return nullptr;1247 return nullptr;
1226 case BO_XorAssign:1248 case BO_RemAssign:
1227 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_XorAssign");1249 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
1228 return nullptr;1250 return nullptr;
1251 case BO_AddAssign:
1252 if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1253 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap);
1254 else
1255 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd);
1256 case BO_SubAssign:
1257 if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1258 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap);
1259 else
1260 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub);
1261 case BO_ShlAssign:
1262 return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft);
1263 case BO_ShrAssign:
1264 return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight);
1265 case BO_AndAssign:
1266 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd);
1267 case BO_XorAssign:
1268 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor);
1229 case BO_OrAssign:1269 case BO_OrAssign:
1230 emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_OrAssign");1270 return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
1231 return nullptr;
1232 case BO_PtrMemD:1271 case BO_PtrMemD:
1233 case BO_PtrMemI:1272 case BO_PtrMemI:
1234 case BO_Assign:1273 case BO_Assign:
...@@ -1251,7 +1290,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast...@@ -1251,7 +1290,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
1251 case BO_LAnd:1290 case BO_LAnd:
1252 case BO_LOr:1291 case BO_LOr:
1253 case BO_Comma:1292 case BO_Comma:
1254 zig_panic("compound assign expected to be handled by binary operator");1293 zig_unreachable();
1255 }1294 }
12561295
1257 zig_unreachable();1296 zig_unreachable();
test/parsec.zig+57
...@@ -630,6 +630,63 @@ pub fn addCases(cases: &tests.ParseCContext) {...@@ -630,6 +630,63 @@ pub fn addCases(cases: &tests.ParseCContext) {
630 \\}630 \\}
631 );631 );
632632
633 cases.addC("compound assignment operators",
634 \\void foo(void) {
635 \\ int a = 0;
636 \\ a += (a += 1);
637 \\ a -= (a -= 1);
638 \\ a *= (a *= 1);
639 \\ a &= (a &= 1);
640 \\ a |= (a |= 1);
641 \\ a ^= (a ^= 1);
642 \\ a >>= (a >>= 1);
643 \\ a <<= (a <<= 1);
644 \\}
645 ,
646 \\export fn foo() {
647 \\ var a: c_int = 0;
648 \\ a += {
649 \\ const _ref = &a;
650 \\ (*_ref) = ((*_ref) + 1);
651 \\ *_ref
652 \\ };
653 \\ a -= {
654 \\ const _ref = &a;
655 \\ (*_ref) = ((*_ref) - 1);
656 \\ *_ref
657 \\ };
658 \\ a *= {
659 \\ const _ref = &a;
660 \\ (*_ref) = ((*_ref) * 1);
661 \\ *_ref
662 \\ };
663 \\ a &= {
664 \\ const _ref = &a;
665 \\ (*_ref) = ((*_ref) & 1);
666 \\ *_ref
667 \\ };
668 \\ a |= {
669 \\ const _ref = &a;
670 \\ (*_ref) = ((*_ref) | 1);
671 \\ *_ref
672 \\ };
673 \\ a ^= {
674 \\ const _ref = &a;
675 \\ (*_ref) = ((*_ref) ^ 1);
676 \\ *_ref
677 \\ };
678 \\ a >>= @import("std").math.Log2Int(c_int)({
679 \\ const _ref = &a;
680 \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1));
681 \\ *_ref
682 \\ });
683 \\ a <<= @import("std").math.Log2Int(c_int)({
684 \\ const _ref = &a;
685 \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1));
686 \\ *_ref
687 \\ });
688 \\}
689 );
633 cases.addC("duplicate typedef",690 cases.addC("duplicate typedef",
634 \\typedef long foo;691 \\typedef long foo;
635 \\typedef int bar;692 \\typedef int bar;