Skip to content

Commit 4c2cdf6

Browse files
committedNov 14, 2017
parsec supports more compound assign operators
1 parent c1fde0e commit 4c2cdf6

File tree

2 files changed

+213
-117
lines changed

2 files changed

+213
-117
lines changed
 

‎src/parsec.cpp

+156-117
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
10341034
// unsigned/float division uses the operator
10351035
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS());
10361036
} else {
1037-
// signed integer division uses @divTrunc
1037+
// signed integer division uses @rem
10381038
AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem");
10391039
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
10401040
if (lhs == nullptr) return nullptr;
@@ -1081,36 +1081,6 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
10811081
return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
10821082
case BO_Assign:
10831083
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;
11141084
case BO_Comma:
11151085
{
11161086
block = trans_create_node(c, NodeTypeBlock);
@@ -1123,112 +1093,181 @@ static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *blo
11231093
block->data.block.last_statement_is_result_expression = true;
11241094
return block;
11251095
}
1126-
}
1127-
1128-
zig_unreachable();
1129-
}
1130-
1131-
static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) {
1132-
switch (stmt->getOpcode()) {
11331096
case BO_MulAssign:
1134-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_MulAssign");
1135-
return nullptr;
11361097
case BO_DivAssign:
1137-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign");
1138-
return nullptr;
11391098
case BO_RemAssign:
1140-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
1141-
return nullptr;
11421099
case BO_AddAssign:
1143-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AddAssign");
1144-
return nullptr;
11451100
case BO_SubAssign:
1146-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_SubAssign");
1147-
return nullptr;
11481101
case BO_ShlAssign:
1149-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_ShlAssign");
1150-
return nullptr;
1151-
case BO_ShrAssign: {
1152-
BinOpType bin_op = BinOpTypeBitShiftRight;
1102+
case BO_ShrAssign:
1103+
case BO_AndAssign:
1104+
case BO_XorAssign:
1105+
case BO_OrAssign:
1106+
zig_unreachable();
1107+
}
11531108

1154-
const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
1155-
AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
1109+
zig_unreachable();
1110+
}
11561111

1157-
bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
1158-
if (!use_intermediate_casts && !result_used) {
1159-
// simple common case, where the C and Zig are identical:
1160-
// lhs >>= rh* s
1161-
AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue);
1162-
if (lhs == nullptr) return nullptr;
1112+
static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) {
1113+
const SourceLocation &rhs_location = stmt->getRHS()->getLocStart();
1114+
AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location);
11631115

1164-
AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
1165-
if (rhs == nullptr) return nullptr;
1166-
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
1116+
bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr();
1117+
if (!use_intermediate_casts && !result_used) {
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);
1169-
} else {
1170-
// need more complexity. worst case, this looks like this:
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
1123+
AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue);
1124+
if (rhs == nullptr) return nullptr;
1125+
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
11781126

1179-
// TODO: avoid mess when we don't need the assignment value for chained assignments or anything.
1180-
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
1127+
return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs);
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;
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);
1138+
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
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);
1194-
if (rhs == nullptr) return nullptr;
1195-
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
1149+
// *_ref = result_type(operation_type(*_ref) >> u5(rhs));
11961150

1197-
AstNode *assign_statement = trans_create_node_bin_op(c,
1198-
trans_create_node_prefix_op(c, PrefixOpDereference,
1199-
trans_create_node_symbol(c, tmp_var_name)),
1200-
BinOpTypeAssign,
1151+
AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue);
1152+
if (rhs == nullptr) return nullptr;
1153+
AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs);
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,
12011162
trans_c_cast(c, rhs_location,
1202-
stmt->getComputationResultType(),
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(
1163+
stmt->getComputationLHSType(),
12151164
trans_create_node_prefix_op(c, PrefixOpDereference,
1216-
trans_create_node_symbol(c, tmp_var_name)));
1217-
child_block->data.block.last_statement_is_result_expression = true;
1218-
}
1219-
1220-
return child_block;
1221-
}
1165+
trans_create_node_symbol(c, tmp_var_name))),
1166+
bin_op,
1167+
coerced_rhs)));
1168+
child_block->data.block.statements.append(assign_statement);
1169+
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;
12221176
}
1223-
case BO_AndAssign:
1224-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_AndAssign");
1177+
1178+
return child_block;
1179+
}
1180+
}
1181+
1182+
static 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+
1238+
static 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");
12251247
return nullptr;
1226-
case BO_XorAssign:
1227-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_XorAssign");
1248+
case BO_RemAssign:
1249+
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign");
12281250
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);
12291269
case BO_OrAssign:
1230-
emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_OrAssign");
1231-
return nullptr;
1270+
return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr);
12321271
case BO_PtrMemD:
12331272
case BO_PtrMemI:
12341273
case BO_Assign:
@@ -1251,7 +1290,7 @@ static AstNode *trans_compound_assign_operator(Context *c, bool result_used, Ast
12511290
case BO_LAnd:
12521291
case BO_LOr:
12531292
case BO_Comma:
1254-
zig_panic("compound assign expected to be handled by binary operator");
1293+
zig_unreachable();
12551294
}
12561295

12571296
zig_unreachable();

‎test/parsec.zig

+57
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,63 @@ pub fn addCases(cases: &tests.ParseCContext) {
630630
\\}
631631
);
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+
);
633690
cases.addC("duplicate typedef",
634691
\\typedef long foo;
635692
\\typedef int bar;

0 commit comments

Comments
 (0)
Please sign in to comment.