|
|
@ -160,6 +160,7 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation) |
|
|
|
|
|
|
|
bool ExpressionCompiler::visit(FunctionCall& _functionCall) |
|
|
|
{ |
|
|
|
using Location = FunctionType::Location; |
|
|
|
if (_functionCall.isTypeConversion()) |
|
|
|
{ |
|
|
|
//@todo struct construction
|
|
|
@ -184,7 +185,7 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) |
|
|
|
if (asserts(arguments.size() == function.getParameterTypes().size())) |
|
|
|
BOOST_THROW_EXCEPTION(InternalCompilerError()); |
|
|
|
|
|
|
|
if (function.getLocation() == FunctionType::Location::INTERNAL) |
|
|
|
if (function.getLocation() == Location::INTERNAL) |
|
|
|
{ |
|
|
|
// Calling convention: Caller pushes return address and arguments
|
|
|
|
// Callee removes them and pushes return values
|
|
|
@ -208,29 +209,57 @@ bool ExpressionCompiler::visit(FunctionCall& _functionCall) |
|
|
|
for (unsigned i = 1; i < function.getReturnParameterTypes().size(); ++i) |
|
|
|
m_context << eth::Instruction::POP; |
|
|
|
} |
|
|
|
else if (function.getLocation() == FunctionType::Location::EXTERNAL) |
|
|
|
{ |
|
|
|
else if (function.getLocation() == Location::EXTERNAL) |
|
|
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("External function calls not implemented yet.")); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
switch (function.getLocation()) |
|
|
|
{ |
|
|
|
case FunctionType::Location::SEND: |
|
|
|
case Location::SEND: |
|
|
|
m_context << u256(0) << u256(0) << u256(0) << u256(0); |
|
|
|
arguments.front()->accept(*this); |
|
|
|
//@todo might not be necessary
|
|
|
|
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); |
|
|
|
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); |
|
|
|
_functionCall.getExpression().accept(*this); |
|
|
|
m_context << u256(25) << eth::Instruction::GAS << eth::Instruction::SUB |
|
|
|
<< eth::Instruction::CALL |
|
|
|
<< eth::Instruction::POP; |
|
|
|
break; |
|
|
|
case FunctionType::Location::SUICIDE: |
|
|
|
case Location::SUICIDE: |
|
|
|
arguments.front()->accept(*this); |
|
|
|
//@todo might not be necessary
|
|
|
|
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front()); |
|
|
|
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); |
|
|
|
m_context << eth::Instruction::SUICIDE; |
|
|
|
break; |
|
|
|
case Location::SHA3: |
|
|
|
arguments.front()->accept(*this); |
|
|
|
appendTypeConversion(*arguments.front()->getType(), *function.getParameterTypes().front(), true); |
|
|
|
// @todo move this once we actually use memory
|
|
|
|
m_context << u256(0) << eth::Instruction::MSTORE << u256(32) << u256(0) << eth::Instruction::SHA3; |
|
|
|
break; |
|
|
|
case Location::ECRECOVER: |
|
|
|
case Location::SHA256: |
|
|
|
case Location::RIPEMD160: |
|
|
|
{ |
|
|
|
static const map<Location, u256> contractAddresses{{Location::ECRECOVER, 1}, |
|
|
|
{Location::SHA256, 2}, |
|
|
|
{Location::RIPEMD160, 3}}; |
|
|
|
u256 contractAddress = contractAddresses.find(function.getLocation())->second; |
|
|
|
// @todo later, combine this code with external function call
|
|
|
|
for (unsigned i = 0; i < arguments.size(); ++i) |
|
|
|
{ |
|
|
|
arguments[i]->accept(*this); |
|
|
|
appendTypeConversion(*arguments[i]->getType(), *function.getParameterTypes()[i], true); |
|
|
|
// @todo move this once we actually use memory
|
|
|
|
m_context << u256(i * 32) << eth::Instruction::MSTORE; |
|
|
|
} |
|
|
|
m_context << u256(32) << u256(0) << u256(arguments.size() * 32) << u256(0) << u256(0) |
|
|
|
<< contractAddress << u256(500) //@todo determine actual gas requirement
|
|
|
|
<< eth::Instruction::CALL |
|
|
|
<< eth::Instruction::POP |
|
|
|
<< u256(0) << eth::Instruction::MLOAD; |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
|
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Function not yet implemented.")); |
|
|
|
} |
|
|
@ -246,9 +275,15 @@ void ExpressionCompiler::endVisit(MemberAccess& _memberAccess) |
|
|
|
{ |
|
|
|
case Type::Category::INTEGER: |
|
|
|
if (member == "balance") |
|
|
|
{ |
|
|
|
appendTypeConversion(*_memberAccess.getExpression().getType(), |
|
|
|
IntegerType(0, IntegerType::Modifier::ADDRESS), true); |
|
|
|
m_context << eth::Instruction::BALANCE; |
|
|
|
} |
|
|
|
else if (member == "send") |
|
|
|
{ // no modification
|
|
|
|
{ |
|
|
|
appendTypeConversion(*_memberAccess.getExpression().getType(), |
|
|
|
IntegerType(0, IntegerType::Modifier::ADDRESS), true); |
|
|
|
} |
|
|
|
else |
|
|
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to integer.")); |
|
|
@ -319,7 +354,7 @@ void ExpressionCompiler::endVisit(Identifier& _identifier) |
|
|
|
Declaration* declaration = _identifier.getReferencedDeclaration(); |
|
|
|
if (MagicVariableDeclaration* magicVar = dynamic_cast<MagicVariableDeclaration*>(declaration)) |
|
|
|
{ |
|
|
|
if (magicVar->getKind() == MagicVariableDeclaration::VariableKind::THIS) |
|
|
|
if (magicVar->getType()->getCategory() == Type::Category::CONTRACT) // must be "this"
|
|
|
|
m_context << eth::Instruction::ADDRESS; |
|
|
|
return; |
|
|
|
} |
|
|
|