Evaluate expressions in convenient order.

This commit is contained in:
Christian 2014-11-06 22:39:02 +01:00
parent afa4e9f575
commit af0aa0f898

View File

@ -48,21 +48,15 @@ bool ExpressionCompiler::visit(Assignment& _assignment)
{ {
m_currentLValue = nullptr; m_currentLValue = nullptr;
Expression& rightHandSide = _assignment.getRightHandSide(); _assignment.getRightHandSide().accept(*this);
rightHandSide.accept(*this); appendTypeConversion(*_assignment.getRightHandSide().getType(), *_assignment.getType());
Type const& resultType = *_assignment.getType();
appendTypeConversion(*rightHandSide.getType(), resultType);
_assignment.getLeftHandSide().accept(*this); _assignment.getLeftHandSide().accept(*this);
Token::Value op = _assignment.getAssignmentOperator(); Token::Value op = _assignment.getAssignmentOperator();
if (op != Token::ASSIGN) if (op != Token::ASSIGN) // compound assignment
{ appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
// compound assignment
m_context << eth::Instruction::SWAP1;
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), resultType);
}
else else
m_context << eth::Instruction::POP; //@todo do not retrieve the value in the first place m_context << eth::Instruction::POP;
storeInLValue(_assignment); storeInLValue(_assignment);
return false; return false;
@ -123,11 +117,8 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
Type const& commonType = _binaryOperation.getCommonType(); Type const& commonType = _binaryOperation.getCommonType();
Token::Value const op = _binaryOperation.getOperator(); Token::Value const op = _binaryOperation.getOperator();
if (op == Token::AND || op == Token::OR) if (op == Token::AND || op == Token::OR) // special case: short-circuiting
{
// special case: short-circuiting
appendAndOrOperatorCode(_binaryOperation); appendAndOrOperatorCode(_binaryOperation);
}
else else
{ {
bool cleanupNeeded = false; bool cleanupNeeded = false;
@ -135,10 +126,10 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD) if (Token::isCompareOp(op) || op == Token::DIV || op == Token::MOD)
cleanupNeeded = true; cleanupNeeded = true;
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
rightExpression.accept(*this); rightExpression.accept(*this);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded); appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
leftExpression.accept(*this);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
if (Token::isCompareOp(op)) if (Token::isCompareOp(op))
appendCompareOperatorCode(op, commonType); appendCompareOperatorCode(op, commonType);
else else
@ -175,8 +166,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall)
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
{ {
arguments[i]->accept(*this); arguments[i]->accept(*this);
appendTypeConversion(*arguments[i]->getType(), appendTypeConversion(*arguments[i]->getType(), *function.getParameters()[i]->getType());
*function.getParameters()[i]->getType());
} }
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
@ -267,23 +257,21 @@ void ExpressionCompiler::appendCompareOperatorCode(Token::Value _operator, Type
IntegerType const& type = dynamic_cast<IntegerType const&>(_type); IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
bool const isSigned = type.isSigned(); bool const isSigned = type.isSigned();
// note that EVM opcodes compare like "stack[0] < stack[1]",
// but our left value is at stack[1], so everyhing is reversed.
switch (_operator) switch (_operator)
{ {
case Token::GTE: case Token::GTE:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT)
<< eth::Instruction::ISZERO;
break;
case Token::LTE:
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT) m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT)
<< eth::Instruction::ISZERO; << eth::Instruction::ISZERO;
break; break;
case Token::LTE:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT)
<< eth::Instruction::ISZERO;
break;
case Token::GT: case Token::GT:
m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT); m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT);
break; break;
case Token::LT: case Token::LT:
m_context << (isSigned ? eth::Instruction::SGT : eth::Instruction::GT); m_context << (isSigned ? eth::Instruction::SLT : eth::Instruction::LT);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown comparison operator."));
@ -314,16 +302,16 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token::Value _operator, Ty
m_context << eth::Instruction::ADD; m_context << eth::Instruction::ADD;
break; break;
case Token::SUB: case Token::SUB:
m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; m_context << eth::Instruction::SUB;
break; break;
case Token::MUL: case Token::MUL:
m_context << eth::Instruction::MUL; m_context << eth::Instruction::MUL;
break; break;
case Token::DIV: case Token::DIV:
m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV); m_context << (isSigned ? eth::Instruction::SDIV : eth::Instruction::DIV);
break; break;
case Token::MOD: case Token::MOD:
m_context << eth::Instruction::SWAP1 << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD); m_context << (isSigned ? eth::Instruction::SMOD : eth::Instruction::MOD);
break; break;
default: default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator.")); BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown arithmetic operator."));
@ -364,10 +352,9 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded) void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
{ {
// If the type of one of the operands is extended, we need to remove all // For a type extension, we need to remove all higher-order bits that we might have ignored in
// higher-order bits that we might have ignored in previous operations. // previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher // @todo: store in the AST whether the operand might have "dirty" higher order bits
// order bits
if (_typeOnStack == _targetType && !_cleanupNeeded) if (_typeOnStack == _targetType && !_cleanupNeeded)
return; return;