diff options
author | Christian <c@ethdev.com> | 2014-11-07 09:06:37 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2014-11-08 03:02:57 +0800 |
commit | 64a4d77c8b8c559c6e9aad712f7288e4f107e946 (patch) | |
tree | 59a8bef45a09ac9b1682bf213886f713a12468c4 /ExpressionCompiler.cpp | |
parent | 4c8e670530675c7b7774b0d5355ee9aadd92f3a2 (diff) | |
download | dexon-solidity-64a4d77c8b8c559c6e9aad712f7288e4f107e946.tar.gz dexon-solidity-64a4d77c8b8c559c6e9aad712f7288e4f107e946.tar.zst dexon-solidity-64a4d77c8b8c559c6e9aad712f7288e4f107e946.zip |
State variables.
Diffstat (limited to 'ExpressionCompiler.cpp')
-rw-r--r-- | ExpressionCompiler.cpp | 127 |
1 files changed, 79 insertions, 48 deletions
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index 6efb8b20..6fbfb9e0 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -46,12 +46,12 @@ void ExpressionCompiler::appendTypeConversion(CompilerContext& _context, bool ExpressionCompiler::visit(Assignment& _assignment) { - m_currentLValue = nullptr; - Expression& rightHandSide = _assignment.getRightHandSide(); rightHandSide.accept(*this); Type const& resultType = *_assignment.getType(); appendTypeConversion(*rightHandSide.getType(), resultType); + + m_currentLValue.reset(); _assignment.getLeftHandSide().accept(*this); Token::Value op = _assignment.getAssignmentOperator(); @@ -99,10 +99,7 @@ void ExpressionCompiler::endVisit(UnaryOperation& _unaryOperation) m_context << eth::Instruction::ADD; else m_context << eth::Instruction::SWAP1 << eth::Instruction::SUB; // @todo avoid the swap - if (_unaryOperation.isPrefixOperation()) - storeInLValue(_unaryOperation); - else - moveToLValue(_unaryOperation); + storeInLValue(_unaryOperation, !_unaryOperation.isPrefixOperation()); break; case Token::ADD: // + // unary add, so basically no-op @@ -164,9 +161,13 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) { // Calling convention: Caller pushes return address and arguments // Callee removes them and pushes return values - m_currentLValue = nullptr; + m_currentLValue.reset(); _functionCall.getExpression().accept(*this); - FunctionDefinition const& function = dynamic_cast<FunctionDefinition&>(*m_currentLValue); + if (asserts(m_currentLValue.isInCode())) + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Code reference expected.")); + eth::AssemblyItem functionTag(eth::PushTag, m_currentLValue.location); + + FunctionDefinition const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()).getFunction(); eth::AssemblyItem returnLabel = m_context.pushNewTag(); std::vector<ASTPointer<Expression>> const& arguments = _functionCall.getArguments(); @@ -179,7 +180,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) *function.getParameters()[i]->getType()); } - m_context.appendJumpTo(m_context.getFunctionEntryLabel(function)); + m_context.appendJumpTo(functionTag); m_context << returnLabel; // callee adds return parameters, but removes arguments and return label @@ -205,24 +206,20 @@ void ExpressionCompiler::endVisit(IndexAccess&) void ExpressionCompiler::endVisit(Identifier& _identifier) { - m_currentLValue = _identifier.getReferencedDeclaration(); - switch (_identifier.getType()->getCategory()) - { - case Type::Category::BOOL: - case Type::Category::INTEGER: - case Type::Category::REAL: - { - //@todo we also have to check where to retrieve them from once we add storage variables - unsigned stackPos = stackPositionOfLValue(); - if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_identifier.getLocation()) - << errinfo_comment("Stack too deep.")); - m_context << eth::dupInstruction(stackPos + 1); - break; - } - default: - break; - } + Declaration const* declaration = _identifier.getReferencedDeclaration(); + if (m_context.isLocalVariable(declaration)) + m_currentLValue = LValueLocation(LValueLocation::STACK, + m_context.getBaseStackOffsetOfVariable(*declaration)); + else if (m_context.isStateVariable(declaration)) + m_currentLValue = LValueLocation(LValueLocation::STORAGE, + m_context.getStorageLocationOfVariable(*declaration)); + else if (m_context.isFunctionDefinition(declaration)) + m_currentLValue = LValueLocation(LValueLocation::CODE, + m_context.getFunctionEntryLabel(dynamic_cast<FunctionDefinition const&>(*declaration)).data()); + else + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Identifier type not supported or identifier not found.")); + + retrieveLValueValue(_identifier); } void ExpressionCompiler::endVisit(Literal& _literal) @@ -388,31 +385,65 @@ void ExpressionCompiler::appendHighBitsCleanup(IntegerType const& _typeOnStack) m_context << ((u256(1) << _typeOnStack.getNumBits()) - 1) << eth::Instruction::AND; } -void ExpressionCompiler::storeInLValue(Expression const& _expression) +void ExpressionCompiler::retrieveLValueValue(Expression const& _expression) { - moveToLValue(_expression); - unsigned stackPos = stackPositionOfLValue(); - if (stackPos > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Stack too deep.")); - m_context << eth::dupInstruction(stackPos + 1); -} - -void ExpressionCompiler::moveToLValue(Expression const& _expression) -{ - unsigned stackPos = stackPositionOfLValue(); - if (stackPos > 16) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) - << errinfo_comment("Stack too deep.")); - else if (stackPos > 0) - m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; + switch (m_currentLValue.locationType) + { + case LValueLocation::CODE: + // not stored on the stack + break; + case LValueLocation::STACK: + { + unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); + if (stackPos >= 15) //@todo correct this by fetching earlier or moving to memory + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + m_context << eth::dupInstruction(stackPos + 1); + break; + } + case LValueLocation::STORAGE: + m_context << m_currentLValue.location << eth::Instruction::SLOAD; + break; + case LValueLocation::MEMORY: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); + break; + } } -unsigned ExpressionCompiler::stackPositionOfLValue() const +void ExpressionCompiler::storeInLValue(Expression const& _expression, bool _move) { - if (asserts(m_currentLValue)) - BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("LValue not available on request.")); - return m_context.getStackPositionOfVariable(*m_currentLValue); + switch (m_currentLValue.locationType) + { + case LValueLocation::STACK: + { + unsigned stackPos = m_context.baseToCurrentStackOffset(unsigned(m_currentLValue.location)); + if (stackPos > 16) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation()) + << errinfo_comment("Stack too deep.")); + else if (stackPos > 0) + m_context << eth::swapInstruction(stackPos) << eth::Instruction::POP; + if (!_move) + retrieveLValueValue(_expression); + break; + } + case LValueLocation::STORAGE: + if (!_move) + m_context << eth::Instruction::DUP1; + m_context << m_currentLValue.location << eth::Instruction::SSTORE; + break; + case LValueLocation::CODE: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type does not support assignment.")); + break; + case LValueLocation::MEMORY: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Location type not yet implemented.")); + break; + default: + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unsupported location type.")); + break; + } } } |