[yul-phaser] Returning an ErrorList from Program::load() if program has errors and printing them in Phaser

This commit is contained in:
Kamil Śliwak 2020-02-28 03:33:46 +01:00
parent 9ef63a9789
commit 8ca0d90aae
5 changed files with 50 additions and 29 deletions

View File

@ -36,7 +36,7 @@ class FitnessMetricFixture
protected: protected:
FitnessMetricFixture(): FitnessMetricFixture():
m_sourceStream(SampleSourceCode, ""), m_sourceStream(SampleSourceCode, ""),
m_program(Program::load(m_sourceStream)) {} m_program(get<Program>(Program::load(m_sourceStream))) {}
static constexpr char SampleSourceCode[] = static constexpr char SampleSourceCode[] =
"{\n" "{\n"

View File

@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(copy_constructor_should_make_deep_copy_of_ast)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
Program programCopy(program); Program programCopy(program);
@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(load_should_rewind_the_stream)
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
sourceStream.setPosition(5); sourceStream.setPosition(5);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
BOOST_TEST(CodeSize::codeSize(program.ast()) == 2); BOOST_TEST(CodeSize::codeSize(program.ast()) == 2);
} }
@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(load_should_disambiguate)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
// skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not. // skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not.
Block const& parentBlock = skipRedundantBlocks(program.ast()); Block const& parentBlock = skipRedundantBlocks(program.ast());
@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_function_grouping_and_hoisting)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
BOOST_TEST(program.ast().statements.size() == 3); BOOST_TEST(program.ast().statements.size() == 3);
BOOST_TEST(holds_alternative<Block>(program.ast().statements[0])); BOOST_TEST(holds_alternative<Block>(program.ast().statements[0]));
@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_loop_init_rewriting)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
// skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not. // skipRedundantBlocks() makes the test independent of whether load() includes function grouping or not.
Block const& parentBlock = skipRedundantBlocks(program.ast()); Block const& parentBlock = skipRedundantBlocks(program.ast());
@ -172,7 +172,7 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_parsed)
string sourceCode("invalid program\n"); string sourceCode("invalid program\n");
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram); BOOST_TEST(holds_alternative<ErrorList>(Program::load(sourceStream)));
} }
BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyzed) BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyzed)
@ -186,7 +186,7 @@ BOOST_AUTO_TEST_CASE(load_should_throw_InvalidProgram_if_program_cant_be_analyze
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram); BOOST_TEST(holds_alternative<ErrorList>(Program::load(sourceStream)));
} }
BOOST_AUTO_TEST_CASE(optimise) BOOST_AUTO_TEST_CASE(optimise)
@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(optimise)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
[[maybe_unused]] Block const& parentBlockBefore = skipRedundantBlocks(program.ast()); [[maybe_unused]] Block const& parentBlockBefore = skipRedundantBlocks(program.ast());
assert(parentBlockBefore.statements.size() == 2); assert(parentBlockBefore.statements.size() == 2);
@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(output_operator)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
// NOTE: The snippet above was chosen so that the few optimisations applied automatically by load() // NOTE: The snippet above was chosen so that the few optimisations applied automatically by load()
// as of now do not change the code significantly. If that changes, you may have to update it. // as of now do not change the code significantly. If that changes, you may have to update it.
@ -250,7 +250,7 @@ BOOST_AUTO_TEST_CASE(toJson)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
Json::Value parsingResult; Json::Value parsingResult;
string errors; string errors;
@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(codeSize)
"}\n" "}\n"
); );
CharStream sourceStream(sourceCode, current_test_case().p_name); CharStream sourceStream(sourceCode, current_test_case().p_name);
auto program = Program::load(sourceStream); Program program = get<Program>(Program::load(sourceStream));
BOOST_TEST(program.codeSize() == CodeSize::codeSizeIncludingFunctions(program.ast())); BOOST_TEST(program.codeSize() == CodeSize::codeSizeIncludingFunctions(program.ast()));
} }

View File

@ -125,7 +125,13 @@ ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_m
Program ProgramFactory::build(Options const& _options) Program ProgramFactory::build(Options const& _options)
{ {
CharStream sourceCode = loadSource(_options.inputFile); CharStream sourceCode = loadSource(_options.inputFile);
return Program::load(sourceCode); variant<Program, ErrorList> programOrErrors = Program::load(sourceCode);
if (holds_alternative<ErrorList>(programOrErrors))
{
cerr << get<ErrorList>(programOrErrors) << endl;
assertThrow(false, InvalidProgram, "Failed to load program " + _options.inputFile);
}
return move(get<Program>(programOrErrors));
} }
CharStream ProgramFactory::loadSource(string const& _sourcePath) CharStream ProgramFactory::loadSource(string const& _sourcePath)

View File

@ -17,11 +17,8 @@
#include <tools/yulPhaser/Program.h> #include <tools/yulPhaser/Program.h>
#include <tools/yulPhaser/Exceptions.h>
#include <liblangutil/CharStream.h> #include <liblangutil/CharStream.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <liblangutil/Exceptions.h>
#include <liblangutil/SourceReferenceFormatter.h> #include <liblangutil/SourceReferenceFormatter.h>
#include <libyul/AsmAnalysis.h> #include <libyul/AsmAnalysis.h>
@ -75,16 +72,29 @@ Program::Program(Program const& program):
{ {
} }
Program Program::load(CharStream& _sourceCode) variant<Program, ErrorList> Program::load(CharStream& _sourceCode)
{ {
// ASSUMPTION: parseSource() rewinds the stream on its own // ASSUMPTION: parseSource() rewinds the stream on its own
Dialect const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{}); Dialect const& dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion{});
unique_ptr<Block> ast = parseSource(dialect, _sourceCode);
unique_ptr<AsmAnalysisInfo> analysisInfo = analyzeAST(dialect, *ast); variant<unique_ptr<Block>, ErrorList> astOrErrors = parseSource(dialect, _sourceCode);
if (holds_alternative<ErrorList>(astOrErrors))
return get<ErrorList>(astOrErrors);
variant<unique_ptr<AsmAnalysisInfo>, ErrorList> analysisInfoOrErrors = analyzeAST(
dialect,
*get<unique_ptr<Block>>(astOrErrors)
);
if (holds_alternative<ErrorList>(analysisInfoOrErrors))
return get<ErrorList>(analysisInfoOrErrors);
Program program( Program program(
dialect, dialect,
disambiguateAST(dialect, *ast, *analysisInfo) disambiguateAST(
dialect,
*get<unique_ptr<Block>>(astOrErrors),
*get<unique_ptr<AsmAnalysisInfo>>(analysisInfoOrErrors)
)
); );
program.optimise({ program.optimise({
FunctionHoister::name, FunctionHoister::name,
@ -111,7 +121,7 @@ string Program::toJson() const
return jsonPrettyPrint(serializedAst); return jsonPrettyPrint(serializedAst);
} }
unique_ptr<Block> Program::parseSource(Dialect const& _dialect, CharStream _source) variant<unique_ptr<Block>, ErrorList> Program::parseSource(Dialect const& _dialect, CharStream _source)
{ {
ErrorList errors; ErrorList errors;
ErrorReporter errorReporter(errors); ErrorReporter errorReporter(errors);
@ -119,13 +129,14 @@ unique_ptr<Block> Program::parseSource(Dialect const& _dialect, CharStream _sour
Parser parser(errorReporter, _dialect); Parser parser(errorReporter, _dialect);
unique_ptr<Block> ast = parser.parse(scanner, false); unique_ptr<Block> ast = parser.parse(scanner, false);
assertThrow(ast != nullptr, InvalidProgram, "Error parsing source"); if (ast == nullptr)
assert(errorReporter.errors().empty()); return errors;
assert(errorReporter.errors().empty());
return ast; return ast;
} }
unique_ptr<AsmAnalysisInfo> Program::analyzeAST(Dialect const& _dialect, Block const& _ast) variant<unique_ptr<AsmAnalysisInfo>, ErrorList> Program::analyzeAST(Dialect const& _dialect, Block const& _ast)
{ {
ErrorList errors; ErrorList errors;
ErrorReporter errorReporter(errors); ErrorReporter errorReporter(errors);
@ -133,9 +144,10 @@ unique_ptr<AsmAnalysisInfo> Program::analyzeAST(Dialect const& _dialect, Block c
AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect); AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect);
bool analysisSuccessful = analyzer.analyze(_ast); bool analysisSuccessful = analyzer.analyze(_ast);
assertThrow(analysisSuccessful, InvalidProgram, "Error analyzing source"); if (!analysisSuccessful)
assert(errorReporter.errors().empty()); return errors;
assert(errorReporter.errors().empty());
return analysisInfo; return analysisInfo;
} }

View File

@ -20,10 +20,13 @@
#include <libyul/optimiser/NameDispenser.h> #include <libyul/optimiser/NameDispenser.h>
#include <libyul/AsmData.h> #include <libyul/AsmData.h>
#include <liblangutil/Exceptions.h>
#include <optional> #include <optional>
#include <ostream> #include <ostream>
#include <set> #include <set>
#include <string> #include <string>
#include <variant>
#include <vector> #include <vector>
namespace solidity::langutil namespace solidity::langutil
@ -72,7 +75,7 @@ public:
Program operator=(Program const& program) = delete; Program operator=(Program const& program) = delete;
Program operator=(Program&& program) = delete; Program operator=(Program&& program) = delete;
static Program load(langutil::CharStream& _sourceCode); static std::variant<Program, langutil::ErrorList> load(langutil::CharStream& _sourceCode);
void optimise(std::vector<std::string> const& _optimisationSteps); void optimise(std::vector<std::string> const& _optimisationSteps);
size_t codeSize() const { return computeCodeSize(*m_ast); } size_t codeSize() const { return computeCodeSize(*m_ast); }
@ -91,11 +94,11 @@ private:
m_nameDispenser(_dialect, *m_ast, {}) m_nameDispenser(_dialect, *m_ast, {})
{} {}
static std::unique_ptr<yul::Block> parseSource( static std::variant<std::unique_ptr<yul::Block>, langutil::ErrorList> parseSource(
yul::Dialect const& _dialect, yul::Dialect const& _dialect,
langutil::CharStream _source langutil::CharStream _source
); );
static std::unique_ptr<yul::AsmAnalysisInfo> analyzeAST( static std::variant<std::unique_ptr<yul::AsmAnalysisInfo>, langutil::ErrorList> analyzeAST(
yul::Dialect const& _dialect, yul::Dialect const& _dialect,
yul::Block const& _ast yul::Block const& _ast
); );