mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2171 from ethereum/splitParseAndAnalyze
refactoring parse() into two separate functions
This commit is contained in:
commit
f33614e1f7
@ -57,7 +57,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,7 +79,6 @@ void CompilerStack::setRemappings(vector<string> const& _remappings)
|
||||
|
||||
void CompilerStack::reset(bool _keepSources)
|
||||
{
|
||||
m_parseSuccessful = false;
|
||||
if (_keepSources)
|
||||
for (auto sourcePair: m_sources)
|
||||
sourcePair.second.reset();
|
||||
@ -94,6 +93,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 +102,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 +115,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 +130,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 +150,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 +182,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;
|
||||
@ -235,8 +247,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 +262,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 +286,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 +300,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()
|
||||
@ -419,7 +448,7 @@ Json::Value const& CompilerStack::interface(string const& _contractName) const
|
||||
|
||||
Json::Value const& CompilerStack::metadata(string const& _contractName, DocumentationType _type) const
|
||||
{
|
||||
if (!m_parseSuccessful)
|
||||
if (m_stackState < AnalysisSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||
|
||||
return metadata(contract(_contractName), _type);
|
||||
@ -427,7 +456,7 @@ Json::Value const& CompilerStack::metadata(string const& _contractName, Document
|
||||
|
||||
Json::Value const& CompilerStack::metadata(Contract const& _contract, DocumentationType _type) const
|
||||
{
|
||||
if (!m_parseSuccessful)
|
||||
if (m_stackState < AnalysisSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||
|
||||
solAssert(_contract.contract, "");
|
||||
@ -458,7 +487,7 @@ Json::Value const& CompilerStack::metadata(Contract const& _contract, Documentat
|
||||
|
||||
string const& CompilerStack::onChainMetadata(string const& _contractName) const
|
||||
{
|
||||
if (!m_parseSuccessful)
|
||||
if (m_stackState != CompilationSuccessful)
|
||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
|
||||
|
||||
return contract(_contractName).onChainMetadata;
|
||||
|
@ -103,6 +103,16 @@ public:
|
||||
/// Sets the given source code as the only source unit apart from standard sources and parses it.
|
||||
/// @returns false on error.
|
||||
bool parse(std::string const& _sourceCode);
|
||||
/// performs the analyisis steps (imports, scopesetting, syntaxCheck, referenceResolving,
|
||||
/// typechecking, staticAnalysis) on previously set sources
|
||||
/// @returns false on error.
|
||||
bool analyze();
|
||||
/// Parses and analyzes all source units that were added
|
||||
/// @returns false on error.
|
||||
bool parseAndAnalyze();
|
||||
/// Sets the given source code as the only source unit apart from standard sources and parses and analyzes it.
|
||||
/// @returns false on error.
|
||||
bool parseAndAnalyze(std::string const& _sourceCode);
|
||||
/// @returns a list of the contract names in the sources.
|
||||
std::vector<std::string> contractNames() const;
|
||||
std::string defaultContractName() const;
|
||||
@ -226,6 +236,13 @@ private:
|
||||
mutable std::unique_ptr<std::string const> sourceMapping;
|
||||
mutable std::unique_ptr<std::string const> runtimeSourceMapping;
|
||||
};
|
||||
enum State {
|
||||
Empty,
|
||||
SourcesSet,
|
||||
ParsingSuccessful,
|
||||
AnalysisSuccessful,
|
||||
CompilationSuccessful
|
||||
};
|
||||
|
||||
/// Loads the missing sources from @a _ast (named @a _path) using the callback
|
||||
/// @a m_readFile and stores the absolute paths of all imports in the AST annotations.
|
||||
@ -266,7 +283,6 @@ private:
|
||||
/// list of path prefix remappings, e.g. mylibrary: github.com/ethereum = /usr/local/ethereum
|
||||
/// "context:prefix=target"
|
||||
std::vector<Remapping> m_remappings;
|
||||
bool m_parseSuccessful;
|
||||
std::map<std::string const, Source> m_sources;
|
||||
std::shared_ptr<GlobalContext> m_globalContext;
|
||||
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>> m_scopes;
|
||||
@ -275,6 +291,7 @@ private:
|
||||
std::string m_formalTranslation;
|
||||
ErrorList m_errors;
|
||||
bool m_metadataLiteralSources = false;
|
||||
State m_stackState = Empty;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C {}");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(source_location)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { function f() { var x = 2; x++; } }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(inheritance_specifier)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C1 {} contract C2 is C1 {}");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "library L {} contract C { using L for uint; }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -91,14 +91,14 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
|
||||
BOOST_CHECK_EQUAL(usingFor["children"][0]["name"], "UserDefinedTypeName");
|
||||
BOOST_CHECK_EQUAL(usingFor["children"][0]["attributes"]["name"], "L");
|
||||
BOOST_CHECK_EQUAL(usingFor["children"][1]["name"], "ElementaryTypeName");
|
||||
BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint");
|
||||
BOOST_CHECK_EQUAL(usingFor["children"][1]["attributes"]["name"], "uint");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(enum_value)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { enum E { A, B } }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(modifier_definition)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(event_definition)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { event E(); }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(array_type_name)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { uint[] i; }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(placeholder_statement)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { modifier M { _; } }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(non_utf8)
|
||||
{
|
||||
CompilerStack c;
|
||||
c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }");
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
@ -204,7 +204,7 @@ BOOST_AUTO_TEST_CASE(function_type)
|
||||
"contract C { function f(function() external payable returns (uint) x) "
|
||||
"returns (function() external constant returns (uint)) {} }"
|
||||
);
|
||||
c.parse();
|
||||
c.parseAndAnalyze();
|
||||
map<string, unsigned> sourceIndices;
|
||||
sourceIndices["a"] = 1;
|
||||
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
|
||||
void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString)
|
||||
{
|
||||
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse("pragma solidity >=0.0;\n" + _code), "Parsing contract failed");
|
||||
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parseAndAnalyze("pragma solidity >=0.0;\n" + _code), "Parsing contract failed");
|
||||
|
||||
Json::Value generatedInterface = m_compilerStack.metadata("", DocumentationType::ABIInterface);
|
||||
Json::Value expectedInterface;
|
||||
|
@ -45,7 +45,7 @@ public:
|
||||
bool _userDocumentation
|
||||
)
|
||||
{
|
||||
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parse("pragma solidity >=0.0;\n" + _code), "Parsing failed");
|
||||
ETH_TEST_REQUIRE_NO_THROW(m_compilerStack.parseAndAnalyze("pragma solidity >=0.0;\n" + _code), "Parsing failed");
|
||||
|
||||
Json::Value generatedDocumentation;
|
||||
if (_userDocumentation)
|
||||
@ -63,7 +63,7 @@ public:
|
||||
|
||||
void expectNatspecError(std::string const& _code)
|
||||
{
|
||||
BOOST_CHECK(!m_compilerStack.parse(_code));
|
||||
BOOST_CHECK(!m_compilerStack.parseAndAnalyze(_code));
|
||||
BOOST_REQUIRE(Error::containsErrorOfType(m_compilerStack.errors(), Error::Type::DocstringParsingError));
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,10 @@ bool containsAtMostWarnings(Json::Value const& _compilerResult)
|
||||
BOOST_REQUIRE(error.isObject());
|
||||
BOOST_REQUIRE(error["severity"].isString());
|
||||
if (error["severity"].asString() != "warning")
|
||||
{
|
||||
cout << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user