refactoring parse() into two separate functions

This commit is contained in:
djuju 2017-04-26 17:03:36 +02:00
parent 3cbdf6d490
commit 99a7aefb75
5 changed files with 50 additions and 23 deletions

View File

@ -128,14 +128,12 @@ bool CompilerStack::parse()
vector<string> sourcesToParse; vector<string> sourcesToParse;
for (auto const& s: m_sources) for (auto const& s: m_sources)
sourcesToParse.push_back(s.first); sourcesToParse.push_back(s.first);
map<string, SourceUnit const*> sourceUnitsByName;
for (size_t i = 0; i < sourcesToParse.size(); ++i) for (size_t i = 0; i < sourcesToParse.size(); ++i)
{ {
string const& path = sourcesToParse[i]; string const& path = sourcesToParse[i];
Source& source = m_sources[path]; Source& source = m_sources[path];
source.scanner->reset(); source.scanner->reset();
source.ast = Parser(m_errors).parse(source.scanner); source.ast = Parser(m_errors).parse(source.scanner);
sourceUnitsByName[path] = source.ast.get();
if (!source.ast) if (!source.ast)
solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error."); solAssert(!Error::containsOnlyWarnings(m_errors), "Parser returned null but did not report error.");
else else
@ -150,9 +148,14 @@ bool CompilerStack::parse()
} }
} }
} }
if (!Error::containsOnlyWarnings(m_errors)) m_parseSuccessful = Error::containsOnlyWarnings(m_errors);
// errors while parsing. should stop before type checking return m_parseSuccessful;
return false; }
bool CompilerStack::analyze()
{
if (m_sources.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("There are no sources to be analyzed."));
resolveImports(); resolveImports();
@ -173,6 +176,9 @@ bool CompilerStack::parse()
if (!resolver.registerDeclarations(*source->ast)) if (!resolver.registerDeclarations(*source->ast))
return false; 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) for (Source const* source: m_sourceOrder)
if (!resolver.performImports(*source->ast, sourceUnitsByName)) if (!resolver.performImports(*source->ast, sourceUnitsByName))
return false; return false;
@ -245,6 +251,17 @@ bool CompilerStack::parse(string const& _sourceCode)
return parse(); return parse();
} }
bool CompilerStack::parseAndAnalyze()
{
return parse() && analyze();
}
bool CompilerStack::parseAndAnalyze(std::string const& _sourceCode)
{
setSource(_sourceCode);
return parseAndAnalyze();
}
vector<string> CompilerStack::contractNames() const vector<string> CompilerStack::contractNames() const
{ {
if (!m_parseSuccessful) if (!m_parseSuccessful)
@ -259,7 +276,7 @@ vector<string> CompilerStack::contractNames() const
bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> const& _libraries) bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> const& _libraries)
{ {
if (!m_parseSuccessful) if (!m_parseSuccessful)
if (!parse()) if (!parseAndAnalyze())
return false; return false;
m_optimize = _optimize; m_optimize = _optimize;
@ -277,7 +294,7 @@ bool CompilerStack::compile(bool _optimize, unsigned _runs, map<string, h160> co
bool CompilerStack::compile(string const& _sourceCode, bool _optimize, unsigned _runs) 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() void CompilerStack::link()

View File

@ -103,6 +103,16 @@ public:
/// Sets the given source code as the only source unit apart from standard sources and parses it. /// Sets the given source code as the only source unit apart from standard sources and parses it.
/// @returns false on error. /// @returns false on error.
bool parse(std::string const& _sourceCode); bool parse(std::string const& _sourceCode);
/// performs the analyisis steps (imports, scopesetting, syntaxCheck, referenceResolving,
/// typechecking, staticAnalysis) on the 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. /// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const; std::vector<std::string> contractNames() const;
std::string defaultContractName() const; std::string defaultContractName() const;

View File

@ -41,7 +41,7 @@ BOOST_AUTO_TEST_CASE(smoke_test)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C {}"); c.addSource("a", "contract C {}");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -52,7 +52,7 @@ BOOST_AUTO_TEST_CASE(source_location)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { function f() { var x = 2; x++; } }"); c.addSource("a", "contract C { function f() { var x = 2; x++; } }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -66,7 +66,7 @@ BOOST_AUTO_TEST_CASE(inheritance_specifier)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C1 {} contract C2 is C1 {}"); c.addSource("a", "contract C1 {} contract C2 is C1 {}");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -81,7 +81,7 @@ BOOST_AUTO_TEST_CASE(using_for_directive)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "library L {} contract C { using L for uint; }"); c.addSource("a", "library L {} contract C { using L for uint; }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -98,7 +98,7 @@ BOOST_AUTO_TEST_CASE(enum_value)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { enum E { A, B } }"); c.addSource("a", "contract C { enum E { A, B } }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(modifier_definition)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }"); c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE(modifier_invocation)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }"); c.addSource("a", "contract C { modifier M(uint i) { _; } function F() M(1) {} }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -145,7 +145,7 @@ BOOST_AUTO_TEST_CASE(event_definition)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { event E(); }"); c.addSource("a", "contract C { event E(); }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(array_type_name)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { uint[] i; }"); c.addSource("a", "contract C { uint[] i; }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(placeholder_statement)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { modifier M { _; } }"); c.addSource("a", "contract C { modifier M { _; } }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();
@ -185,7 +185,7 @@ BOOST_AUTO_TEST_CASE(non_utf8)
{ {
CompilerStack c; CompilerStack c;
c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }"); c.addSource("a", "contract C { function f() { var x = hex\"ff\"; } }");
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); 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) " "contract C { function f(function() external payable returns (uint) x) "
"returns (function() external constant returns (uint)) {} }" "returns (function() external constant returns (uint)) {} }"
); );
c.parse(); c.parseAndAnalyze();
map<string, unsigned> sourceIndices; map<string, unsigned> sourceIndices;
sourceIndices["a"] = 1; sourceIndices["a"] = 1;
Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json(); Json::Value astJson = ASTJsonConverter(c.ast("a"), sourceIndices).json();

View File

@ -42,7 +42,7 @@ public:
void checkInterface(std::string const& _code, std::string const& _expectedInterfaceString) 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 generatedInterface = m_compilerStack.metadata("", DocumentationType::ABIInterface);
Json::Value expectedInterface; Json::Value expectedInterface;

View File

@ -45,7 +45,7 @@ public:
bool _userDocumentation 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; Json::Value generatedDocumentation;
if (_userDocumentation) if (_userDocumentation)
@ -63,7 +63,7 @@ public:
void expectNatspecError(std::string const& _code) 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)); BOOST_REQUIRE(Error::containsErrorOfType(m_compilerStack.errors(), Error::Type::DocstringParsingError));
} }