2016-02-22 01:13:41 +00:00
/*
2016-11-18 23:13:20 +00:00
This file is part of solidity .
2016-02-22 01:13:41 +00:00
2016-11-18 23:13:20 +00:00
solidity is free software : you can redistribute it and / or modify
2016-02-22 01:13:41 +00:00
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 .
2016-11-18 23:13:20 +00:00
solidity is distributed in the hope that it will be useful ,
2016-02-22 01:13:41 +00:00
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
2016-11-18 23:13:20 +00:00
along with solidity . If not , see < http : //www.gnu.org/licenses/>.
2016-02-22 01:13:41 +00:00
*/
/**
* @ author Christian < c @ ethdev . com >
* @ date 2016
* Unit tests for inline assembly .
*/
2020-01-14 16:48:17 +00:00
# include <test/Common.h>
2017-02-17 15:04:42 +00:00
2019-02-13 11:07:20 +00:00
# include <test/libsolidity/ErrorCheck.h>
# include <libsolidity/ast/AST.h>
# include <libyul/AssemblyStack.h>
2018-11-14 13:59:30 +00:00
# include <liblangutil/Scanner.h>
# include <liblangutil/Exceptions.h>
2019-05-22 22:25:39 +00:00
# include <liblangutil/SourceReferenceFormatter.h>
2019-02-13 11:07:20 +00:00
2017-02-17 15:04:42 +00:00
# include <libevmasm/Assembly.h>
2017-04-21 22:05:12 +00:00
# include <boost/algorithm/string/replace.hpp>
2020-01-14 14:55:31 +00:00
# include <boost/test/unit_test.hpp>
2017-02-17 15:04:42 +00:00
# include <memory>
2019-10-28 10:39:30 +00:00
# include <optional>
# include <string>
2016-02-22 01:13:41 +00:00
using namespace std ;
2019-12-23 15:50:30 +00:00
using namespace solidity : : langutil ;
using namespace solidity : : yul ;
2016-02-22 01:13:41 +00:00
2019-12-23 15:50:30 +00:00
namespace solidity : : frontend : : test
2016-02-22 01:13:41 +00:00
{
namespace
{
2019-10-28 10:39:30 +00:00
std : : optional < Error > parseAndReturnFirstError (
2017-05-31 10:39:50 +00:00
string const & _source ,
bool _assemble = false ,
bool _allowWarnings = true ,
2018-01-06 00:24:45 +00:00
AssemblyStack : : Language _language = AssemblyStack : : Language : : Assembly ,
2017-05-31 10:39:50 +00:00
AssemblyStack : : Machine _machine = AssemblyStack : : Machine : : EVM
)
2016-02-22 01:13:41 +00:00
{
2020-01-14 16:48:17 +00:00
AssemblyStack stack ( solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) , _language , solidity : : frontend : : OptimiserSettings : : none ( ) ) ;
2017-02-17 15:04:42 +00:00
bool success = false ;
2016-02-22 01:13:41 +00:00
try
{
2017-05-31 10:39:50 +00:00
success = stack . parseAndAnalyze ( " " , _source ) ;
2017-02-17 15:04:42 +00:00
if ( success & & _assemble )
2019-03-27 11:49:50 +00:00
stack . assemble ( _machine ) ;
2016-02-22 01:13:41 +00:00
}
2017-02-20 10:57:50 +00:00
catch ( FatalError const & )
2016-02-22 01:13:41 +00:00
{
2017-02-17 15:04:42 +00:00
BOOST_FAIL ( " Fatal error leaked. " ) ;
success = false ;
2016-02-22 01:13:41 +00:00
}
2017-06-28 17:30:13 +00:00
shared_ptr < Error const > error ;
for ( auto const & e : stack . errors ( ) )
2017-02-17 15:04:42 +00:00
{
2017-06-28 17:30:13 +00:00
if ( _allowWarnings & & e - > type ( ) = = Error : : Type : : Warning )
continue ;
if ( error )
2019-05-22 22:25:39 +00:00
{
string errors ;
for ( auto const & err : stack . errors ( ) )
errors + = SourceReferenceFormatter : : formatErrorInformation ( * err ) ;
BOOST_FAIL ( " Found more than one error: \n " + errors ) ;
}
2017-06-28 17:30:13 +00:00
error = e ;
2017-02-17 15:04:42 +00:00
}
2017-06-28 17:30:13 +00:00
if ( ! success )
BOOST_REQUIRE ( error ) ;
if ( error )
return * error ;
2017-02-17 15:04:42 +00:00
return { } ;
}
2016-02-22 01:13:41 +00:00
2017-05-31 10:39:50 +00:00
bool successParse (
string const & _source ,
bool _assemble = false ,
bool _allowWarnings = true ,
2018-01-06 00:24:45 +00:00
AssemblyStack : : Language _language = AssemblyStack : : Language : : Assembly ,
2017-05-31 10:39:50 +00:00
AssemblyStack : : Machine _machine = AssemblyStack : : Machine : : EVM
)
2017-02-17 15:04:42 +00:00
{
2018-01-06 00:24:45 +00:00
return ! parseAndReturnFirstError ( _source , _assemble , _allowWarnings , _language , _machine ) ;
2016-02-22 01:13:41 +00:00
}
2018-01-06 00:24:45 +00:00
bool successAssemble ( string const & _source , bool _allowWarnings = true , AssemblyStack : : Language _language = AssemblyStack : : Language : : Assembly )
2016-03-01 21:56:39 +00:00
{
2018-01-06 00:24:45 +00:00
return
successParse ( _source , true , _allowWarnings , _language , AssemblyStack : : Machine : : EVM ) & &
successParse ( _source , true , _allowWarnings , _language , AssemblyStack : : Machine : : EVM15 ) ;
2016-03-01 21:56:39 +00:00
}
2018-01-06 00:24:45 +00:00
Error expectError (
std : : string const & _source ,
bool _assemble ,
bool _allowWarnings = false ,
AssemblyStack : : Language _language = AssemblyStack : : Language : : Assembly
)
2017-02-17 15:04:42 +00:00
{
2018-01-06 00:24:45 +00:00
auto error = parseAndReturnFirstError ( _source , _assemble , _allowWarnings , _language ) ;
2017-02-17 15:04:42 +00:00
BOOST_REQUIRE ( error ) ;
return * error ;
}
2017-06-28 17:30:13 +00:00
void parsePrintCompare ( string const & _source , bool _canWarn = false )
2017-02-14 14:40:58 +00:00
{
2020-01-14 16:48:17 +00:00
AssemblyStack stack ( solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) , AssemblyStack : : Language : : Assembly , OptimiserSettings : : none ( ) ) ;
2017-05-31 10:39:50 +00:00
BOOST_REQUIRE ( stack . parseAndAnalyze ( " " , _source ) ) ;
2017-06-28 17:30:13 +00:00
if ( _canWarn )
BOOST_REQUIRE ( Error : : containsOnlyWarnings ( stack . errors ( ) ) ) ;
else
BOOST_REQUIRE ( stack . errors ( ) . empty ( ) ) ;
2018-11-07 11:01:43 +00:00
string expectation = " object \" object \" { \n code " + boost : : replace_all_copy ( _source , " \n " , " \n " ) + " \n } \n " ;
BOOST_CHECK_EQUAL ( stack . print ( ) , expectation ) ;
2017-02-14 14:40:58 +00:00
}
2016-02-22 01:13:41 +00:00
}
2018-01-06 00:24:45 +00:00
# define CHECK_ERROR_LANG(text, assemble, typ, substring, warnings, language) \
2017-02-17 15:04:42 +00:00
do \
{ \
2018-01-06 00:24:45 +00:00
Error err = expectError ( ( text ) , ( assemble ) , warnings , ( language ) ) ; \
2017-02-17 15:04:42 +00:00
BOOST_CHECK ( err . type ( ) = = ( Error : : Type : : typ ) ) ; \
BOOST_CHECK ( searchErrorMessage ( err , ( substring ) ) ) ; \
} while ( 0 )
2018-01-06 00:24:45 +00:00
# define CHECK_ERROR(text, assemble, typ, substring, warnings) \
CHECK_ERROR_LANG ( text , assemble , typ , substring , warnings , AssemblyStack : : Language : : Assembly )
2017-02-17 15:04:42 +00:00
# define CHECK_PARSE_ERROR(text, type, substring) \
2017-06-28 17:30:13 +00:00
CHECK_ERROR ( text , false , type , substring , false )
# define CHECK_PARSE_WARNING(text, type, substring) \
CHECK_ERROR ( text , false , type , substring , false )
2017-02-17 15:04:42 +00:00
# define CHECK_ASSEMBLE_ERROR(text, type, substring) \
2017-06-28 17:30:13 +00:00
CHECK_ERROR ( text , true , type , substring , false )
2017-02-17 15:04:42 +00:00
2018-01-06 00:24:45 +00:00
# define CHECK_STRICT_ERROR(text, type, substring) \
CHECK_ERROR_LANG ( text , false , type , substring , false , AssemblyStack : : Language : : StrictAssembly )
# define CHECK_STRICT_WARNING(text, type, substring) \
CHECK_ERROR ( text , false , type , substring , false , AssemblyStack : : Language : : StrictAssembly )
# define SUCCESS_STRICT(text) \
do { successParse ( ( text ) , false , false , AssemblyStack : : Language : : StrictAssembly ) ; } while ( false )
2017-02-17 15:04:42 +00:00
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_SUITE ( SolidityInlineAssembly )
2017-02-14 14:40:58 +00:00
BOOST_AUTO_TEST_SUITE ( Parsing )
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( smoke_test )
{
BOOST_CHECK ( successParse ( " { } " ) ) ;
}
2018-02-20 17:39:00 +00:00
BOOST_AUTO_TEST_CASE ( surplus_input )
{
2018-05-02 18:49:36 +00:00
CHECK_PARSE_ERROR ( " { } { } " , ParserError , " Expected end of source but got '{' " ) ;
2018-02-20 17:39:00 +00:00
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( simple_instructions )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { let y := mul(0x10, mul(0x20, mload(0x40)))} " ) ) ;
2016-02-22 01:13:41 +00:00
}
2018-04-16 22:46:14 +00:00
BOOST_AUTO_TEST_CASE ( selfdestruct )
2016-10-05 11:00:36 +00:00
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { selfdestruct(0x02) } " ) ) ;
2016-10-05 11:00:36 +00:00
}
2016-04-05 12:57:40 +00:00
BOOST_AUTO_TEST_CASE ( keywords )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { return (byte(1, 2), 2) pop(address()) } " ) ) ;
2016-04-05 12:57:40 +00:00
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( constants )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { pop(mul(7, 8)) } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( vardecl )
{
BOOST_CHECK ( successParse ( " { let x := 7 } " ) ) ;
}
2017-05-06 14:49:22 +00:00
BOOST_AUTO_TEST_CASE ( vardecl_name_clashes )
{
CHECK_PARSE_ERROR ( " { let x := 1 let x := 2 } " , DeclarationError , " Variable name x already taken in this scope. " ) ;
}
BOOST_AUTO_TEST_CASE ( vardecl_multi )
{
BOOST_CHECK ( successParse ( " { function f() -> x, y {} let x, y := f() } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( vardecl_multi_conflict )
{
CHECK_PARSE_ERROR ( " { function f() -> x, y {} let x, x := f() } " , DeclarationError , " Variable name x already taken in this scope. " ) ;
}
2017-05-17 12:20:24 +00:00
BOOST_AUTO_TEST_CASE ( vardecl_bool )
{
2019-12-19 16:58:20 +00:00
successParse ( " { let x := true } " ) ;
successParse ( " { let x := false } " ) ;
2017-05-17 12:20:24 +00:00
}
2017-05-05 15:46:26 +00:00
BOOST_AUTO_TEST_CASE ( vardecl_empty )
{
BOOST_CHECK ( successParse ( " { let x } " ) ) ;
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( functional )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { let x := 2 x := add(add(7, mul(6, x)), mul(7, 8)) } " ) ) ;
2016-02-22 01:13:41 +00:00
}
2017-06-13 16:38:55 +00:00
BOOST_AUTO_TEST_CASE ( functional_partial )
{
2019-09-10 11:35:55 +00:00
CHECK_PARSE_ERROR ( " { let x := byte } " , ParserError , " Expected '(' but got '}' " ) ;
2017-06-13 16:38:55 +00:00
}
BOOST_AUTO_TEST_CASE ( functional_partial_success )
{
BOOST_CHECK ( successParse ( " { let x := byte(1, 2) } " ) ) ;
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( functional_assignment )
{
2017-02-17 15:05:22 +00:00
BOOST_CHECK ( successParse ( " { let x := 2 x := 7 } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( functional_assignment_complex )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { let x := 2 x := add(add(7, mul(6, x)), mul(7, 8)) } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( vardecl_complex )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successParse ( " { let y := 2 let x := add(add(7, mul(6, y)), mul(7, 8)) } " ) ) ;
2017-02-17 15:05:22 +00:00
}
BOOST_AUTO_TEST_CASE ( variable_use_before_decl )
{
CHECK_PARSE_ERROR ( " { x := 2 let x := 3 } " , DeclarationError , " Variable x used before it was declared. " ) ;
CHECK_PARSE_ERROR ( " { let x := mul(2, x) } " , DeclarationError , " Variable x used before it was declared. " ) ;
2016-02-22 01:13:41 +00:00
}
2017-11-21 12:36:41 +00:00
BOOST_AUTO_TEST_CASE ( if_statement )
{
BOOST_CHECK ( successParse ( " { if 42 {} } " ) ) ;
BOOST_CHECK ( successParse ( " { if 42 { let x := 3 } } " ) ) ;
BOOST_CHECK ( successParse ( " { function f() -> x {} if f() { pop(f()) } } " ) ) ;
}
2017-11-22 15:24:59 +00:00
BOOST_AUTO_TEST_CASE ( if_statement_scope )
{
BOOST_CHECK ( successParse ( " { let x := 2 if 42 { x := 3 } } " ) ) ;
CHECK_PARSE_ERROR ( " { if 32 { let x := 3 } x := 2 } " , DeclarationError , " Variable not found or variable not lvalue. " ) ;
}
2017-11-21 12:36:41 +00:00
BOOST_AUTO_TEST_CASE ( if_statement_invalid )
{
2019-09-10 11:35:55 +00:00
CHECK_PARSE_ERROR ( " { if mload {} } " , ParserError , " Expected '(' but got '{' " ) ;
2017-11-21 12:36:41 +00:00
BOOST_CHECK ( " { if calldatasize() {} " ) ;
2020-01-16 17:56:05 +00:00
CHECK_PARSE_ERROR ( " { if mstore(1, 1) {} } " , TypeError , " Expected expression to evaluate to one value, but got 0 values instead. " ) ;
2018-05-02 18:49:36 +00:00
CHECK_PARSE_ERROR ( " { if 32 let x := 3 } " , ParserError , " Expected '{' but got reserved keyword 'let' " ) ;
2017-11-21 12:36:41 +00:00
}
2017-05-23 11:26:01 +00:00
BOOST_AUTO_TEST_CASE ( switch_statement )
{
BOOST_CHECK ( successParse ( " { switch 42 default {} } " ) ) ;
BOOST_CHECK ( successParse ( " { switch 42 case 1 {} } " ) ) ;
BOOST_CHECK ( successParse ( " { switch 42 case 1 {} case 2 {} } " ) ) ;
BOOST_CHECK ( successParse ( " { switch 42 case 1 {} default {} } " ) ) ;
BOOST_CHECK ( successParse ( " { switch 42 case 1 {} case 2 {} default {} } " ) ) ;
BOOST_CHECK ( successParse ( " { switch mul(1, 2) case 1 {} case 2 {} default {} } " ) ) ;
BOOST_CHECK ( successParse ( " { function f() -> x {} switch f() case 1 {} case 2 {} default {} } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( switch_no_cases )
{
CHECK_PARSE_ERROR ( " { switch 42 } " , ParserError , " Switch statement without any cases. " ) ;
}
BOOST_AUTO_TEST_CASE ( switch_duplicate_case )
{
2019-01-15 12:40:10 +00:00
CHECK_PARSE_ERROR ( " { switch 42 case 1 {} case 1 {} default {} } " , DeclarationError , " Duplicate case defined. " ) ;
2017-05-23 11:26:01 +00:00
}
BOOST_AUTO_TEST_CASE ( switch_invalid_expression )
{
2020-05-27 14:30:48 +00:00
CHECK_PARSE_ERROR ( " { switch {} case 1 {} default {} } " , ParserError , " Literal or identifier expected. " ) ;
CHECK_PARSE_ERROR (
" { switch mload case 1 {} default {} } " ,
ParserError ,
" Expected '(' but got reserved keyword 'case' "
) ;
CHECK_PARSE_ERROR (
" { switch mstore(1, 1) case 1 {} default {} } " ,
TypeError ,
" Expected expression to evaluate to one value, but got 0 values instead. "
) ;
2017-05-23 11:26:01 +00:00
}
BOOST_AUTO_TEST_CASE ( switch_default_before_case )
{
2017-05-26 00:49:32 +00:00
CHECK_PARSE_ERROR ( " { switch 42 default {} case 1 {} } " , ParserError , " Case not allowed after default case. " ) ;
2017-05-23 11:26:01 +00:00
}
BOOST_AUTO_TEST_CASE ( switch_duplicate_default_case )
{
2017-05-26 00:49:32 +00:00
CHECK_PARSE_ERROR ( " { switch 42 default {} default {} } " , ParserError , " Only one default case allowed. " ) ;
2017-05-23 11:26:01 +00:00
}
BOOST_AUTO_TEST_CASE ( switch_invalid_case )
{
CHECK_PARSE_ERROR ( " { switch 42 case mul(1, 2) {} case 2 {} default {} } " , ParserError , " Literal expected. " ) ;
}
BOOST_AUTO_TEST_CASE ( switch_invalid_body )
{
2018-05-02 18:49:36 +00:00
CHECK_PARSE_ERROR ( " { switch 42 case 1 mul case 2 {} default {} } " , ParserError , " Expected '{' but got identifier " ) ;
2017-05-23 11:26:01 +00:00
}
2017-04-28 13:33:52 +00:00
BOOST_AUTO_TEST_CASE ( for_statement )
{
BOOST_CHECK ( successParse ( " { for {} 1 {} {} } " ) ) ;
2017-06-09 11:29:28 +00:00
BOOST_CHECK ( successParse ( " { for { let i := 1 } lt(i, 5) { i := add(i, 1) } {} } " ) ) ;
2017-04-28 13:33:52 +00:00
}
BOOST_AUTO_TEST_CASE ( for_invalid_expression )
{
2019-12-19 16:58:20 +00:00
CHECK_PARSE_ERROR ( " { for {} {} {} {} } " , ParserError , " Literal or identifier expected. " ) ;
2018-05-02 18:49:36 +00:00
CHECK_PARSE_ERROR ( " { for 1 1 {} {} } " , ParserError , " Expected '{' but got 'Number' " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 1 {} } " , ParserError , " Expected '{' but got 'Number' " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 {} 1 } " , ParserError , " Expected '{' but got 'Number' " ) ;
2019-09-10 11:35:55 +00:00
CHECK_PARSE_ERROR ( " { for {} mload {} {} } " , ParserError , " Expected '(' but got '{' " ) ;
2020-01-16 17:56:05 +00:00
CHECK_PARSE_ERROR ( " { for {} mstore(1, 1) {} {} } " , TypeError , " Expected expression to evaluate to one value, but got 0 values instead. " ) ;
2017-04-28 13:33:52 +00:00
}
2017-06-09 14:14:07 +00:00
BOOST_AUTO_TEST_CASE ( for_visibility )
{
BOOST_CHECK ( successParse ( " { for { let i := 1 } i { pop(i) } { pop(i) } } " ) ) ;
CHECK_PARSE_ERROR ( " { for {} i { let i := 1 } {} } " , DeclarationError , " Identifier not found " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 { let i := 1 } { pop(i) } } " , DeclarationError , " Identifier not found " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 { pop(i) } { let i := 1 } } " , DeclarationError , " Identifier not found " ) ;
CHECK_PARSE_ERROR ( " { for { pop(i) } 1 { let i := 1 } {} } " , DeclarationError , " Identifier not found " ) ;
CHECK_PARSE_ERROR ( " { for { pop(i) } 1 { } { let i := 1 } } " , DeclarationError , " Identifier not found " ) ;
CHECK_PARSE_ERROR ( " { for {} i {} { let i := 1 } } " , DeclarationError , " Identifier not found " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 { pop(i) } { let i := 1 } } " , DeclarationError , " Identifier not found " ) ;
2017-06-16 09:58:59 +00:00
CHECK_PARSE_ERROR ( " { for { let x := 1 } 1 { let x := 1 } {} } " , DeclarationError , " Variable name x already taken in this scope " ) ;
CHECK_PARSE_ERROR ( " { for { let x := 1 } 1 {} { let x := 1 } } " , DeclarationError , " Variable name x already taken in this scope " ) ;
CHECK_PARSE_ERROR ( " { let x := 1 for { let x := 1 } 1 {} {} } " , DeclarationError , " Variable name x already taken in this scope " ) ;
CHECK_PARSE_ERROR ( " { let x := 1 for {} 1 { let x := 1 } {} } " , DeclarationError , " Variable name x already taken in this scope " ) ;
CHECK_PARSE_ERROR ( " { let x := 1 for {} 1 {} { let x := 1 } } " , DeclarationError , " Variable name x already taken in this scope " ) ;
2017-06-09 14:14:07 +00:00
// Check that body and post are not sub-scopes of each other.
BOOST_CHECK ( successParse ( " { for {} 1 { let x := 1 } { let x := 1 } } " ) ) ;
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( blocks )
{
BOOST_CHECK ( successParse ( " { let x := 7 { let y := 3 } { let z := 2 } } " ) ) ;
}
2017-08-21 10:08:29 +00:00
BOOST_AUTO_TEST_CASE ( number_literals )
{
BOOST_CHECK ( successParse ( " { let x := 1 } " ) ) ;
CHECK_PARSE_ERROR ( " { let x := .1 } " , ParserError , " Invalid number literal. " ) ;
CHECK_PARSE_ERROR ( " { let x := 1e5 } " , ParserError , " Invalid number literal. " ) ;
CHECK_PARSE_ERROR ( " { let x := 67.235 } " , ParserError , " Invalid number literal. " ) ;
2018-01-04 23:25:41 +00:00
CHECK_STRICT_ERROR ( " { let x := 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff } " , TypeError , " Number literal too large (> 256 bits) " ) ;
2017-08-21 10:08:29 +00:00
}
2017-01-31 22:59:41 +00:00
BOOST_AUTO_TEST_CASE ( function_definitions )
{
2017-04-26 16:12:26 +00:00
BOOST_CHECK ( successParse ( " { function f() { } function g(a) -> x { } } " ) ) ;
2017-01-31 22:59:41 +00:00
}
BOOST_AUTO_TEST_CASE ( function_definitions_multiple_args )
{
2017-04-26 16:12:26 +00:00
BOOST_CHECK ( successParse ( " { function f(a, d) { } function g(a, d) -> x, y { } } " ) ) ;
2017-01-31 22:59:41 +00:00
}
2017-02-01 20:20:21 +00:00
BOOST_AUTO_TEST_CASE ( function_calls )
{
2017-04-26 16:12:26 +00:00
BOOST_CHECK ( successParse ( " { function f(a) -> b {} function g(a, b, c) {} function x() { g(1, 2, f(mul(2, 3))) x() } } " ) ) ;
2017-02-17 15:05:22 +00:00
}
BOOST_AUTO_TEST_CASE ( opcode_for_functions )
{
2019-05-22 22:25:39 +00:00
CHECK_PARSE_ERROR ( " { function gas() { } } " , ParserError , " Cannot use builtin " ) ;
2017-02-17 15:05:22 +00:00
}
BOOST_AUTO_TEST_CASE ( opcode_for_function_args )
{
2019-05-22 22:25:39 +00:00
CHECK_PARSE_ERROR ( " { function f(gas) { } } " , ParserError , " Cannot use builtin " ) ;
CHECK_PARSE_ERROR ( " { function f() -> gas { } } " , ParserError , " Cannot use builtin " ) ;
2017-02-17 15:05:22 +00:00
}
BOOST_AUTO_TEST_CASE ( name_clashes )
{
2019-02-18 13:51:05 +00:00
CHECK_PARSE_ERROR ( " { let g := 2 function g() { } } " , DeclarationError , " Variable name g already taken in this scope " ) ;
}
BOOST_AUTO_TEST_CASE ( name_clashes_function_subscope )
{
CHECK_PARSE_ERROR ( " { function g() { function g() {} } } " , DeclarationError , " Function name g already taken in this scope " ) ;
}
BOOST_AUTO_TEST_CASE ( name_clashes_function_subscope_reverse )
{
CHECK_PARSE_ERROR ( " { { function g() {} } function g() { } } " , DeclarationError , " Function name g already taken in this scope " ) ;
}
BOOST_AUTO_TEST_CASE ( name_clashes_function_variable_subscope )
{
CHECK_PARSE_ERROR ( " { function g() { let g := 0 } } " , DeclarationError , " Variable name g already taken in this scope " ) ;
}
BOOST_AUTO_TEST_CASE ( name_clashes_function_variable_subscope_reverse )
{
CHECK_PARSE_ERROR ( " { { let g := 0 } function g() { } } " , DeclarationError , " Variable name g already taken in this scope " ) ;
}
BOOST_AUTO_TEST_CASE ( functions_in_parallel_scopes )
{
BOOST_CHECK ( successParse ( " { { function g() {} } { function g() {} } } " ) ) ;
2017-02-17 15:05:22 +00:00
}
BOOST_AUTO_TEST_CASE ( variable_access_cross_functions )
{
2019-09-10 11:35:55 +00:00
CHECK_PARSE_ERROR ( " { let x := 2 function g() { pop(x) } } " , DeclarationError , " Identifier not found. " ) ;
2017-02-01 20:20:21 +00:00
}
2017-05-06 14:49:22 +00:00
BOOST_AUTO_TEST_CASE ( invalid_tuple_assignment )
{
2018-12-04 10:22:49 +00:00
CHECK_PARSE_ERROR ( " { let x, y := 1 } " , DeclarationError , " Variable count mismatch: 2 variables and 1 values " ) ;
2017-05-06 14:49:22 +00:00
}
2017-05-24 12:23:53 +00:00
BOOST_AUTO_TEST_CASE ( instruction_too_few_arguments )
{
2019-05-22 22:25:39 +00:00
CHECK_PARSE_ERROR ( " { pop(mul()) } " , TypeError , " Function expects 2 arguments but got 0. " ) ;
CHECK_PARSE_ERROR ( " { pop(mul(1)) } " , TypeError , " Function expects 2 arguments but got 1. " ) ;
2017-05-24 12:23:53 +00:00
}
BOOST_AUTO_TEST_CASE ( instruction_too_many_arguments )
{
2019-05-22 22:25:39 +00:00
CHECK_PARSE_ERROR ( " { pop(mul(1, 2, 3)) } " , TypeError , " Function expects 2 arguments but got 3 " ) ;
2017-05-24 12:23:53 +00:00
}
2017-08-21 10:29:04 +00:00
BOOST_AUTO_TEST_CASE ( recursion_depth )
{
string input ;
for ( size_t i = 0 ; i < 20000 ; i + + )
input + = " { " ;
input + = " let x := 0 " ;
for ( size_t i = 0 ; i < 20000 ; i + + )
input + = " } " ;
CHECK_PARSE_ERROR ( input , ParserError , " recursion " ) ;
}
2017-05-19 16:06:26 +00:00
BOOST_AUTO_TEST_CASE ( multiple_assignment )
{
2019-02-18 14:07:15 +00:00
CHECK_PARSE_ERROR ( " { let x function f() -> a, b {} 123, x := f() } " , ParserError , " Variable name must precede \" , \" in multiple assignment. " ) ;
CHECK_PARSE_ERROR ( " { let x function f() -> a, b {} x, 123 := f() } " , ParserError , " Variable name must precede \" := \" in assignment. " ) ;
2017-08-21 10:29:04 +00:00
2017-05-19 16:06:26 +00:00
/// NOTE: Travis hiccups if not having a variable
char const * text = R " (
{
function f ( a ) - > r1 , r2 {
r1 : = a
r2 : = 7
}
let x : = 9
let y : = 2
x , y : = f ( x )
}
) " ;
BOOST_CHECK ( successParse ( text ) ) ;
}
2017-08-21 10:29:04 +00:00
2017-02-14 14:40:58 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
BOOST_AUTO_TEST_SUITE ( Printing )
BOOST_AUTO_TEST_CASE ( print_smoke )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { } " ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_instructions )
{
2019-09-10 11:35:55 +00:00
parsePrintCompare ( " { pop(7) } " ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_subblock )
{
2019-09-10 11:35:55 +00:00
parsePrintCompare ( " { { pop(7) } } " ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_functional )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { let x := mul(sload(0x12), 7) } " ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_assignments )
{
2019-09-10 11:35:55 +00:00
parsePrintCompare ( " { \n let x := mul(2, 3) \n pop(7) \n x := add(1, 2) \n } " ) ;
2017-02-14 14:40:58 +00:00
}
2017-05-06 14:49:22 +00:00
BOOST_AUTO_TEST_CASE ( print_multi_assignments )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { \n function f() -> x, y \n { } \n let x, y := f() \n } " ) ;
2017-05-06 14:49:22 +00:00
}
2017-02-14 14:40:58 +00:00
BOOST_AUTO_TEST_CASE ( print_string_literals )
{
2019-09-10 11:35:55 +00:00
parsePrintCompare ( " { let x := \" \\ n' \\ xab \\ x95 \\ \" \" } " ) ;
2017-02-14 14:40:58 +00:00
}
2017-02-15 14:21:11 +00:00
BOOST_AUTO_TEST_CASE ( print_string_literal_unicode )
{
2017-03-22 12:21:41 +00:00
string source = " { let x := \" \\ u1bac \" } " ;
2019-05-08 10:41:19 +00:00
string parsed = " object \" object \" { \n code { let x := \" \\ xe1 \\ xae \\ xac \" } \n } \n " ;
2020-01-14 16:48:17 +00:00
AssemblyStack stack ( solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) , AssemblyStack : : Language : : Assembly , OptimiserSettings : : none ( ) ) ;
2017-05-31 10:39:50 +00:00
BOOST_REQUIRE ( stack . parseAndAnalyze ( " " , source ) ) ;
2017-02-15 14:21:11 +00:00
BOOST_REQUIRE ( stack . errors ( ) . empty ( ) ) ;
2017-05-31 10:39:50 +00:00
BOOST_CHECK_EQUAL ( stack . print ( ) , parsed ) ;
2018-11-07 11:01:43 +00:00
2019-05-08 10:41:19 +00:00
string parsedInner = " { let x := \" \\ xe1 \\ xae \\ xac \" } " ;
2018-11-07 11:01:43 +00:00
parsePrintCompare ( parsedInner ) ;
2017-02-15 14:21:11 +00:00
}
2017-11-22 15:24:59 +00:00
BOOST_AUTO_TEST_CASE ( print_if )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { if 2 { pop(mload(0)) } } " ) ;
2017-11-22 15:24:59 +00:00
}
2017-05-23 11:26:01 +00:00
BOOST_AUTO_TEST_CASE ( print_switch )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { \n switch 42 \n case 1 { } \n case 2 { } \n default { } \n } " ) ;
2017-05-23 11:26:01 +00:00
}
2017-04-28 13:33:52 +00:00
BOOST_AUTO_TEST_CASE ( print_for )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { \n let ret := 5 \n for { let i := 1 } lt(i, 15) { i := add(i, 1) } \n { ret := mul(ret, i) } \n } " ) ;
2017-04-28 13:33:52 +00:00
}
2017-02-14 15:08:33 +00:00
BOOST_AUTO_TEST_CASE ( function_definitions_multiple_args )
{
2019-05-08 10:41:19 +00:00
parsePrintCompare ( " { \n function f(a, d) \n { mstore(a, d) } \n function g(a, d) -> x, y \n { } \n } " ) ;
2017-02-14 15:08:33 +00:00
}
BOOST_AUTO_TEST_CASE ( function_calls )
{
2017-03-22 15:53:15 +00:00
string source = R " ({
function y ( )
2019-05-08 10:41:19 +00:00
{ }
2017-04-26 16:12:26 +00:00
function f ( a ) - > b
2019-05-08 10:41:19 +00:00
{ }
2017-03-22 15:53:15 +00:00
function g ( a , b , c )
2019-05-08 10:41:19 +00:00
{ }
2017-12-13 11:28:02 +00:00
g ( 1 , mul ( 2 , address ( ) ) , f ( mul ( 2 , caller ( ) ) ) )
2017-03-22 15:53:15 +00:00
y ( )
} ) " ;
boost : : replace_all ( source , " \t " , " " ) ;
parsePrintCompare ( source ) ;
2017-02-14 15:08:33 +00:00
}
2017-02-14 14:40:58 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
BOOST_AUTO_TEST_SUITE ( Analysis )
2016-03-01 21:56:39 +00:00
BOOST_AUTO_TEST_CASE ( string_literals )
{
BOOST_CHECK ( successAssemble ( " { let x := \" 12345678901234567890123456789012 \" } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( oversize_string_literals )
{
2017-02-20 10:42:23 +00:00
CHECK_ASSEMBLE_ERROR ( " { let x := \" 123456789012345678901234567890123 \" } " , TypeError , " String literal too long " ) ;
2016-03-01 21:56:39 +00:00
}
2016-10-07 23:03:56 +00:00
BOOST_AUTO_TEST_CASE ( magic_variables )
{
2019-09-10 11:35:55 +00:00
CHECK_ASSEMBLE_ERROR ( " { pop(this) } " , DeclarationError , " Identifier not found " ) ;
CHECK_ASSEMBLE_ERROR ( " { pop(ecrecover) } " , DeclarationError , " Identifier not found " ) ;
BOOST_CHECK ( successAssemble ( " { let ecrecover := 1 pop(ecrecover) } " ) ) ;
2016-10-07 23:03:56 +00:00
}
2017-04-11 17:24:38 +00:00
BOOST_AUTO_TEST_CASE ( stack_variables )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successAssemble ( " { let y := 3 { let z := 2 { let x := y } } } " ) ) ;
2016-10-20 11:30:10 +00:00
}
2017-01-27 21:24:58 +00:00
BOOST_AUTO_TEST_CASE ( designated_invalid_instruction )
{
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successAssemble ( " { invalid() } " ) ) ;
2017-01-27 21:24:58 +00:00
}
2017-01-25 16:27:01 +00:00
BOOST_AUTO_TEST_CASE ( inline_assembly_shadowed_instruction_declaration )
2017-01-25 16:24:43 +00:00
{
2019-05-22 22:25:39 +00:00
CHECK_ASSEMBLE_ERROR ( " { let gas := 1 } " , ParserError , " Cannot use builtin " ) ;
2017-01-25 16:24:43 +00:00
}
2017-02-09 16:34:48 +00:00
BOOST_AUTO_TEST_CASE ( revert )
{
BOOST_CHECK ( successAssemble ( " { revert(0, 0) } " ) ) ;
}
2017-05-24 16:34:19 +00:00
BOOST_AUTO_TEST_CASE ( function_calls )
{
BOOST_CHECK ( successAssemble ( " { function f() {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f() { let y := 2 } } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f() -> z { let y := 2 } } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f(a) { let y := 2 } } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f(a) { let y := a } } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f() -> x, y, z {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f(x, y, z) {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f(a, b) -> x, y, z { y := a } } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f() {} f() } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f() -> x, y { x := 1 y := 2} let a, b := f() } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function f(a, b) -> x, y { x := b y := a } let a, b := f(2, 3) } " ) ) ;
BOOST_CHECK ( successAssemble ( " { function rec(a) { rec(sub(a, 1)) } rec(2) } " ) ) ;
BOOST_CHECK ( successAssemble ( " { let r := 2 function f() -> x, y { x := 1 y := 2} let a, b := f() b := r } " ) ) ;
2017-06-09 09:43:33 +00:00
BOOST_CHECK ( successAssemble ( " { function f() { g() } function g() { f() } } " ) ) ;
2017-05-24 16:34:19 +00:00
}
2017-06-01 15:59:29 +00:00
BOOST_AUTO_TEST_CASE ( embedded_functions )
{
BOOST_CHECK ( successAssemble ( " { function f(r, s) -> x { function g(a) -> b { } x := g(2) } let x := f(2, 3) } " ) ) ;
}
2017-05-24 16:34:19 +00:00
BOOST_AUTO_TEST_CASE ( switch_statement )
{
BOOST_CHECK ( successAssemble ( " { switch 1 default {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { switch 1 case 1 {} default {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { switch 1 case 1 {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { let a := 3 switch a case 1 { a := 1 } case 2 { a := 5 } a := 9} " ) ) ;
BOOST_CHECK ( successAssemble ( " { let a := 2 switch calldataload(0) case 1 { a := 1 } case 2 { a := 5 } } " ) ) ;
}
2017-06-09 11:29:28 +00:00
BOOST_AUTO_TEST_CASE ( for_statement )
{
BOOST_CHECK ( successAssemble ( " { for {} 1 {} {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { let x := calldatasize() for { let i := 0} lt(i, x) { i := add(i, 1) } { mstore(i, 2) } } " ) ) ;
}
2017-11-22 15:24:59 +00:00
BOOST_AUTO_TEST_CASE ( if_statement )
{
BOOST_CHECK ( successAssemble ( " { if 1 {} } " ) ) ;
BOOST_CHECK ( successAssemble ( " { let x := 0 if eq(calldatasize(), 0) { x := 1 } mstore(0, x) } " ) ) ;
}
2017-06-09 11:29:28 +00:00
2017-05-24 16:34:19 +00:00
BOOST_AUTO_TEST_CASE ( large_constant )
{
auto source = R " ({
switch mul ( 1 , 2 )
case 0x0000000000000000000000000000000000000000000000000000000026121ff0 {
}
} ) " ;
BOOST_CHECK ( successAssemble ( source ) ) ;
}
2017-05-30 09:29:15 +00:00
BOOST_AUTO_TEST_CASE ( keccak256 )
{
BOOST_CHECK ( successAssemble ( " { pop(keccak256(0, 0)) } " ) ) ;
}
2017-05-16 16:45:08 +00:00
BOOST_AUTO_TEST_CASE ( returndatasize )
2017-05-29 12:46:42 +00:00
{
2020-01-14 16:48:17 +00:00
if ( ! solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . supportsReturndata ( ) )
2019-02-26 18:21:32 +00:00
return ;
2017-05-29 12:46:42 +00:00
BOOST_CHECK ( successAssemble ( " { let r := returndatasize() } " ) ) ;
}
2017-05-16 16:45:08 +00:00
BOOST_AUTO_TEST_CASE ( returndatacopy )
2017-05-29 12:46:42 +00:00
{
2020-01-14 16:48:17 +00:00
if ( ! solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . supportsReturndata ( ) )
2019-02-26 18:21:32 +00:00
return ;
2019-09-10 11:35:55 +00:00
BOOST_CHECK ( successAssemble ( " { returndatacopy(0, 32, 64) } " ) ) ;
2017-05-29 12:46:42 +00:00
}
BOOST_AUTO_TEST_CASE ( returndatacopy_functional )
2017-05-16 16:45:08 +00:00
{
2020-01-14 16:48:17 +00:00
if ( ! solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . supportsReturndata ( ) )
2019-02-26 18:21:32 +00:00
return ;
2017-05-16 16:45:08 +00:00
BOOST_CHECK ( successAssemble ( " { returndatacopy(0, 32, 64) } " ) ) ;
}
2017-06-08 14:44:03 +00:00
BOOST_AUTO_TEST_CASE ( staticcall )
{
2020-01-14 16:48:17 +00:00
if ( ! solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . hasStaticCall ( ) )
2019-02-26 18:21:32 +00:00
return ;
2017-06-08 14:44:03 +00:00
BOOST_CHECK ( successAssemble ( " { pop(staticcall(10000, 0x123, 64, 0x10, 128, 0x10)) } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( create2 )
{
2020-01-14 16:48:17 +00:00
if ( ! solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . hasCreate2 ( ) )
2019-02-26 18:21:32 +00:00
return ;
2017-06-08 14:44:03 +00:00
BOOST_CHECK ( successAssemble ( " { pop(create2(10, 0x123, 32, 64)) } " ) ) ;
}
2018-02-27 11:09:22 +00:00
BOOST_AUTO_TEST_CASE ( shift )
{
2020-01-14 16:48:17 +00:00
if ( ! solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . hasBitwiseShifting ( ) )
2019-02-26 18:21:32 +00:00
return ;
2018-02-27 11:09:22 +00:00
BOOST_CHECK ( successAssemble ( " { pop(shl(10, 32)) } " ) ) ;
BOOST_CHECK ( successAssemble ( " { pop(shr(10, 32)) } " ) ) ;
BOOST_CHECK ( successAssemble ( " { pop(sar(10, 32)) } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( shift_constantinople_warning )
{
2020-01-14 16:48:17 +00:00
if ( solidity : : test : : CommonOptions : : get ( ) . evmVersion ( ) . hasBitwiseShifting ( ) )
2018-04-06 12:48:17 +00:00
return ;
2020-02-17 11:56:44 +00:00
CHECK_PARSE_WARNING ( " { shl(10, 32) } " , TypeError , " The \" shl \" instruction is only available for Constantinople-compatible VMs " ) ;
CHECK_PARSE_WARNING ( " { shr(10, 32) } " , TypeError , " The \" shr \" instruction is only available for Constantinople-compatible VMs " ) ;
CHECK_PARSE_WARNING ( " { sar(10, 32) } " , TypeError , " The \" sar \" instruction is only available for Constantinople-compatible VMs " ) ;
2018-02-27 11:09:22 +00:00
}
2019-09-10 11:35:55 +00:00
BOOST_AUTO_TEST_CASE ( jump_error )
2017-06-13 18:10:26 +00:00
{
2019-10-25 15:01:18 +00:00
CHECK_PARSE_WARNING ( " { jump(44) } " , DeclarationError , " Function not found. " ) ;
CHECK_PARSE_WARNING ( " { jumpi(44, 2) } " , DeclarationError , " Function not found. " ) ;
2017-06-13 18:10:26 +00:00
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
2017-02-14 14:40:58 +00:00
BOOST_AUTO_TEST_SUITE_END ( )
2016-02-22 01:13:41 +00:00
} // end namespaces