From fc10e701fc21fcf5c8b0fc0c6d7c9a3c5095a0ce Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 4 Feb 2020 19:40:32 +0100 Subject: [PATCH] Implement yul syntax tests --- test/CMakeLists.txt | 4 + test/CommonSyntaxTest.cpp | 252 ++++++++++++++++++ test/CommonSyntaxTest.h | 86 ++++++ test/InteractiveTests.h | 2 + test/libsolidity/SyntaxTest.cpp | 205 +------------- test/libsolidity/SyntaxTest.h | 46 +--- test/libyul/SyntaxTest.cpp | 139 ++++++++++ test/libyul/SyntaxTest.h | 53 ++++ .../yulSyntaxTests/simple_functions.yul | 8 + test/tools/CMakeLists.txt | 2 + 10 files changed, 551 insertions(+), 246 deletions(-) create mode 100644 test/CommonSyntaxTest.cpp create mode 100644 test/CommonSyntaxTest.h create mode 100644 test/libyul/SyntaxTest.cpp create mode 100644 test/libyul/SyntaxTest.h create mode 100644 test/libyul/yulSyntaxTests/simple_functions.yul diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ce1c12739..e7a9d903f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -2,6 +2,8 @@ set(sources boostTest.cpp Common.cpp Common.h + CommonSyntaxTest.cpp + CommonSyntaxTest.h EVMHost.cpp EVMHost.h ExecutionFramework.cpp @@ -127,6 +129,8 @@ set(libyul_sources libyul/ObjectParser.cpp libyul/Parser.cpp libyul/StackReuseCodegen.cpp + libyul/SyntaxTest.h + libyul/SyntaxTest.cpp libyul/YulInterpreterTest.cpp libyul/YulInterpreterTest.h libyul/YulOptimizerTest.cpp diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp new file mode 100644 index 000000000..6d72ce010 --- /dev/null +++ b/test/CommonSyntaxTest.cpp @@ -0,0 +1,252 @@ +/* + 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 . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::util::formatting; +using namespace solidity::langutil; +using namespace solidity::frontend; +using namespace solidity::frontend::test; +using namespace solidity::test; +using namespace boost::unit_test; +namespace fs = boost::filesystem; + +namespace +{ + +int parseUnsignedInteger(string::iterator& _it, string::iterator _end) +{ + if (_it == _end || !isdigit(*_it)) + throw runtime_error("Invalid test expectation. Source location expected."); + int result = 0; + while (_it != _end && isdigit(*_it)) + { + result *= 10; + result += *_it - '0'; + ++_it; + } + return result; +} + +} + +CommonSyntaxTest::CommonSyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion): m_evmVersion(_evmVersion) +{ + ifstream file(_filename); + if (!file) + BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); + file.exceptions(ios::badbit); + + m_sources = parseSourcesAndSettings(file); + + m_expectations = parseExpectations(file); +} + +TestCase::TestResult CommonSyntaxTest::run(ostream& _stream, string const& _linePrefix, bool _formatted) +{ + parseAndAnalyze(); + + return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; +} + +bool CommonSyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) +{ + if (m_expectations != m_errorList) + { + string nextIndentLevel = _linePrefix + " "; + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; + printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); + AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; + printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); + return false; + } + return true; +} + +void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const +{ + if (m_sources.empty()) + return; + + bool outputSourceNames = true; + if (m_sources.size() == 1 && m_sources.begin()->first.empty()) + outputSourceNames = false; + + if (_formatted) + for (auto const& [name, source]: m_sources) + { + if (source.empty()) + continue; + + if (outputSourceNames) + _stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl; + vector sourceFormatting(source.length(), formatting::RESET); + for (auto const& error: m_errorList) + if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0) + { + assert(static_cast(error.locationStart) <= source.length()); + assert(static_cast(error.locationEnd) <= source.length()); + bool isWarning = error.type == "Warning"; + for (int i = error.locationStart; i < error.locationEnd; i++) + if (isWarning) + { + if (sourceFormatting[i] == formatting::RESET) + sourceFormatting[i] = formatting::ORANGE_BACKGROUND_256; + } + else + sourceFormatting[i] = formatting::RED_BACKGROUND; + } + + _stream << _linePrefix << sourceFormatting.front() << source.front(); + for (size_t i = 1; i < source.length(); i++) + { + if (sourceFormatting[i] != sourceFormatting[i - 1]) + _stream << sourceFormatting[i]; + if (source[i] != '\n') + _stream << source[i]; + else + { + _stream << formatting::RESET << endl; + if (i + 1 < source.length()) + _stream << _linePrefix << sourceFormatting[i]; + } + } + _stream << formatting::RESET; + } + else + for (auto const& [name, source]: m_sources) + { + if (outputSourceNames) + _stream << _linePrefix << "==== Source: " + name << " ====" << endl; + stringstream stream(source); + string line; + while (getline(stream, line)) + _stream << _linePrefix << line << endl; + } +} + +void CommonSyntaxTest::printErrorList( + ostream& _stream, + vector const& _errorList, + string const& _linePrefix, + bool _formatted +) +{ + if (_errorList.empty()) + AnsiColorized(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl; + else + for (auto const& error: _errorList) + { + { + AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == "Warning") ? YELLOW : RED}); + _stream << _linePrefix; + _stream << error.type << ": "; + } + if (!error.sourceName.empty() || error.locationStart >= 0 || error.locationEnd >= 0) + { + _stream << "("; + if (!error.sourceName.empty()) + _stream << error.sourceName << ":"; + if (error.locationStart >= 0) + _stream << error.locationStart; + _stream << "-"; + if (error.locationEnd >= 0) + _stream << error.locationEnd; + _stream << "): "; + } + _stream << error.message << endl; + } +} + +string CommonSyntaxTest::errorMessage(Exception const& _e) +{ + if (_e.comment() && !_e.comment()->empty()) + return boost::replace_all_copy(*_e.comment(), "\n", "\\n"); + else + return "NONE"; +} + +vector CommonSyntaxTest::parseExpectations(istream& _stream) +{ + vector expectations; + string line; + while (getline(_stream, line)) + { + auto it = line.begin(); + + skipSlashes(it, line.end()); + skipWhitespace(it, line.end()); + + if (it == line.end()) continue; + + auto typeBegin = it; + while (it != line.end() && *it != ':') + ++it; + string errorType(typeBegin, it); + + // skip colon + if (it != line.end()) it++; + + skipWhitespace(it, line.end()); + + int locationStart = -1; + int locationEnd = -1; + std::string sourceName; + + if (it != line.end() && *it == '(') + { + ++it; + if (it != line.end() && !isdigit(*it)) + { + auto sourceNameStart = it; + while (it != line.end() && *it != ':') + ++it; + sourceName = std::string(sourceNameStart, it); + expect(it, line.end(), ':'); + } + locationStart = parseUnsignedInteger(it, line.end()); + expect(it, line.end(), '-'); + locationEnd = parseUnsignedInteger(it, line.end()); + expect(it, line.end(), ')'); + expect(it, line.end(), ':'); + } + + skipWhitespace(it, line.end()); + + string errorMessage(it, line.end()); + expectations.emplace_back(SyntaxTestError{ + move(errorType), + move(errorMessage), + move(sourceName), + locationStart, + locationEnd + }); + } + return expectations; +} diff --git a/test/CommonSyntaxTest.h b/test/CommonSyntaxTest.h new file mode 100644 index 000000000..22acd5413 --- /dev/null +++ b/test/CommonSyntaxTest.h @@ -0,0 +1,86 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace solidity::test +{ + +struct SyntaxTestError +{ + std::string type; + std::string message; + std::string sourceName; + int locationStart = -1; + int locationEnd = -1; + bool operator==(SyntaxTestError const& _rhs) const + { + return type == _rhs.type && + message == _rhs.message && + sourceName == _rhs.sourceName && + locationStart == _rhs.locationStart && + locationEnd == _rhs.locationEnd; + } +}; + + +class CommonSyntaxTest: public frontend::test::EVMVersionRestrictedTestCase +{ +public: + CommonSyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion); + + TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; + + void printSource(std::ostream& _stream, std::string const &_linePrefix = "", bool _formatted = false) const override; + void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override + { + if (!m_errorList.empty()) + printErrorList(_stream, m_errorList, _linePrefix, false); + } + + static std::string errorMessage(util::Exception const& _e); +protected: + virtual void parseAndAnalyze() = 0; + + static void printErrorList( + std::ostream& _stream, + std::vector const& _errors, + std::string const& _linePrefix, + bool _formatted = false + ); + + virtual bool printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); + + static std::vector parseExpectations(std::istream& _stream); + + std::map m_sources; + std::vector m_expectations; + std::vector m_errorList; + langutil::EVMVersion const m_evmVersion; +}; + +} diff --git a/test/InteractiveTests.h b/test/InteractiveTests.h index 8069ae522..409d8607d 100644 --- a/test/InteractiveTests.h +++ b/test/InteractiveTests.h @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -57,6 +58,7 @@ Testsuite const g_interactiveTestsuites[] = { {"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, {"Function Side Effects","libyul", "functionSideEffects", false, false, &yul::test::FunctionSideEffects::create}, + {"Yul Syntax", "libyul", "yulSyntaxTests", false, false, &yul::test::SyntaxTest::create}, {"Syntax", "libsolidity", "syntaxTests", false, false, &SyntaxTest::create}, {"Error Recovery", "libsolidity", "errorRecoveryTests", false, false, &SyntaxTest::createErrorRecovery}, {"Semantic", "libsolidity", "semanticTests", false, true, &SemanticTest::create}, diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index b28d6c9da..1938cfe86 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -35,34 +35,8 @@ using namespace solidity::frontend::test; using namespace boost::unit_test; namespace fs = boost::filesystem; -namespace +SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion, bool _parserErrorRecovery): CommonSyntaxTest(_filename, _evmVersion) { - -int parseUnsignedInteger(string::iterator& _it, string::iterator _end) -{ - if (_it == _end || !isdigit(*_it)) - throw runtime_error("Invalid test expectation. Source location expected."); - int result = 0; - while (_it != _end && isdigit(*_it)) - { - result *= 10; - result += *_it - '0'; - ++_it; - } - return result; -} - -} - -SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion, bool _parserErrorRecovery): m_evmVersion(_evmVersion) -{ - ifstream file(_filename); - if (!file) - BOOST_THROW_EXCEPTION(runtime_error("Cannot open test contract: \"" + _filename + "\".")); - file.exceptions(ios::badbit); - - m_sources = parseSourcesAndSettings(file); - if (m_settings.count("optimize-yul")) { if (m_settings["optimize-yul"] == "true") @@ -77,7 +51,6 @@ SyntaxTest::SyntaxTest(string const& _filename, langutil::EVMVersion _evmVersion m_optimiseYul = false; } } - m_expectations = parseExpectations(file); m_parserErrorRecovery = _parserErrorRecovery; } @@ -90,83 +63,6 @@ TestCase::TestResult SyntaxTest::run(ostream& _stream, string const& _linePrefix return printExpectationAndError(_stream, _linePrefix, _formatted) ? TestResult::Success : TestResult::Failure; } -bool SyntaxTest::printExpectationAndError(ostream& _stream, string const& _linePrefix, bool _formatted) -{ - if (m_expectations != m_errorList) - { - string nextIndentLevel = _linePrefix + " "; - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Expected result:" << endl; - printErrorList(_stream, m_expectations, nextIndentLevel, _formatted); - AnsiColorized(_stream, _formatted, {BOLD, CYAN}) << _linePrefix << "Obtained result:" << endl; - printErrorList(_stream, m_errorList, nextIndentLevel, _formatted); - return false; - } - return true; -} - -void SyntaxTest::printSource(ostream& _stream, string const& _linePrefix, bool _formatted) const -{ - - if (m_sources.empty()) - return; - - bool outputSourceNames = true; - if (m_sources.size() == 1 && m_sources.begin()->first.empty()) - outputSourceNames = false; - - if (_formatted) - { - for (auto const& [name, source]: m_sources) - { - if (outputSourceNames) - _stream << _linePrefix << formatting::CYAN << "==== Source: " << name << " ====" << formatting::RESET << endl; - vector sourceFormatting(source.length(), formatting::RESET); - for (auto const& error: m_errorList) - if (error.sourceName == name && error.locationStart >= 0 && error.locationEnd >= 0) - { - assert(static_cast(error.locationStart) <= source.length()); - assert(static_cast(error.locationEnd) <= source.length()); - bool isWarning = error.type == "Warning"; - for (int i = error.locationStart; i < error.locationEnd; i++) - if (isWarning) - { - if (sourceFormatting[i] == formatting::RESET) - sourceFormatting[i] = formatting::ORANGE_BACKGROUND_256; - } - else - sourceFormatting[i] = formatting::RED_BACKGROUND; - } - - _stream << _linePrefix << sourceFormatting.front() << source.front(); - for (size_t i = 1; i < source.length(); i++) - { - if (sourceFormatting[i] != sourceFormatting[i - 1]) - _stream << sourceFormatting[i]; - if (source[i] != '\n') - _stream << source[i]; - else - { - _stream << formatting::RESET << endl; - if (i + 1 < source.length()) - _stream << _linePrefix << sourceFormatting[i]; - } - } - _stream << formatting::RESET; - } - - } - else - for (auto const& [name, source]: m_sources) - { - if (outputSourceNames) - _stream << _linePrefix << "==== Source: " + name << " ====" << endl; - stringstream stream(source); - string line; - while (getline(stream, line)) - _stream << _linePrefix << line << endl; - } -} - void SyntaxTest::setupCompiler() { string const versionPragma = "pragma solidity >=0.0;\n"; @@ -231,102 +127,3 @@ void SyntaxTest::filterObtainedErrors() } } -void SyntaxTest::printErrorList( - ostream& _stream, - vector const& _errorList, - string const& _linePrefix, - bool _formatted -) -{ - if (_errorList.empty()) - AnsiColorized(_stream, _formatted, {BOLD, GREEN}) << _linePrefix << "Success" << endl; - else - for (auto const& error: _errorList) - { - { - AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == "Warning") ? YELLOW : RED}); - _stream << _linePrefix; - _stream << error.type << ": "; - } - if (!error.sourceName.empty() || error.locationStart >= 0 || error.locationEnd >= 0) - { - _stream << "("; - if (!error.sourceName.empty()) - _stream << error.sourceName << ":"; - if (error.locationStart >= 0) - _stream << error.locationStart; - _stream << "-"; - if (error.locationEnd >= 0) - _stream << error.locationEnd; - _stream << "): "; - } - _stream << error.message << endl; - } -} - -string SyntaxTest::errorMessage(Exception const& _e) -{ - if (_e.comment() && !_e.comment()->empty()) - return boost::replace_all_copy(*_e.comment(), "\n", "\\n"); - else - return "NONE"; -} - -vector SyntaxTest::parseExpectations(istream& _stream) -{ - vector expectations; - string line; - while (getline(_stream, line)) - { - auto it = line.begin(); - - skipSlashes(it, line.end()); - skipWhitespace(it, line.end()); - - if (it == line.end()) continue; - - auto typeBegin = it; - while (it != line.end() && *it != ':') - ++it; - string errorType(typeBegin, it); - - // skip colon - if (it != line.end()) it++; - - skipWhitespace(it, line.end()); - - int locationStart = -1; - int locationEnd = -1; - std::string sourceName; - - if (it != line.end() && *it == '(') - { - ++it; - if (it != line.end() && !isdigit(*it)) - { - auto sourceNameStart = it; - while (it != line.end() && *it != ':') - ++it; - sourceName = std::string(sourceNameStart, it); - expect(it, line.end(), ':'); - } - locationStart = parseUnsignedInteger(it, line.end()); - expect(it, line.end(), '-'); - locationEnd = parseUnsignedInteger(it, line.end()); - expect(it, line.end(), ')'); - expect(it, line.end(), ':'); - } - - skipWhitespace(it, line.end()); - - string errorMessage(it, line.end()); - expectations.emplace_back(SyntaxTestError{ - move(errorType), - move(errorMessage), - move(sourceName), - locationStart, - locationEnd - }); - } - return expectations; -} diff --git a/test/libsolidity/SyntaxTest.h b/test/libsolidity/SyntaxTest.h index 0a1752f10..dbc5d68b3 100644 --- a/test/libsolidity/SyntaxTest.h +++ b/test/libsolidity/SyntaxTest.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -30,25 +31,9 @@ namespace solidity::frontend::test { -struct SyntaxTestError -{ - std::string type; - std::string message; - std::string sourceName; - int locationStart; - int locationEnd; - bool operator==(SyntaxTestError const& _rhs) const - { - return type == _rhs.type && - message == _rhs.message && - sourceName == _rhs.sourceName && - locationStart == _rhs.locationStart && - locationEnd == _rhs.locationEnd; - } -}; +using solidity::test::SyntaxTestError; - -class SyntaxTest: public AnalysisFramework, public EVMVersionRestrictedTestCase +class SyntaxTest: public AnalysisFramework, public solidity::test::CommonSyntaxTest { public: static std::unique_ptr create(Config const& _config) @@ -63,35 +48,12 @@ public: TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; - void printSource(std::ostream &_stream, std::string const &_linePrefix = "", bool _formatted = false) const override; - void printUpdatedExpectations(std::ostream& _stream, std::string const& _linePrefix) const override - { - if (!m_errorList.empty()) - printErrorList(_stream, m_errorList, _linePrefix, false); - } - - static std::string errorMessage(util::Exception const& _e); protected: void setupCompiler(); - void parseAndAnalyze(); + void parseAndAnalyze() override; void filterObtainedErrors(); - static void printErrorList( - std::ostream& _stream, - std::vector const& _errors, - std::string const& _linePrefix, - bool _formatted = false - ); - - virtual bool printExpectationAndError(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false); - - static std::vector parseExpectations(std::istream& _stream); - - std::map m_sources; - std::vector m_expectations; - std::vector m_errorList; bool m_optimiseYul = true; - langutil::EVMVersion const m_evmVersion; bool m_parserErrorRecovery = false; }; diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp new file mode 100644 index 000000000..330aba2ee --- /dev/null +++ b/test/libyul/SyntaxTest.cpp @@ -0,0 +1,139 @@ +/* + 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 . +*/ + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace std; +using namespace solidity; +using namespace solidity::util; +using namespace solidity::langutil; +using namespace solidity::yul::test; + +namespace +{ +std::map const validDialects = { + { + "evm", + [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& + { return yul::EVMDialect::strictAssemblyForEVM(_evmVersion); } + }, + { + "evmTyped", + [](langutil::EVMVersion _evmVersion) -> yul::Dialect const& + { return yul::EVMDialectTyped::strictAssemblyForEVM(_evmVersion); } + }, + { + "yul", + [](langutil::EVMVersion) -> yul::Dialect const& + { return yul::Dialect::yulDeprecated(); } + }, + { + "ewasm", + [](langutil::EVMVersion) -> yul::Dialect const& + { return yul::WasmDialect::instance(); } + } +}; + +vector validDialectNames() +{ + vector names{size(validDialects), ""}; + transform(begin(validDialects), end(validDialects), names.begin(), [](auto const& dialect) { return dialect.first; }); + + return names; +} +} + +void SyntaxTest::parseAndAnalyze() +{ + string dialectName = m_validatedSettings.count("Dialect") ? m_validatedSettings["Dialect"] : "evmTyped"; + + yul::Dialect const& dialect = validDialects.at(dialectName)(m_evmVersion); + + if (m_sources.size() != 1) + BOOST_THROW_EXCEPTION(runtime_error{"Expected only one source for yul test."}); + + string const& name = m_sources.begin()->first; + string const& source = m_sources.begin()->second; + + ErrorList errorList{}; + ErrorReporter errorReporter{errorList}; + + auto scanner = make_shared(CharStream(source, name)); + auto parserResult = yul::Parser(errorReporter, dialect).parse(scanner, false); + + if (parserResult) + { + yul::AsmAnalysisInfo analysisInfo; + yul::AsmAnalyzer(analysisInfo, errorReporter, dialect).analyze(*parserResult); + } + + for (auto const& error: errorList) + { + int locationStart = -1; + int locationEnd = -1; + + if (auto location = boost::get_error_info(*error)) + { + locationStart = location->start; + locationEnd = location->end; + } + + m_errorList.emplace_back(SyntaxTestError{ + error->typeName(), + errorMessage(*error), + name, + locationStart, + locationEnd + }); + } + +} + +bool SyntaxTest::validateSettings(langutil::EVMVersion _evmVersion) +{ + if (!CommonSyntaxTest::validateSettings(_evmVersion)) + return false; + + if (!m_settings.count("Dialect")) + return true; + + string const dialect = m_settings["Dialect"]; + m_validatedSettings["Dialect"] = dialect; + m_settings.erase("Dialect"); + + if (!validDialects.count(dialect)) + BOOST_THROW_EXCEPTION(runtime_error{ + "Invalid Dialect \"" + + dialect + + "\". Valid dialects are " + + joinHumanReadable(validDialectNames(), ", ", " and ") + + "." + }); + + return true; +} diff --git a/test/libyul/SyntaxTest.h b/test/libyul/SyntaxTest.h new file mode 100644 index 000000000..e355a5932 --- /dev/null +++ b/test/libyul/SyntaxTest.h @@ -0,0 +1,53 @@ +/* + 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 . +*/ + +#pragma once + +#include +#include + +namespace solidity::yul::test +{ + +using solidity::test::SyntaxTestError; + +class SyntaxTest: public solidity::test::CommonSyntaxTest +{ +public: + static std::unique_ptr create(Config const& _config) + { + return std::make_unique(_config.filename, _config.evmVersion); + } + static std::unique_ptr createErrorRecovery(Config const& _config) + { + return std::make_unique(_config.filename, _config.evmVersion); + } + SyntaxTest(std::string const& _filename, langutil::EVMVersion _evmVersion): + CommonSyntaxTest(_filename, _evmVersion) {} + virtual ~SyntaxTest() {} + + /// Validates the settings, i.e. moves them from m_settings to m_validatedSettings. + /// Throws a runtime exception if any setting is left at this class (i.e. unknown setting). + /// Returns true, if the test case is supported in the current environment and false + /// otherwise which causes this test to be skipped. + /// This might check e.g. for restrictions on the EVM version. + bool validateSettings(langutil::EVMVersion _evmVersion) override; +protected: + void parseAndAnalyze() override; +}; + +} diff --git a/test/libyul/yulSyntaxTests/simple_functions.yul b/test/libyul/yulSyntaxTests/simple_functions.yul new file mode 100644 index 000000000..dd5c8bdde --- /dev/null +++ b/test/libyul/yulSyntaxTests/simple_functions.yul @@ -0,0 +1,8 @@ +{ + function a() {} + function f() { mstore(0, 1) } + function g() { sstore(0, 1) } + function h() { let x := msize() } + function i() { let z := mload(0) } +} +// ---- diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 9fabfae68..5ea8486ec 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(isoltest isoltest.cpp IsolTestOptions.cpp ../Common.cpp + ../CommonSyntaxTest.cpp ../EVMHost.cpp ../TestCase.cpp ../libsolidity/util/BytesUtils.cpp @@ -34,6 +35,7 @@ add_executable(isoltest ../libyul/EwasmTranslationTest.cpp ../libyul/FunctionSideEffects.cpp ../libyul/ObjectCompilerTest.cpp + ../libyul/SyntaxTest.cpp ../libyul/YulOptimizerTest.cpp ../libyul/YulInterpreterTest.cpp )