diff options
author | Christian <c@ethdev.com> | 2014-12-04 00:45:12 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2014-12-04 01:51:59 +0800 |
commit | 254df50feab6bb4c9f013257591b73919e4013a5 (patch) | |
tree | f8258a07f87046e1695373bc6024af87f51f51be /CompilerStack.cpp | |
parent | 328387d6d0a14143f1634df11036a91fad85cec9 (diff) | |
download | dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.tar dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.tar.gz dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.tar.bz2 dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.tar.lz dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.tar.xz dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.tar.zst dexon-solidity-254df50feab6bb4c9f013257591b73919e4013a5.zip |
Multi-source and multi-contract compiler.
Diffstat (limited to 'CompilerStack.cpp')
-rw-r--r-- | CompilerStack.cpp | 219 |
1 files changed, 154 insertions, 65 deletions
diff --git a/CompilerStack.cpp b/CompilerStack.cpp index 8f8c84fe..49ac3b64 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -35,24 +35,43 @@ namespace dev namespace solidity { +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_sourceUnitASTNode = 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>(); - for (ASTPointer<ASTNode> const& node: m_sourceUnitASTNode->getNodes()) - if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) - { - m_globalContext->setCurrentContract(*contract); - NameAndTypeResolver(m_globalContext->getDeclarations()).resolveNamesAndTypes(*contract); - } + 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; } @@ -62,82 +81,91 @@ void CompilerStack::parse(string const& _sourceCode) parse(); } -bytes const& CompilerStack::compile(bool _optimize) +void CompilerStack::compile(bool _optimize) { if (!m_parseSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - //@todo returns only the last contract for now - for (ASTPointer<ASTNode> const& node: m_sourceUnitASTNode->getNodes()) - if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) - { - m_bytecode.clear(); - m_compiler = make_shared<Compiler>(); - m_compiler->compileContract(*contract, m_globalContext->getMagicVariables()); - m_bytecode = m_compiler->getAssembledBytecode(_optimize); - } - return m_bytecode; + 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; } -string const& CompilerStack::getInterface() +void CompilerStack::streamAssembly(ostream& _outStream, string const& _contractName) { - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - if (m_interface.empty()) + getContract(_contractName).compiler->streamAssembly(_outStream); +} + +string const& CompilerStack::getInterface(std::string const& _contractName) +{ + Contract& contract = getContract(_contractName); + if (contract.interface.empty()) { - //@todo returns only the last contract for now - for (ASTPointer<ASTNode> const& node: m_sourceUnitASTNode->getNodes()) - if (ContractDefinition const* contract = dynamic_cast<ContractDefinition*>(node.get())) + stringstream interface; + interface << '['; + vector<FunctionDefinition const*> exportedFunctions = contract.contract->getInterfaceFunctions(); + unsigned functionsCount = exportedFunctions.size(); + for (FunctionDefinition const* f: exportedFunctions) + { + auto streamVariables = [&](vector<ASTPointer<VariableDeclaration>> const& _vars) { - stringstream interface; - interface << '['; - vector<FunctionDefinition const*> exportedFunctions = contract->getInterfaceFunctions(); - unsigned functionsCount = exportedFunctions.size(); - for (FunctionDefinition const* f: exportedFunctions) + unsigned varCount = _vars.size(); + for (ASTPointer<VariableDeclaration> const& var: _vars) { - auto streamVariables = [&](vector<ASTPointer<VariableDeclaration>> const& _vars) - { - unsigned varCount = _vars.size(); - for (ASTPointer<VariableDeclaration> const& var: _vars) - { - interface << "{" - << "\"name\":" << escaped(var->getName(), false) << "," - << "\"type\":" << escaped(var->getType()->toString(), false) - << "}"; - if (--varCount > 0) - interface << ","; - } - }; - - interface << '{' - << "\"name\":" << escaped(f->getName(), false) << "," - << "\"inputs\":["; - streamVariables(f->getParameters()); - interface << "]," - << "\"outputs\":["; - streamVariables(f->getReturnParameters()); - interface << "]" + interface << "{" + << "\"name\":" << escaped(var->getName(), false) << "," + << "\"type\":" << escaped(var->getType()->toString(), false) << "}"; - if (--functionsCount > 0) + if (--varCount > 0) interface << ","; } - interface << ']'; - m_interface = interface.str(); - } + }; + + interface << '{' + << "\"name\":" << escaped(f->getName(), false) << "," + << "\"inputs\":["; + streamVariables(f->getParameters()); + interface << "]," + << "\"outputs\":["; + streamVariables(f->getReturnParameters()); + interface << "]" + << "}"; + if (--functionsCount > 0) + interface << ","; + } + interface << ']'; + contract.interface = interface.str(); } - return m_interface; + return contract.interface; +} + +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) @@ -146,7 +174,68 @@ 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_compiler.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; +} } } |