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 .
*/
2017-02-17 15:04:42 +00:00
# include "../TestHelper.h"
2017-05-31 10:39:50 +00:00
# include <libsolidity/interface/AssemblyStack.h>
2017-02-17 15:04:42 +00:00
# include <libsolidity/parsing/Scanner.h>
2016-02-22 01:13:41 +00:00
# include <libsolidity/interface/Exceptions.h>
# include <libsolidity/ast/AST.h>
2017-02-17 15:04:42 +00:00
# include <test/libsolidity/ErrorCheck.h>
# include <libevmasm/Assembly.h>
# include <boost/optional.hpp>
2017-04-21 22:05:12 +00:00
# include <boost/algorithm/string/replace.hpp>
2017-02-17 15:04:42 +00:00
# include <string>
# include <memory>
2016-02-22 01:13:41 +00:00
using namespace std ;
namespace dev
{
namespace solidity
{
namespace test
{
namespace
{
2017-05-31 10:39:50 +00:00
boost : : optional < Error > parseAndReturnFirstError (
string const & _source ,
bool _assemble = false ,
bool _allowWarnings = true ,
AssemblyStack : : Machine _machine = AssemblyStack : : Machine : : EVM
)
2016-02-22 01:13:41 +00:00
{
2017-05-31 10:39:50 +00:00
AssemblyStack stack ;
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 )
2017-05-31 10:39: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 )
BOOST_FAIL ( " Found more than one error. " ) ;
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 ,
AssemblyStack : : Machine _machine = AssemblyStack : : Machine : : EVM
)
2017-02-17 15:04:42 +00:00
{
2017-05-31 10:39:50 +00:00
return ! parseAndReturnFirstError ( _source , _assemble , _allowWarnings , _machine ) ;
2016-02-22 01:13:41 +00:00
}
2016-11-15 08:16:33 +00:00
bool successAssemble ( string const & _source , bool _allowWarnings = true )
2016-03-01 21:56:39 +00:00
{
2017-05-31 10:39:50 +00:00
return successParse ( _source , true , _allowWarnings , AssemblyStack : : Machine : : EVM ) & &
successParse ( _source , true , _allowWarnings , AssemblyStack : : Machine : : EVM15 ) ;
2016-03-01 21:56:39 +00:00
}
2017-02-17 15:04:42 +00:00
Error expectError ( std : : string const & _source , bool _assemble , bool _allowWarnings = false )
{
auto error = parseAndReturnFirstError ( _source , _assemble , _allowWarnings ) ;
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
{
2017-05-31 10:39:50 +00:00
AssemblyStack stack ;
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 ( ) ) ;
2017-05-31 10:39:50 +00:00
BOOST_CHECK_EQUAL ( stack . print ( ) , _source ) ;
2017-02-14 14:40:58 +00:00
}
2016-02-22 01:13:41 +00:00
}
2017-06-28 17:30:13 +00:00
# define CHECK_ERROR(text, assemble, typ, substring, warnings) \
2017-02-17 15:04:42 +00:00
do \
{ \
2017-06-28 17:30:13 +00:00
Error err = expectError ( ( text ) , ( assemble ) , warnings ) ; \
2017-02-17 15:04:42 +00:00
BOOST_CHECK ( err . type ( ) = = ( Error : : Type : : typ ) ) ; \
BOOST_CHECK ( searchErrorMessage ( err , ( substring ) ) ) ; \
} while ( 0 )
# 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
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 ( " { } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( simple_instructions )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { dup1 dup1 mul dup1 sub pop } " ) ) ;
2016-02-22 01:13:41 +00:00
}
2016-10-05 11:00:36 +00:00
BOOST_AUTO_TEST_CASE ( suicide_selfdestruct )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { 0x01 suicide 0x02 selfdestruct } " ) ) ;
2016-10-05 11:00:36 +00:00
}
2016-04-05 12:57:40 +00:00
BOOST_AUTO_TEST_CASE ( keywords )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { 1 2 byte 2 return address pop } " ) ) ;
2016-04-05 12:57:40 +00:00
}
2016-02-22 01:13:41 +00:00
BOOST_AUTO_TEST_CASE ( constants )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { 7 8 mul pop } " ) ) ;
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 )
{
CHECK_PARSE_ERROR ( " { let x := true } " , ParserError , " True and false are not valid literals. " ) ;
CHECK_PARSE_ERROR ( " { let x := false } " , ParserError , " True and false are not valid literals. " ) ;
}
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 ( assignment )
{
2017-02-17 15:05:22 +00:00
BOOST_CHECK ( successParse ( " { let x := 2 7 8 add =: x } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( label )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { 7 abc: 8 eq abc jump pop } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( label_complex )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { 7 abc: 8 eq jump(abc) jumpi(eq(7, 8), abc) pop } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( functional )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { let x := 2 add(7, mul(6, x)) mul(7, 8) add =: x } " ) ) ;
2016-02-22 01:13:41 +00:00
}
2017-06-13 16:38:55 +00:00
BOOST_AUTO_TEST_CASE ( functional_partial )
{
CHECK_PARSE_ERROR ( " { let x := byte } " , ParserError , " Expected token \" ( \" " ) ;
}
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 )
{
2017-02-17 15:05:22 +00:00
BOOST_CHECK ( successParse ( " { let x := 2 x := add(7, mul(6, x)) mul(7, 8) add } " ) ) ;
2016-02-22 01:13:41 +00:00
}
BOOST_AUTO_TEST_CASE ( vardecl_complex )
{
2017-02-17 15:05:22 +00:00
BOOST_CHECK ( successParse ( " { let y := 2 let x := add(7, mul(6, y)) add mul(7, 8) } " ) ) ;
}
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 )
{
CHECK_PARSE_ERROR ( " { if calldatasize {} " , ParserError , " Instructions are not supported as conditions for if " ) ;
BOOST_CHECK ( " { if calldatasize() {} " ) ;
CHECK_PARSE_ERROR ( " { if mstore(1, 1) {} } " , ParserError , " Instruction \" mstore \" not allowed in this context " ) ;
CHECK_PARSE_ERROR ( " { if 32 let x := 3 } " , ParserError , " Expected token LBrace " ) ;
}
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 )
{
CHECK_PARSE_ERROR ( " { switch 42 case 1 {} case 1 {} default {} } " , DeclarationError , " Duplicate case defined " ) ;
}
BOOST_AUTO_TEST_CASE ( switch_invalid_expression )
{
2017-05-26 10:16:12 +00:00
CHECK_PARSE_ERROR ( " { switch {} default {} } " , ParserError , " Literal, identifier or instruction expected. " ) ;
2017-11-21 12:36:41 +00:00
CHECK_PARSE_ERROR ( " { switch calldatasize default {} } " , ParserError , " Instructions are not supported as expressions for switch " ) ;
2017-06-09 11:29:28 +00:00
CHECK_PARSE_ERROR ( " { switch mstore(1, 1) default {} } " , ParserError , " Instruction \" mstore \" not allowed in this context " ) ;
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 )
{
CHECK_PARSE_ERROR ( " { switch 42 case 1 mul case 2 {} default {} } " , ParserError , " Expected token LBrace got 'Identifier' " ) ;
}
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 )
{
CHECK_PARSE_ERROR ( " { for {} {} {} {} } " , ParserError , " Literal, identifier or instruction expected. " ) ;
2017-06-09 11:29:28 +00:00
CHECK_PARSE_ERROR ( " { for 1 1 {} {} } " , ParserError , " Expected token LBrace got 'Number' " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 1 {} } " , ParserError , " Expected token LBrace got 'Number' " ) ;
CHECK_PARSE_ERROR ( " { for {} 1 {} 1 } " , ParserError , " Expected token LBrace got 'Number' " ) ;
2017-06-14 16:53:10 +00:00
CHECK_PARSE_ERROR ( " { for {} calldatasize {} {} } " , ParserError , " Instructions are not supported as conditions for the for statement. " ) ;
2017-06-09 11:29:28 +00:00
CHECK_PARSE_ERROR ( " { for {} mstore(1, 1) {} {} } " , ParserError , " Instruction \" mstore \" not allowed in this context " ) ;
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. " ) ;
}
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 )
{
CHECK_PARSE_ERROR ( " { function gas() { } } " , ParserError , " Cannot use instruction names for identifier names. " ) ;
}
BOOST_AUTO_TEST_CASE ( opcode_for_function_args )
{
CHECK_PARSE_ERROR ( " { function f(gas) { } } " , ParserError , " Cannot use instruction names for identifier names. " ) ;
2017-04-26 16:12:26 +00:00
CHECK_PARSE_ERROR ( " { function f() -> gas { } } " , ParserError , " Cannot use instruction names for identifier names. " ) ;
2017-02-17 15:05:22 +00:00
}
BOOST_AUTO_TEST_CASE ( name_clashes )
{
CHECK_PARSE_ERROR ( " { let g := 2 function g() { } } " , DeclarationError , " Function name g already taken in this scope " ) ;
}
BOOST_AUTO_TEST_CASE ( variable_access_cross_functions )
{
2017-03-22 12:21:41 +00:00
CHECK_PARSE_ERROR ( " { let x := 2 function g() { x pop } } " , 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 )
{
/// The push(42) is added here to silence the unbalanced stack error, so that there's only one error reported.
CHECK_PARSE_ERROR ( " { 42 let x, y := 1 } " , DeclarationError , " Variable count mismatch. " ) ;
}
2017-05-24 12:23:53 +00:00
BOOST_AUTO_TEST_CASE ( instruction_too_few_arguments )
{
2017-06-09 12:44:38 +00:00
CHECK_PARSE_ERROR ( " { mul() } " , ParserError , " Expected expression ( \" mul \" expects 2 arguments) " ) ;
CHECK_PARSE_ERROR ( " { mul(1) } " , ParserError , " Expected comma ( \" mul \" expects 2 arguments) " ) ;
2017-05-24 12:23:53 +00:00
}
BOOST_AUTO_TEST_CASE ( instruction_too_many_arguments )
{
2017-06-09 12:44:38 +00:00
CHECK_PARSE_ERROR ( " { mul(1, 2, 3) } " , ParserError , " Expected ')' ( \" mul \" expects 2 arguments) " ) ;
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 )
{
CHECK_PARSE_ERROR ( " { let x function f() -> a, b {} 123, x := f() } " , ParserError , " Label name / variable name must precede \" , \" (multiple assignment). " ) ;
CHECK_PARSE_ERROR ( " { let x function f() -> a, b {} x, 123 := f() } " , ParserError , " Variable name expected in multiple assignemnt. " ) ;
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 )
{
parsePrintCompare ( " { \n } " ) ;
}
BOOST_AUTO_TEST_CASE ( print_instructions )
{
2017-03-22 12:21:41 +00:00
parsePrintCompare ( " { \n 7 \n 8 \n mul \n dup10 \n add \n pop \n } " ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_subblock )
{
parsePrintCompare ( " { \n { \n dup4 \n add \n } \n } " ) ;
}
BOOST_AUTO_TEST_CASE ( print_functional )
{
2017-03-22 12:21:41 +00:00
parsePrintCompare ( " { \n let x := mul(sload(0x12), 7) \n } " ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_label )
{
2017-06-28 17:30:13 +00:00
parsePrintCompare ( " { \n loop: \n jump(loop) \n } " , true ) ;
2017-02-14 14:40:58 +00:00
}
BOOST_AUTO_TEST_CASE ( print_assignments )
{
parsePrintCompare ( " { \n let x := mul(2, 3) \n 7 \n =: x \n x := add(1, 2) \n } " ) ;
}
2017-05-06 14:49:22 +00:00
BOOST_AUTO_TEST_CASE ( print_multi_assignments )
{
parsePrintCompare ( " { \n function f() -> x, y \n { \n } \n let x, y := f() \n } " ) ;
}
2017-02-14 14:40:58 +00:00
BOOST_AUTO_TEST_CASE ( print_string_literals )
{
2017-03-22 12:21:41 +00:00
parsePrintCompare ( " { \n \" \\ n' \\ xab \\ x95 \\ \" \" \n pop \n } " ) ;
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 \" } " ;
string parsed = " { \n let x := \" \\ xe1 \\ xae \\ xac \" \n } " ;
2017-05-31 10:39:50 +00:00
AssemblyStack stack ;
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 ) ;
2017-02-15 14:21:11 +00:00
parsePrintCompare ( parsed ) ;
}
2017-11-22 15:24:59 +00:00
BOOST_AUTO_TEST_CASE ( print_if )
{
parsePrintCompare ( " { \n if 2 \n { \n pop(mload(0)) \n } \n } " ) ;
}
2017-05-23 11:26:01 +00:00
BOOST_AUTO_TEST_CASE ( print_switch )
{
parsePrintCompare ( " { \n switch 42 \n case 1 { \n } \n case 2 { \n } \n default { \n } \n } " ) ;
}
2017-04-28 13:33:52 +00:00
BOOST_AUTO_TEST_CASE ( print_for )
{
2017-06-09 11:29:28 +00:00
parsePrintCompare ( " { \n let ret := 5 \n for { \n let i := 1 \n } \n lt(i, 15) \n { \n i := add(i, 1) \n } \n { \n ret := mul(ret, i) \n } \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 )
{
2017-04-26 16:12:26 +00:00
parsePrintCompare ( " { \n function f(a, d) \n { \n mstore(a, d) \n } \n function g(a, d) -> x, y \n { \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 ( )
{
}
2017-04-26 16:12:26 +00:00
function f ( a ) - > b
2017-03-22 15:53:15 +00:00
{
}
function g ( a , b , c )
{
}
g ( 1 , mul ( 2 , address ) , f ( mul ( 2 , caller ) ) )
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-06 13:32:11 +00:00
BOOST_AUTO_TEST_CASE ( assignment_after_tag )
{
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successParse ( " { let x := 1 { 7 tag: =: x } } " ) ) ;
2016-10-06 13:32:11 +00:00
}
2016-10-07 23:03:56 +00:00
BOOST_AUTO_TEST_CASE ( magic_variables )
{
2017-02-17 15:05:22 +00:00
CHECK_ASSEMBLE_ERROR ( " { this pop } " , DeclarationError , " Identifier not found " ) ;
CHECK_ASSEMBLE_ERROR ( " { ecrecover pop } " , DeclarationError , " Identifier not found " ) ;
2017-03-22 12:21:41 +00:00
BOOST_CHECK ( successAssemble ( " { let ecrecover := 1 ecrecover pop } " ) ) ;
2016-10-07 23:03:56 +00:00
}
2017-04-11 17:24:38 +00:00
BOOST_AUTO_TEST_CASE ( stack_variables )
{
BOOST_CHECK ( successAssemble ( " { let y := 3 { 2 { let x := y } pop} } " ) ) ;
}
2016-11-15 08:16:33 +00:00
BOOST_AUTO_TEST_CASE ( imbalanced_stack )
{
BOOST_CHECK ( successAssemble ( " { 1 2 mul pop } " , false ) ) ;
2017-03-22 12:21:41 +00:00
CHECK_ASSEMBLE_ERROR ( " { 1 } " , DeclarationError , " Unbalanced stack at the end of a block: 1 surplus item(s). " ) ;
CHECK_ASSEMBLE_ERROR ( " { pop } " , DeclarationError , " Unbalanced stack at the end of a block: 1 missing item(s). " ) ;
2016-11-15 08:16:33 +00:00
BOOST_CHECK ( successAssemble ( " { let x := 4 7 add } " , false ) ) ;
}
2016-10-20 11:30:10 +00:00
BOOST_AUTO_TEST_CASE ( error_tag )
{
2017-06-28 17:30:13 +00:00
CHECK_ERROR ( " { jump(invalidJumpLabel) } " , true , DeclarationError , " Identifier not found " , true ) ;
2016-10-20 11:30:10 +00:00
}
2017-01-27 21:24:58 +00:00
BOOST_AUTO_TEST_CASE ( designated_invalid_instruction )
{
BOOST_CHECK ( successAssemble ( " { invalid } " ) ) ;
}
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
{
2017-02-17 15:04:42 +00:00
CHECK_ASSEMBLE_ERROR ( " { let gas := 1 } " , ParserError , " Cannot use instruction names for identifier names. " ) ;
2017-01-25 16:24:43 +00:00
}
2017-01-25 16:27:01 +00:00
BOOST_AUTO_TEST_CASE ( inline_assembly_shadowed_instruction_assignment )
{
2017-02-17 15:04:42 +00:00
CHECK_ASSEMBLE_ERROR ( " { 2 =: gas } " , ParserError , " Identifier expected, got instruction name. " ) ;
2017-01-25 16:27:01 +00:00
}
2017-01-26 12:40:40 +00:00
BOOST_AUTO_TEST_CASE ( inline_assembly_shadowed_instruction_functional_assignment )
{
2017-02-17 15:04:42 +00:00
CHECK_ASSEMBLE_ERROR ( " { gas := 2 } " , ParserError , " Label name / variable name must precede \" : \" " ) ;
2017-01-26 12:40:40 +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 ( " { 0 0 keccak256 pop } " ) ) ;
BOOST_CHECK ( successAssemble ( " { pop(keccak256(0, 0)) } " ) ) ;
BOOST_CHECK ( successAssemble ( " { 0 0 sha3 pop } " ) ) ;
BOOST_CHECK ( successAssemble ( " { pop(sha3(0, 0)) } " ) ) ;
}
2017-05-16 16:45:08 +00:00
BOOST_AUTO_TEST_CASE ( returndatasize )
{
BOOST_CHECK ( successAssemble ( " { let r := returndatasize } " ) ) ;
}
2017-05-29 12:46:42 +00:00
BOOST_AUTO_TEST_CASE ( returndatasize_functional )
{
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
{
BOOST_CHECK ( successAssemble ( " { 64 32 0 returndatacopy } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( returndatacopy_functional )
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 )
{
BOOST_CHECK ( successAssemble ( " { pop(staticcall(10000, 0x123, 64, 0x10, 128, 0x10)) } " ) ) ;
}
BOOST_AUTO_TEST_CASE ( create2 )
{
BOOST_CHECK ( successAssemble ( " { pop(create2(10, 0x123, 32, 64)) } " ) ) ;
}
2017-06-13 18:10:26 +00:00
BOOST_AUTO_TEST_CASE ( jump_warning )
{
2017-06-28 17:30:13 +00:00
CHECK_PARSE_WARNING ( " { 1 jump } " , Warning , " Jump instructions " ) ;
CHECK_PARSE_WARNING ( " { 1 2 jumpi } " , Warning , " Jump instructions " ) ;
CHECK_PARSE_WARNING ( " { a: jump(a) } " , Warning , " Jump instructions " ) ;
CHECK_PARSE_WARNING ( " { a: jumpi(a, 2) } " , Warning , " Jump instructions " ) ;
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