aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AST.cpp38
-rw-r--r--AST.h28
-rw-r--r--ASTForward.h1
-rw-r--r--ASTPrinter.cpp13
-rw-r--r--ASTPrinter.h2
-rw-r--r--ASTVisitor.h4
-rw-r--r--AST_accept.h20
-rw-r--r--Compiler.cpp17
-rw-r--r--Compiler.h6
-rw-r--r--CompilerContext.cpp8
-rw-r--r--CompilerContext.h12
-rw-r--r--CompilerStack.cpp6
-rw-r--r--CompilerStack.h2
-rw-r--r--ExpressionCompiler.cpp38
-rw-r--r--ExpressionCompiler.h1
-rw-r--r--InterfaceHandler.cpp8
-rw-r--r--InterfaceHandler.h8
-rw-r--r--Parser.cpp12
-rw-r--r--Types.cpp13
-rw-r--r--Types.h11
-rw-r--r--grammar.txt3
21 files changed, 221 insertions, 30 deletions
diff --git a/AST.cpp b/AST.cpp
index 8174d138..3fcf8ba0 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -54,6 +54,14 @@ vector<FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() co
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
{
for (ASTPointer<VariableDeclaration> const& member: getMembers())
@@ -235,13 +243,12 @@ void FunctionCall::checkTypeRequirements()
BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed."));
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
// and then ask if that is implicitly convertible to the struct represented by the
// 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())
BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call."));
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."));
// @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
- if (functionType.getReturnParameterTypes().empty())
+ if (functionType->getReturnParameterTypes().empty())
m_type = make_shared<VoidType>();
else
- m_type = functionType.getReturnParameterTypes().front();
+ m_type = functionType->getReturnParameterTypes().front();
}
+ else
+ BOOST_THROW_EXCEPTION(createTypeError("Type is not callable."));
}
bool FunctionCall::isTypeConversion() const
@@ -261,6 +270,25 @@ bool FunctionCall::isTypeConversion() const
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()
{
m_expression->checkTypeRequirements();
diff --git a/AST.h b/AST.h
index 19c4b427..3a15bbeb 100644
--- a/AST.h
+++ b/AST.h
@@ -181,6 +181,9 @@ public:
/// Returns the functions that make up the calling interface in the intended order.
std::vector<FunctionDefinition const*> getInterfaceFunctions() const;
+ /// Returns the constructor or nullptr if no constructor was specified
+ FunctionDefinition const* getConstructor() const;
+
private:
std::vector<ASTPointer<StructDefinition>> m_definedStructs;
std::vector<ASTPointer<VariableDeclaration>> m_stateVariables;
@@ -741,6 +744,31 @@ private:
};
/**
+ * 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
*/
class MemberAccess: public Expression
diff --git a/ASTForward.h b/ASTForward.h
index 8b4bac1c..d6c4c9f4 100644
--- a/ASTForward.h
+++ b/ASTForward.h
@@ -62,6 +62,7 @@ class Assignment;
class UnaryOperation;
class BinaryOperation;
class FunctionCall;
+class NewExpression;
class MemberAccess;
class IndexAccess;
class PrimaryExpression;
diff --git a/ASTPrinter.cpp b/ASTPrinter.cpp
index eddb5134..970822a9 100644
--- a/ASTPrinter.cpp
+++ b/ASTPrinter.cpp
@@ -226,6 +226,14 @@ bool ASTPrinter::visit(FunctionCall const& _node)
return goDeeper();
}
+bool ASTPrinter::visit(NewExpression const& _node)
+{
+ writeLine("NewExpression");
+ printType(_node);
+ printSourcePart(_node);
+ return goDeeper();
+}
+
bool ASTPrinter::visit(MemberAccess const& _node)
{
writeLine("MemberAccess to member " + _node.getMemberName());
@@ -402,6 +410,11 @@ void ASTPrinter::endVisit(FunctionCall const&)
m_indentation--;
}
+void ASTPrinter::endVisit(NewExpression const&)
+{
+ m_indentation--;
+}
+
void ASTPrinter::endVisit(MemberAccess const&)
{
m_indentation--;
diff --git a/ASTPrinter.h b/ASTPrinter.h
index 5a918715..15b65e3f 100644
--- a/ASTPrinter.h
+++ b/ASTPrinter.h
@@ -67,6 +67,7 @@ public:
bool visit(UnaryOperation const& _node) override;
bool visit(BinaryOperation const& _node) override;
bool visit(FunctionCall const& _node) override;
+ bool visit(NewExpression const& _node) override;
bool visit(MemberAccess const& _node) override;
bool visit(IndexAccess const& _node) override;
bool visit(PrimaryExpression const& _node) override;
@@ -99,6 +100,7 @@ public:
void endVisit(UnaryOperation const&) override;
void endVisit(BinaryOperation const&) override;
void endVisit(FunctionCall const&) override;
+ void endVisit(NewExpression const&) override;
void endVisit(MemberAccess const&) override;
void endVisit(IndexAccess const&) override;
void endVisit(PrimaryExpression const&) override;
diff --git a/ASTVisitor.h b/ASTVisitor.h
index 4e1a4945..5728cd3d 100644
--- a/ASTVisitor.h
+++ b/ASTVisitor.h
@@ -68,6 +68,7 @@ public:
virtual bool visit(UnaryOperation&) { return true; }
virtual bool visit(BinaryOperation&) { return true; }
virtual bool visit(FunctionCall&) { return true; }
+ virtual bool visit(NewExpression&) { return true; }
virtual bool visit(MemberAccess&) { return true; }
virtual bool visit(IndexAccess&) { return true; }
virtual bool visit(PrimaryExpression&) { return true; }
@@ -102,6 +103,7 @@ public:
virtual void endVisit(UnaryOperation&) { }
virtual void endVisit(BinaryOperation&) { }
virtual void endVisit(FunctionCall&) { }
+ virtual void endVisit(NewExpression&) { }
virtual void endVisit(MemberAccess&) { }
virtual void endVisit(IndexAccess&) { }
virtual void endVisit(PrimaryExpression&) { }
@@ -140,6 +142,7 @@ public:
virtual bool visit(UnaryOperation const&) { return true; }
virtual bool visit(BinaryOperation 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(IndexAccess const&) { return true; }
virtual bool visit(PrimaryExpression const&) { return true; }
@@ -174,6 +177,7 @@ public:
virtual void endVisit(UnaryOperation const&) { }
virtual void endVisit(BinaryOperation const&) { }
virtual void endVisit(FunctionCall const&) { }
+ virtual void endVisit(NewExpression const&) { }
virtual void endVisit(MemberAccess const&) { }
virtual void endVisit(IndexAccess const&) { }
virtual void endVisit(PrimaryExpression const&) { }
diff --git a/AST_accept.h b/AST_accept.h
index 173273c6..e0454d33 100644
--- a/AST_accept.h
+++ b/AST_accept.h
@@ -419,6 +419,26 @@ void FunctionCall::accept(ASTConstVisitor& _visitor) const
_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)
{
if (_visitor.visit(*this))
diff --git a/Compiler.cpp b/Compiler.cpp
index 25833691..48d8be88 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -33,9 +33,11 @@ using namespace std;
namespace dev {
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.setCompiledContracts(_contracts);
for (MagicVariableDeclaration const* variable: _magicGlobals)
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
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;
+ runtimeContext.setCompiledContracts(_contracts);
swap(m_context, runtimeContext);
registerStateVariables(_contract);
@@ -67,11 +71,14 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
constructor = function.get();
break;
}
+ eth::AssemblyItem sub = m_context.addSubroutine(runtimeContext.getAssembly());
+ // stack contains sub size
if (constructor)
{
eth::AssemblyItem returnTag = m_context.pushNewTag();
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
//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.
@@ -81,8 +88,6 @@ void Compiler::packIntoContractCreator(ContractDefinition const& _contract)
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 << u256(0) << eth::Instruction::RETURN;
}
diff --git a/Compiler.h b/Compiler.h
index 639e9841..57e40cda 100644
--- a/Compiler.h
+++ b/Compiler.h
@@ -32,14 +32,16 @@ class Compiler: private ASTConstVisitor
public:
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); }
void streamAssembly(std::ostream& _stream) const { m_context.streamAssembly(_stream); }
private:
/// Creates a new compiler context / assembly, packs the current code into the data part and
/// 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);
/// 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.
diff --git a/CompilerContext.cpp b/CompilerContext.cpp
index cd22c4e8..47401436 100644
--- a/CompilerContext.cpp
+++ b/CompilerContext.cpp
@@ -62,6 +62,14 @@ void CompilerContext::addFunction(FunctionDefinition const& _function)
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
{
return m_localVariables.count(_declaration) > 0;
diff --git a/CompilerContext.h b/CompilerContext.h
index 652e65a6..99f5ae94 100644
--- a/CompilerContext.h
+++ b/CompilerContext.h
@@ -39,8 +39,6 @@ namespace solidity {
class CompilerContext
{
public:
- CompilerContext(): m_stateVariablesSize(0) {}
-
void addMagicGlobal(MagicVariableDeclaration const& _declaration);
void addStateVariable(VariableDeclaration const& _declaration);
void startNewFunction() { m_localVariables.clear(); m_asm.setDeposit(0); }
@@ -48,6 +46,9 @@ public:
void addAndInitializeVariable(VariableDeclaration const& _declaration);
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); }
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)
/// 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); }
+ /// 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.
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; }
void streamAssembly(std::ostream& _stream) const { _stream << m_asm; }
bytes getAssembledBytecode(bool _optimize = false) { return m_asm.optimise(_optimize).assemble(); }
+
private:
eth::Assembly m_asm;
/// Magic global variables like msg, tx or this, distinguished by type.
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.
- u256 m_stateVariablesSize;
+ u256 m_stateVariablesSize = 0;
/// Storage offsets of state variables
std::map<Declaration const*, u256> m_stateVariables;
/// Offsets of local variables on the stack (relative to stack base).
diff --git a/CompilerStack.cpp b/CompilerStack.cpp
index 7aaa79b1..23f5fd68 100644
--- a/CompilerStack.cpp
+++ b/CompilerStack.cpp
@@ -96,16 +96,20 @@ void CompilerStack::compile(bool _optimize)
{
if (!m_parseSuccessful)
parse();
+
+ map<ContractDefinition const*, bytes const*> contractBytecode;
for (Source const* source: m_sourceOrder)
for (ASTPointer<ASTNode> const& node: source->ast->getNodes())
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
{
m_globalContext->setCurrentContract(*contract);
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()];
compiledContract.bytecode = compiler->getAssembledBytecode();
compiledContract.compiler = move(compiler);
+ contractBytecode[compiledContract.contract] = &compiledContract.bytecode;
}
}
diff --git a/CompilerStack.h b/CompilerStack.h
index b6c34f1a..5ad6f0a6 100644
--- a/CompilerStack.h
+++ b/CompilerStack.h
@@ -108,7 +108,7 @@ private:
struct Contract
{
- ContractDefinition* contract;
+ ContractDefinition const* contract;
std::shared_ptr<Compiler> compiler;
bytes bytecode;
std::shared_ptr<InterfaceHandler> interfaceHandler;
diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp
index f872e058..743503bb 100644
--- a/ExpressionCompiler.cpp
+++ b/ExpressionCompiler.cpp
@@ -279,6 +279,44 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
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)
{
ASTString const& member = _memberAccess.getMemberName();
diff --git a/ExpressionCompiler.h b/ExpressionCompiler.h
index 0bba211c..67b16aac 100644
--- a/ExpressionCompiler.h
+++ b/ExpressionCompiler.h
@@ -60,6 +60,7 @@ private:
virtual void endVisit(UnaryOperation const& _unaryOperation) override;
virtual bool visit(BinaryOperation const& _binaryOperation) override;
virtual bool visit(FunctionCall const& _functionCall) override;
+ virtual bool visit(NewExpression const& _newExpression) override;
virtual void endVisit(MemberAccess const& _memberAccess) override;
virtual bool visit(IndexAccess const& _indexAccess) override;
virtual void endVisit(Identifier const& _identifier) override;
diff --git a/InterfaceHandler.cpp b/InterfaceHandler.cpp
index f26088af..1310f504 100644
--- a/InterfaceHandler.cpp
+++ b/InterfaceHandler.cpp
@@ -15,7 +15,7 @@ InterfaceHandler::InterfaceHandler()
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)
{
switch(_type)
@@ -32,7 +32,7 @@ std::unique_ptr<std::string> InterfaceHandler::getDocumentation(ContractDefiniti
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);
@@ -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)));
}
-std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition& _contractDef)
+std::unique_ptr<std::string> InterfaceHandler::getUserDocumentation(ContractDefinition const& _contractDef)
{
Json::Value doc;
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)));
}
-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
// should be thrown
diff --git a/InterfaceHandler.h b/InterfaceHandler.h
index b1cd4b56..d271a669 100644
--- a/InterfaceHandler.h
+++ b/InterfaceHandler.h
@@ -67,23 +67,23 @@ public:
/// types provided by @c DocumentationType
/// @return A unique pointer contained string with the json
/// representation of provided type
- std::unique_ptr<std::string> getDocumentation(ContractDefinition& _contractDef,
+ std::unique_ptr<std::string> getDocumentation(ContractDefinition const& _contractDef,
DocumentationType _type);
/// Get the ABI Interface of the contract
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// 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
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// 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
/// @param _contractDef The contract definition
/// @return A unique pointer contained string with the json
/// 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:
void resetUser();
diff --git a/Parser.cpp b/Parser.cpp
index b678b2fc..21651eb1 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -437,7 +437,17 @@ ASTPointer<Expression> Parser::parseUnaryExpression()
{
ASTNodeFactory nodeFactory(*this);
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
m_scanner->next();
diff --git a/Types.cpp b/Types.cpp
index c2d48841..f1cd7c22 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -310,6 +310,19 @@ MemberList const& ContractType::getMembers() const
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 index = 0;
diff --git a/Types.h b/Types.h
index 807e60c7..48539a1d 100644
--- a/Types.h
+++ b/Types.h
@@ -39,6 +39,7 @@ namespace solidity
// @todo realMxN, dynamic strings, text, arrays
class Type; // forward
+class FunctionType; // forward
using TypePointer = std::shared_ptr<Type const>;
using TypePointers = std::vector<TypePointer>;
@@ -249,10 +250,16 @@ public:
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;
private:
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.
mutable std::unique_ptr<MemberList> m_members;
};
@@ -339,8 +346,8 @@ public:
virtual std::string toString() const override;
virtual bool canLiveOutsideStorage() const override { return false; }
- TypePointer getKeyType() const { return m_keyType; }
- TypePointer getValueType() const { return m_valueType; }
+ TypePointer const& getKeyType() const { return m_keyType; }
+ TypePointer const& getValueType() const { return m_valueType; }
private:
TypePointer m_keyType;
diff --git a/grammar.txt b/grammar.txt
index c0ab0607..793e9188 100644
--- a/grammar.txt
+++ b/grammar.txt
@@ -25,11 +25,12 @@ Break = 'break' ';'
Return = 'return' Expression? ';'
VariableDefinition = VariableDeclaration ( = Expression )? ';'
-Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | IndexAccess |
+Expression = Assignment | UnaryOperation | BinaryOperation | FunctionCall | NewExpression | IndexAccess |
MemberAccess | PrimaryExpression
// The expression syntax is actually much more complicated
Assignment = Expression (AssignmentOp Expression)
FunctionCall = Expression '(' ( Expression ( ',' Expression )* ) ')'
+NewExpression = 'new' Identifier '(' ( Expression ( ',' Expression )* ) ')'
MemberAccess = Expression '.' Identifier
IndexAccess = Expression '[' Expresison ']'
PrimaryExpression = Identifier | NumberLiteral | StringLiteral | ElementaryTypeName | '(' Expression ')'