diff options
Diffstat (limited to 'test/libyul')
-rw-r--r-- | test/libyul/Common.cpp | 38 | ||||
-rw-r--r-- | test/libyul/Common.h | 19 | ||||
-rw-r--r-- | test/libyul/Inliner.cpp | 7 | ||||
-rw-r--r-- | test/libyul/ObjectParser.cpp | 257 | ||||
-rw-r--r-- | test/libyul/Parser.cpp | 29 | ||||
-rw-r--r-- | test/libyul/YulOptimizerTest.cpp | 37 | ||||
-rw-r--r-- | test/libyul/YulOptimizerTest.h | 22 | ||||
-rw-r--r-- | test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul | 23 | ||||
-rw-r--r-- | test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul | 20 | ||||
-rw-r--r-- | test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul | 21 |
10 files changed, 398 insertions, 75 deletions
diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index d224bdcd..a247a169 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -23,24 +23,24 @@ #include <test/Options.h> -#include <libyul/optimiser/Disambiguator.h> - -#include <libsolidity/parsing/Scanner.h> +#include <liblangutil/SourceReferenceFormatter.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/optimiser/Disambiguator.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmPrinter.h> -#include <libsolidity/interface/SourceReferenceFormatter.h> -#include <libsolidity/interface/ErrorReporter.h> +#include <liblangutil/Scanner.h> +#include <liblangutil/ErrorReporter.h> #include <boost/test/unit_test.hpp> using namespace std; -using namespace dev::yul; +using namespace langutil; +using namespace yul; using namespace dev::solidity; -void dev::yul::test::printErrors(ErrorList const& _errors, Scanner const& _scanner) +void yul::test::printErrors(ErrorList const& _errors, Scanner const& _scanner) { SourceReferenceFormatter formatter(cout, [&](std::string const&) -> Scanner const& { return _scanner; }); @@ -52,18 +52,18 @@ void dev::yul::test::printErrors(ErrorList const& _errors, Scanner const& _scann } -pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::yul::test::parse(string const& _source, bool _yul) +pair<shared_ptr<Block>, shared_ptr<yul::AsmAnalysisInfo>> yul::test::parse(string const& _source, bool _yul) { - auto flavour = _yul ? assembly::AsmFlavour::Yul : assembly::AsmFlavour::Strict; + auto flavour = _yul ? yul::AsmFlavour::Yul : yul::AsmFlavour::Strict; ErrorList errors; ErrorReporter errorReporter(errors); - auto scanner = make_shared<Scanner>(CharStream(_source), ""); - auto parserResult = assembly::Parser(errorReporter, flavour).parse(scanner, false); + auto scanner = make_shared<Scanner>(CharStream(_source, "")); + auto parserResult = yul::Parser(errorReporter, flavour).parse(scanner, false); if (parserResult) { BOOST_REQUIRE(errorReporter.errors().empty()); - auto analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer( + auto analysisInfo = make_shared<yul::AsmAnalysisInfo>(); + yul::AsmAnalyzer analyzer( *analysisInfo, errorReporter, dev::test::Options::get().evmVersion(), @@ -83,13 +83,13 @@ pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::yul::test::p return {}; } -assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul) +yul::Block yul::test::disambiguate(string const& _source, bool _yul) { auto result = parse(_source, _yul); return boost::get<Block>(Disambiguator(*result.second, {})(*result.first)); } -string dev::yul::test::format(string const& _source, bool _yul) +string yul::test::format(string const& _source, bool _yul) { - return assembly::AsmPrinter(_yul)(*parse(_source, _yul).first); + return yul::AsmPrinter(_yul)(*parse(_source, _yul).first); } diff --git a/test/libyul/Common.h b/test/libyul/Common.h index ee191494..a1c64ca5 100644 --- a/test/libyul/Common.h +++ b/test/libyul/Common.h @@ -21,35 +21,34 @@ #pragma once -#include <libsolidity/inlineasm/AsmData.h> +#include <libyul/AsmData.h> #include <string> #include <vector> #include <memory> -namespace dev -{ -namespace solidity +namespace langutil { class Scanner; class Error; using ErrorList = std::vector<std::shared_ptr<Error const>>; -namespace assembly +} + +namespace yul { struct AsmAnalysisInfo; } -} + namespace yul { namespace test { -void printErrors(solidity::ErrorList const& _errors, solidity::Scanner const& _scanner); -std::pair<std::shared_ptr<solidity::assembly::Block>, std::shared_ptr<solidity::assembly::AsmAnalysisInfo>> +void printErrors(langutil::ErrorList const& _errors, langutil::Scanner const& _scanner); +std::pair<std::shared_ptr<Block>, std::shared_ptr<AsmAnalysisInfo>> parse(std::string const& _source, bool _yul = true); -solidity::assembly::Block disambiguate(std::string const& _source, bool _yul = true); +Block disambiguate(std::string const& _source, bool _yul = true); std::string format(std::string const& _source, bool _yul = true); } } -} diff --git a/test/libyul/Inliner.cpp b/test/libyul/Inliner.cpp index 66810298..631cda08 100644 --- a/test/libyul/Inliner.cpp +++ b/test/libyul/Inliner.cpp @@ -26,8 +26,7 @@ #include <libyul/optimiser/FullInliner.h> #include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/FunctionGrouper.h> - -#include <libsolidity/inlineasm/AsmPrinter.h> +#include <libyul/AsmPrinter.h> #include <boost/test/unit_test.hpp> @@ -36,8 +35,8 @@ using namespace std; using namespace dev; -using namespace dev::yul; -using namespace dev::yul::test; +using namespace yul; +using namespace yul::test; using namespace dev::solidity; namespace diff --git a/test/libyul/ObjectParser.cpp b/test/libyul/ObjectParser.cpp new file mode 100644 index 00000000..bb88e4da --- /dev/null +++ b/test/libyul/ObjectParser.cpp @@ -0,0 +1,257 @@ +/* + 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/>. +*/ +/** + * @date 2018 + * Unit tests for the Yul object parser. + */ + +#include <test/Options.h> + +#include <test/libsolidity/ErrorCheck.h> + +#include <libsolidity/interface/AssemblyStack.h> + +#include <boost/optional.hpp> +#include <boost/algorithm/string/replace.hpp> + +#include <string> +#include <memory> + +using namespace std; +using namespace langutil; + +namespace dev +{ +namespace yul +{ +namespace test +{ + +namespace +{ + +std::pair<bool, ErrorList> parse(string const& _source) +{ + try + { + solidity::AssemblyStack asmStack( + dev::test::Options::get().evmVersion(), + solidity::AssemblyStack::Language::StrictAssembly + ); + bool success = asmStack.parseAndAnalyze("source", _source); + return {success, asmStack.errors()}; + } + catch (FatalError const&) + { + BOOST_FAIL("Fatal error leaked."); + } + return {false, {}}; +} + +boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _allowWarnings = 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 (_allowWarnings && Error::containsOnlyWarnings(errors)) + return {}; + else if (!errors.empty()) + { + if (!_allowWarnings) + BOOST_CHECK_EQUAL(errors.size(), 1); + return *errors.front(); + } + } + return {}; +} + +bool successParse(std::string const& _source, bool _allowWarnings = true) +{ + return !parseAndReturnFirstError(_source, _allowWarnings); +} + +Error expectError(std::string const& _source, bool _allowWarnings = false) +{ + + auto error = parseAndReturnFirstError(_source, _allowWarnings); + BOOST_REQUIRE(error); + return *error; +} + +} + +#define CHECK_ERROR(text, typ, substring) \ +do \ +{ \ + Error err = expectError((text), false); \ + BOOST_CHECK(err.type() == (Error::Type::typ)); \ + BOOST_CHECK(solidity::searchErrorMessage(err, (substring))); \ +} while(0) + +BOOST_AUTO_TEST_SUITE(YulObjectParser) + +BOOST_AUTO_TEST_CASE(empty_code) +{ + BOOST_CHECK(successParse("{ }")); +} + +BOOST_AUTO_TEST_CASE(object_with_empty_code) +{ + BOOST_CHECK(successParse("object \"a\" { code { } }")); +} + +BOOST_AUTO_TEST_CASE(non_object) +{ + CHECK_ERROR("code {}", ParserError, "Expected keyword \"object\""); +} + +BOOST_AUTO_TEST_CASE(empty_name) +{ + CHECK_ERROR("object \"\" { code {} }", ParserError, "Object name cannot be empty"); +} + +BOOST_AUTO_TEST_CASE(recursion_depth) +{ + string input; + for (size_t i = 0; i < 20000; i++) + input += "object \"a" + to_string(i) + "\" { code {} "; + for (size_t i = 0; i < 20000; i++) + input += "}"; + + CHECK_ERROR(input, ParserError, "recursion"); +} + +BOOST_AUTO_TEST_CASE(object_with_code) +{ + BOOST_CHECK(successParse("object \"a\" { code { let x := mload(0) sstore(0, x) } }")); +} + +BOOST_AUTO_TEST_CASE(object_with_code_and_data) +{ + BOOST_CHECK(successParse("object \"a\" { code { let x := mload(0) sstore(0, x) } data \"b\" hex\"01010202\" }")); +} + +BOOST_AUTO_TEST_CASE(object_with_non_code_at_start) +{ + CHECK_ERROR("object \"a\" { data \"d\" hex\"0102\" code { } }", ParserError, "Expected keyword \"code\""); +} + +BOOST_AUTO_TEST_CASE(nested_object) +{ + string code = R"( + object "outer" { + code { let x := mload(0) } + data "x" "stringdata" + object "inner" { + code { mstore(0, 1) } + object "inner inner" { code {} } + data "innerx" "abc" + data "innery" "def" + } + } + )"; + BOOST_CHECK(successParse(code)); +} + +BOOST_AUTO_TEST_CASE(incomplete) +{ + CHECK_ERROR("object \"abc\" { code {} } object", ParserError, "Expected end of source"); +} + +BOOST_AUTO_TEST_CASE(reuse_object_name) +{ + string code = R"( + object "outer" { + code { } + data "outer" "stringdata" + } + )"; + CHECK_ERROR(code, ParserError, "Object name cannot be the same as the name of the containing object"); +} + +BOOST_AUTO_TEST_CASE(reuse_object_in_subobject) +{ + string code = R"( + object "outer" { + code { } + object "outer" { code {} } + } + )"; + CHECK_ERROR(code, ParserError, "Object name cannot be the same as the name of the containing object"); +} + +BOOST_AUTO_TEST_CASE(reuse_object_of_sibling) +{ + string code = R"( + object "O" { + code { } + object "i" { code {} } + data "i" "abc" + } + )"; + CHECK_ERROR(code, ParserError, "already exists inside the"); +} + +BOOST_AUTO_TEST_CASE(to_string) +{ + string code = R"( + object "O" { + code { let x := mload(0) if x { sstore(0, 1) } } + object "i" { code {} data "j" "def" } + data "j" "abc" + data "k" hex"010203" + } + )"; + string expectation = R"(object "O" { + code { + let x := mload(0) + if x + { + sstore(0, 1) + } + } + object "i" { + code { + } + data "j" hex"646566" + } + data "j" hex"616263" + data "k" hex"010203" +} +)"; + expectation = boost::replace_all_copy(expectation, "\t", " "); + solidity::AssemblyStack asmStack( + dev::test::Options::get().evmVersion(), + solidity::AssemblyStack::Language::StrictAssembly + ); + BOOST_REQUIRE(asmStack.parseAndAnalyze("source", code)); + BOOST_CHECK_EQUAL(asmStack.print(), expectation); +} + +BOOST_AUTO_TEST_SUITE_END() + +} +} +} // end namespaces diff --git a/test/libyul/Parser.cpp b/test/libyul/Parser.cpp index 3f329d28..caaf2719 100644 --- a/test/libyul/Parser.cpp +++ b/test/libyul/Parser.cpp @@ -23,11 +23,11 @@ #include <test/libsolidity/ErrorCheck.h> -#include <libsolidity/inlineasm/AsmParser.h> -#include <libsolidity/inlineasm/AsmAnalysis.h> -#include <libsolidity/inlineasm/AsmAnalysisInfo.h> -#include <libsolidity/parsing/Scanner.h> -#include <libsolidity/interface/ErrorReporter.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> +#include <libyul/AsmAnalysisInfo.h> +#include <liblangutil/Scanner.h> +#include <liblangutil/ErrorReporter.h> #include <boost/optional.hpp> #include <boost/algorithm/string/replace.hpp> @@ -36,10 +36,10 @@ #include <memory> using namespace std; +using namespace dev; +using namespace langutil; -namespace dev -{ -namespace solidity +namespace yul { namespace test { @@ -51,17 +51,17 @@ bool parse(string const& _source, ErrorReporter& errorReporter) { try { - auto scanner = make_shared<Scanner>(CharStream(_source)); - auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::Yul).parse(scanner, false); + auto scanner = make_shared<Scanner>(CharStream(_source, "")); + auto parserResult = yul::Parser(errorReporter, yul::AsmFlavour::Yul).parse(scanner, false); if (parserResult) { - assembly::AsmAnalysisInfo analysisInfo; - return (assembly::AsmAnalyzer( + yul::AsmAnalysisInfo analysisInfo; + return (yul::AsmAnalyzer( analysisInfo, errorReporter, dev::test::Options::get().evmVersion(), boost::none, - assembly::AsmFlavour::Yul + yul::AsmFlavour::Yul )).analyze(*parserResult); } } @@ -116,7 +116,7 @@ do \ { \ Error err = expectError((text), false); \ BOOST_CHECK(err.type() == (Error::Type::typ)); \ - BOOST_CHECK(searchErrorMessage(err, (substring))); \ + BOOST_CHECK(dev::solidity::searchErrorMessage(err, (substring))); \ } while(0) BOOST_AUTO_TEST_SUITE(YulParser) @@ -302,5 +302,4 @@ BOOST_AUTO_TEST_CASE(if_statement_invalid) BOOST_AUTO_TEST_SUITE_END() } -} } // end namespaces diff --git a/test/libyul/YulOptimizerTest.cpp b/test/libyul/YulOptimizerTest.cpp index 03cd6446..15d70faa 100644 --- a/test/libyul/YulOptimizerTest.cpp +++ b/test/libyul/YulOptimizerTest.cpp @@ -31,6 +31,7 @@ #include <libyul/optimiser/FunctionHoister.h> #include <libyul/optimiser/ExpressionInliner.h> #include <libyul/optimiser/FullInliner.h> +#include <libyul/optimiser/ForLoopInitRewriter.h> #include <libyul/optimiser/MainFunction.h> #include <libyul/optimiser/Rematerialiser.h> #include <libyul/optimiser/ExpressionSimplifier.h> @@ -39,13 +40,13 @@ #include <libyul/optimiser/SSATransform.h> #include <libyul/optimiser/RedundantAssignEliminator.h> #include <libyul/optimiser/Suite.h> +#include <libyul/AsmPrinter.h> +#include <libyul/AsmParser.h> +#include <libyul/AsmAnalysis.h> +#include <liblangutil/SourceReferenceFormatter.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 <liblangutil/ErrorReporter.h> +#include <liblangutil/Scanner.h> #include <boost/test/unit_test.hpp> #include <boost/algorithm/string.hpp> @@ -53,8 +54,9 @@ #include <fstream> using namespace dev; -using namespace dev::yul; -using namespace dev::yul::test; +using namespace langutil; +using namespace yul; +using namespace yul::test; using namespace dev::solidity; using namespace dev::solidity::test; using namespace std; @@ -90,9 +92,9 @@ YulOptimizerTest::YulOptimizerTest(string const& _filename) bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool const _formatted) { - assembly::AsmPrinter printer{m_yul}; + yul::AsmPrinter printer{m_yul}; shared_ptr<Block> ast; - shared_ptr<assembly::AsmAnalysisInfo> analysisInfo; + shared_ptr<yul::AsmAnalysisInfo> analysisInfo; if (!parse(_stream, _linePrefix, _formatted)) return false; @@ -108,6 +110,11 @@ bool YulOptimizerTest::run(ostream& _stream, string const& _linePrefix, bool con disambiguate(); VarDeclPropagator{}(*m_ast); } + else if (m_optimizerStep == "forLoopInitRewriter") + { + disambiguate(); + ForLoopInitRewriter{}(*m_ast); + } else if (m_optimizerStep == "commonSubexpressionEliminator") { disambiguate(); @@ -249,19 +256,19 @@ void YulOptimizerTest::printIndented(ostream& _stream, string const& _output, st bool YulOptimizerTest::parse(ostream& _stream, string const& _linePrefix, bool const _formatted) { - assembly::AsmFlavour flavour = m_yul ? assembly::AsmFlavour::Yul : assembly::AsmFlavour::Strict; + yul::AsmFlavour flavour = m_yul ? yul::AsmFlavour::Yul : yul::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); + shared_ptr<Scanner> scanner = make_shared<Scanner>(CharStream(m_source, "")); + m_ast = yul::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 = make_shared<yul::AsmAnalysisInfo>(); + yul::AsmAnalyzer analyzer( *m_analysisInfo, errorReporter, dev::test::Options::get().evmVersion(), diff --git a/test/libyul/YulOptimizerTest.h b/test/libyul/YulOptimizerTest.h index 7db17ceb..90026e24 100644 --- a/test/libyul/YulOptimizerTest.h +++ b/test/libyul/YulOptimizerTest.h @@ -17,28 +17,27 @@ #pragma once -#include <test/libsolidity/TestCase.h> +#include <test/TestCase.h> - -namespace dev -{ -namespace solidity +namespace langutil { class Scanner; class Error; using ErrorList = std::vector<std::shared_ptr<Error const>>; -namespace assembly +} + +namespace yul { struct AsmAnalysisInfo; struct Block; } -} + namespace yul { namespace test { -class YulOptimizerTest: public solidity::test::TestCase +class YulOptimizerTest: public dev::solidity::test::TestCase { public: static std::unique_ptr<TestCase> create(std::string const& _filename) @@ -58,18 +57,17 @@ private: 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); + static void printErrors(std::ostream& _stream, langutil::ErrorList const& _errors, langutil::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::shared_ptr<Block> m_ast; + std::shared_ptr<AsmAnalysisInfo> m_analysisInfo; std::string m_obtainedResult; }; } } -} diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul new file mode 100644 index 00000000..3ca00f55 --- /dev/null +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/complex_pre.yul @@ -0,0 +1,23 @@ +{ + let random := 42 + for { let a := 1 + let b := 1 } iszero(eq(a, 10)) { a := add(a, b) } { + a := add(a, 1) + } +} +// ---- +// forLoopInitRewriter +// { +// let random := 42 +// let a := 1 +// let b := 1 +// for { +// } +// iszero(eq(a, 10)) +// { +// a := add(a, b) +// } +// { +// a := add(a, 1) +// } +// } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul new file mode 100644 index 00000000..05aceb52 --- /dev/null +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/empty_pre.yul @@ -0,0 +1,20 @@ +{ + let a := 1 + for {} iszero(eq(a, 10)) { a := add(a, 1) } { + a := add(a, 1) + } +} +// ---- +// forLoopInitRewriter +// { +// let a := 1 +// for { +// } +// iszero(eq(a, 10)) +// { +// a := add(a, 1) +// } +// { +// a := add(a, 1) +// } +// } diff --git a/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul b/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul new file mode 100644 index 00000000..565b7725 --- /dev/null +++ b/test/libyul/yulOptimizerTests/forLoopInitRewriter/simple.yul @@ -0,0 +1,21 @@ +{ + let random := 42 + for { let a := 1 } iszero(eq(a, 10)) { a := add(a, 1) } { + a := add(a, 1) + } +} +// ---- +// forLoopInitRewriter +// { +// let random := 42 +// let a := 1 +// for { +// } +// iszero(eq(a, 10)) +// { +// a := add(a, 1) +// } +// { +// a := add(a, 1) +// } +// } |