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
)