mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Global functions.
This commit is contained in:
parent
f30dc68cdd
commit
c4a43c64c2
11
AST.h
11
AST.h
@ -233,23 +233,20 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* Pseudo AST node that is used as declaration for "this", "msg", "tx" and "block" when the
|
||||
* identifier is encountered. Will never have a valid location in the source code.
|
||||
* Pseudo AST node that is used as declaration for "this", "msg", "tx", "block" and the global
|
||||
* functions when such an identifier is encountered. Will never have a valid location in the source code.
|
||||
*/
|
||||
class MagicVariableDeclaration: public Declaration
|
||||
{
|
||||
public:
|
||||
enum class VariableKind { THIS, MSG, TX, BLOCK };
|
||||
MagicVariableDeclaration(VariableKind _kind, ASTString const& _name, std::shared_ptr<Type const> const& _type):
|
||||
Declaration(Location(), std::make_shared<ASTString>(_name)), m_kind(_kind), m_type(_type) {}
|
||||
MagicVariableDeclaration(ASTString const& _name, std::shared_ptr<Type const> const& _type):
|
||||
Declaration(Location(), std::make_shared<ASTString>(_name)), m_type(_type) {}
|
||||
virtual void accept(ASTVisitor&) override { BOOST_THROW_EXCEPTION(InternalCompilerError()
|
||||
<< errinfo_comment("MagicVariableDeclaration used inside real AST.")); }
|
||||
|
||||
std::shared_ptr<Type const> const& getType() const { return m_type; }
|
||||
VariableKind getKind() const { return m_kind; }
|
||||
|
||||
private:
|
||||
VariableKind m_kind;
|
||||
std::shared_ptr<Type const> m_type;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -33,15 +33,33 @@ namespace solidity
|
||||
{
|
||||
|
||||
GlobalContext::GlobalContext():
|
||||
m_magicVariables{make_shared<MagicVariableDeclaration>(MagicVariableDeclaration::VariableKind::BLOCK,
|
||||
"block",
|
||||
make_shared<MagicType>(MagicType::Kind::BLOCK)),
|
||||
make_shared<MagicVariableDeclaration>(MagicVariableDeclaration::VariableKind::MSG,
|
||||
"msg",
|
||||
make_shared<MagicType>(MagicType::Kind::MSG)),
|
||||
make_shared<MagicVariableDeclaration>(MagicVariableDeclaration::VariableKind::TX,
|
||||
"tx",
|
||||
make_shared<MagicType>(MagicType::Kind::TX))}
|
||||
m_magicVariables{make_shared<MagicVariableDeclaration>("block", make_shared<MagicType>(MagicType::Kind::BLOCK)),
|
||||
make_shared<MagicVariableDeclaration>("msg", make_shared<MagicType>(MagicType::Kind::MSG)),
|
||||
make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::TX)),
|
||||
make_shared<MagicVariableDeclaration>("suicide",
|
||||
make_shared<FunctionType>(TypePointers({std::make_shared<IntegerType>(0,
|
||||
IntegerType::Modifier::ADDRESS)}),
|
||||
TypePointers(),
|
||||
FunctionType::Location::SUICIDE)),
|
||||
make_shared<MagicVariableDeclaration>("sha3",
|
||||
make_shared<FunctionType>(TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
FunctionType::Location::SHA3)),
|
||||
make_shared<MagicVariableDeclaration>("sha256",
|
||||
make_shared<FunctionType>(TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
FunctionType::Location::SHA256)),
|
||||
make_shared<MagicVariableDeclaration>("ecrecover",
|
||||
make_shared<FunctionType>(TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH),
|
||||
std::make_shared<IntegerType>(8, IntegerType::Modifier::HASH),
|
||||
std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH),
|
||||
std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
TypePointers({std::make_shared<IntegerType>(0, IntegerType::Modifier::ADDRESS)}),
|
||||
FunctionType::Location::ECRECOVER)),
|
||||
make_shared<MagicVariableDeclaration>("ripemd160",
|
||||
make_shared<FunctionType>(TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
TypePointers({std::make_shared<IntegerType>(256, IntegerType::Modifier::HASH)}),
|
||||
FunctionType::Location::RIPEMD160))}
|
||||
{
|
||||
}
|
||||
|
||||
@ -64,7 +82,6 @@ MagicVariableDeclaration*GlobalContext::getCurrentThis() const
|
||||
{
|
||||
if (!m_thisPointer[m_currentContract])
|
||||
m_thisPointer[m_currentContract] = make_shared<MagicVariableDeclaration>(
|
||||
MagicVariableDeclaration::VariableKind::THIS,
|
||||
"this", make_shared<ContractType>(*m_currentContract));
|
||||
return m_thisPointer[m_currentContract].get();
|
||||
|
||||
|
2
Types.h
2
Types.h
@ -356,7 +356,7 @@ private:
|
||||
class MagicType: public Type
|
||||
{
|
||||
public:
|
||||
enum class Kind { BLOCK, MSG, TX }; //@todo should be unified with MagicVariableDeclaration::VariableKind;
|
||||
enum class Kind { BLOCK, MSG, TX };
|
||||
virtual Category getCategory() const override { return Category::MAGIC; }
|
||||
|
||||
MagicType(Kind _kind);
|
||||
|
Loading…
Reference in New Issue
Block a user