aboutsummaryrefslogtreecommitdiffstats
path: root/CompilerStack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'CompilerStack.cpp')
-rw-r--r--CompilerStack.cpp180
1 files changed, 150 insertions, 30 deletions
diff --git a/CompilerStack.cpp b/CompilerStack.cpp
index c83257a1..62172384 100644
--- a/CompilerStack.cpp
+++ b/CompilerStack.cpp
@@ -36,22 +36,43 @@ namespace dev
namespace solidity
{
-CompilerStack::CompilerStack(): m_interfaceHandler(make_shared<InterfaceHandler>()) {}
+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<Scanner>(CharStream(_content), _name);
+}
void CompilerStack::setSource(string const& _sourceCode)
{
reset();
- m_scanner = make_shared<Scanner>(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<GlobalContext>();
- 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<ASTNode> const& node: source->ast->getNodes())
+ if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(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<string> CompilerStack::getContractNames()
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- m_bytecode.clear();
- m_compiler = make_shared<Compiler>();
- m_compiler->compileContract(*m_contractASTNode, m_globalContext->getMagicVariables());
- return m_bytecode = m_compiler->getAssembledBytecode(_optimize);
+ vector<string> 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<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>();
+ 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(enum 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, enum DocumentationType _type)
{
if (!m_parseSuccessful)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
- auto createDocIfNotThere = [this, _type](std::unique_ptr<string>& _doc)
- {
- if (!_doc)
- _doc = m_interfaceHandler->getDocumentation(m_contractASTNode, _type);
- };
+ Contract& contract = getContract(_contractName);
+ std::unique_ptr<string>* doc;
switch (_type)
{
case NATSPEC_USER:
- createDocIfNotThere(m_userDocumentation);
- return *m_userDocumentation;
+ doc = &contract.userDocumentation;
+ break;
case NATSPEC_DEV:
- createDocIfNotThere(m_devDocumentation);
- return *m_devDocumentation;
+ doc = &contract.devDocumentation;
+ break;
case 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<Source const*> sourceOrder;
+ set<Source const*> sourcesSeen;
+
+ function<void(Source const*)> toposort = [&](Source const* _source)
+ {
+ if (sourcesSeen.count(_source))
+ return;
+ sourcesSeen.insert(_source);
+ for (ASTPointer<ASTNode> const& node: _source->ast->getNodes())
+ if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
+ {
+ string const& url = import->getURL();
+ if (!m_sources.count(url))
+ BOOST_THROW_EXCEPTION(ParserError()
+ << errinfo_sourceLocation(import->getLocation())
+ << errinfo_comment("Source not found."));
+ toposort(&m_sources[url]);
+ }
+ sourceOrder.push_back(_source);
+ };
+
+ for (auto const& sourcePair: m_sources)
+ toposort(&sourcePair.second);
+
+ swap(m_sourceOrder, sourceOrder);
+}
+
+CompilerStack::Contract& CompilerStack::getContract(string const& _contractName)
+{
+ if (m_contracts.empty())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
+ if (_contractName.empty())
+ return m_contracts.begin()->second;
+ auto it = m_contracts.find(_contractName);
+ if (it == m_contracts.end())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
+ return it->second;
+}
+
+CompilerStack::Source& CompilerStack::getSource(string const& _sourceName)
+{
+ auto it = m_sources.find(_sourceName);
+ if (it == m_sources.end())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Given source file not found."));
+ return it->second;
+}
+CompilerStack::Contract::Contract(): interfaceHandler(make_shared<InterfaceHandler>()) {}
}
}