mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Evaluate expressions in convenient order.
This commit is contained in:
parent
afa4e9f575
commit
af0aa0f898
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user