diff options
Diffstat (limited to 'libsolidity/interface/CompilerStack.cpp')
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 146 |
1 files changed, 112 insertions, 34 deletions
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 6ea9ea78..72712298 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -37,7 +37,8 @@ #include <libsolidity/analysis/PostTypeChecker.h> #include <libsolidity/analysis/SyntaxChecker.h> #include <libsolidity/codegen/Compiler.h> -#include <libsolidity/interface/InterfaceHandler.h> +#include <libsolidity/interface/ABI.h> +#include <libsolidity/interface/Natspec.h> #include <libsolidity/interface/GasEstimator.h> #include <libsolidity/formal/Why3Translator.h> @@ -57,7 +58,7 @@ using namespace dev; using namespace dev::solidity; CompilerStack::CompilerStack(ReadFile::Callback const& _readFile): - m_readFile(_readFile), m_parseSuccessful(false) {} + m_readFile(_readFile) {} void CompilerStack::setRemappings(vector<string> const& _remappings) { @@ -79,10 +80,12 @@ void CompilerStack::setRemappings(vector<string> const& _remappings) void CompilerStack::reset(bool _keepSources) { - m_parseSuccessful = false; if (_keepSources) + { + m_stackState = SourcesSet; for (auto sourcePair: m_sources) sourcePair.second.reset(); + } else { m_sources.clear(); @@ -94,6 +97,7 @@ void CompilerStack::reset(bool _keepSources) m_sourceOrder.clear(); m_contracts.clear(); m_errors.clear(); + m_stackState = Empty; } bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) @@ -102,6 +106,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool reset(true); m_sources[_name].scanner = make_shared<Scanner>(CharStream(_content), _name); m_sources[_name].isLibrary = _isLibrary; + m_stackState = SourcesSet; return existed; } @@ -114,9 +119,10 @@ void CompilerStack::setSource(string const& _sourceCode) bool CompilerStack::parse() { //reset + if(m_stackState != SourcesSet) + return false; m_errors.clear(); ASTNode::resetID(); - m_parseSuccessful = false; if (SemVerVersion{string(VersionString)}.isPrerelease()) { @@ -128,14 +134,12 @@ bool CompilerStack::parse() vector<string> sourcesToParse; for (auto const& s: m_sources) sourcesToParse.push_back(s.first); - map<string, SourceUnit const*> sourceUnitsByName; for (size_t i = 0; i < sourcesToParse.size(); ++i) { string const& path = sourcesToParse[i]; Source& source = m_sources[path]; source.scanner->reset(); source.ast = Parser(m_errors).parse(source.scanner); - sourceUnitsByName[path] = source.ast.get(); if (!source.ast) solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error."); else @@ -150,10 +154,19 @@ bool CompilerStack::parse() } } } - if (!Error::containsOnlyWarnings(m_errors)) - // errors while parsing. should stop before type checking + if (Error::containsOnlyWarnings(m_errors)) + { + m_stackState = ParsingSuccessful; + return true; + } + else return false; +} +bool CompilerStack::analyze() +{ + if (m_stackState != ParsingSuccessful) + return false; resolveImports(); bool noErrors = true; @@ -173,6 +186,9 @@ bool CompilerStack::parse() if (!resolver.registerDeclarations(*source->ast)) return false; + map<string, SourceUnit const*> sourceUnitsByName; + for (auto& source: m_sources) + sourceUnitsByName[source.first] = source.second.ast.get(); for (Source const* source: m_sourceOrder) if (!resolver.performImports(*source->ast, sourceUnitsByName)) return false; @@ -204,8 +220,8 @@ bool CompilerStack::parse() TypeChecker typeChecker(m_errors); if (typeChecker.checkTypeRequirements(*contract)) { - contract->setDevDocumentation(InterfaceHandler::devDocumentation(*contract)); - contract->setUserDocumentation(InterfaceHandler::userDocumentation(*contract)); + contract->setDevDocumentation(Natspec::devDocumentation(*contract)); + contract->setUserDocumentation(Natspec::userDocumentation(*contract)); } else noErrors = false; @@ -235,8 +251,13 @@ bool CompilerStack::parse() noErrors = false; } - m_parseSuccessful = noErrors; - return m_parseSuccessful; + if (noErrors) + { + m_stackState = AnalysisSuccessful; + return true; + } + else + return false; } bool CompilerStack::parse(string const& _sourceCode) @@ -245,9 +266,20 @@ bool CompilerStack::parse(string const& _sourceCode) return parse(); } +bool CompilerStack::parseAndAnalyze() +{ + return parse() && analyze(); +} + +bool CompilerStack::parseAndAnalyze(std::string const& _sourceCode) +{ + setSource(_sourceCode); + return parseAndAnalyze(); +} + vector<string> CompilerStack::contractNames() const { - if (!m_parseSuccessful) + if (m_stackState < AnalysisSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); vector<string> contractNames; for (auto const& contract: m_contracts) @@ -258,8 +290,8 @@ vector<string> CompilerStack::contractNames() const bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> const& _libraries) { - if (!m_parseSuccessful) - if (!parse()) + if (m_stackState < AnalysisSuccessful) + if (!parseAndAnalyze()) return false; m_optimize = _optimize; @@ -272,12 +304,13 @@ bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> co if (auto contract = dynamic_cast<ContractDefinition const*>(node.get())) compileContract(*contract, compiledContracts); this->link(); + m_stackState = CompilationSuccessful; return true; } bool CompilerStack::compile(string const& _sourceCode, bool _optimize, unsigned _runs) { - return parse(_sourceCode) && compile(_optimize, _runs); + return parseAndAnalyze(_sourceCode) && compile(_optimize, _runs); } void CompilerStack::link() @@ -412,22 +445,33 @@ map<string, unsigned> CompilerStack::sourceIndices() const return indices; } -Json::Value const& CompilerStack::interface(string const& _contractName) const +Json::Value const& CompilerStack::contractABI(string const& _contractName) const { - return metadata(_contractName, DocumentationType::ABIInterface); + return contractABI(contract(_contractName)); } -Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const +Json::Value const& CompilerStack::contractABI(Contract const& _contract) const { - if (!m_parseSuccessful) + if (m_stackState < AnalysisSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); - return metadata(contract(_contractName), _type); + solAssert(_contract.contract, ""); + + // caches the result + if (!_contract.abi) + _contract.abi.reset(new Json::Value(ABI::generate(*_contract.contract))); + + return *_contract.abi; } -Json::Value const& CompilerStack::metadata(Contract const& _contract, DocumentationType _type) const +Json::Value const& CompilerStack::natspec(string const& _contractName, DocumentationType _type) const { - if (!m_parseSuccessful) + return natspec(contract(_contractName), _type); +} + +Json::Value const& CompilerStack::natspec(Contract const& _contract, DocumentationType _type) const +{ + if (m_stackState < AnalysisSuccessful) BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); solAssert(_contract.contract, ""); @@ -442,40 +486,46 @@ Json::Value const& CompilerStack::metadata(Contract const& _contract, Documentat case DocumentationType::NatspecDev: doc = &_contract.devDocumentation; break; - case DocumentationType::ABIInterface: - doc = &_contract.interface; - break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Illegal documentation type.")); } // caches the result if (!*doc) - doc->reset(new Json::Value(InterfaceHandler::documentation(*_contract.contract, _type))); + doc->reset(new Json::Value(Natspec::documentation(*_contract.contract, _type))); return *(*doc); } string const& CompilerStack::onChainMetadata(string const& _contractName) const { - if (!m_parseSuccessful) - BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + if (m_stackState != CompilationSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); return contract(_contractName).onChainMetadata; } Scanner const& CompilerStack::scanner(string const& _sourceName) const { + if (m_stackState < ParsingSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + return *source(_sourceName).scanner; } SourceUnit const& CompilerStack::ast(string const& _sourceName) const { + if (m_stackState < ParsingSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful.")); + return *source(_sourceName).ast; } ContractDefinition const& CompilerStack::contractDefinition(string const& _contractName) const { + if (m_stackState != CompilationSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + return *contract(_contractName).contract; } @@ -657,8 +707,33 @@ void CompilerStack::compileContract( cborEncodedMetadata += toCompactBigEndian(cborEncodedMetadata.size(), 2); compiler->compileContract(_contract, _compiledContracts, cborEncodedMetadata); compiledContract.compiler = compiler; - compiledContract.object = compiler->assembledObject(); - compiledContract.runtimeObject = compiler->runtimeObject(); + + try + { + compiledContract.object = compiler->assembledObject(); + } + catch(eth::OptimizerException const&) + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Assembly optimizer exception for bytecode")); + } + catch(eth::AssemblyException const&) + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Assembly exception for bytecode")); + } + + try + { + compiledContract.runtimeObject = compiler->runtimeObject(); + } + catch(eth::OptimizerException const&) + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Assembly optimizer exception for deployed bytecode")); + } + catch(eth::AssemblyException const&) + { + BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Assembly exception for deployed bytecode")); + } + compiledContract.onChainMetadata = onChainMetadata; _compiledContracts[compiledContract.contract] = &compiler->assembly(); @@ -679,6 +754,9 @@ void CompilerStack::compileContract( std::string CompilerStack::defaultContractName() const { + if (m_stackState != CompilationSuccessful) + BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful.")); + return contract("").contract->name(); } @@ -764,9 +842,9 @@ string CompilerStack::createOnChainMetadata(Contract const& _contract) const for (auto const& library: m_libraries) meta["settings"]["libraries"][library.first] = "0x" + toHex(library.second.asBytes()); - meta["output"]["abi"] = metadata(_contract, DocumentationType::ABIInterface); - meta["output"]["userdoc"] = metadata(_contract, DocumentationType::NatspecUser); - meta["output"]["devdoc"] = metadata(_contract, DocumentationType::NatspecDev); + meta["output"]["abi"] = contractABI(_contract); + meta["output"]["userdoc"] = natspec(_contract, DocumentationType::NatspecUser); + meta["output"]["devdoc"] = natspec(_contract, DocumentationType::NatspecDev); return jsonCompactPrint(meta); } |