mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Create contracts.
This commit is contained in:
parent
c858699605
commit
2f64c56ef3
38
AST.cpp
38
AST.cpp
@ -54,6 +54,14 @@ vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() co
|
|||||||
return exportedFunctions;
|
return exportedFunctions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionDefinition const* ContractDefinition::getConstructor() const
|
||||||
|
{
|
||||||
|
for (ASTPointer<FunctionDefinition> const& f: m_definedFunctions)
|
||||||
|
if (f->getName() == getName())
|
||||||
|
return f.get();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void StructDefinition::checkMemberTypes() const
|
void StructDefinition::checkMemberTypes() const
|
||||||
{
|
{
|
||||||
for (ASTPointer<VariableDeclaration> const& member: getMembers())
|
for (ASTPointer<VariableDeclaration> const& member: getMembers())
|
||||||
@ -235,13 +243,12 @@ void FunctionCall::checkTypeRequirements()
|
|||||||
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
|
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
|
||||||
m_type = type.getActualType();
|
m_type = type.getActualType();
|
||||||
}
|
}
|
||||||
else
|
else if (FunctionType const* functionType = dynamic_cast<FunctionType const*>(expressionType))
|
||||||
{
|
{
|
||||||
//@todo would be nice to create a struct type from the arguments
|
//@todo would be nice to create a struct type from the arguments
|
||||||
// and then ask if that is implicitly convertible to the struct represented by the
|
// and then ask if that is implicitly convertible to the struct represented by the
|
||||||
// function parameters
|
// function parameters
|
||||||
FunctionType const& functionType = dynamic_cast<FunctionType const&>(*expressionType);
|
TypePointers const& parameterTypes = functionType->getParameterTypes();
|
||||||
TypePointers const& parameterTypes = functionType.getParameterTypes();
|
|
||||||
if (parameterTypes.size() != m_arguments.size())
|
if (parameterTypes.size() != m_arguments.size())
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
|
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
|
||||||
for (size_t i = 0; i < m_arguments.size(); ++i)
|
for (size_t i = 0; i < m_arguments.size(); ++i)
|
||||||
@ -249,11 +256,13 @@ void FunctionCall::checkTypeRequirements()
|
|||||||
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
|
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in function call."));
|
||||||
// @todo actually the return type should be an anonymous struct,
|
// @todo actually the return type should be an anonymous struct,
|
||||||
// but we change it to the type of the first return value until we have structs
|
// but we change it to the type of the first return value until we have structs
|
||||||
if (functionType.getReturnParameterTypes().empty())
|
if (functionType->getReturnParameterTypes().empty())
|
||||||
m_type = make_shared<VoidType>();
|
m_type = make_shared<VoidType>();
|
||||||
else
|
else
|
||||||
m_type = functionType.getReturnParameterTypes().front();
|
m_type = functionType->getReturnParameterTypes().front();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Type is not callable."));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FunctionCall::isTypeConversion() const
|
bool FunctionCall::isTypeConversion() const
|
||||||
@ -261,6 +270,25 @@ bool FunctionCall::isTypeConversion() const
|
|||||||
return m_expression->getType()->getCategory() == Type::Category::TYPE;
|
return m_expression->getType()->getCategory() == Type::Category::TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewExpression::checkTypeRequirements()
|
||||||
|
{
|
||||||
|
m_contractName->checkTypeRequirements();
|
||||||
|
for (ASTPointer<Expression> const& argument: m_arguments)
|
||||||
|
argument->checkTypeRequirements();
|
||||||
|
|
||||||
|
m_contract = dynamic_cast<ContractDefinition const*>(m_contractName->getReferencedDeclaration());
|
||||||
|
if (!m_contract)
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Identifier is not a contract."));
|
||||||
|
shared_ptr<ContractType const> type = make_shared<ContractType const>(*m_contract);
|
||||||
|
m_type = type;
|
||||||
|
TypePointers const& parameterTypes = type->getConstructorType()->getParameterTypes();
|
||||||
|
if (parameterTypes.size() != m_arguments.size())
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for constructor call."));
|
||||||
|
for (size_t i = 0; i < m_arguments.size(); ++i)
|
||||||
|
if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]))
|
||||||
|
BOOST_THROW_EXCEPTION(createTypeError("Invalid type for argument in constructor call."));
|
||||||
|
}
|
||||||
|
|
||||||
void MemberAccess::checkTypeRequirements()
|
void MemberAccess::checkTypeRequirements()
|
||||||
{
|
{
|
||||||
m_expression->checkTypeRequirements();
|
m_expression->checkTypeRequirements();
|
||||||
|
28
AST.h
28
AST.h
@ -181,6 +181,9 @@ public:
|
|||||||
/// Returns the functions that make up the calling interface in the intended order.
|
/// Returns the functions that make up the calling interface in the intended order.
|
||||||
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
|
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
|
||||||
|
|
||||||
|
/// Returns the constructor or nullptr if no constructor was specified
|
||||||
|
FunctionDefinition const* getConstructor() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
|
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
|
||||||
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
|
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
|
||||||
@ -740,6 +743,31 @@ private:
|
|||||||
std::vector<ASTPointer<Expression>> m_arguments;
|
std::vector<ASTPointer<Expression>> m_arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expression that creates a new contract, e.g. "new SomeContract(1, 2)".
|
||||||
|
*/
|
||||||
|
class NewExpression: public Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NewExpression(Location const& _location, ASTPointer<Identifier> const& _contractName,
|
||||||
|
std::vector<ASTPointer<Expression>> const& _arguments):
|
||||||
|
Expression(_location), m_contractName(_contractName), m_arguments(_arguments) {}
|
||||||
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
virtual void checkTypeRequirements() override;
|
||||||
|
|
||||||
|
std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; }
|
||||||
|
|
||||||
|
/// Returns the referenced contract. Can only be called after type checking.
|
||||||
|
ContractDefinition const* getContract() const { return m_contract; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ASTPointer<Identifier> m_contractName;
|
||||||
|
std::vector<ASTPointer<Expression>> m_arguments;
|
||||||
|
|
||||||
|
ContractDefinition const* m_contract = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to a member of an object. Example: x.name
|
* Access to a member of an object. Example: x.name
|
||||||
*/
|
*/
|
||||||
|
@ -62,6 +62,7 @@ class Assignment;
|
|||||||
class UnaryOperation;
|
class UnaryOperation;
|
||||||
class BinaryOperation;
|
class BinaryOperation;
|
||||||
class FunctionCall;
|
class FunctionCall;
|
||||||
|
class NewExpression;
|
||||||
class MemberAccess;
|
class MemberAccess;
|
||||||
class IndexAccess;
|
class IndexAccess;
|
||||||
class PrimaryExpression;
|
class PrimaryExpression;
|
||||||
|
@ -226,6 +226,14 @@ bool ASTPrinter::visit(FunctionCall const& _node)
|
|||||||
return goDeeper();
|
return goDeeper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ASTPrinter::visit(NewExpression const& _node)
|
||||||
|
{
|
||||||
|
writeLine("NewExpression");
|
||||||
|
printType(_node);
|
||||||
|
printSourcePart(_node);
|
||||||
|
return goDeeper();
|
||||||
|
}
|
||||||
|
|
||||||
bool ASTPrinter::visit(MemberAccess const& _node)
|
bool ASTPrinter::visit(MemberAccess const& _node)
|
||||||
{
|
{
|
||||||
writeLine("MemberAccess to member " + _node.getMemberName());
|
writeLine("MemberAccess to member " + _node.getMemberName());
|
||||||
@ -402,6 +410,11 @@ void ASTPrinter::endVisit(FunctionCall const&)
|
|||||||
m_indentation--;
|
m_indentation--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTPrinter::endVisit(NewExpression const&)
|
||||||
|
{
|
||||||
|
m_indentation--;
|
||||||
|
}
|
||||||
|
|
||||||
void ASTPrinter::endVisit(MemberAccess const&)
|
void ASTPrinter::endVisit(MemberAccess const&)
|
||||||
{
|
{
|
||||||
m_indentation--;
|
m_indentation--;
|
||||||
|
@ -67,6 +67,7 @@ public:
|
|||||||
bool visit(UnaryOperation const& _node) override;
|
bool visit(UnaryOperation const& _node) override;
|
||||||
bool visit(BinaryOperation const& _node) override;
|
bool visit(BinaryOperation const& _node) override;
|
||||||
bool visit(FunctionCall const& _node) override;
|
bool visit(FunctionCall const& _node) override;
|
||||||
|
bool visit(NewExpression const& _node) override;
|
||||||
bool visit(MemberAccess const& _node) override;
|
bool visit(MemberAccess const& _node) override;
|
||||||
bool visit(IndexAccess const& _node) override;
|
bool visit(IndexAccess const& _node) override;
|
||||||
bool visit(PrimaryExpression const& _node) override;
|
bool visit(PrimaryExpression const& _node) override;
|
||||||
@ -99,6 +100,7 @@ public:
|
|||||||
void endVisit(UnaryOperation const&) override;
|
void endVisit(UnaryOperation const&) override;
|
||||||
void endVisit(BinaryOperation const&) override;
|
void endVisit(BinaryOperation const&) override;
|
||||||
void endVisit(FunctionCall const&) override;
|
void endVisit(FunctionCall const&) override;
|
||||||
|
void endVisit(NewExpression const&) override;
|
||||||
void endVisit(MemberAccess const&) override;
|
void endVisit(MemberAccess const&) override;
|
||||||
void endVisit(IndexAccess const&) override;
|
void endVisit(IndexAccess const&) override;
|
||||||
void endVisit(PrimaryExpression const&) override;
|
void endVisit(PrimaryExpression const&) override;
|
||||||
|
@ -68,6 +68,7 @@ public:
|
|||||||
virtual bool visit(UnaryOperation&) { return true; }
|
virtual bool visit(UnaryOperation&) { return true; }
|
||||||
virtual bool visit(BinaryOperation&) { return true; }
|
virtual bool visit(BinaryOperation&) { return true; }
|
||||||
virtual bool visit(FunctionCall&) { return true; }
|
virtual bool visit(FunctionCall&) { return true; }
|
||||||
|
virtual bool visit(NewExpression&) { return true; }
|
||||||
virtual bool visit(MemberAccess&) { return true; }
|
virtual bool visit(MemberAccess&) { return true; }
|
||||||
virtual bool visit(IndexAccess&) { return true; }
|
virtual bool visit(IndexAccess&) { return true; }
|
||||||
virtual bool visit(PrimaryExpression&) { return true; }
|
virtual bool visit(PrimaryExpression&) { return true; }
|
||||||
@ -102,6 +103,7 @@ public:
|
|||||||
virtual void endVisit(UnaryOperation&) { }
|
virtual void endVisit(UnaryOperation&) { }
|
||||||
virtual void endVisit(BinaryOperation&) { }
|
virtual void endVisit(BinaryOperation&) { }
|
||||||
virtual void endVisit(FunctionCall&) { }
|
virtual void endVisit(FunctionCall&) { }
|
||||||
|
virtual void endVisit(NewExpression&) { }
|
||||||
virtual void endVisit(MemberAccess&) { }
|
virtual void endVisit(MemberAccess&) { }
|
||||||
virtual void endVisit(IndexAccess&) { }
|
virtual void endVisit(IndexAccess&) { }
|
||||||
virtual void endVisit(PrimaryExpression&) { }
|
virtual void endVisit(PrimaryExpression&) { }
|
||||||
@ -140,6 +142,7 @@ public:
|
|||||||
virtual bool visit(UnaryOperation const&) { return true; }
|
virtual bool visit(UnaryOperation const&) { return true; }
|
||||||
virtual bool visit(BinaryOperation const&) { return true; }
|
virtual bool visit(BinaryOperation const&) { return true; }
|
||||||
virtual bool visit(FunctionCall const&) { return true; }
|
virtual bool visit(FunctionCall const&) { return true; }
|
||||||
|
virtual bool visit(NewExpression const&) { return true; }
|
||||||
virtual bool visit(MemberAccess const&) { return true; }
|
virtual bool visit(MemberAccess const&) { return true; }
|
||||||
virtual bool visit(IndexAccess const&) { return true; }
|
virtual bool visit(IndexAccess const&) { return true; }
|
||||||
virtual bool visit(PrimaryExpression const&) { return true; }
|
virtual bool visit(PrimaryExpression const&) { return true; }
|
||||||
@ -174,6 +177,7 @@ public:
|
|||||||
virtual void endVisit(UnaryOperation const&) { }
|
virtual void endVisit(UnaryOperation const&) { }
|
||||||
virtual void endVisit(BinaryOperation const&) { }
|
virtual void endVisit(BinaryOperation const&) { }
|
||||||
virtual void endVisit(FunctionCall const&) { }
|
virtual void endVisit(FunctionCall const&) { }
|
||||||
|
virtual void endVisit(NewExpression const&) { }
|
||||||
virtual void endVisit(MemberAccess const&) { }
|
virtual void endVisit(MemberAccess const&) { }
|
||||||
virtual void endVisit(IndexAccess const&) { }
|
virtual void endVisit(IndexAccess const&) { }
|
||||||
virtual void endVisit(PrimaryExpression const&) { }
|
virtual void endVisit(PrimaryExpression const&) { }
|
||||||
|
20
AST_accept.h
20
AST_accept.h
@ -419,6 +419,26 @@ void FunctionCall::accept(ASTConstVisitor& _visitor) const
|
|||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewExpression::accept(ASTVisitor& _visitor)
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
|
m_contractName->accept(_visitor);
|
||||||
|
listAccept(m_arguments, _visitor);
|
||||||
|
}
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NewExpression::accept(ASTConstVisitor& _visitor) const
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
|
m_contractName->accept(_visitor);
|
||||||
|
listAccept(m_arguments, _visitor);
|
||||||
|
}
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void MemberAccess::accept(ASTVisitor& _visitor)
|
void MemberAccess::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
|
17
Compiler.cpp
17
Compiler.cpp
@ -33,9 +33,11 @@ using namespace std;
|
|||||||
namespace dev {
|
namespace dev {
|
||||||
namespace solidity {
|
namespace solidity {
|
||||||
|
|
||||||
void Compiler::compileContract(ContractDefinition const& _contract, vector<MagicVariableDeclaration const*> const& _magicGlobals)
|
void Compiler::compileContract(ContractDefinition const& _contract, vector<MagicVariableDeclaration const*> const& _magicGlobals,
|
||||||
|
map<ContractDefinition const*, bytes const*> const& _contracts)
|
||||||
{
|
{
|
||||||
m_context = CompilerContext(); // clear it just in case
|
m_context = CompilerContext(); // clear it just in case
|
||||||
|
m_context.setCompiledContracts(_contracts);
|
||||||
|
|
||||||
for (MagicVariableDeclaration const* variable: _magicGlobals)
|
for (MagicVariableDeclaration const* variable: _magicGlobals)
|
||||||
m_context.addMagicGlobal(*variable);
|
m_context.addMagicGlobal(*variable);
|
||||||
@ -50,12 +52,14 @@ void Compiler::compileContract(ContractDefinition const& _contract, vector<Magic
|
|||||||
if (function->getName() != _contract.getName()) // don't add the constructor here
|
if (function->getName() != _contract.getName()) // don't add the constructor here
|
||||||
function->accept(*this);
|
function->accept(*this);
|
||||||
|
|
||||||
packIntoContractCreator(_contract);
|
packIntoContractCreator(_contract, _contracts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
|
void Compiler::packIntoContractCreator(ContractDefinition const& _contract,
|
||||||
|
map<ContractDefinition const*, bytes const*> const& _contracts)
|
||||||
{
|
{
|
||||||
CompilerContext runtimeContext;
|
CompilerContext runtimeContext;
|
||||||
|
runtimeContext.setCompiledContracts(_contracts);
|
||||||
swap(m_context, runtimeContext);
|
swap(m_context, runtimeContext);
|
||||||
|
|
||||||
registerStateVariables(_contract);
|
registerStateVariables(_contract);
|
||||||
@ -67,11 +71,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
|
|||||||
constructor = function.get();
|
constructor = function.get();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
eth::AssemblyItem sub = m_context.addSubroutine(runtimeContext.getAssembly());
|
||||||
|
// stack contains sub size
|
||||||
if (constructor)
|
if (constructor)
|
||||||
{
|
{
|
||||||
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
||||||
m_context.addFunction(*constructor); // note that it cannot be called due to syntactic reasons
|
m_context.addFunction(*constructor); // note that it cannot be called due to syntactic reasons
|
||||||
//@todo copy constructor arguments from calldata to memory prior to this
|
// copy constructor arguments
|
||||||
|
//@todo ask assembly for the size of the current program
|
||||||
//@todo calling other functions inside the constructor should either trigger a parse error
|
//@todo calling other functions inside the constructor should either trigger a parse error
|
||||||
//or we should copy them here (register them above and call "accept") - detecting which
|
//or we should copy them here (register them above and call "accept") - detecting which
|
||||||
// functions are referenced / called needs to be done in a recursive way.
|
// functions are referenced / called needs to be done in a recursive way.
|
||||||
@ -81,8 +88,6 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
|
|||||||
m_context << returnTag;
|
m_context << returnTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
eth::AssemblyItem sub = m_context.addSubroutine(runtimeContext.getAssembly());
|
|
||||||
// stack contains sub size
|
|
||||||
m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
|
m_context << eth::Instruction::DUP1 << sub << u256(0) << eth::Instruction::CODECOPY;
|
||||||
m_context << u256(0) << eth::Instruction::RETURN;
|
m_context << u256(0) << eth::Instruction::RETURN;
|
||||||
}
|
}
|
||||||
|
@ -32,14 +32,16 @@ class Compiler: private ASTConstVisitor
|
|||||||
public:
|
public:
|
||||||
explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_returnTag(m_context.newTag()) {}
|
explicit Compiler(bool _optimize = false): m_optimize(_optimize), m_returnTag(m_context.newTag()) {}
|
||||||
|
|
||||||
void compileContract(ContractDefinition const& _contract, std::vector<MagicVariableDeclaration const*> const& _magicGlobals);
|
void compileContract(ContractDefinition const& _contract, std::vector<MagicVariableDeclaration const*> const& _magicGlobals,
|
||||||
|
std::map<ContractDefinition const*, bytes const*> const& _contracts);
|
||||||
bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); }
|
bytes getAssembledBytecode() { return m_context.getAssembledBytecode(m_optimize); }
|
||||||
void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); }
|
void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Creates a new compiler context / assembly, packs the current code into the data part and
|
/// Creates a new compiler context / assembly, packs the current code into the data part and
|
||||||
/// adds the constructor code.
|
/// adds the constructor code.
|
||||||
void packIntoContractCreator(ContractDefinition const& _contract);
|
void packIntoContractCreator(ContractDefinition const& _contract,
|
||||||
|
std::map<ContractDefinition const*, bytes const*> const& _contracts);
|
||||||
void appendFunctionSelector(ContractDefinition const& _contract);
|
void appendFunctionSelector(ContractDefinition const& _contract);
|
||||||
/// Creates code that unpacks the arguments for the given function, from memory if
|
/// Creates code that unpacks the arguments for the given function, from memory if
|
||||||
/// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
|
/// @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes.
|
||||||
|
@ -62,6 +62,14 @@ void CompilerContext::addFunction(FunctionDefinition const& _function)
|
|||||||
m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag()));
|
m_functionEntryLabels.insert(std::make_pair(&_function, m_asm.newTag()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytes const& CompilerContext::getCompiledContract(const ContractDefinition& _contract) const
|
||||||
|
{
|
||||||
|
auto ret = m_compiledContracts.find(&_contract);
|
||||||
|
if (asserts(ret != m_compiledContracts.end()))
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Compiled contract not found."));
|
||||||
|
return *ret->second;
|
||||||
|
}
|
||||||
|
|
||||||
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
|
bool CompilerContext::isLocalVariable(Declaration const* _declaration) const
|
||||||
{
|
{
|
||||||
return m_localVariables.count(_declaration) > 0;
|
return m_localVariables.count(_declaration) > 0;
|
||||||
|
@ -39,8 +39,6 @@ namespace solidity {
|
|||||||
class CompilerContext
|
class CompilerContext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CompilerContext(): m_stateVariablesSize(0) {}
|
|
||||||
|
|
||||||
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
|
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
|
||||||
void addStateVariable(VariableDeclaration const& _declaration);
|
void addStateVariable(VariableDeclaration const& _declaration);
|
||||||
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
|
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
|
||||||
@ -48,6 +46,9 @@ public:
|
|||||||
void addAndInitializeVariable(VariableDeclaration const& _declaration);
|
void addAndInitializeVariable(VariableDeclaration const& _declaration);
|
||||||
void addFunction(FunctionDefinition const& _function);
|
void addFunction(FunctionDefinition const& _function);
|
||||||
|
|
||||||
|
void setCompiledContracts(std::map<ContractDefinition const*, bytes const*> const& _contracts) { m_compiledContracts = _contracts; }
|
||||||
|
bytes const& getCompiledContract(ContractDefinition const& _contract) const;
|
||||||
|
|
||||||
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
|
void adjustStackOffset(int _adjustment) { m_asm.adjustDeposit(_adjustment); }
|
||||||
|
|
||||||
bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration); }
|
bool isMagicGlobal(Declaration const* _declaration) const { return m_magicGlobals.count(_declaration); }
|
||||||
@ -80,6 +81,8 @@ public:
|
|||||||
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
|
/// Adds a subroutine to the code (in the data section) and pushes its size (via a tag)
|
||||||
/// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset.
|
/// on the stack. @returns the assembly item corresponding to the pushed subroutine, i.e. its offset.
|
||||||
eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); }
|
eth::AssemblyItem addSubroutine(eth::Assembly const& _assembly) { return m_asm.appendSubSize(_assembly); }
|
||||||
|
/// Adds data to the data section, pushes a reference to the stack
|
||||||
|
eth::AssemblyItem appendData(bytes const& _data) { return m_asm.append(_data); }
|
||||||
|
|
||||||
/// Append elements to the current instruction list and adjust @a m_stackOffset.
|
/// Append elements to the current instruction list and adjust @a m_stackOffset.
|
||||||
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; }
|
CompilerContext& operator<<(eth::AssemblyItem const& _item) { m_asm.append(_item); return *this; }
|
||||||
@ -90,13 +93,16 @@ public:
|
|||||||
eth::Assembly const& getAssembly() const { return m_asm; }
|
eth::Assembly const& getAssembly() const { return m_asm; }
|
||||||
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
|
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
|
||||||
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }
|
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
eth::Assembly m_asm;
|
eth::Assembly m_asm;
|
||||||
|
|
||||||
/// Magic global variables like msg, tx or this, distinguished by type.
|
/// Magic global variables like msg, tx or this, distinguished by type.
|
||||||
std::set<Declaration const*> m_magicGlobals;
|
std::set<Declaration const*> m_magicGlobals;
|
||||||
|
/// Other already compiled contracts to be used in contract creation calls.
|
||||||
|
std::map<ContractDefinition const*, bytes const*> m_compiledContracts;
|
||||||
/// Size of the state variables, offset of next variable to be added.
|
/// Size of the state variables, offset of next variable to be added.
|
||||||
u256 m_stateVariablesSize;
|
u256 m_stateVariablesSize = 0;
|
||||||
/// Storage offsets of state variables
|
/// Storage offsets of state variables
|
||||||
std::map<Declaration const*, u256> m_stateVariables;
|
std::map<Declaration const*, u256> m_stateVariables;
|
||||||
/// Offsets of local variables on the stack (relative to stack base).
|
/// Offsets of local variables on the stack (relative to stack base).
|
||||||
|
@ -96,16 +96,20 @@ void CompilerStack::compile(bool _optimize)
|
|||||||
{
|
{
|
||||||
if (!m_parseSuccessful)
|
if (!m_parseSuccessful)
|
||||||
parse();
|
parse();
|
||||||
|
|
||||||
|
map<ContractDefinition const*, bytes const*> contractBytecode;
|
||||||
for (Source const* source: m_sourceOrder)
|
for (Source const* source: m_sourceOrder)
|
||||||
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
|
||||||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
|
||||||
{
|
{
|
||||||
m_globalContext->setCurrentContract(*contract);
|
m_globalContext->setCurrentContract(*contract);
|
||||||
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize);
|
shared_ptr<Compiler> compiler = make_shared<Compiler>(_optimize);
|
||||||
compiler->compileContract(*contract, m_globalContext->getMagicVariables());
|
compiler->compileContract(*contract, m_globalContext->getMagicVariables(),
|
||||||
|
contractBytecode);
|
||||||
Contract& compiledContract = m_contracts[contract->getName()];
|
Contract& compiledContract = m_contracts[contract->getName()];
|
||||||
compiledContract.bytecode = compiler->getAssembledBytecode();
|
compiledContract.bytecode = compiler->getAssembledBytecode();
|
||||||
compiledContract.compiler = move(compiler);
|
compiledContract.compiler = move(compiler);
|
||||||
|
contractBytecode[compiledContract.contract] = &compiledContract.bytecode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ private:
|
|||||||
|
|
||||||
struct Contract
|
struct Contract
|
||||||
{
|
{
|
||||||
ContractDefinition* contract;
|
ContractDefinition const* contract;
|
||||||
std::shared_ptr<Compiler> compiler;
|
std::shared_ptr<Compiler> compiler;
|
||||||
bytes bytecode;
|
bytes bytecode;
|
||||||
std::shared_ptr<InterfaceHandler> interfaceHandler;
|
std::shared_ptr<InterfaceHandler> interfaceHandler;
|
||||||
|
@ -279,6 +279,44 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ExpressionCompiler::visit(NewExpression const& _newExpression)
|
||||||
|
{
|
||||||
|
ContractType const* type = dynamic_cast<ContractType const*>(_newExpression.getType().get());
|
||||||
|
if (asserts(type))
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||||
|
TypePointers const& types = type->getConstructorType()->getParameterTypes();
|
||||||
|
vector<ASTPointer<Expression const>> arguments = _newExpression.getArguments();
|
||||||
|
if (asserts(arguments.size() == types.size()))
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError());
|
||||||
|
|
||||||
|
// copy the contracts code into memory
|
||||||
|
bytes const& bytecode = m_context.getCompiledContract(*_newExpression.getContract());
|
||||||
|
m_context << u256(bytecode.size());
|
||||||
|
//@todo could be done by actually appending the Assembly, but then we probably need to compile
|
||||||
|
// multiple times. Will revisit once external fuctions are inlined.
|
||||||
|
m_context.appendData(bytecode);
|
||||||
|
//@todo copy to memory position 0, shift as soon as we use memory
|
||||||
|
m_context << u256(0) << eth::Instruction::CODECOPY;
|
||||||
|
|
||||||
|
unsigned dataOffset = bytecode.size();
|
||||||
|
for (unsigned i = 0; i < arguments.size(); ++i)
|
||||||
|
{
|
||||||
|
arguments[i]->accept(*this);
|
||||||
|
appendTypeConversion(*arguments[i]->getType(), *types[i]);
|
||||||
|
unsigned const numBytes = types[i]->getCalldataEncodedSize();
|
||||||
|
if (numBytes > 32)
|
||||||
|
BOOST_THROW_EXCEPTION(CompilerError()
|
||||||
|
<< errinfo_sourceLocation(arguments[i]->getLocation())
|
||||||
|
<< errinfo_comment("Type " + types[i]->toString() + " not yet supported."));
|
||||||
|
bool const leftAligned = types[i]->getCategory() == Type::Category::STRING;
|
||||||
|
CompilerUtils(m_context).storeInMemory(dataOffset, numBytes, leftAligned);
|
||||||
|
dataOffset += numBytes;
|
||||||
|
}
|
||||||
|
// size, offset, endowment
|
||||||
|
m_context << u256(dataOffset) << u256(0) << u256(0) << eth::Instruction::CREATE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
||||||
{
|
{
|
||||||
ASTString const& member = _memberAccess.getMemberName();
|
ASTString const& member = _memberAccess.getMemberName();
|
||||||
|
@ -60,6 +60,7 @@ private:
|
|||||||
virtual void endVisit(UnaryOperation const& _unaryOperation) override;
|
virtual void endVisit(UnaryOperation const& _unaryOperation) override;
|
||||||
virtual bool visit(BinaryOperation const& _binaryOperation) override;
|
virtual bool visit(BinaryOperation const& _binaryOperation) override;
|
||||||
virtual bool visit(FunctionCall const& _functionCall) override;
|
virtual bool visit(FunctionCall const& _functionCall) override;
|
||||||
|
virtual bool visit(NewExpression const& _newExpression) override;
|
||||||
virtual void endVisit(MemberAccess const& _memberAccess) override;
|
virtual void endVisit(MemberAccess const& _memberAccess) override;
|
||||||
virtual bool visit(IndexAccess const& _indexAccess) override;
|
virtual bool visit(IndexAccess const& _indexAccess) override;
|
||||||
virtual void endVisit(Identifier const& _identifier) override;
|
virtual void endVisit(Identifier const& _identifier) override;
|
||||||
|
@ -15,7 +15,7 @@ InterfaceHandler::InterfaceHandler()
|
|||||||
m_lastTag = DocTagType::NONE;
|
m_lastTag = DocTagType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefinition& _contractDef,
|
std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefinition const& _contractDef,
|
||||||
DocumentationType _type)
|
DocumentationType _type)
|
||||||
{
|
{
|
||||||
switch(_type)
|
switch(_type)
|
||||||
@ -32,7 +32,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefiniti
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinition& _contractDef)
|
std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinition const& _contractDef)
|
||||||
{
|
{
|
||||||
Json::Value methods(Json::arrayValue);
|
Json::Value methods(Json::arrayValue);
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ std::unique_ptr<std::string> InterfaceHandler::getABIInterface(ContractDefinitio
|
|||||||
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(methods)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition& _contractDef)
|
std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef)
|
||||||
{
|
{
|
||||||
Json::Value doc;
|
Json::Value doc;
|
||||||
Json::Value methods(Json::objectValue);
|
Json::Value methods(Json::objectValue);
|
||||||
@ -88,7 +88,7 @@ std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefi
|
|||||||
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
|
return std::unique_ptr<std::string>(new std::string(m_writer.write(doc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefinition& _contractDef)
|
std::unique_ptr<std::string> InterfaceHandler::getDevDocumentation(ContractDefinition const& _contractDef)
|
||||||
{
|
{
|
||||||
// LTODO: Somewhere in this function warnings for mismatch of param names
|
// LTODO: Somewhere in this function warnings for mismatch of param names
|
||||||
// should be thrown
|
// should be thrown
|
||||||
|
@ -67,23 +67,23 @@ public:
|
|||||||
/// types provided by @c DocumentationType
|
/// types provided by @c DocumentationType
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of provided type
|
/// representation of provided type
|
||||||
std::unique_ptr<std::string> getDocumentation(ContractDefinition& _contractDef,
|
std::unique_ptr<std::string> getDocumentation(ContractDefinition const& _contractDef,
|
||||||
DocumentationType _type);
|
DocumentationType _type);
|
||||||
/// Get the ABI Interface of the contract
|
/// Get the ABI Interface of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of the contract's ABI Interface
|
/// representation of the contract's ABI Interface
|
||||||
std::unique_ptr<std::string> getABIInterface(ContractDefinition& _contractDef);
|
std::unique_ptr<std::string> getABIInterface(ContractDefinition const& _contractDef);
|
||||||
/// Get the User documentation of the contract
|
/// Get the User documentation of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of the contract's user documentation
|
/// representation of the contract's user documentation
|
||||||
std::unique_ptr<std::string> getUserDocumentation(ContractDefinition& _contractDef);
|
std::unique_ptr<std::string> getUserDocumentation(ContractDefinition const& _contractDef);
|
||||||
/// Get the Developer's documentation of the contract
|
/// Get the Developer's documentation of the contract
|
||||||
/// @param _contractDef The contract definition
|
/// @param _contractDef The contract definition
|
||||||
/// @return A unique pointer contained string with the json
|
/// @return A unique pointer contained string with the json
|
||||||
/// representation of the contract's developer documentation
|
/// representation of the contract's developer documentation
|
||||||
std::unique_ptr<std::string> getDevDocumentation(ContractDefinition& _contractDef);
|
std::unique_ptr<std::string> getDevDocumentation(ContractDefinition const& _contractDef);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resetUser();
|
void resetUser();
|
||||||
|
12
Parser.cpp
12
Parser.cpp
@ -437,7 +437,17 @@ ASTPointer<Expression> Parser::parseUnaryExpression()
|
|||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
Token::Value token = m_scanner->getCurrentToken();
|
Token::Value token = m_scanner->getCurrentToken();
|
||||||
if (Token::isUnaryOp(token) || Token::isCountOp(token))
|
if (token == Token::NEW)
|
||||||
|
{
|
||||||
|
expectToken(Token::NEW);
|
||||||
|
ASTPointer<Identifier> contractName = ASTNodeFactory(*this).createNode<Identifier>(expectIdentifierToken());
|
||||||
|
expectToken(Token::LPAREN);
|
||||||
|
vector<ASTPointer<Expression>> arguments(parseFunctionCallArguments());
|
||||||
|
expectToken(Token::RPAREN);
|
||||||
|
nodeFactory.markEndPosition();
|
||||||
|
return nodeFactory.createNode<NewExpression>(contractName, arguments);
|
||||||
|
}
|
||||||
|
else if (Token::isUnaryOp(token) || Token::isCountOp(token))
|
||||||
{
|
{
|
||||||
// prefix expression
|
// prefix expression
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
|
13
Types.cpp
13
Types.cpp
@ -310,6 +310,19 @@ MemberList const& ContractType::getMembers() const
|
|||||||
return *m_members;
|
return *m_members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_ptr<FunctionType const> const& ContractType::getConstructorType() const
|
||||||
|
{
|
||||||
|
if (!m_constructorType)
|
||||||
|
{
|
||||||
|
FunctionDefinition const* constr = m_contract.getConstructor();
|
||||||
|
if (constr)
|
||||||
|
m_constructorType = make_shared<FunctionType const>(*constr);
|
||||||
|
else
|
||||||
|
m_constructorType = make_shared<FunctionType const>(TypePointers(), TypePointers());
|
||||||
|
}
|
||||||
|
return m_constructorType;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned ContractType::getFunctionIndex(string const& _functionName) const
|
unsigned ContractType::getFunctionIndex(string const& _functionName) const
|
||||||
{
|
{
|
||||||
unsigned index = 0;
|
unsigned index = 0;
|
||||||
|
11
Types.h
11
Types.h
@ -39,6 +39,7 @@ namespace solidity
|
|||||||
// @todo realMxN, dynamic strings, text, arrays
|
// @todo realMxN, dynamic strings, text, arrays
|
||||||
|
|
||||||
class Type; // forward
|
class Type; // forward
|
||||||
|
class FunctionType; // forward
|
||||||
using TypePointer = std::shared_ptr<Type const>;
|
using TypePointer = std::shared_ptr<Type const>;
|
||||||
using TypePointers = std::vector<TypePointer>;
|
using TypePointers = std::vector<TypePointer>;
|
||||||
|
|
||||||
@ -249,10 +250,16 @@ public:
|
|||||||
|
|
||||||
virtual MemberList const& getMembers() const override;
|
virtual MemberList const& getMembers() const override;
|
||||||
|
|
||||||
|
/// Returns the function type of the constructor. Note that the location part of the function type
|
||||||
|
/// is not used, as this type cannot be the type of a variable or expression.
|
||||||
|
std::shared_ptr<FunctionType const> const& getConstructorType() const;
|
||||||
|
|
||||||
unsigned getFunctionIndex(std::string const& _functionName) const;
|
unsigned getFunctionIndex(std::string const& _functionName) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ContractDefinition const& m_contract;
|
ContractDefinition const& m_contract;
|
||||||
|
/// Type of the constructor, @see getConstructorType. Lazily initialized.
|
||||||
|
mutable std::shared_ptr<FunctionType const> m_constructorType;
|
||||||
/// List of member types, will be lazy-initialized because of recursive references.
|
/// List of member types, will be lazy-initialized because of recursive references.
|
||||||
mutable std::unique_ptr<MemberList> m_members;
|
mutable std::unique_ptr<MemberList> m_members;
|
||||||
};
|
};
|
||||||
@ -339,8 +346,8 @@ public:
|
|||||||
virtual std::string toString() const override;
|
virtual std::string toString() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
|
|
||||||
TypePointer getKeyType() const { return m_keyType; }
|
TypePointer const& getKeyType() const { return m_keyType; }
|
||||||
TypePointer getValueType() const { return m_valueType; }
|
TypePointer const& getValueType() const { return m_valueType; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypePointer m_keyType;
|
TypePointer m_keyType;
|
||||||
|
@ -25,11 +25,12 @@ Break = 'break' ';'
|
|||||||
Return = 'return' Expression? ';'
|
Return = 'return' Expression? ';'
|
||||||
VariableDefinition = VariableDeclaration ( = Expression )? ';'
|
VariableDefinition = VariableDeclaration ( = Expression )? ';'
|
||||||
|
|
||||||
Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | IndexAccess |
|
Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | NewExpression | IndexAccess |
|
||||||
MemberAccess | PrimaryExpression
|
MemberAccess | PrimaryExpression
|
||||||
// The expression syntax is actually much more complicated
|
// The expression syntax is actually much more complicated
|
||||||
Assignment = Expression (AssignmentOp Expression)
|
Assignment = Expression (AssignmentOp Expression)
|
||||||
FunctionCall = Expression '(' ( Expression ( ',' Expression )* ) ')'
|
FunctionCall = Expression '(' ( Expression ( ',' Expression )* ) ')'
|
||||||
|
NewExpression = 'new' Identifier '(' ( Expression ( ',' Expression )* ) ')'
|
||||||
MemberAccess = Expression '.' Identifier
|
MemberAccess = Expression '.' Identifier
|
||||||
IndexAccess = Expression '[' Expresison ']'
|
IndexAccess = Expression '[' Expresison ']'
|
||||||
PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')'
|
PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')'
|
||||||
|
Loading…
Reference in New Issue
Block a user