@ -4,20 +4,16 @@
using namespace peg ;
# if !defined(PEGLIB_NO_UNICODE_CHARS)
TEST_CASE ( " Simple syntax test (with unicode) " , " [general] " )
{
parser parser (
u8 " ROOT ← _ "
" _ <- ' ' "
) ;
TEST_CASE ( " Simple syntax test (with unicode) " , " [general] " ) {
parser parser ( u8 " ROOT ← _ "
" _ <- ' ' " ) ;
bool ret = parser ;
REQUIRE ( ret = = true ) ;
}
# endif
TEST_CASE ( " Simple syntax test " , " [general] " )
{
TEST_CASE ( " Simple syntax test " , " [general] " ) {
parser parser ( R " (
ROOT < - _
_ < - ' '
@ -27,15 +23,13 @@ TEST_CASE("Simple syntax test", "[general]")
REQUIRE ( ret = = true ) ;
}
TEST_CASE ( " Empty syntax test " , " [general] " )
{
TEST_CASE ( " Empty syntax test " , " [general] " ) {
parser parser ( " " ) ;
bool ret = parser ;
REQUIRE ( ret = = false ) ;
}
TEST_CASE ( " Start rule with ignore operator test " , " [general] " )
{
TEST_CASE ( " Start rule with ignore operator test " , " [general] " ) {
parser parser ( R " (
~ ROOT < - _
_ < - ' '
@ -45,19 +39,17 @@ TEST_CASE("Start rule with ignore operator test", "[general]")
REQUIRE ( ret = = false ) ;
}
TEST_CASE ( " Invalid UTF-8 text test " , " [general] " )
{
TEST_CASE ( " Invalid UTF-8 text test " , " [general] " ) {
std : : string s = " a <- ' " ;
s + = static_cast < char > ( 0xe8 ) ; // Make invalid utf8 text...
parser parser ( s . c_str ( ) ) ;
parser parser ( s . data ( ) ) ;
bool ret = parser ;
REQUIRE ( ret = = false ) ;
}
TEST_CASE ( " Backslash escape sequence test " , " [general] " )
{
TEST_CASE ( " Backslash escape sequence test " , " [general] " ) {
parser parser ( R " (
ROOT < - _
_ < - ' \\ '
@ -67,8 +59,7 @@ TEST_CASE("Backslash escape sequence test", "[general]")
REQUIRE ( ret = = true ) ;
}
TEST_CASE ( " Invalid escape sequence test " , " [general] " )
{
TEST_CASE ( " Invalid escape sequence test " , " [general] " ) {
parser parser ( R " (
ROOT < - _
_ < - ' \ '
@ -78,22 +69,19 @@ TEST_CASE("Invalid escape sequence test", "[general]")
REQUIRE ( ret = = false ) ;
}
TEST_CASE ( " Action taking non const Semantic Values parameter " , " [general] " )
{
TEST_CASE ( " Action taking non const Semantic Values parameter " , " [general] " ) {
parser parser ( R " (
ROOT < - TEXT
TEXT < - [ a - zA - Z ] +
) " );
parser [ " ROOT " ] = [ & ] ( SemanticValues & s v) {
auto s = any_cast < std : : string > ( s v[ 0 ] ) ;
parser [ " ROOT " ] = [ & ] ( SemanticValues & vs ) {
auto s = std : : string ( std : : any_cast < std : : string_view > ( vs [ 0 ] ) ) ;
s [ 0 ] = ' H ' ; // mutate
return std : : string ( std : : move ( s ) ) ; // move
return s ; // move
} ;
parser [ " TEXT " ] = [ & ] ( SemanticValues & sv ) {
return sv . token ( ) ;
} ;
parser [ " TEXT " ] = [ & ] ( SemanticValues & vs ) { return vs . token ( ) ; } ;
std : : string val ;
auto ret = parser . parse ( " hello " , val ) ;
@ -101,18 +89,17 @@ TEST_CASE("Action taking non const Semantic Values parameter", "[general]")
REQUIRE ( val = = " Hello " ) ;
}
TEST_CASE ( " String capture test " , " [general] " )
{
TEST_CASE ( " String capture test " , " [general] " ) {
parser parser ( R " (
ROOT < - _ ( ' [ ' TAG_NAME ' ] ' _ ) *
TAG_NAME < - ( ! ' ] ' . ) +
_ < - [ \ t ] *
) " );
std : : vector < std : : string > tags ;
std : : vector < std : : string_view > tags ;
parser [ " TAG_NAME " ] = [ & ] ( const SemanticValues & s v) {
tags . push_back ( sv . str ( ) ) ;
parser [ " TAG_NAME " ] = [ & ] ( const SemanticValues & vs ) {
tags . push_back ( vs . sv ( ) ) ;
} ;
auto ret = parser . parse ( " [tag1] [tag:2] [tag-3] " ) ;
@ -126,14 +113,14 @@ TEST_CASE("String capture test", "[general]")
using namespace peg ;
TEST_CASE ( " String capture test2 " , " [general] " )
{
std : : vector < std : : string > tags ;
TEST_CASE ( " String capture test2 " , " [general] " ) {
std : : vector < std : : string_view > tags ;
Definition ROOT , TAG , TAG_NAME , WS ;
ROOT < = seq ( WS , zom ( TAG ) ) ;
TAG < = seq ( chr ( ' [ ' ) , TAG_NAME , chr ( ' ] ' ) , WS ) ;
TAG_NAME < = oom ( seq ( npd ( chr ( ' ] ' ) ) , dot ( ) ) ) , [ & ] ( const SemanticValues & sv ) { tags . push_back ( sv . str ( ) ) ; } ;
TAG_NAME < = oom ( seq ( npd ( chr ( ' ] ' ) ) , dot ( ) ) ) ,
[ & ] ( const SemanticValues & vs ) { tags . push_back ( vs . sv ( ) ) ; } ;
WS < = zom ( cls ( " \t " ) ) ;
auto r = ROOT . parse ( " [tag1] [tag:2] [tag-3] " ) ;
@ -145,20 +132,16 @@ TEST_CASE("String capture test2", "[general]")
REQUIRE ( tags [ 2 ] = = " tag-3 " ) ;
}
TEST_CASE ( " String capture test3 " , " [general] " )
{
TEST_CASE ( " String capture test3 " , " [general] " ) {
parser pg ( R " (
ROOT < - _ TOKEN *
TOKEN < - ' [ ' < ( ! ' ] ' . ) + > ' ] ' _
_ < - [ \ t \ r \ n ] *
) " );
std : : vector < std : : string_view > tags ;
std : : vector < std : : string > tags ;
pg [ " TOKEN " ] = [ & ] ( const SemanticValues & sv ) {
tags . push_back ( sv . token ( ) ) ;
} ;
pg [ " TOKEN " ] = [ & ] ( const SemanticValues & vs ) { tags . push_back ( vs . token ( ) ) ; } ;
auto ret = pg . parse ( " [tag1] [tag:2] [tag-3] " ) ;
@ -169,8 +152,7 @@ TEST_CASE("String capture test3", "[general]")
REQUIRE ( tags [ 2 ] = = " tag-3 " ) ;
}
TEST_CASE ( " Cyclic grammer test " , " [general] " )
{
TEST_CASE ( " Cyclic grammer test " , " [general] " ) {
Definition PARENT ;
Definition CHILD ;
@ -178,8 +160,7 @@ TEST_CASE("Cyclic grammer test", "[general]")
CHILD < = seq ( PARENT ) ;
}
TEST_CASE ( " Visit test " , " [general] " )
{
TEST_CASE ( " Visit test " , " [general] " ) {
Definition ROOT , TAG , TAG_NAME , WS ;
ROOT < = seq ( WS , zom ( TAG ) ) ;
@ -193,8 +174,7 @@ TEST_CASE("Visit test", "[general]")
REQUIRE ( defIds . ids . size ( ) = = 4 ) ;
}
TEST_CASE ( " Token check test " , " [general] " )
{
TEST_CASE ( " Token check test " , " [general] " ) {
parser parser ( R " (
EXPRESSION < - _ TERM ( TERM_OPERATOR TERM ) *
TERM < - FACTOR ( FACTOR_OPERATOR FACTOR ) *
@ -212,25 +192,21 @@ TEST_CASE("Token check test", "[general]")
REQUIRE ( parser [ " _ " ] . is_token ( ) = = true ) ;
}
TEST_CASE ( " Lambda action test " , " [general] " )
{
TEST_CASE ( " Lambda action test " , " [general] " ) {
parser parser ( R " (
START < - ( CHAR ) *
CHAR < - .
) " );
std : : string ss ;
parser [ " CHAR " ] = [ & ] ( const SemanticValues & sv ) {
ss + = * sv . c_str ( ) ;
} ;
parser [ " CHAR " ] = [ & ] ( const SemanticValues & vs ) { ss + = * vs . sv ( ) . data ( ) ; } ;
bool ret = parser . parse ( " hello " ) ;
REQUIRE ( ret = = true ) ;
REQUIRE ( ss = = " hello " ) ;
}
TEST_CASE ( " enter/leave handlers test " , " [general] " )
{
TEST_CASE ( " enter/leave handlers test " , " [general] " ) {
parser parser ( R " (
START < - LTOKEN ' = ' RTOKEN
LTOKEN < - TOKEN
@ -238,21 +214,22 @@ TEST_CASE("enter/leave handlers test", "[general]")
TOKEN < - [ A - Za - z ] +
) " );
parser [ " LTOKEN " ] . enter = [ & ] ( const char * , size_t , any & dt ) {
auto & require_upper_case = * any_cast < bool * > ( dt ) ;
parser [ " LTOKEN " ] . enter = [ & ] ( const char * , size_t , std : : any & dt ) {
auto & require_upper_case = * std : : any_cast < bool * > ( dt ) ;
require_upper_case = false ;
} ;
parser [ " LTOKEN " ] . leave = [ & ] ( const char * , size_t , size_t , any & , any & dt ) {
auto & require_upper_case = * any_cast < bool * > ( dt ) ;
parser [ " LTOKEN " ] . leave = [ & ] ( const char * , size_t , size_t , std : : any & ,
std : : any & dt ) {
auto & require_upper_case = * std : : any_cast < bool * > ( dt ) ;
require_upper_case = true ;
} ;
auto message = " should be upper case string... " ;
parser [ " TOKEN " ] = [ & ] ( const SemanticValues & s v, any & dt ) {
auto & require_upper_case = * any_cast < bool * > ( dt ) ;
parser [ " TOKEN " ] = [ & ] ( const SemanticValues & vs , std : : any & dt ) {
auto & require_upper_case = * std : : any_cast < bool * > ( dt ) ;
if ( require_upper_case ) {
const auto & s = sv . str ( ) ;
const auto & s = vs . sv ( ) ;
if ( ! std : : all_of ( s . begin ( ) , s . end ( ) , : : isupper ) ) {
throw parse_error ( message ) ;
}
@ -260,13 +237,13 @@ TEST_CASE("enter/leave handlers test", "[general]")
} ;
bool require_upper_case = false ;
any dt = & require_upper_case ;
std : : any dt = & require_upper_case ;
REQUIRE ( parser . parse ( " hello=world " , dt ) = = false ) ;
REQUIRE ( parser . parse ( " HELLO=world " , dt ) = = false ) ;
REQUIRE ( parser . parse ( " hello=WORLD " , dt ) = = true ) ;
REQUIRE ( parser . parse ( " HELLO=WORLD " , dt ) = = true ) ;
parser . log = [ & ] ( size_t ln , size_t col , const std : : string & msg ) {
parser . log = [ & ] ( size_t ln , size_t col , const std : : string & msg ) {
REQUIRE ( ln = = 1 ) ;
REQUIRE ( col = = 7 ) ;
REQUIRE ( msg = = message ) ;
@ -274,8 +251,7 @@ TEST_CASE("enter/leave handlers test", "[general]")
parser . parse ( " hello=world " , dt ) ;
}
TEST_CASE ( " WHITESPACE test " , " [general] " )
{
TEST_CASE ( " WHITESPACE test " , " [general] " ) {
parser parser ( R " (
# Rules
ROOT < - ITEM ( ' , ' ITEM ) *
@ -293,8 +269,7 @@ TEST_CASE("WHITESPACE test", "[general]")
REQUIRE ( ret = = true ) ;
}
TEST_CASE ( " WHITESPACE test2 " , " [general] " )
{
TEST_CASE ( " WHITESPACE test2 " , " [general] " ) {
parser parser ( R " (
# Rules
ROOT < - ITEM ( ' , ' ITEM ) *
@ -305,9 +280,9 @@ TEST_CASE("WHITESPACE test2", "[general]")
TAB < - ' \t '
) " );
std : : vector < std : : string > items ;
parser [ " ITEM " ] = [ & ] ( const SemanticValues & s v) {
items . push_back ( s v. token ( ) ) ;
std : : vector < std : : string_view > items ;
parser [ " ITEM " ] = [ & ] ( const SemanticValues & vs ) {
items . push_back ( vs . token ( ) ) ;
} ;
auto ret = parser . parse ( R " ([one], [two] ,[three] ) " ) ;
@ -328,8 +303,8 @@ TEST_CASE("WHITESPACE test3", "[general]") {
% whitespace < - [ \ t ] *
) " );
parser [ " StrQuot " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. token ( ) = = R " ( aaa \" bbb ) " ) ;
parser [ " StrQuot " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . token ( ) = = R " ( aaa \" bbb ) " ) ;
} ;
auto ret = parser . parse ( R " ( " aaa \ " bbb " ) " );
@ -345,16 +320,14 @@ TEST_CASE("WHITESPACE test4", "[general]") {
% whitespace < - [ \ t \ r \ n ] *
) " );
parser [ " HELLO " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. token ( ) = = " hello " ) ;
parser [ " HELLO " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . token ( ) = = " hello " ) ;
} ;
parser [ " OPE " ] = [ ] ( const SemanticValues & sv ) {
REQUIRE ( sv . token ( ) = = " + " ) ;
} ;
parser [ " OPE " ] = [ ] ( const SemanticValues & vs ) { REQUIRE ( vs . token ( ) = = " + " ) ; } ;
parser [ " WORLD " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. token ( ) = = " world " ) ;
parser [ " WORLD " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . token ( ) = = " world " ) ;
} ;
auto ret = parser . parse ( " hello + world " ) ;
@ -375,42 +348,33 @@ TEST_CASE("Word expression test", "[general]") {
REQUIRE ( parser . parse ( " hello , world " ) = = true ) ;
}
TEST_CASE ( " Skip token test " , " [general] " )
{
parser parser (
" ROOT <- _ ITEM (',' _ ITEM _)* "
TEST_CASE ( " Skip token test " , " [general] " ) {
parser parser ( " ROOT <- _ ITEM (',' _ ITEM _)* "
" ITEM <- ([a-z0-9])+ "
" ~_ <- [ \t ]* "
) ;
" ~_ <- [ \t ]* " ) ;
parser [ " ROOT " ] = [ & ] ( const SemanticValues & sv ) {
REQUIRE ( sv . size ( ) = = 2 ) ;
} ;
parser [ " ROOT " ] = [ & ] ( const SemanticValues & vs ) { REQUIRE ( vs . size ( ) = = 2 ) ; } ;
auto ret = parser . parse ( " item1, item2 " ) ;
REQUIRE ( ret = = true ) ;
}
TEST_CASE ( " Skip token test2 " , " [general] " )
{
TEST_CASE ( " Skip token test2 " , " [general] " ) {
parser parser ( R " (
ROOT < - ITEM ( ' , ' ITEM ) *
ITEM < - < ( [ a - z0 - 9 ] ) + >
% whitespace < - [ \ t ] *
) " );
parser [ " ROOT " ] = [ & ] ( const SemanticValues & sv ) {
REQUIRE ( sv . size ( ) = = 2 ) ;
} ;
parser [ " ROOT " ] = [ & ] ( const SemanticValues & vs ) { REQUIRE ( vs . size ( ) = = 2 ) ; } ;
auto ret = parser . parse ( " item1, item2 " ) ;
REQUIRE ( ret = = true ) ;
}
TEST_CASE ( " Custom AST test " , " [general] " )
{
TEST_CASE ( " Custom AST test " , " [general] " ) {
struct CustomType { } ;
using CustomAst = AstBase < CustomType > ;
@ -427,8 +391,7 @@ TEST_CASE("Custom AST test", "[general]")
REQUIRE ( ast - > nodes . size ( ) = = 4 ) ;
}
TEST_CASE ( " Backtracking test " , " [general] " )
{
TEST_CASE ( " Backtracking test " , " [general] " ) {
parser parser ( R " (
START < - PAT1 / PAT2
PAT1 < - HELLO ' One '
@ -437,9 +400,7 @@ TEST_CASE("Backtracking test", "[general]")
) " );
size_t count = 0 ;
parser [ " HELLO " ] = [ & ] ( const SemanticValues & /*sv*/ ) {
count + + ;
} ;
parser [ " HELLO " ] = [ & ] ( const SemanticValues & /*vs*/ ) { count + + ; } ;
parser . enable_packrat_parsing ( ) ;
@ -448,8 +409,7 @@ TEST_CASE("Backtracking test", "[general]")
REQUIRE ( count = = 1 ) ; // Skip second time
}
TEST_CASE ( " Backtracking with AST " , " [general] " )
{
TEST_CASE ( " Backtracking with AST " , " [general] " ) {
parser parser ( R " (
S < - A ? B ( A B ) * A
A < - ' a '
@ -463,11 +423,8 @@ TEST_CASE("Backtracking with AST", "[general]")
REQUIRE ( ast - > nodes . size ( ) = = 2 ) ;
}
TEST_CASE ( " Octal/Hex/Unicode value test " , " [general] " )
{
parser parser (
R " ( ROOT <- ' \132 \x7a \u30f3 ' ) "
) ;
TEST_CASE ( " Octal/Hex/Unicode value test " , " [general] " ) {
parser parser ( R " ( ROOT <- ' \132 \x7a \u30f3 ' ) " ) ;
auto ret = parser . parse ( " Zzン " ) ;
@ -482,32 +439,30 @@ TEST_CASE("Ignore case test", "[general]") {
% whitespace < - [ \ t \ r \ n ] *
) " );
parser [ " HELLO " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. token ( ) = = " Hello " ) ;
parser [ " HELLO " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . token ( ) = = " Hello " ) ;
} ;
parser [ " WORLD " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. token ( ) = = " World " ) ;
parser [ " WORLD " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . token ( ) = = " World " ) ;
} ;
auto ret = parser . parse ( " Hello World " ) ;
REQUIRE ( ret = = true ) ;
}
TEST_CASE ( " mutable lambda test " , " [general] " )
{
std : : vector < std : : string > vec ;
TEST_CASE ( " mutable lambda test " , " [general] " ) {
std : : vector < std : : string_view > vec ;
parser pg ( " ROOT <- 'mutable lambda test' " ) ;
// This test makes sure if the following code can be compiled.
pg [ " TOKEN " ] = [ = ] ( const SemanticValues & s v) mutable {
vec . push_back ( sv . str ( ) ) ;
pg [ " TOKEN " ] = [ = ] ( const SemanticValues & vs ) mutable {
vec . push_back ( vs . sv ( ) ) ;
} ;
}
TEST_CASE ( " Simple calculator test " , " [general] " )
{
TEST_CASE ( " Simple calculator test " , " [general] " ) {
parser parser ( R " (
Additive < - Multitive ' + ' Additive / Multitive
Multitive < - Primary ' * ' Multitive / Primary
@ -515,27 +470,21 @@ TEST_CASE("Simple calculator test", "[general]")
Number < - [ 0 - 9 ] +
) " );
parser [ " Additive " ] = [ ] ( const SemanticValues & sv ) {
switch ( sv . choice ( ) ) {
case 0 :
return any_cast < int > ( sv [ 0 ] ) + any_cast < int > ( sv [ 1 ] ) ;
default :
return any_cast < int > ( sv [ 0 ] ) ;
parser [ " Additive " ] = [ ] ( const SemanticValues & vs ) {
switch ( vs . choice ( ) ) {
case 0 : return std : : any_cast < int > ( vs [ 0 ] ) + std : : any_cast < int > ( vs [ 1 ] ) ;
default : return std : : any_cast < int > ( vs [ 0 ] ) ;
}
} ;
parser [ " Multitive " ] = [ ] ( const SemanticValues & sv ) {
switch ( sv . choice ( ) ) {
case 0 :
return any_cast < int > ( sv [ 0 ] ) * any_cast < int > ( sv [ 1 ] ) ;
default :
return any_cast < int > ( sv [ 0 ] ) ;
parser [ " Multitive " ] = [ ] ( const SemanticValues & vs ) {
switch ( vs . choice ( ) ) {
case 0 : return std : : any_cast < int > ( vs [ 0 ] ) * std : : any_cast < int > ( vs [ 1 ] ) ;
default : return std : : any_cast < int > ( vs [ 0 ] ) ;
}
} ;
parser [ " Number " ] = [ ] ( const SemanticValues & sv ) {
return atoi ( sv . c_str ( ) ) ;
} ;
parser [ " Number " ] = [ ] ( const SemanticValues & vs ) { return vs . token_to_number < int > ( ) ; } ;
int val ;
parser . parse ( " (1+2)*3 " , val ) ;
@ -543,8 +492,7 @@ TEST_CASE("Simple calculator test", "[general]")
REQUIRE ( val = = 9 ) ;
}
TEST_CASE ( " Calculator test " , " [general] " )
{
TEST_CASE ( " Calculator test " , " [general] " ) {
// Construct grammer
Definition EXPRESSION , TERM , FACTOR , TERM_OPERATOR , FACTOR_OPERATOR , NUMBER ;
@ -556,11 +504,11 @@ TEST_CASE("Calculator test", "[general]")
NUMBER < = oom ( cls ( " 0-9 " ) ) ;
// Setup actions
auto reduce = [ ] ( const SemanticValues & s v) - > long {
long ret = any_cast < long > ( s v[ 0 ] ) ;
for ( auto i = 1u ; i < s v. size ( ) ; i + = 2 ) {
auto num = any_cast < long > ( s v[ i + 1 ] ) ;
switch ( any_cast < char > ( s v[ i ] ) ) {
auto reduce = [ ] ( const SemanticValues & vs ) - > long {
long ret = std : : any_cast < long > ( vs [ 0 ] ) ;
for ( auto i = 1u ; i < vs . size ( ) ; i + = 2 ) {
auto num = std : : any_cast < long > ( vs [ i + 1 ] ) ;
switch ( std : : any_cast < char > ( vs [ i ] ) ) {
case ' + ' : ret + = num ; break ;
case ' - ' : ret - = num ; break ;
case ' * ' : ret * = num ; break ;
@ -572,9 +520,9 @@ TEST_CASE("Calculator test", "[general]")
EXPRESSION = reduce ;
TERM = reduce ;
TERM_OPERATOR = [ ] ( const SemanticValues & s v) { return * sv . c_str ( ) ; } ;
FACTOR_OPERATOR = [ ] ( const SemanticValues & s v) { return * sv . c_str ( ) ; } ;
NUMBER = [ ] ( const SemanticValues & s v) { return stol ( sv . str ( ) , nullptr , 10 ) ; } ;
TERM_OPERATOR = [ ] ( const SemanticValues & vs ) { return * vs . sv ( ) . data ( ) ; } ;
FACTOR_OPERATOR = [ ] ( const SemanticValues & vs ) { return * vs . sv ( ) . data ( ) ; } ;
NUMBER = [ ] ( const SemanticValues & vs ) { return vs . token_to_number < long > ( ) ; } ;
// Parse
long val ;
@ -584,8 +532,7 @@ TEST_CASE("Calculator test", "[general]")
REQUIRE ( val = = - 3 ) ;
}
TEST_CASE ( " Calculator test2 " , " [general] " )
{
TEST_CASE ( " Calculator test2 " , " [general] " ) {
// Parse syntax
auto syntax = R " (
# Grammar for Calculator...
@ -599,14 +546,14 @@ TEST_CASE("Calculator test2", "[general]")
std : : string start ;
auto grammar = ParserGenerator : : parse ( syntax , strlen ( syntax ) , start , nullptr ) ;
auto & g = * grammar ;
auto & g = * grammar ;
// Setup actions
auto reduce = [ ] ( const SemanticValues & s v) - > long {
long ret = any_cast < long > ( s v[ 0 ] ) ;
for ( auto i = 1u ; i < s v. size ( ) ; i + = 2 ) {
auto num = any_cast < long > ( s v[ i + 1 ] ) ;
switch ( any_cast < char > ( s v[ i ] ) ) {
auto reduce = [ ] ( const SemanticValues & vs ) - > long {
long ret = std : : any_cast < long > ( vs [ 0 ] ) ;
for ( auto i = 1u ; i < vs . size ( ) ; i + = 2 ) {
auto num = std : : any_cast < long > ( vs [ i + 1 ] ) ;
switch ( std : : any_cast < char > ( vs [ i ] ) ) {
case ' + ' : ret + = num ; break ;
case ' - ' : ret - = num ; break ;
case ' * ' : ret * = num ; break ;
@ -618,9 +565,9 @@ TEST_CASE("Calculator test2", "[general]")
g [ " EXPRESSION " ] = reduce ;
g [ " TERM " ] = reduce ;
g [ " TERM_OPERATOR " ] = [ ] ( const SemanticValues & s v) { return * sv . c_str ( ) ; } ;
g [ " FACTOR_OPERATOR " ] = [ ] ( const SemanticValues & s v) { return * sv . c_str ( ) ; } ;
g [ " NUMBER " ] = [ ] ( const SemanticValues & s v) { return stol ( sv . str ( ) , nullptr , 10 ) ; } ;
g [ " TERM_OPERATOR " ] = [ ] ( const SemanticValues & vs ) { return * vs . sv ( ) . data ( ) ; } ;
g [ " FACTOR_OPERATOR " ] = [ ] ( const SemanticValues & vs ) { return * vs . sv ( ) . data ( ) ; } ;
g [ " NUMBER " ] = [ ] ( const SemanticValues & vs ) { return vs . token_to_number < long > ( ) ; } ;
// Parse
long val ;
@ -630,8 +577,7 @@ TEST_CASE("Calculator test2", "[general]")
REQUIRE ( val = = - 3 ) ;
}
TEST_CASE ( " Calculator test3 " , " [general] " )
{
TEST_CASE ( " Calculator test3 " , " [general] " ) {
// Parse syntax
parser parser ( R " (
# Grammar for Calculator...
@ -643,11 +589,11 @@ TEST_CASE("Calculator test3", "[general]")
NUMBER < - [ 0 - 9 ] +
) " );
auto reduce = [ ] ( const SemanticValues & s v) - > long {
long ret = any_cast < long > ( s v[ 0 ] ) ;
for ( auto i = 1u ; i < s v. size ( ) ; i + = 2 ) {
auto num = any_cast < long > ( s v[ i + 1 ] ) ;
switch ( any_cast < char > ( s v[ i ] ) ) {
auto reduce = [ ] ( const SemanticValues & vs ) - > long {
long ret = std : : any_cast < long > ( vs [ 0 ] ) ;
for ( auto i = 1u ; i < vs . size ( ) ; i + = 2 ) {
auto num = std : : any_cast < long > ( vs [ i + 1 ] ) ;
switch ( std : : any_cast < char > ( vs [ i ] ) ) {
case ' + ' : ret + = num ; break ;
case ' - ' : ret - = num ; break ;
case ' * ' : ret * = num ; break ;
@ -660,9 +606,13 @@ TEST_CASE("Calculator test3", "[general]")
// Setup actions
parser [ " EXPRESSION " ] = reduce ;
parser [ " TERM " ] = reduce ;
parser [ " TERM_OPERATOR " ] = [ ] ( const SemanticValues & sv ) { return static_cast < char > ( * sv . c_str ( ) ) ; } ;
parser [ " FACTOR_OPERATOR " ] = [ ] ( const SemanticValues & sv ) { return static_cast < char > ( * sv . c_str ( ) ) ; } ;
parser [ " NUMBER " ] = [ ] ( const SemanticValues & sv ) { return stol ( sv . str ( ) , nullptr , 10 ) ; } ;
parser [ " TERM_OPERATOR " ] = [ ] ( const SemanticValues & vs ) {
return static_cast < char > ( * vs . sv ( ) . data ( ) ) ;
} ;
parser [ " FACTOR_OPERATOR " ] = [ ] ( const SemanticValues & vs ) {
return static_cast < char > ( * vs . sv ( ) . data ( ) ) ;
} ;
parser [ " NUMBER " ] = [ ] ( const SemanticValues & vs ) { return vs . token_to_number < long > ( ) ; } ;
// Parse
long val ;
@ -672,8 +622,7 @@ TEST_CASE("Calculator test3", "[general]")
REQUIRE ( val = = - 3 ) ;
}
TEST_CASE ( " Calculator test with AST " , " [general] " )
{
TEST_CASE ( " Calculator test with AST " , " [general] " ) {
parser parser ( R " (
EXPRESSION < - _ TERM ( TERM_OPERATOR TERM ) *
TERM < - FACTOR ( FACTOR_OPERATOR FACTOR ) *
@ -686,11 +635,11 @@ TEST_CASE("Calculator test with AST", "[general]")
parser . enable_ast ( ) ;
std : : function < long ( const Ast & ) > eval = [ & ] ( const Ast & ast ) {
std : : function < long ( const Ast & ) > eval = [ & ] ( const Ast & ast ) {
if ( ast . name = = " NUMBER " ) {
return stol ( ast . token ) ;
return ast . token_to_number < long > ( ) ;
} else {
const auto & nodes = ast . nodes ;
const auto & nodes = ast . nodes ;
auto result = eval ( * nodes [ 0 ] ) ;
for ( auto i = 1u ; i < nodes . size ( ) ; i + = 2 ) {
auto num = eval ( * nodes [ i + 1 ] ) ;
@ -717,7 +666,8 @@ TEST_CASE("Calculator test with AST", "[general]")
TEST_CASE ( " Calculator test with combinators and AST " , " [general] " ) {
// Construct grammer
AST_DEFINITIONS ( EXPRESSION , TERM , FACTOR , TERM_OPERATOR , FACTOR_OPERATOR , NUMBER ) ;
AST_DEFINITIONS ( EXPRESSION , TERM , FACTOR , TERM_OPERATOR , FACTOR_OPERATOR ,
NUMBER ) ;
EXPRESSION < = seq ( TERM , zom ( seq ( TERM_OPERATOR , TERM ) ) ) ;
TERM < = seq ( FACTOR , zom ( seq ( FACTOR_OPERATOR , FACTOR ) ) ) ;
@ -728,7 +678,7 @@ TEST_CASE("Calculator test with combinators and AST", "[general]") {
std : : function < long ( const Ast & ) > eval = [ & ] ( const Ast & ast ) {
if ( ast . name = = " NUMBER " ) {
return stol ( ast . token ) ;
return ast . token_to_number < long > ( ) ;
} else {
const auto & nodes = ast . nodes ;
auto result = eval ( * nodes [ 0 ] ) ;
@ -755,8 +705,7 @@ TEST_CASE("Calculator test with combinators and AST", "[general]") {
REQUIRE ( val = = - 3 ) ;
}
TEST_CASE ( " Ignore semantic value test " , " [general] " )
{
TEST_CASE ( " Ignore semantic value test " , " [general] " ) {
parser parser ( R " (
START < - ~ HELLO WORLD
HELLO < - ' Hello ' _
@ -774,8 +723,7 @@ TEST_CASE("Ignore semantic value test", "[general]")
REQUIRE ( ast - > nodes [ 0 ] - > name = = " WORLD " ) ;
}
TEST_CASE ( " Ignore semantic value of 'or' predicate test " , " [general] " )
{
TEST_CASE ( " Ignore semantic value of 'or' predicate test " , " [general] " ) {
parser parser ( R " (
START < - _ ! DUMMY HELLO_WORLD ' . '
HELLO_WORLD < - HELLO ' World ' _
@ -794,8 +742,7 @@ TEST_CASE("Ignore semantic value of 'or' predicate test", "[general]")
REQUIRE ( ast - > nodes [ 0 ] - > name = = " HELLO_WORLD " ) ;
}
TEST_CASE ( " Ignore semantic value of 'and' predicate test " , " [general] " )
{
TEST_CASE ( " Ignore semantic value of 'and' predicate test " , " [general] " ) {
parser parser ( R " (
START < - _ & HELLO HELLO_WORLD ' . '
HELLO_WORLD < - HELLO ' World ' _
@ -813,8 +760,7 @@ TEST_CASE("Ignore semantic value of 'and' predicate test", "[general]")
REQUIRE ( ast - > nodes [ 0 ] - > name = = " HELLO_WORLD " ) ;
}
TEST_CASE ( " Literal token on AST test1 " , " [general] " )
{
TEST_CASE ( " Literal token on AST test1 " , " [general] " ) {
parser parser ( R " (
STRING_LITERAL < - ' " ' ( ( ' \ \ " ' / ' \\ t' / ' \\ n') / (![ " ] . ) ) * ' " '
) " );
@ -829,8 +775,7 @@ TEST_CASE("Literal token on AST test1", "[general]")
REQUIRE ( ast - > nodes . empty ( ) ) ;
}
TEST_CASE ( " Literal token on AST test2 " , " [general] " )
{
TEST_CASE ( " Literal token on AST test2 " , " [general] " ) {
parser parser ( R " (
STRING_LITERAL < - ' " ' ( ESC / CHAR ) * ' " '
ESC < - ( ' \ \ " ' / ' \\ t' / ' \\ n')
@ -847,8 +792,7 @@ TEST_CASE("Literal token on AST test2", "[general]")
REQUIRE ( ast - > nodes . size ( ) = = 3 ) ;
}
TEST_CASE ( " Literal token on AST test3 " , " [general] " )
{
TEST_CASE ( " Literal token on AST test3 " , " [general] " ) {
parser parser ( R " (
STRING_LITERAL < - < ' " ' ( ESC / CHAR ) * ' " ' >
ESC < - ( ' \ \ " ' / ' \\ t' / ' \\ n')
@ -865,8 +809,7 @@ TEST_CASE("Literal token on AST test3", "[general]")
REQUIRE ( ast - > nodes . empty ( ) ) ;
}
TEST_CASE ( " Missing missing definitions test " , " [general] " )
{
TEST_CASE ( " Missing missing definitions test " , " [general] " ) {
parser parser ( R " (
A < - B C
) " );
@ -874,8 +817,7 @@ TEST_CASE("Missing missing definitions test", "[general]")
REQUIRE ( ! parser ) ;
}
TEST_CASE ( " Definition duplicates test " , " [general] " )
{
TEST_CASE ( " Definition duplicates test " , " [general] " ) {
parser parser ( R " (
A < - ' '
A < - ' '
@ -884,8 +826,7 @@ TEST_CASE("Definition duplicates test", "[general]")
REQUIRE ( ! parser ) ;
}
TEST_CASE ( " Semantic values test " , " [general] " )
{
TEST_CASE ( " Semantic values test " , " [general] " ) {
parser parser ( R " (
term < - ( a b c x ) ? a b c
a < - ' a '
@ -894,15 +835,15 @@ TEST_CASE("Semantic values test", "[general]")
x < - ' x '
) " );
for ( const auto & rule : parser . get_rule_names ( ) ) {
parser [ rule . c_str ( ) ] = [ rule ] ( const SemanticValues & s v, any & ) {
for ( const auto & rule : parser . get_rule_names ( ) ) {
parser [ rule . data ( ) ] = [ rule ] ( const SemanticValues & vs , std : : any & ) {
if ( rule = = " term " ) {
REQUIRE ( any_cast < std : : string > ( s v[ 0 ] ) = = " a at 0 " ) ;
REQUIRE ( any_cast < std : : string > ( s v[ 1 ] ) = = " b at 1 " ) ;
REQUIRE ( any_cast < std : : string > ( s v[ 2 ] ) = = " c at 2 " ) ;
REQUIRE ( std : : any_cast < std : : string > ( vs [ 0 ] ) = = " a at 0 " ) ;
REQUIRE ( std : : any_cast < std : : string > ( vs [ 1 ] ) = = " b at 1 " ) ;
REQUIRE ( std : : any_cast < std : : string > ( vs [ 2 ] ) = = " c at 2 " ) ;
return std : : string ( ) ;
} else {
return rule + " at " + std : : to_string ( sv . c_str ( ) - s v. ss ) ;
return rule + " at " + std : : to_string ( vs . sv ( ) . data ( ) - vs . ss ) ;
}
} ;
}
@ -910,36 +851,33 @@ TEST_CASE("Semantic values test", "[general]")
REQUIRE ( parser . parse ( " abc " ) ) ;
}
TEST_CASE ( " Ordered choice count " , " [general] " )
{
TEST_CASE ( " Ordered choice count " , " [general] " ) {
parser parser ( R " (
S < - ' a ' / ' b '
) " );
parser [ " S " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. choice ( ) = = 1 ) ;
REQUIRE ( s v. choice_count ( ) = = 2 ) ;
parser [ " S " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . choice ( ) = = 1 ) ;
REQUIRE ( vs . choice_count ( ) = = 2 ) ;
} ;
parser . parse ( " b " ) ;
}
TEST_CASE ( " Ordered choice count 2 " , " [general] " )
{
TEST_CASE ( " Ordered choice count 2 " , " [general] " ) {
parser parser ( R " (
S < - ( ' a ' / ' b ' ) *
) " );
parser [ " S " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. choice ( ) = = 0 ) ;
REQUIRE ( s v. choice_count ( ) = = 0 ) ;
parser [ " S " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . choice ( ) = = 0 ) ;
REQUIRE ( vs . choice_count ( ) = = 0 ) ;
} ;
parser . parse ( " b " ) ;
}
TEST_CASE ( " Semantic value tag " , " [general] " )
{
TEST_CASE ( " Semantic value tag " , " [general] " ) {
parser parser ( R " (
S < - A ? B * C ?
A < - ' a '
@ -949,10 +887,10 @@ TEST_CASE("Semantic value tag", "[general]")
{
using namespace udl ;
parser [ " S " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. size ( ) = = 1 ) ;
REQUIRE ( s v. tags . size ( ) = = 1 ) ;
REQUIRE ( s v. tags [ 0 ] = = " C " _ ) ;
parser [ " S " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . size ( ) = = 1 ) ;
REQUIRE ( vs . tags . size ( ) = = 1 ) ;
REQUIRE ( vs . tags [ 0 ] = = " C " _ ) ;
} ;
auto ret = parser . parse ( " c " ) ;
REQUIRE ( ret = = true ) ;
@ -960,11 +898,11 @@ TEST_CASE("Semantic value tag", "[general]")
{
using namespace udl ;
parser [ " S " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. size ( ) = = 2 ) ;
REQUIRE ( s v. tags . size ( ) = = 2 ) ;
REQUIRE ( s v. tags [ 0 ] = = " B " _ ) ;
REQUIRE ( s v. tags [ 1 ] = = " B " _ ) ;
parser [ " S " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . size ( ) = = 2 ) ;
REQUIRE ( vs . tags . size ( ) = = 2 ) ;
REQUIRE ( vs . tags [ 0 ] = = " B " _ ) ;
REQUIRE ( vs . tags [ 1 ] = = " B " _ ) ;
} ;
auto ret = parser . parse ( " bb " ) ;
REQUIRE ( ret = = true ) ;
@ -972,19 +910,18 @@ TEST_CASE("Semantic value tag", "[general]")
{
using namespace udl ;
parser [ " S " ] = [ ] ( const SemanticValues & s v) {
REQUIRE ( s v. size ( ) = = 2 ) ;
REQUIRE ( s v. tags . size ( ) = = 2 ) ;
REQUIRE ( s v. tags [ 0 ] = = " A " _ ) ;
REQUIRE ( s v. tags [ 1 ] = = " C " _ ) ;
parser [ " S " ] = [ ] ( const SemanticValues & vs ) {
REQUIRE ( vs . size ( ) = = 2 ) ;
REQUIRE ( vs . tags . size ( ) = = 2 ) ;
REQUIRE ( vs . tags [ 0 ] = = " A " _ ) ;
REQUIRE ( vs . tags [ 1 ] = = " C " _ ) ;
} ;
auto ret = parser . parse ( " ac " ) ;
REQUIRE ( ret = = true ) ;
}
}
TEST_CASE ( " Negated Class test " , " [general] " )
{
TEST_CASE ( " Negated Class test " , " [general] " ) {
parser parser ( R " (
ROOT < - [ ^ a - z_ ] +
) " );