chain assignment

master
Josh Wolfe 2017-09-20 23:45:46 -07:00
parent be37b03f4c
commit d7775e3dca
2 changed files with 61 additions and 15 deletions

View File

@ -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;

View File

@ -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 <stdint.h>
\\int log2(uint32_t a) {