2017-05-03 08:30:01 +00:00
/*
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 2017
2018-06-12 18:55:14 +00:00
* Unit tests for parsing Yul .
2017-05-03 08:30:01 +00:00
*/
2020-01-14 16:48:17 +00:00
# include <test/Common.h>
2017-05-03 08:30:01 +00:00
2017-05-24 16:34:19 +00:00
# include <test/libsolidity/ErrorCheck.h>
2018-12-04 10:23:28 +00:00
# include <test/libyul/Common.h>
2017-05-24 16:34:19 +00:00
2018-11-23 10:18:57 +00:00
# include <libyul/AsmParser.h>
2020-01-16 17:06:27 +00:00
# include <libyul/AsmPrinter.h>
2018-11-23 10:18:57 +00:00
# include <libyul/AsmAnalysis.h>
# include <libyul/AsmAnalysisInfo.h>
2020-10-29 14:00:27 +00:00
# include <libyul/AST.h>
2018-12-04 10:23:28 +00:00
# include <libyul/Dialect.h>
2018-11-14 13:59:30 +00:00
# include <liblangutil/Scanner.h>
# include <liblangutil/ErrorReporter.h>
2017-05-03 08:30:01 +00:00
# include <boost/algorithm/string/replace.hpp>
2020-01-14 14:55:31 +00:00
# include <boost/test/unit_test.hpp>
2017-05-03 08:30:01 +00:00
# include <memory>
2019-10-28 10:39:30 +00:00
# include <optional>
# include <string>
2017-05-03 08:30:01 +00:00
using namespace std ;
2019-12-23 15:50:30 +00:00
using namespace solidity ;
using namespace solidity : : util ;
using namespace solidity : : langutil ;
2017-05-03 08:30:01 +00:00
2019-12-23 15:50:30 +00:00
namespace solidity : : yul : : test
2017-05-03 08:30:01 +00:00
{
namespace
{
2020-01-16 17:06:27 +00:00
shared_ptr < Block > parse ( string const & _source , Dialect const & _dialect , ErrorReporter & errorReporter )
2017-05-03 08:30:01 +00:00
{
try
{
2018-11-28 15:13:36 +00:00
auto scanner = make_shared < Scanner > ( CharStream ( _source , " " ) ) ;
2018-12-03 17:06:07 +00:00
auto parserResult = yul : : Parser ( errorReporter , _dialect ) . parse ( scanner , false ) ;
2017-05-03 08:30:01 +00:00
if ( parserResult )
2017-05-25 00:28:47 +00:00
{
2018-11-21 11:42:34 +00:00
yul : : AsmAnalysisInfo analysisInfo ;
2020-01-16 17:06:27 +00:00
if ( yul : : AsmAnalyzer (
2018-02-23 10:42:53 +00:00
analysisInfo ,
errorReporter ,
2018-12-03 17:06:07 +00:00
_dialect
2020-01-16 17:06:27 +00:00
) . analyze ( * parserResult ) )
return parserResult ;
2017-05-25 00:28:47 +00:00
}
2017-05-03 08:30:01 +00:00
}
catch ( FatalError const & )
{
BOOST_FAIL ( " Fatal error leaked. " ) ;
}
2020-01-16 17:06:27 +00:00
return { } ;
2017-05-03 08:30:01 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Error > parseAndReturnFirstError ( string const & _source , Dialect const & _dialect , bool _allowWarnings = true )
2017-05-03 08:30:01 +00:00
{
ErrorList errors ;
2017-05-11 13:26:35 +00:00
ErrorReporter errorReporter ( errors ) ;
2018-12-03 17:06:07 +00:00
if ( ! parse ( _source , _dialect , errorReporter ) )
2017-05-03 08:30:01 +00:00
{
2018-12-04 10:23:58 +00:00
BOOST_REQUIRE ( ! errors . empty ( ) ) ;
BOOST_CHECK_EQUAL ( errors . size ( ) , 1 ) ;
2017-05-03 08:30:01 +00:00
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 { } ;
}
2020-01-29 17:14:03 +00:00
bool successParse ( std : : string const & _source , Dialect const & _dialect = Dialect : : yulDeprecated ( ) , bool _allowWarnings = true )
2017-05-03 08:30:01 +00:00
{
2018-12-03 17:06:07 +00:00
return ! parseAndReturnFirstError ( _source , _dialect , _allowWarnings ) ;
2017-05-03 08:30:01 +00:00
}
2020-01-29 17:14:03 +00:00
Error expectError ( std : : string const & _source , Dialect const & _dialect = Dialect : : yulDeprecated ( ) , bool _allowWarnings = false )
2017-05-03 08:30:01 +00:00
{
2018-12-03 17:06:07 +00:00
auto error = parseAndReturnFirstError ( _source , _dialect , _allowWarnings ) ;
2017-05-03 08:30:01 +00:00
BOOST_REQUIRE ( error ) ;
return * error ;
}
}
2018-12-03 17:06:07 +00:00
# define CHECK_ERROR_DIALECT(text, typ, substring, dialect) \
2017-05-03 08:30:01 +00:00
do \
{ \
2018-12-03 17:06:07 +00:00
Error err = expectError ( ( text ) , dialect , false ) ; \
2017-05-03 08:30:01 +00:00
BOOST_CHECK ( err . type ( ) = = ( Error : : Type : : typ ) ) ; \
2019-12-23 15:50:30 +00:00
BOOST_CHECK ( solidity : : frontend : : test : : searchErrorMessage ( err , ( substring ) ) ) ; \
2017-05-03 08:30:01 +00:00
} while ( 0 )
2020-01-29 17:14:03 +00:00
# define CHECK_ERROR(text, typ, substring) CHECK_ERROR_DIALECT(text, typ, substring, Dialect::yulDeprecated())
2018-12-03 17:06:07 +00:00
2018-06-14 22:29:45 +00:00
BOOST_AUTO_TEST_SUITE ( YulParser )
2017-05-03 08:30:01 +00:00
2018-12-04 10:23:28 +00:00
BOOST_AUTO_TEST_CASE ( builtins_analysis )
{
2018-12-06 23:56:16 +00:00
struct SimpleDialect : public Dialect
2018-12-04 10:23:28 +00:00
{
2018-12-06 23:56:16 +00:00
BuiltinFunction const * builtin ( YulString _name ) const override
2018-12-04 10:23:28 +00:00
{
2018-12-10 03:25:51 +00:00
return _name = = " builtin " _yulstring ? & f : nullptr ;
2018-12-04 10:23:28 +00:00
}
2020-04-06 12:47:44 +00:00
BuiltinFunction f { " builtin " _yulstring , vector < Type > ( 2 ) , vector < Type > ( 3 ) , { } , { } , false , { } } ;
2018-12-04 10:23:28 +00:00
} ;
2019-05-16 08:56:56 +00:00
SimpleDialect dialect ;
2018-12-04 10:23:28 +00:00
BOOST_CHECK ( successParse ( " { let a, b, c := builtin(1, 2) } " , dialect ) ) ;
2021-02-09 13:25:34 +00:00
CHECK_ERROR_DIALECT ( " { let a, b, c := builtin(1) } " , TypeError , " Function \" builtin \" expects 2 arguments but got 1 " , dialect ) ;
CHECK_ERROR_DIALECT ( " { let a, b := builtin(1, 2) } " , DeclarationError , " Variable count mismatch for declaration of \" a, b \" : 2 variables and 3 values. " , dialect ) ;
2018-12-04 10:23:28 +00:00
}
2020-01-16 17:06:27 +00:00
BOOST_AUTO_TEST_CASE ( default_types_set )
{
ErrorList errorList ;
ErrorReporter reporter ( errorList ) ;
shared_ptr < Block > result = parse (
" { "
" let x:bool := true:bool "
2020-01-29 17:14:20 +00:00
" let z:bool := true "
2020-01-16 17:06:27 +00:00
" let y := add(1, 2) "
" switch y case 0 {} default {} "
" } " ,
EVMDialectTyped : : instance ( EVMVersion { } ) ,
reporter
) ;
BOOST_REQUIRE ( ! ! result ) ;
// Use no dialect so that all types are printed.
// This tests that the default types are properly assigned.
BOOST_CHECK_EQUAL ( AsmPrinter { } ( * result ) ,
" { \n "
" let x:bool := true:bool \n "
2020-01-29 17:14:20 +00:00
" let z:bool := true:bool \n "
2020-01-16 17:06:27 +00:00
" let y:u256 := add(1:u256, 2:u256) \n "
" switch y \n "
" case 0:u256 { } \n "
" default { } \n "
" } "
) ;
// Now test again with type dialect. Now the default types
// should be omitted.
BOOST_CHECK_EQUAL ( AsmPrinter { EVMDialectTyped : : instance ( EVMVersion { } ) } ( * result ) ,
" { \n "
2020-01-29 17:14:20 +00:00
" let x:bool := true \n "
" let z:bool := true \n "
2020-01-16 17:06:27 +00:00
" let y := add(1, 2) \n "
" switch y \n "
" case 0 { } \n "
" default { } \n "
" } "
) ;
}
2019-07-09 15:23:14 +00:00
2017-05-03 08:30:01 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
} // end namespaces