aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/interface/CompilerStack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/interface/CompilerStack.cpp')
-rw-r--r--libsolidity/interface/CompilerStack.cpp146
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);
}