diff --git a/libyul/YulStack.cpp b/libyul/YulStack.cpp index dfab4b6878c0..791b7103ded8 100644 --- a/libyul/YulStack.cpp +++ b/libyul/YulStack.cpp @@ -430,6 +430,13 @@ std::shared_ptr YulStack::parserResult() const return m_parserResult; } +Dialect const& YulStack::dialect() const +{ + yulAssert(m_stackState >= AnalysisSuccessful); + yulAssert(m_parserResult && m_parserResult->dialect()); + return *m_parserResult->dialect(); +} + void YulStack::reportUnimplementedFeatureError(UnimplementedFeatureError const& _error) { yulAssert(_error.comment(), "Errors must include a message for the user."); diff --git a/libyul/YulStack.h b/libyul/YulStack.h index f9837e553ed4..94688fddcaaf 100644 --- a/libyul/YulStack.h +++ b/libyul/YulStack.h @@ -139,6 +139,7 @@ class YulStack: public langutil::CharStreamProvider /// @returns the errors generated during parsing, analysis (and potentially assembly). langutil::ErrorList const& errors() const { return m_errors; } bool hasErrors() const { return m_errorReporter.hasErrors(); } + bool hasErrorsWarningsOrInfos() const { return m_errorReporter.hasErrorsWarningsOrInfos(); } /// Pretty-print the input after having parsed it. std::string print() const; @@ -150,6 +151,8 @@ class YulStack: public langutil::CharStreamProvider /// Return the parsed and analyzed object. std::shared_ptr parserResult() const; + Dialect const& dialect() const; + langutil::DebugInfoSelection debugInfoSelection() const { return m_debugInfoSelection; } private: diff --git a/test/libsolidity/MemoryGuardTest.cpp b/test/libsolidity/MemoryGuardTest.cpp index 9826f4b19468..0f4230d5adec 100644 --- a/test/libsolidity/MemoryGuardTest.cpp +++ b/test/libsolidity/MemoryGuardTest.cpp @@ -20,13 +20,17 @@ #include #include + #include + #include #include + #include -#include #include #include +#include + #include #include #include @@ -38,6 +42,7 @@ using namespace solidity::langutil; using namespace solidity::frontend; using namespace solidity::frontend::test; using namespace solidity::test; +using namespace solidity::yul::test; using namespace yul; void MemoryGuardTest::setupCompiler(CompilerStack& _compiler) @@ -59,20 +64,14 @@ TestCase::TestResult MemoryGuardTest::run(std::ostream& _stream, std::string con m_obtainedResult.clear(); for (std::string contractName: compiler().contractNames()) { - auto const& dialect = CommonOptions::get().evmDialect(); ErrorList errors; std::optional const& ir = compiler().yulIR(contractName); - solAssert(ir); - auto [object, analysisInfo] = yul::test::parse( - *ir, - dialect, - errors - ); + soltestAssert(ir); - if (!object || !analysisInfo || Error::containsErrors(errors)) + YulStack yulStack = parseYul(*ir); + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing IR:" << std::endl; - printPrefixed(_stream, formatErrors(filterErrors(errors), _formatted), _linePrefix); + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; } @@ -80,14 +79,14 @@ TestCase::TestResult MemoryGuardTest::run(std::ostream& _stream, std::string con m_obtainedResult += contractName + "(" + _kind + ") " + (findFunctionCalls( _object.code()->root(), "memoryguard", - dialect + yulStack.dialect() ).empty() ? "false" : "true") + "\n"; }; - handleObject("creation", *object); - size_t deployedIndex = object->subIndexByName.at( + handleObject("creation", *yulStack.parserResult()); + size_t deployedIndex = yulStack.parserResult()->subIndexByName.at( IRNames::deployedObject(compiler().contractDefinition(contractName)) ); - handleObject("runtime", dynamic_cast(*object->subObjects[deployedIndex])); + handleObject("runtime", dynamic_cast(*yulStack.parserResult()->subObjects[deployedIndex])); } return checkResult(_stream, _linePrefix, _formatted); } diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 32f60c8ebe6f..e64558bd48a9 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -21,6 +21,8 @@ #include +#include + #include #include @@ -30,76 +32,69 @@ #include #include +#include + #include #include #include +#include #include #include using namespace solidity; +using namespace solidity::frontend; using namespace solidity::yul; using namespace solidity::langutil; +using namespace solidity::util; +using namespace solidity::test; -namespace -{ -Dialect const& defaultDialect() -{ - return yul::EVMDialect::strictAssemblyForEVM( - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion() - ); -} -} - -std::pair, std::shared_ptr> yul::test::parse(std::string const& _source) +YulStack yul::test::parseYul( + std::string const& _source, + std::string _sourceUnitName, + std::optional _optimiserSettings +) { - YulStack stack( - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion(), + YulStack yulStack( + CommonOptions::get().evmVersion(), + CommonOptions::get().eofVersion(), YulStack::Language::StrictAssembly, - solidity::test::CommonOptions::get().optimize ? - solidity::frontend::OptimiserSettings::standard() : - solidity::frontend::OptimiserSettings::minimal(), + _optimiserSettings.has_value() ? + *_optimiserSettings : + (CommonOptions::get().optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal()), DebugInfoSelection::All() ); - if (!stack.parseAndAnalyze("", _source) || Error::hasErrorsWarningsOrInfos(stack.errors())) - BOOST_FAIL("Invalid source."); - return std::make_pair(stack.parserResult()->code(), stack.parserResult()->analysisInfo); -} - -std::pair, std::shared_ptr> yul::test::parse( - std::string const& _source, - Dialect const& _dialect, - ErrorList& _errors -) -{ - ErrorReporter errorReporter(_errors); - CharStream stream(_source, ""); - std::shared_ptr scanner = std::make_shared(stream); - std::shared_ptr parserResult = yul::ObjectParser(errorReporter, _dialect).parse(scanner, false); - if (!parserResult) - return {}; - if (!parserResult->hasCode() || errorReporter.hasErrors()) - return {}; - std::shared_ptr analysisInfo = std::make_shared(); - AsmAnalyzer analyzer(*analysisInfo, errorReporter, _dialect, {}, parserResult->summarizeStructure()); - // TODO this should be done recursively. - if (!analyzer.analyze(parserResult->code()->root()) || errorReporter.hasErrors()) - return {}; - return {std::move(parserResult), std::move(analysisInfo)}; + bool successful = yulStack.parseAndAnalyze(_sourceUnitName, _source); + if (!successful) + soltestAssert(yulStack.hasErrors()); + else + { + soltestAssert(!yulStack.hasErrors()); + soltestAssert(yulStack.parserResult()); + soltestAssert(yulStack.parserResult()->code()); + soltestAssert(yulStack.parserResult()->analysisInfo); + } + return yulStack; } yul::Block yul::test::disambiguate(std::string const& _source) { - auto result = parse(_source); - return std::get(Disambiguator(defaultDialect(), *result.second, {})(result.first->root())); + YulStack yulStack = parseYul(_source); + soltestAssert(!yulStack.hasErrorsWarningsOrInfos()); + return std::get(Disambiguator( + yulStack.dialect(), + *yulStack.parserResult()->analysisInfo, + {} + )(yulStack.parserResult()->code()->root())); } std::string yul::test::format(std::string const& _source) { - return AsmPrinter::format(*parse(_source).first); + YulStack yulStack = parseYul(_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Subobjects not supported."); + soltestAssert(!yulStack.hasErrorsWarningsOrInfos()); + return AsmPrinter::format(*yulStack.parserResult()->code()); } namespace @@ -134,3 +129,18 @@ yul::Dialect const& yul::test::dialect(std::string const& _name, langutil::EVMVe return validDialects.at(_name)(_evmVersion, _eofVersion); } + +void yul::test::printYulErrors( + YulStack const& _yulStack, + std::ostream& _stream, + std::string const& _linePrefix, + bool const _formatted +) +{ + AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) + << _linePrefix + << "Error parsing source." + << std::endl; + SourceReferenceFormatter formatter{_stream, _yulStack, true, false}; + formatter.printErrorInformation(_yulStack.errors()); +} diff --git a/test/libyul/Common.h b/test/libyul/Common.h index e36e81052cc9..de402c29a9da 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -21,11 +21,14 @@ #pragma once +#include + #include #include #include #include +#include namespace solidity::langutil { @@ -40,20 +43,28 @@ struct Block; class Object; class Dialect; class AST; +class YulStack; } namespace solidity::yul::test { -std::pair, std::shared_ptr> -parse(std::string const& _source); - -std::pair, std::shared_ptr> -parse(std::string const& _source, Dialect const& _dialect, langutil::ErrorList& _errors); +yul::YulStack parseYul( + std::string const& _source, + std::string _sourceUnitName = "", + std::optional _optimiserSettings = std::nullopt +); Block disambiguate(std::string const& _source); std::string format(std::string const& _source); solidity::yul::Dialect const& dialect(std::string const& _name, langutil::EVMVersion _evmVersion, std::optional _eofVersion); +void printYulErrors( + yul::YulStack const& _yulStack, + std::ostream& _stream, + std::string const& _linePrefix, + bool const _formatted +); + } diff --git a/test/libyul/CompilabilityChecker.cpp b/test/libyul/CompilabilityChecker.cpp index 1956db84c6b7..a030af487eb1 100644 --- a/test/libyul/CompilabilityChecker.cpp +++ b/test/libyul/CompilabilityChecker.cpp @@ -20,10 +20,12 @@ #include +#include + #include -#include #include +#include #include @@ -34,12 +36,11 @@ namespace { std::string check(std::string const& _input) { - Object obj; - auto parsingResult = yul::test::parse(_input); - obj.setCode(parsingResult.first, parsingResult.second); - BOOST_REQUIRE(obj.hasCode()); - BOOST_REQUIRE(obj.dialect()); - auto functions = CompilabilityChecker(obj, true).stackDeficit; + YulStack yulStack = parseYul(_input); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + soltestAssert(!yulStack.hasErrorsWarningsOrInfos()); + + auto functions = CompilabilityChecker(*yulStack.parserResult(), true).stackDeficit; std::string out; for (auto const& function: functions) out += function.first.str() + ": " + std::to_string(function.second) + " "; diff --git a/test/libyul/ControlFlowGraphTest.cpp b/test/libyul/ControlFlowGraphTest.cpp index bd0bf0a802d2..c0ab37956e4c 100644 --- a/test/libyul/ControlFlowGraphTest.cpp +++ b/test/libyul/ControlFlowGraphTest.cpp @@ -24,8 +24,8 @@ #include #include #include +#include -#include #include #ifdef ISOLTEST @@ -45,11 +45,7 @@ ControlFlowGraphTest::ControlFlowGraphTest(std::string const& _filename): { m_source = m_reader.source(); auto dialectName = m_reader.stringSetting("dialect", "evm"); - m_dialect = &dialect( - dialectName, - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion() - ); + soltestAssert(dialectName == "evm"); // We only have one dialect now m_expectation = m_reader.simpleExpectations(); } @@ -201,20 +197,24 @@ class ControlFlowGraphPrinter TestCase::TestResult ControlFlowGraphTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - ErrorList errors; - auto [object, analysisInfo] = parse(m_source, *m_dialect, errors); - if (!object || !analysisInfo || Error::containsErrors(errors)) + YulStack yulStack = parseYul(m_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; } std::ostringstream output; - std::unique_ptr cfg = ControlFlowGraphBuilder::build(*analysisInfo, *m_dialect, object->code()->root()); + std::unique_ptr cfg = ControlFlowGraphBuilder::build( + *yulStack.parserResult()->analysisInfo, + yulStack.dialect(), + yulStack.parserResult()->code()->root() + ); output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n"; - ControlFlowGraphPrinter printer{output, *m_dialect}; + ControlFlowGraphPrinter printer{output, yulStack.dialect()}; printer(*cfg->entry); for (auto function: cfg->functions) printer(cfg->functionInfo.at(function)); diff --git a/test/libyul/ControlFlowGraphTest.h b/test/libyul/ControlFlowGraphTest.h index 953a27b22004..f6c8ddfce5db 100644 --- a/test/libyul/ControlFlowGraphTest.h +++ b/test/libyul/ControlFlowGraphTest.h @@ -20,11 +20,7 @@ #include -namespace solidity::yul -{ -class Dialect; - -namespace test +namespace solidity::yul::test { class ControlFlowGraphTest: public frontend::test::EVMVersionRestrictedTestCase @@ -36,8 +32,6 @@ class ControlFlowGraphTest: public frontend::test::EVMVersionRestrictedTestCase } explicit ControlFlowGraphTest(std::string const& _filename); TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; -private: - Dialect const* m_dialect = nullptr; }; -} + } diff --git a/test/libyul/ControlFlowSideEffectsTest.cpp b/test/libyul/ControlFlowSideEffectsTest.cpp index 50c546e36c5d..2249ba110cb1 100644 --- a/test/libyul/ControlFlowSideEffectsTest.cpp +++ b/test/libyul/ControlFlowSideEffectsTest.cpp @@ -25,13 +25,15 @@ #include #include #include -#include +#include using namespace solidity; using namespace solidity::test; using namespace solidity::yul; using namespace solidity::yul::test; using namespace solidity::frontend::test; +using namespace solidity::util; +using namespace solidity::langutil; namespace { @@ -57,19 +59,21 @@ ControlFlowSideEffectsTest::ControlFlowSideEffectsTest(std::string const& _filen TestCase::TestResult ControlFlowSideEffectsTest::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) { - auto const& dialect = CommonOptions::get().evmDialect(); - Object obj; - auto parsingResult = parse(m_source); - obj.setCode(parsingResult.first, parsingResult.second); - if (!obj.hasCode()) - BOOST_THROW_EXCEPTION(std::runtime_error("Parsing input failed.")); + YulStack yulStack = parseYul(m_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + + if (yulStack.hasErrors()) + { + printYulErrors(yulStack, _stream, _linePrefix, _formatted); + return TestResult::FatalError; + } ControlFlowSideEffectsCollector sideEffects( - dialect, - obj.code()->root() + yulStack.dialect(), + yulStack.parserResult()->code()->root() ); m_obtainedResult.clear(); - forEach(obj.code()->root(), [&](FunctionDefinition const& _fun) { + forEach(yulStack.parserResult()->code()->root(), [&](FunctionDefinition const& _fun) { std::string effectStr = toString(sideEffects.functionSideEffects().at(&_fun)); m_obtainedResult += _fun.name.str() + (effectStr.empty() ? ":" : ": " + effectStr) + "\n"; }); diff --git a/test/libyul/EVMCodeTransformTest.cpp b/test/libyul/EVMCodeTransformTest.cpp index 288c35570fe8..04807f239906 100644 --- a/test/libyul/EVMCodeTransformTest.cpp +++ b/test/libyul/EVMCodeTransformTest.cpp @@ -27,9 +27,7 @@ #include -#include - -#include +#include using namespace solidity; using namespace solidity::test; @@ -56,32 +54,29 @@ TestCase::TestResult EVMCodeTransformTest::run(std::ostream& _stream, std::strin settings.optimizeStackAllocation = m_stackOpt; // Restrict to a single EVM/EOF version combination (the default one) as code generation // can be different from version to version. - YulStack stack( + YulStack yulStack( EVMVersion{}, std::nullopt, YulStack::Language::StrictAssembly, settings, DebugInfoSelection::All() ); - if (!stack.parseAndAnalyze("", m_source)) + yulStack.parseAndAnalyze("", m_source); + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; - SourceReferenceFormatter{_stream, stack, true, false} - .printErrorInformation(stack.errors()); + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; } evmasm::Assembly assembly{CommonOptions::get().evmVersion(), false, std::nullopt, {}}; EthAssemblyAdapter adapter(assembly); EVMObjectCompiler::compile( - *stack.parserResult(), + *yulStack.parserResult(), adapter, m_stackOpt ); - std::ostringstream output; - output << assembly; - m_obtainedResult = output.str(); + m_obtainedResult = toString(assembly); return checkResult(_stream, _linePrefix, _formatted); } diff --git a/test/libyul/FunctionSideEffects.cpp b/test/libyul/FunctionSideEffects.cpp index d19d87844fcf..4dab4ace2d49 100644 --- a/test/libyul/FunctionSideEffects.cpp +++ b/test/libyul/FunctionSideEffects.cpp @@ -20,12 +20,11 @@ #include #include -#include - #include #include #include #include +#include #include #include @@ -84,16 +83,18 @@ FunctionSideEffects::FunctionSideEffects(std::string const& _filename): TestCase::TestResult FunctionSideEffects::run(std::ostream& _stream, std::string const& _linePrefix, bool _formatted) { - auto const& dialect = CommonOptions::get().evmDialect(); - Object obj; - auto parsingResult = parse(m_source); - obj.setCode(parsingResult.first, parsingResult.second); - if (!obj.hasCode()) - BOOST_THROW_EXCEPTION(std::runtime_error("Parsing input failed.")); + YulStack yulStack = parseYul(m_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + + if (yulStack.hasErrors()) + { + printYulErrors(yulStack, _stream, _linePrefix, _formatted); + return TestResult::FatalError; + } std::map functionSideEffects = SideEffectsPropagator::sideEffects( - dialect, - CallGraphGenerator::callGraph(obj.code()->root()) + yulStack.dialect(), + CallGraphGenerator::callGraph(yulStack.parserResult()->code()->root()) ); std::map functionSideEffectsStr; @@ -101,7 +102,7 @@ TestCase::TestResult FunctionSideEffects::run(std::ostream& _stream, std::string { auto const& functionNameStr = std::visit(GenericVisitor{ [](YulName const& _name) { return _name.str(); }, - [&](BuiltinHandle const& _builtin) { return dialect.builtin(_builtin).name; } + [&](BuiltinHandle const& _builtin) { return yulStack.dialect().builtin(_builtin).name; } }, fun.first); functionSideEffectsStr[functionNameStr] = toString(fun.second); } diff --git a/test/libyul/FunctionSideEffects.h b/test/libyul/FunctionSideEffects.h index ac0653733f03..3490c854a0b5 100644 --- a/test/libyul/FunctionSideEffects.h +++ b/test/libyul/FunctionSideEffects.h @@ -18,7 +18,6 @@ #pragma once -#include #include #include diff --git a/test/libyul/KnowledgeBaseTest.cpp b/test/libyul/KnowledgeBaseTest.cpp index eefeb90109bc..6e75442f0621 100644 --- a/test/libyul/KnowledgeBaseTest.cpp +++ b/test/libyul/KnowledgeBaseTest.cpp @@ -20,9 +20,12 @@ #include +#include + #include #include +#include #include #include #include @@ -30,8 +33,6 @@ #include #include -#include - #include using namespace solidity::langutil; @@ -44,27 +45,28 @@ class KnowledgeBaseTest protected: KnowledgeBase constructKnowledgeBase(std::string const& _source) { - ErrorList errorList; - std::shared_ptr analysisInfo; - std::tie(m_object, analysisInfo) = yul::test::parse(_source, m_dialect, errorList); - BOOST_REQUIRE(m_object && errorList.empty() && m_object->hasCode()); + YulStack yulStack = parseYul(_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + soltestAssert(!yulStack.hasErrors()); + m_object = yulStack.parserResult(); auto astRoot = std::get(yul::ASTCopier{}(m_object->code()->root())); - NameDispenser dispenser(m_dialect, astRoot); + NameDispenser dispenser(*m_object->dialect(), astRoot); std::set reserved; - OptimiserStepContext context{m_dialect, dispenser, reserved, 0}; + OptimiserStepContext context{*m_object->dialect(), dispenser, reserved, 0}; CommonSubexpressionEliminator::run(context, astRoot); m_ssaValues(astRoot); for (auto const& [name, expression]: m_ssaValues.values()) m_values[name].value = expression; - m_object->setCode(std::make_shared(m_dialect, std::move(astRoot))); - return KnowledgeBase([this](YulName _var) { return util::valueOrNullptr(m_values, _var); }, m_dialect); + m_object->setCode(std::make_shared(*m_object->dialect(), std::move(astRoot))); + return KnowledgeBase( + [this](YulName _var) { return util::valueOrNullptr(m_values, _var); }, + *m_object->dialect() + ); } - EVMDialect m_dialect{solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion(), true}; std::shared_ptr m_object; SSAValueTracker m_ssaValues; std::map m_values; diff --git a/test/libyul/Metrics.cpp b/test/libyul/Metrics.cpp index 5c7b5fc34de0..9e74cd150e49 100644 --- a/test/libyul/Metrics.cpp +++ b/test/libyul/Metrics.cpp @@ -20,11 +20,14 @@ #include +#include + #include #include #include #include +#include #include @@ -38,9 +41,10 @@ namespace size_t codeSize(std::string const& _source, CodeWeights const _weights = {}) { - std::shared_ptr ast = parse(_source).first; - BOOST_REQUIRE(ast); - return CodeSize::codeSize(ast->root(), _weights); + YulStack yulStack = parseYul(_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + soltestAssert(!yulStack.hasErrors()); + return CodeSize::codeSize(yulStack.parserResult()->code()->root(), _weights); } } diff --git a/test/libyul/ObjectCompilerTest.cpp b/test/libyul/ObjectCompilerTest.cpp index d507aa333b06..f7d331d94acb 100644 --- a/test/libyul/ObjectCompilerTest.cpp +++ b/test/libyul/ObjectCompilerTest.cpp @@ -21,8 +21,7 @@ #include #include - -#include +#include #include @@ -31,11 +30,10 @@ #include #include -#include #include -#include +#include using namespace solidity; using namespace solidity::util; @@ -64,31 +62,23 @@ ObjectCompilerTest::ObjectCompilerTest(std::string const& _filename): TestCase::TestResult ObjectCompilerTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - YulStack stack( - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion(), - YulStack::Language::StrictAssembly, - OptimiserSettings::preset(m_optimisationPreset), - DebugInfoSelection::All() - ); - bool successful = stack.parseAndAnalyze("source", m_source); + YulStack yulStack = parseYul(m_source, "source", OptimiserSettings::preset(m_optimisationPreset)); MachineAssemblyObject obj; - if (successful) + if (!yulStack.hasErrors()) { - stack.optimize(); - obj = stack.assemble(YulStack::Machine::EVM); + yulStack.optimize(); + obj = yulStack.assemble(YulStack::Machine::EVM); } - if (stack.hasErrors()) + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; - SourceReferenceFormatter{_stream, stack, true, false} - .printErrorInformation(stack.errors()); + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; } + solAssert(obj.bytecode); solAssert(obj.sourceMappings); - m_obtainedResult = "Assembly:\n" + obj.assembly->assemblyString(stack.debugInfoSelection()); + m_obtainedResult = "Assembly:\n" + obj.assembly->assemblyString(yulStack.debugInfoSelection()); if (obj.bytecode->bytecode.empty()) m_obtainedResult += "-- empty bytecode --\n"; else diff --git a/test/libyul/ObjectCompilerTest.h b/test/libyul/ObjectCompilerTest.h index 3310d80b8e26..604ad0346c27 100644 --- a/test/libyul/ObjectCompilerTest.h +++ b/test/libyul/ObjectCompilerTest.h @@ -51,7 +51,6 @@ class ObjectCompilerTest: public solidity::frontend::test::EVMVersionRestrictedT TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; private: - bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted); void disambiguate(); frontend::OptimisationPreset m_optimisationPreset; diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp index 9a891be915d7..23d8aaa57f8e 100644 --- a/test/libyul/ObjectParser.cpp +++ b/test/libyul/ObjectParser.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -53,42 +54,14 @@ namespace solidity::yul::test namespace { -std::pair parse(std::string const& _source) -{ - YulStack asmStack( - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion(), - YulStack::Language::StrictAssembly, - solidity::frontend::OptimiserSettings::none(), - DebugInfoSelection::All() - ); - bool success = asmStack.parseAndAnalyze("source", _source); - return {success, asmStack.errors()}; -} - std::optional parseAndReturnFirstError(std::string const& _source, bool _allowWarningsAndInfos = true) { - bool success; - ErrorList errors; - tie(success, errors) = parse(_source); - if (!success) - { - BOOST_REQUIRE_EQUAL(errors.size(), 1); - return *errors.front(); - } - else - { - // If success is true, there might still be an error in the assembly stage. - if (_allowWarningsAndInfos && !Error::containsErrors(errors)) - return {}; - else if (!errors.empty()) - { - if (!_allowWarningsAndInfos) - BOOST_CHECK_EQUAL(errors.size(), 1); - return *errors.front(); - } - } - return {}; + YulStack yulStack = parseYul(_source, "source", OptimiserSettings::none()); + if (!yulStack.hasErrorsWarningsOrInfos() || (!yulStack.hasErrors() && _allowWarningsAndInfos)) + return {}; + + BOOST_REQUIRE_EQUAL(yulStack.errors().size(), 1); + return *yulStack.errors().front(); } bool successParse(std::string const& _source, bool _allowWarningsAndInfos = true) diff --git a/test/libyul/SSAControlFlowGraphTest.cpp b/test/libyul/SSAControlFlowGraphTest.cpp index ad825cdf5073..c23a2ca5faf9 100644 --- a/test/libyul/SSAControlFlowGraphTest.cpp +++ b/test/libyul/SSAControlFlowGraphTest.cpp @@ -25,8 +25,7 @@ #include #include - -#include +#include #ifdef ISOLTEST #include @@ -48,29 +47,25 @@ SSAControlFlowGraphTest::SSAControlFlowGraphTest(std::string const& _filename): { m_source = m_reader.source(); auto dialectName = m_reader.stringSetting("dialect", "evm"); - m_dialect = &dialect( - dialectName, - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion() - ); + soltestAssert(dialectName == "evm"); // We only have one dialect now m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult SSAControlFlowGraphTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - ErrorList errors; - auto [object, analysisInfo] = parse(m_source, *m_dialect, errors); - if (!object || !analysisInfo || Error::containsErrors(errors)) + YulStack yulStack = parseYul(m_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; } - auto info = AsmAnalyzer::analyzeStrictAssertCorrect(*object); std::unique_ptr controlFlow = SSAControlFlowGraphBuilder::build( - info, - *m_dialect, - object->code()->root() + *yulStack.parserResult()->analysisInfo, + yulStack.dialect(), + yulStack.parserResult()->code()->root() ); ControlFlowLiveness liveness(*controlFlow); m_obtainedResult = controlFlow->toDot(&liveness); diff --git a/test/libyul/SSAControlFlowGraphTest.h b/test/libyul/SSAControlFlowGraphTest.h index 13ca2027ab98..51dd3c86d1a0 100644 --- a/test/libyul/SSAControlFlowGraphTest.h +++ b/test/libyul/SSAControlFlowGraphTest.h @@ -22,11 +22,7 @@ #include -namespace solidity::yul -{ -class Dialect; - -namespace test +namespace solidity::yul::test { class SSAControlFlowGraphTest: public solidity::frontend::test::TestCase @@ -35,8 +31,6 @@ class SSAControlFlowGraphTest: public solidity::frontend::test::TestCase static std::unique_ptr create(Config const& _config); explicit SSAControlFlowGraphTest(std::string const& _filename); TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; -private: - Dialect const* m_dialect = nullptr; }; -} + } diff --git a/test/libyul/StackLayoutGeneratorTest.cpp b/test/libyul/StackLayoutGeneratorTest.cpp index b41f7f21e820..0db063740006 100644 --- a/test/libyul/StackLayoutGeneratorTest.cpp +++ b/test/libyul/StackLayoutGeneratorTest.cpp @@ -26,9 +26,8 @@ #include #include #include -#include +#include -#include #include #include @@ -50,11 +49,7 @@ StackLayoutGeneratorTest::StackLayoutGeneratorTest(std::string const& _filename) { m_source = m_reader.source(); auto dialectName = m_reader.stringSetting("dialect", "evm"); - m_dialect = &dialect( - dialectName, - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion() - ); + soltestAssert(dialectName == "evm"); // We only have one dialect now m_expectation = m_reader.simpleExpectations(); } @@ -220,26 +215,31 @@ class StackLayoutPrinter TestCase::TestResult StackLayoutGeneratorTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - ErrorList errors; - auto [object, analysisInfo] = parse(m_source, *m_dialect, errors); - if (!object || !analysisInfo || Error::containsErrors(errors)) + YulStack yulStack = parseYul(m_source); + solUnimplementedAssert(yulStack.parserResult()->subObjects.empty(), "Tests with subobjects not supported."); + + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; } std::ostringstream output; - std::unique_ptr cfg = ControlFlowGraphBuilder::build(*analysisInfo, *m_dialect, object->code()->root()); + std::unique_ptr cfg = ControlFlowGraphBuilder::build( + *yulStack.parserResult()->analysisInfo, + yulStack.dialect(), + yulStack.parserResult()->code()->root() + ); bool simulateFunctionsWithJumps = true; - if (auto const* evmDialect = dynamic_cast(m_dialect)) + if (auto const* evmDialect = dynamic_cast(&yulStack.dialect())) simulateFunctionsWithJumps = !evmDialect->eofVersion().has_value(); StackLayout stackLayout = StackLayoutGenerator::run(*cfg, simulateFunctionsWithJumps); output << "digraph CFG {\nnodesep=0.7;\nnode[shape=box];\n\n"; - StackLayoutPrinter printer{output, stackLayout, *m_dialect}; + StackLayoutPrinter printer{output, stackLayout, yulStack.dialect()}; printer(*cfg->entry); for (auto function: cfg->functions) printer(cfg->functionInfo.at(function)); diff --git a/test/libyul/StackLayoutGeneratorTest.h b/test/libyul/StackLayoutGeneratorTest.h index e1c6dc7f912f..c7259a02a963 100644 --- a/test/libyul/StackLayoutGeneratorTest.h +++ b/test/libyul/StackLayoutGeneratorTest.h @@ -20,11 +20,7 @@ #include -namespace solidity::yul -{ -class Dialect; - -namespace test +namespace solidity::yul::test { class StackLayoutGeneratorTest: public frontend::test::EVMVersionRestrictedTestCase @@ -36,8 +32,6 @@ class StackLayoutGeneratorTest: public frontend::test::EVMVersionRestrictedTestC } explicit StackLayoutGeneratorTest(std::string const& _filename); TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; -private: - Dialect const* m_dialect = nullptr; }; -} + } diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index aa37e85afdd8..70f54b86ac71 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -16,39 +16,32 @@ */ // SPDX-License-Identifier: GPL-3.0 -#include -#include - -#include -#include +#include #include -#include #include #include #include +#include + using namespace solidity; using namespace solidity::util; using namespace solidity::langutil; +using namespace solidity::test; using namespace solidity::yul::test; +using namespace solidity::frontend; using namespace solidity::frontend::test; void SyntaxTest::parseAndAnalyze() { - if (m_sources.sources.size() != 1) - BOOST_THROW_EXCEPTION(std::runtime_error{"Expected only one source for yul test."}); - - std::string const& name = m_sources.sources.begin()->first; - std::string const& source = m_sources.sources.begin()->second; + solUnimplementedAssert(m_sources.sources.size() == 1, "Multi-source Yul tests are not supported."); + auto const& [sourceUnitName, source] = *m_sources.sources.begin(); - ErrorList errorList{}; - soltestAssert(m_dialect, ""); - // Silently ignoring the results. - yul::test::parse(source, *m_dialect, errorList); - for (auto const& error: errorList) + YulStack yulStack = parseYul(source); + for (auto const& error: yulStack.errors()) { int locationStart = -1; int locationEnd = -1; @@ -63,21 +56,16 @@ void SyntaxTest::parseAndAnalyze() error->type(), error->errorId(), errorMessage(*error), - name, + sourceUnitName, locationStart, locationEnd }); } - } SyntaxTest::SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion): CommonSyntaxTest(_filename, _evmVersion) { std::string dialectName = m_reader.stringSetting("dialect", "evm"); - m_dialect = &dialect( - dialectName, - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion() - ); + soltestAssert(dialectName == "evm"); // We only have one dialect now } diff --git a/test/libyul/SyntaxTest.h b/test/libyul/SyntaxTest.h index 27e59ee61439..9aab3298e1c5 100644 --- a/test/libyul/SyntaxTest.h +++ b/test/libyul/SyntaxTest.h @@ -19,7 +19,6 @@ #pragma once #include -#include namespace solidity::yul::test { @@ -37,9 +36,6 @@ class SyntaxTest: public solidity::test::CommonSyntaxTest ~SyntaxTest() override {} protected: void parseAndAnalyze() override; - -private: - Dialect const* m_dialect = nullptr; }; } diff --git a/test/libyul/YulInterpreterTest.cpp b/test/libyul/YulInterpreterTest.cpp index 25b348dfb2d9..d97211b9761d 100644 --- a/test/libyul/YulInterpreterTest.cpp +++ b/test/libyul/YulInterpreterTest.cpp @@ -18,20 +18,18 @@ #include +#include + #include #include -#include #include #include #include #include #include -#include - -#include #include #include @@ -57,40 +55,23 @@ YulInterpreterTest::YulInterpreterTest(std::string const& _filename): TestCase::TestResult YulInterpreterTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - if (!parse(_stream, _linePrefix, _formatted)) + YulStack yulStack = parseYul(m_source, "", solidity::frontend::OptimiserSettings::none()); + + if (yulStack.hasErrors()) + { + printYulErrors(yulStack, _stream, _linePrefix, _formatted); return TestResult::FatalError; + } - m_obtainedResult = interpret(); + m_obtainedResult = interpret(yulStack.parserResult()); return checkResult(_stream, _linePrefix, _formatted); } -bool YulInterpreterTest::parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) +std::string YulInterpreterTest::interpret(std::shared_ptr const& _object) { - YulStack stack( - CommonOptions::get().evmVersion(), - CommonOptions::get().eofVersion(), - YulStack::Language::StrictAssembly, - OptimiserSettings::none(), - DebugInfoSelection::All() - ); - if (stack.parseAndAnalyze("", m_source)) - { - m_ast = stack.parserResult()->code(); - m_analysisInfo = stack.parserResult()->analysisInfo; - return true; - } - else - { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; - SourceReferenceFormatter{_stream, stack, true, false} - .printErrorInformation(stack.errors()); - return false; - } -} + solAssert(_object && _object->hasCode()); -std::string YulInterpreterTest::interpret() -{ InterpreterState state; state.maxTraceSize = 32; state.maxSteps = 512; @@ -99,8 +80,8 @@ std::string YulInterpreterTest::interpret() { Interpreter::run( state, - CommonOptions::get().evmDialect(), - m_ast->root(), + *_object->dialect(), + _object->code()->root(), /*disableExternalCalls=*/ !m_simulateExternalCallsToSelf, /*disableMemoryTracing=*/ false ); diff --git a/test/libyul/YulInterpreterTest.h b/test/libyul/YulInterpreterTest.h index d591591332ce..b4a21b69a277 100644 --- a/test/libyul/YulInterpreterTest.h +++ b/test/libyul/YulInterpreterTest.h @@ -22,8 +22,7 @@ namespace solidity::yul { -struct AsmAnalysisInfo; -class AST; +class Object; } namespace solidity::yul::test @@ -42,11 +41,8 @@ class YulInterpreterTest: public solidity::frontend::test::EVMVersionRestrictedT TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; private: - bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted); - std::string interpret(); + std::string interpret(std::shared_ptr const& _object); - std::shared_ptr m_ast; - std::shared_ptr m_analysisInfo; bool m_simulateExternalCallsToSelf = false; }; diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 03f05ffa2ae9..1048fb468854 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -56,24 +57,17 @@ YulOptimizerTest::YulOptimizerTest(std::string const& _filename): m_source = m_reader.source(); auto dialectName = m_reader.stringSetting("dialect", "evm"); - m_dialect = &dialect( - dialectName, - solidity::test::CommonOptions::get().evmVersion(), - solidity::test::CommonOptions::get().eofVersion() - ); + soltestAssert(dialectName == "evm"); // We only have one dialect now m_expectation = m_reader.simpleExpectations(); } TestCase::TestResult YulOptimizerTest::run(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted) { - std::tie(m_object, m_analysisInfo) = parse(_stream, _linePrefix, _formatted, m_source); + m_object = parse(_stream, _linePrefix, _formatted, m_source); if (!m_object) return TestResult::FatalError; - soltestAssert(m_dialect, "Dialect not set."); - - m_object->analysisInfo = m_analysisInfo; YulOptimizerTestCommon tester(m_object); tester.setStep(m_optimizerStep); @@ -91,7 +85,7 @@ TestCase::TestResult YulOptimizerTest::run(std::ostream& _stream, std::string co printedOptimizedObject = optimizedObject->toString(); // Re-parse new code for compilability - if (!std::get<0>(parse(_stream, _linePrefix, _formatted, printedOptimizedObject))) + if (!parse(_stream, _linePrefix, _formatted, printedOptimizedObject)) { util::AnsiColorized(_stream, _formatted, {util::formatting::BOLD, util::formatting::CYAN}) << _linePrefix << "Result after the optimiser:" << std::endl; @@ -104,25 +98,19 @@ TestCase::TestResult YulOptimizerTest::run(std::ostream& _stream, std::string co return checkResult(_stream, _linePrefix, _formatted); } -std::pair, std::shared_ptr> YulOptimizerTest::parse( +std::shared_ptr YulOptimizerTest::parse( std::ostream& _stream, std::string const& _linePrefix, bool const _formatted, std::string const& _source ) { - ErrorList errors; - soltestAssert(m_dialect, ""); - std::shared_ptr object; - std::shared_ptr analysisInfo; - std::tie(object, analysisInfo) = yul::test::parse(_source, *m_dialect, errors); - if (!object || !analysisInfo || Error::containsErrors(errors)) + YulStack yulStack = parseYul(_source); + if (yulStack.hasErrors()) { - AnsiColorized(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << std::endl; - CharStream charStream(_source, ""); - SourceReferenceFormatter{_stream, SingletonCharStreamProvider(charStream), true, false} - .printErrorInformation(errors); - return {}; + printYulErrors(yulStack, _stream, _linePrefix, _formatted); + return nullptr; } - return {std::move(object), std::move(analysisInfo)}; + + return yulStack.parserResult(); } diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 207a4b8ce09e..02fd6a0b2700 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -48,16 +48,16 @@ class YulOptimizerTest: public solidity::frontend::test::EVMVersionRestrictedTes TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; private: - std::pair, std::shared_ptr> parse( - std::ostream& _stream, std::string const& _linePrefix, bool const _formatted, std::string const& _source + std::shared_ptr parse( + std::ostream& _stream, + std::string const& _linePrefix, + bool const _formatted, + std::string const& _source ); std::string m_optimizerStep; - Dialect const* m_dialect = nullptr; - std::shared_ptr m_object; - std::shared_ptr m_analysisInfo; }; }