aboutsummaryrefslogtreecommitdiffstats
path: root/CompilerStack.cpp
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-12-04 00:45:12 +0800
committerChristian <c@ethdev.com>2014-12-04 01:51:59 +0800
commit254df50feab6bb4c9f013257591b73919e4013a5 (patch)
treef8258a07f87046e1695373bc6024af87f51f51be /CompilerStack.cpp
parent328387d6d0a14143f1634df11036a91fad85cec9 (diff)
downloaddexon-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.cpp219
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;
+}
}
}