diff options
Diffstat (limited to 'test/libjulia')
-rw-r--r-- | test/libjulia/YulOptimizerTest.cpp | 167 | ||||
-rw-r--r-- | test/libjulia/YulOptimizerTest.h | 75 |
2 files changed, 242 insertions, 0 deletions
diff --git a/test/libjulia/YulOptimizerTest.cpp b/test/libjulia/YulOptimizerTest.cpp new file mode 100644 index 00000000..fd15623c --- /dev/null +++ b/test/libjulia/YulOptimizerTest.cpp @@ -0,0 +1,167 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include <test/libjulia/YulOptimizerTest.h> + +#include <test/libsolidity/FormattedScope.h> + +#include <test/Options.h> + +#include <libjulia/optimiser/Disambiguator.h> +#include <libsolidity/parsing/Scanner.h> +#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libsolidity/inlineasm/AsmParser.h> +#include <libsolidity/inlineasm/AsmAnalysis.h> +#include <libsolidity/interface/SourceReferenceFormatter.h> +#include <libsolidity/interface/ErrorReporter.h> + +#include <boost/test/unit_test.hpp> +#include <boost/algorithm/string.hpp> + +#include <fstream> + +using namespace dev; +using namespace dev::julia; +using namespace dev::julia::test; +using namespace dev::solidity; +using namespace dev::solidity::test; +using namespace std; + +YulOptimizerTest::YulOptimizerTest(string const& _filename) +{ + boost::filesystem::path path(_filename); + + if (path.empty() || std::next(path.begin()) == path.end() || std::next(std::next(path.begin())) == path.end()) + BOOST_THROW_EXCEPTION(runtime_error("Filename path has to contain a directory: \"" + _filename + "\".")); + m_optimizerStep = std::prev(std::prev(path.end()))->string(); + + ifstream file(_filename); + if (!file) + BOOST_THROW_EXCEPTION(runtime_error("Cannot open test case: \"" + _filename + "\".")); + file.exceptions(ios::badbit); + + string line; + while (getline(file, line)) + { + if (boost::algorithm::starts_with(line, "// ----")) + break; + if (m_source.empty() && boost::algorithm::starts_with(line, "// yul")) + m_yul = true; + m_source += line + "\n"; + } + while (getline(file, line)) + if (boost::algorithm::starts_with(line, "// ")) + m_expectation += line.substr(3) + "\n"; + else + m_expectation += line + "\n"; +} + +bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) +{ + assembly::AsmPrinter printer{m_yul}; + shared_ptr<Block> ast; + shared_ptr<assembly::AsmAnalysisInfo> analysisInfo; + if (!parse(_stream, _linePrefix, _formatted)) + return false; + + if (m_optimizerStep == "disambiguator") + disambiguate(); + else + { + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Invalid optimizer step: " << m_optimizerStep << endl; + return false; + } + + m_obtainedResult = m_optimizerStep + "\n" + printer(*m_ast) + "\n"; + + if (m_expectation != m_obtainedResult) + { + string nextIndentLevel = _linePrefix + " "; + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Expected result:" << endl; + // TODO could compute a simple diff with highlighted lines + printIndented(_stream, m_expectation, nextIndentLevel); + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::CYAN}) << _linePrefix << "Obtained result:" << endl; + printIndented(_stream, m_obtainedResult, nextIndentLevel); + return false; + } + return true; +} + +void YulOptimizerTest::printSource(ostream& _stream, string const& _linePrefix, bool const) const +{ + printIndented(_stream, m_source, _linePrefix); +} + +void YulOptimizerTest::printUpdatedExpectations(ostream& _stream, string const& _linePrefix) const +{ + printIndented(_stream, m_obtainedResult, _linePrefix); +} + +void YulOptimizerTest::printIndented(ostream& _stream, string const& _output, string const& _linePrefix) const +{ + stringstream output(_output); + string line; + while (getline(output, line)) + _stream << _linePrefix << line << endl; +} + +bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted) +{ + assembly::AsmFlavour flavour = m_yul ? assembly::AsmFlavour::Yul : assembly::AsmFlavour::Strict; + ErrorList errors; + ErrorReporter errorReporter(errors); + shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(m_source), ""); + m_ast = assembly::Parser(errorReporter, flavour).parse(scanner, false); + if (!m_ast || !errorReporter.errors().empty()) + { + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error parsing source." << endl; + printErrors(_stream, errorReporter.errors(), *scanner); + return false; + } + m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); + assembly::AsmAnalyzer analyzer( + *m_analysisInfo, + errorReporter, + dev::test::Options::get().evmVersion(), + boost::none, + flavour + ); + if (!analyzer.analyze(*m_ast) || !errorReporter.errors().empty()) + { + FormattedScope(_stream, _formatted, {formatting::BOLD, formatting::RED}) << _linePrefix << "Error analyzing source." << endl; + printErrors(_stream, errorReporter.errors(), *scanner); + return false; + } + return true; +} + +void YulOptimizerTest::disambiguate() +{ + *m_ast = boost::get<Block>(Disambiguator(*m_analysisInfo)(*m_ast)); + m_analysisInfo.reset(); +} + +void YulOptimizerTest::printErrors(ostream& _stream, ErrorList const& _errors, Scanner const& _scanner) +{ + SourceReferenceFormatter formatter(_stream, [&](string const&) -> Scanner const& { return _scanner; }); + + for (auto const& error: _errors) + formatter.printExceptionInformation( + *error, + (error->type() == Error::Type::Warning) ? "Warning" : "Error" + ); +} diff --git a/test/libjulia/YulOptimizerTest.h b/test/libjulia/YulOptimizerTest.h new file mode 100644 index 00000000..8f9a81f7 --- /dev/null +++ b/test/libjulia/YulOptimizerTest.h @@ -0,0 +1,75 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see <http://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <test/libsolidity/TestCase.h> + + +namespace dev +{ +namespace solidity +{ +class Scanner; +class Error; +using ErrorList = std::vector<std::shared_ptr<Error const>>; +namespace assembly +{ +struct AsmAnalysisInfo; +struct Block; +} +} +namespace julia +{ +namespace test +{ + +class YulOptimizerTest: public solidity::test::TestCase +{ +public: + static std::unique_ptr<TestCase> create(std::string const& _filename) + { + return std::unique_ptr<TestCase>(new YulOptimizerTest(_filename)); + } + + explicit YulOptimizerTest(std::string const& _filename); + + bool run(std::ostream& _stream, std::string const& _linePrefix = "", bool const _formatted = false) override; + + void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool const _formatted = false) const override; + void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override; + +private: + void printIndented(std::ostream& _stream, std::string const& _output, std::string const& _linePrefix = "") const; + bool parse(std::ostream& _stream, std::string const& _linePrefix, bool const _formatted); + void disambiguate(); + + static void printErrors(std::ostream& _stream, solidity::ErrorList const& _errors, solidity::Scanner const& _scanner); + + std::string m_source; + bool m_yul = false; + std::string m_optimizerStep; + std::string m_expectation; + + std::shared_ptr<solidity::assembly::Block> m_ast; + std::shared_ptr<solidity::assembly::AsmAnalysisInfo> m_analysisInfo; + std::string m_obtainedResult; +}; + +} +} +} |