mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[yul-phaser] Returning an ErrorList from Program::load() if program has errors and printing them in Phaser
This commit is contained in:
parent
9ef63a9789
commit
8ca0d90aae
@ -36,7 +36,7 @@ class FitnessMetricFixture
|
||||
protected:
|
||||
FitnessMetricFixture():
|
||||
m_sourceStream(SampleSourceCode, ""),
|
||||
m_program(Program::load(m_sourceStream)) {}
|
||||
m_program(get<Program>(Program::load(m_sourceStream))) {}
|
||||
|
||||
static constexpr char SampleSourceCode[] =
|
||||
"{\n"
|
||||
|
@ -68,7 +68,7 @@ BOOST_AUTO_TEST_CASE(copy_constructor_should_make_deep_copy_of_ast)
|
||||
"}\n"
|
||||
);
|
||||
CharStream sourceStream(sourceCode, current_test_case().p_name);
|
||||
auto program = Program::load(sourceStream);
|
||||
Program program = get<Program>(Program::load(sourceStream));
|
||||
|
||||
Program programCopy(program);
|
||||
|
||||
@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(load_should_rewind_the_stream)
|
||||
CharStream sourceStream(sourceCode, current_test_case().p_name);
|
||||
sourceStream.setPosition(5);
|
||||
|
||||
auto program = Program::load(sourceStream);
|
||||
Program program = get<Program>(Program::load(sourceStream));
|
||||
|
||||
BOOST_TEST(CodeSize::codeSize(program.ast()) == 2);
|
||||
}
|
||||
@ -109,7 +109,7 @@ BOOST_AUTO_TEST_CASE(load_should_disambiguate)
|
||||
"}\n"
|
||||
);
|
||||
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.
|
||||
Block const& parentBlock = skipRedundantBlocks(program.ast());
|
||||
@ -141,7 +141,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_function_grouping_and_hoisting)
|
||||
"}\n"
|
||||
);
|
||||
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(holds_alternative<Block>(program.ast().statements[0]));
|
||||
@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(load_should_do_loop_init_rewriting)
|
||||
"}\n"
|
||||
);
|
||||
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.
|
||||
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");
|
||||
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)
|
||||
@ -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);
|
||||
|
||||
BOOST_CHECK_THROW(Program::load(sourceStream), InvalidProgram);
|
||||
BOOST_TEST(holds_alternative<ErrorList>(Program::load(sourceStream)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(optimise)
|
||||
@ -200,7 +200,7 @@ BOOST_AUTO_TEST_CASE(optimise)
|
||||
"}\n"
|
||||
);
|
||||
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());
|
||||
assert(parentBlockBefore.statements.size() == 2);
|
||||
@ -231,7 +231,7 @@ BOOST_AUTO_TEST_CASE(output_operator)
|
||||
"}\n"
|
||||
);
|
||||
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()
|
||||
// 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"
|
||||
);
|
||||
CharStream sourceStream(sourceCode, current_test_case().p_name);
|
||||
auto program = Program::load(sourceStream);
|
||||
Program program = get<Program>(Program::load(sourceStream));
|
||||
|
||||
Json::Value parsingResult;
|
||||
string errors;
|
||||
@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(codeSize)
|
||||
"}\n"
|
||||
);
|
||||
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()));
|
||||
}
|
||||
|
@ -125,7 +125,13 @@ ProgramFactory::Options ProgramFactory::Options::fromCommandLine(po::variables_m
|
||||
Program ProgramFactory::build(Options const& _options)
|
||||
{
|
||||
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)
|
||||
|
@ -17,11 +17,8 @@
|
||||
|
||||
#include <tools/yulPhaser/Program.h>
|
||||
|
||||
#include <tools/yulPhaser/Exceptions.h>
|
||||
|
||||
#include <liblangutil/CharStream.h>
|
||||
#include <liblangutil/ErrorReporter.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <liblangutil/SourceReferenceFormatter.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
|
||||
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(
|
||||
dialect,
|
||||
disambiguateAST(dialect, *ast, *analysisInfo)
|
||||
disambiguateAST(
|
||||
dialect,
|
||||
*get<unique_ptr<Block>>(astOrErrors),
|
||||
*get<unique_ptr<AsmAnalysisInfo>>(analysisInfoOrErrors)
|
||||
)
|
||||
);
|
||||
program.optimise({
|
||||
FunctionHoister::name,
|
||||
@ -111,7 +121,7 @@ string Program::toJson() const
|
||||
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;
|
||||
ErrorReporter errorReporter(errors);
|
||||
@ -119,13 +129,14 @@ unique_ptr<Block> Program::parseSource(Dialect const& _dialect, CharStream _sour
|
||||
Parser parser(errorReporter, _dialect);
|
||||
|
||||
unique_ptr<Block> ast = parser.parse(scanner, false);
|
||||
assertThrow(ast != nullptr, InvalidProgram, "Error parsing source");
|
||||
assert(errorReporter.errors().empty());
|
||||
if (ast == nullptr)
|
||||
return errors;
|
||||
|
||||
assert(errorReporter.errors().empty());
|
||||
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;
|
||||
ErrorReporter errorReporter(errors);
|
||||
@ -133,9 +144,10 @@ unique_ptr<AsmAnalysisInfo> Program::analyzeAST(Dialect const& _dialect, Block c
|
||||
AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect);
|
||||
|
||||
bool analysisSuccessful = analyzer.analyze(_ast);
|
||||
assertThrow(analysisSuccessful, InvalidProgram, "Error analyzing source");
|
||||
assert(errorReporter.errors().empty());
|
||||
if (!analysisSuccessful)
|
||||
return errors;
|
||||
|
||||
assert(errorReporter.errors().empty());
|
||||
return analysisInfo;
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,13 @@
|
||||
#include <libyul/optimiser/NameDispenser.h>
|
||||
#include <libyul/AsmData.h>
|
||||
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace solidity::langutil
|
||||
@ -72,7 +75,7 @@ public:
|
||||
Program operator=(Program const& 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);
|
||||
|
||||
size_t codeSize() const { return computeCodeSize(*m_ast); }
|
||||
@ -91,11 +94,11 @@ private:
|
||||
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,
|
||||
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::Block const& _ast
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user