diff --git a/alethzero/MainWin.cpp b/alethzero/MainWin.cpp
index 2a66a6d69..04fc7757c 100644
--- a/alethzero/MainWin.cpp
+++ b/alethzero/MainWin.cpp
@@ -1626,7 +1626,7 @@ void Main::on_data_textChanged()
catch (dev::Exception const& exception)
{
ostringstream error;
- solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler.getScanner());
+ solidity::SourceReferenceFormatter::printExceptionInformation(error, exception, "Error", compiler);
solidity = "
Solidity
" + QString::fromStdString(error.str()).toHtmlEscaped() + "
";
}
catch (...)
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index 4bd0b2c0e..697ffe8e3 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -33,6 +33,19 @@ namespace dev
namespace solidity
{
+void SourceUnit::accept(ASTVisitor& _visitor)
+{
+ if (_visitor.visit(*this))
+ listAccept(m_nodes, _visitor);
+ _visitor.endVisit(*this);
+}
+
+void ImportDirective::accept(ASTVisitor& _visitor)
+{
+ _visitor.visit(*this);
+ _visitor.endVisit(*this);
+}
+
void ContractDefinition::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
@@ -57,34 +70,6 @@ void StructDefinition::checkValidityOfMembers()
checkRecursion();
}
-void StructDefinition::checkMemberTypes()
-{
- for (ASTPointer const& member: getMembers())
- if (!member->getType()->canBeStored())
- BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct."));
-}
-
-void StructDefinition::checkRecursion()
-{
- set definitionsSeen;
- vector queue = {this};
- while (!queue.empty())
- {
- StructDefinition const* def = queue.back();
- queue.pop_back();
- if (definitionsSeen.count(def))
- BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation())
- << errinfo_comment("Recursive struct definition."));
- definitionsSeen.insert(def);
- for (ASTPointer const& member: def->getMembers())
- if (member->getType()->getCategory() == Type::Category::STRUCT)
- {
- UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName());
- queue.push_back(&dynamic_cast(*typeName.getReferencedDeclaration()));
- }
- }
-}
-
void ParameterList::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
@@ -312,6 +297,34 @@ vector ContractDefinition::getInterfaceFunctions() co
return exportedFunctions;
}
+void StructDefinition::checkMemberTypes()
+{
+ for (ASTPointer const& member: getMembers())
+ if (!member->getType()->canBeStored())
+ BOOST_THROW_EXCEPTION(member->createTypeError("Type cannot be used in struct."));
+}
+
+void StructDefinition::checkRecursion()
+{
+ set definitionsSeen;
+ vector queue = {this};
+ while (!queue.empty())
+ {
+ StructDefinition const* def = queue.back();
+ queue.pop_back();
+ if (definitionsSeen.count(def))
+ BOOST_THROW_EXCEPTION(ParserError() << errinfo_sourceLocation(def->getLocation())
+ << errinfo_comment("Recursive struct definition."));
+ definitionsSeen.insert(def);
+ for (ASTPointer const& member: def->getMembers())
+ if (member->getType()->getCategory() == Type::Category::STRUCT)
+ {
+ UserDefinedTypeName const& typeName = dynamic_cast(*member->getTypeName());
+ queue.push_back(&dynamic_cast(*typeName.getReferencedDeclaration()));
+ }
+ }
+}
+
void FunctionDefinition::checkTypeRequirements()
{
for (ASTPointer const& var: getParameters() + getReturnParameters())
diff --git a/libsolidity/AST.h b/libsolidity/AST.h
index d29e84a0a..10616022b 100644
--- a/libsolidity/AST.h
+++ b/libsolidity/AST.h
@@ -79,6 +79,42 @@ private:
Location m_location;
};
+/**
+ * Source unit containing import directives and contract definitions.
+ */
+class SourceUnit: public ASTNode
+{
+public:
+ SourceUnit(Location const& _location, std::vector> const& _nodes):
+ ASTNode(_location), m_nodes(_nodes) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+
+ std::vector> getNodes() const { return m_nodes; }
+
+private:
+ std::vector> m_nodes;
+};
+
+/**
+ * Import directive for referencing other files / source objects.
+ * Example: import "abc.sol"
+ * Source objects are identified by a string which can be a file name but does not have to be.
+ */
+class ImportDirective: public ASTNode
+{
+public:
+ ImportDirective(Location const& _location, ASTPointer const& _identifier):
+ ASTNode(_location), m_identifier(_identifier) {}
+
+ virtual void accept(ASTVisitor& _visitor) override;
+
+ ASTString const& getIdentifier() const { return *m_identifier; }
+
+private:
+ ASTPointer m_identifier;
+};
+
/**
* Abstract AST class for a declaration (contract, function, struct, variable).
*/
diff --git a/libsolidity/ASTForward.h b/libsolidity/ASTForward.h
index a369c8a79..8b4bac1ce 100644
--- a/libsolidity/ASTForward.h
+++ b/libsolidity/ASTForward.h
@@ -34,6 +34,8 @@ namespace solidity
{
class ASTNode;
+class SourceUnit;
+class ImportDirective;
class Declaration;
class ContractDefinition;
class StructDefinition;
diff --git a/libsolidity/ASTPrinter.cpp b/libsolidity/ASTPrinter.cpp
index 987ad11cc..3d09fd9af 100644
--- a/libsolidity/ASTPrinter.cpp
+++ b/libsolidity/ASTPrinter.cpp
@@ -43,6 +43,13 @@ void ASTPrinter::print(ostream& _stream)
}
+bool ASTPrinter::visit(ImportDirective& _node)
+{
+ writeLine("ImportDirective \"" + _node.getIdentifier() + "\"");
+ printSourcePart(_node);
+ return goDeeper();
+}
+
bool ASTPrinter::visit(ContractDefinition& _node)
{
writeLine("ContractDefinition \"" + _node.getName() + "\"");
@@ -270,7 +277,7 @@ bool ASTPrinter::visit(Literal& _node)
return goDeeper();
}
-void ASTPrinter::endVisit(ASTNode&)
+void ASTPrinter::endVisit(ImportDirective&)
{
m_indentation--;
}
diff --git a/libsolidity/ASTPrinter.h b/libsolidity/ASTPrinter.h
index e0757fbc4..1a18fc4a1 100644
--- a/libsolidity/ASTPrinter.h
+++ b/libsolidity/ASTPrinter.h
@@ -42,6 +42,7 @@ public:
/// Output the string representation of the AST to _stream.
void print(std::ostream& _stream);
+ bool visit(ImportDirective& _node) override;
bool visit(ContractDefinition& _node) override;
bool visit(StructDefinition& _node) override;
bool visit(ParameterList& _node) override;
@@ -73,7 +74,7 @@ public:
bool visit(ElementaryTypeNameExpression& _node) override;
bool visit(Literal& _node) override;
- void endVisit(ASTNode& _node) override;
+ void endVisit(ImportDirective&) override;
void endVisit(ContractDefinition&) override;
void endVisit(StructDefinition&) override;
void endVisit(ParameterList&) override;
diff --git a/libsolidity/ASTVisitor.h b/libsolidity/ASTVisitor.h
index 6e579f358..bf1ccc410 100644
--- a/libsolidity/ASTVisitor.h
+++ b/libsolidity/ASTVisitor.h
@@ -42,6 +42,8 @@ class ASTVisitor
{
public:
virtual bool visit(ASTNode&) { return true; }
+ virtual bool visit(SourceUnit&) { return true; }
+ virtual bool visit(ImportDirective&) { return true; }
virtual bool visit(ContractDefinition&) { return true; }
virtual bool visit(StructDefinition&) { return true; }
virtual bool visit(ParameterList&) { return true; }
@@ -74,6 +76,8 @@ public:
virtual bool visit(Literal&) { return true; }
virtual void endVisit(ASTNode&) { }
+ virtual void endVisit(SourceUnit&) { }
+ virtual void endVisit(ImportDirective&) { }
virtual void endVisit(ContractDefinition&) { }
virtual void endVisit(StructDefinition&) { }
virtual void endVisit(ParameterList&) { }
diff --git a/libsolidity/BaseTypes.h b/libsolidity/BaseTypes.h
index d1ffd7bbc..a8fd77c86 100644
--- a/libsolidity/BaseTypes.h
+++ b/libsolidity/BaseTypes.h
@@ -22,6 +22,8 @@
#pragma once
+#include
+#include
#include
namespace dev
@@ -35,19 +37,19 @@ namespace solidity
*/
struct Location
{
- Location(int _start, int _end): start(_start), end(_end) { }
+ Location(int _start, int _end, std::shared_ptr _sourceName):
+ start(_start), end(_end), sourceName(_sourceName) { }
Location(): start(-1), end(-1) { }
- bool IsValid() const { return start >= 0 && end >= start; }
-
int start;
int end;
+ std::shared_ptr sourceName;
};
/// Stream output for Location (used e.g. in boost exceptions).
inline std::ostream& operator<<(std::ostream& _out, Location const& _location)
{
- return _out << "[" << _location.start << "," << _location.end << ")";
+ return _out << *_location.sourceName << "[" << _location.start << "," << _location.end << ")";
}
}
diff --git a/libsolidity/CompilerStack.cpp b/libsolidity/CompilerStack.cpp
index 01bf99d94..d0b1df181 100644
--- a/libsolidity/CompilerStack.cpp
+++ b/libsolidity/CompilerStack.cpp
@@ -36,22 +36,43 @@ namespace dev
namespace solidity
{
-CompilerStack::CompilerStack(): m_interfaceHandler(make_shared()) {}
+void CompilerStack::addSource(string const& _name, string const& _content)
+{
+ if (m_sources.count(_name))
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source by given name already exists."));
+
+ reset(true);
+ m_sources[_name].scanner = make_shared(CharStream(_content), _name);
+}
void CompilerStack::setSource(string const& _sourceCode)
{
reset();
- m_scanner = make_shared(CharStream(_sourceCode));
+ addSource("", _sourceCode);
}
void CompilerStack::parse()
{
- if (!m_scanner)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Source not available."));
- m_contractASTNode = Parser().parse(m_scanner);
+ for (auto& sourcePair: m_sources)
+ {
+ sourcePair.second.scanner->reset();
+ sourcePair.second.ast = Parser().parse(sourcePair.second.scanner);
+ }
+ resolveImports();
+
m_globalContext = make_shared();
- m_globalContext->setCurrentContract(*m_contractASTNode);
- NameAndTypeResolver(m_globalContext->getDeclarations()).resolveNamesAndTypes(*m_contractASTNode);
+ NameAndTypeResolver resolver(m_globalContext->getDeclarations());
+ for (Source const* source: m_sourceOrder)
+ resolver.registerDeclarations(*source->ast);
+ for (Source const* source: m_sourceOrder)
+ for (ASTPointer const& node: source->ast->getNodes())
+ if (ContractDefinition* contract = dynamic_cast(node.get()))
+ {
+ m_globalContext->setCurrentContract(*contract);
+ resolver.updateDeclaration(*m_globalContext->getCurrentThis());
+ resolver.resolveNamesAndTypes(*contract);
+ m_contracts[contract->getName()].contract = contract;
+ }
m_parseSuccessful = true;
}
@@ -61,54 +82,90 @@ void CompilerStack::parse(string const& _sourceCode)
parse();
}
-bytes const& CompilerStack::compile(bool _optimize)
+vector CompilerStack::getContractNames()
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- m_bytecode.clear();
- m_compiler = make_shared();
- m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables());
- return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
+ vector contractNames;
+ for (auto const& contract: m_contracts)
+ contractNames.push_back(contract.first);
+ return contractNames;
+}
+
+void CompilerStack::compile(bool _optimize)
+{
+ if (!m_parseSuccessful)
+ parse();
+ for (Source const* source: m_sourceOrder)
+ for (ASTPointer const& node: source->ast->getNodes())
+ if (ContractDefinition* contract = dynamic_cast(node.get()))
+ {
+ m_globalContext->setCurrentContract(*contract);
+ shared_ptr compiler = make_shared();
+ compiler->compileContract(*contract, m_globalContext->getMagicVariables());
+ Contract& compiledContract = m_contracts[contract->getName()];
+ compiledContract.bytecode = compiler->getAssembledBytecode(_optimize);
+ compiledContract.compiler = move(compiler);
+ }
}
bytes const& CompilerStack::compile(string const& _sourceCode, bool _optimize)
{
parse(_sourceCode);
- return compile(_optimize);
+ compile(_optimize);
+ return getBytecode();
}
-void CompilerStack::streamAssembly(ostream& _outStream)
+bytes const& CompilerStack::getBytecode(string const& _contractName)
{
- if (!m_compiler || m_bytecode.empty())
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
- m_compiler->streamAssembly(_outStream);
+ return getContract(_contractName).bytecode;
}
-std::string const& CompilerStack::getJsonDocumentation(DocumentationType _type)
+void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName)
+{
+ getContract(_contractName).compiler->streamAssembly(_outStream);
+}
+
+string const& CompilerStack::getInterface(std::string const& _contractName)
+{
+ return getJsonDocumentation(_contractName, ABI_INTERFACE);
+}
+
+std::string const& CompilerStack::getJsonDocumentation(std::string const& _contractName, DocumentationType _type)
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- auto createDocIfNotThere = [this, _type](std::unique_ptr& _doc)
- {
- if (!_doc)
- _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type);
- };
+ Contract& contract = getContract(_contractName);
+ std::unique_ptr* doc;
switch (_type)
{
case DocumentationType::NATSPEC_USER:
- createDocIfNotThere(m_userDocumentation);
- return *m_userDocumentation;
+ doc = &contract.userDocumentation;
+ break;
case DocumentationType::NATSPEC_DEV:
- createDocIfNotThere(m_devDocumentation);
- return *m_devDocumentation;
+ doc = &contract.devDocumentation;
+ break;
case DocumentationType::ABI_INTERFACE:
- createDocIfNotThere(m_interface);
- return *m_interface;
+ doc = &contract.interface;
+ break;
+ default:
+ BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
}
+ if (!*doc)
+ *doc = contract.interfaceHandler->getDocumentation(*contract.contract, _type);
+ return *(*doc);
+}
- BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type."));
+Scanner const& CompilerStack::getScanner(string const& _sourceName)
+{
+ return *getSource(_sourceName).scanner;
+}
+
+SourceUnit& CompilerStack::getAST(string const& _sourceName)
+{
+ return *getSource(_sourceName).ast;
}
bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimize)
@@ -117,7 +174,70 @@ bytes CompilerStack::staticCompile(std::string const& _sourceCode, bool _optimiz
return stack.compile(_sourceCode, _optimize);
}
+void CompilerStack::reset(bool _keepSources)
+{
+ m_parseSuccessful = false;
+ if (_keepSources)
+ for (auto sourcePair: m_sources)
+ sourcePair.second.reset();
+ else
+ m_sources.clear();
+ m_globalContext.reset();
+ m_sourceOrder.clear();
+ m_contracts.clear();
+}
+
+void CompilerStack::resolveImports()
+{
+ // topological sorting (depth first search) of the import graph, cutting potential cycles
+ vector