From 6d3ba85cdf719b624a17a9e318cb5a82dcd535b0 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Fri, 12 Oct 2018 23:19:22 +0200 Subject: [PATCH] kernel: also reject invalid AND-filters in compiled code --- src/c_oper1.c | 27 +- src/c_type1.c | 9 +- src/compiler.c | 11 +- src/exprs.c | 9 +- src/hpc/c_oper1.c | 27 +- src/hpc/c_type1.c | 9 +- src/intrprtr.c | 9 +- src/opers.c | 8 + tst/test-compile/and_filter.g | 18 + tst/test-compile/and_filter.g.dynamic.c | 504 ++++++++++++++++++++++++ tst/test-compile/and_filter.g.out | 7 + tst/test-compile/and_filter.g.static.c | 504 ++++++++++++++++++++++++ tst/testinstall/boolean.tst | 16 +- 13 files changed, 1107 insertions(+), 51 deletions(-) create mode 100644 tst/test-compile/and_filter.g create mode 100644 tst/test-compile/and_filter.g.dynamic.c create mode 100644 tst/test-compile/and_filter.g.out create mode 100644 tst/test-compile/and_filter.g.static.c diff --git a/src/c_oper1.c b/src/c_oper1.c index 8bf66124b8..ba2ba5df91 100644 --- a/src/c_oper1.c +++ b/src/c_oper1.c @@ -890,17 +890,20 @@ static Obj HdlrFunc3 ( t_4 = (EQ( t_5, t_6 ) ? True : False); t_3 = t_4; } - else { - CHECK_FUNC( l_match ) + else if (IS_FILTER( l_match ) ) { C_SUM_FIA( t_8, l_k, l_j ) C_SUM_FIA( t_7, t_8, INTOBJ_INT(1) ) CHECK_INT_POS( t_7 ) C_ELM_LIST_FPL( t_6, l_methods, t_7 ) C_ELM_LIST_FPL( t_7, a_flags, l_j ) t_5 = (EQ( t_6, t_7 ) ? True : False); - CHECK_FUNC( t_5 ) t_3 = NewAndFilter( l_match, t_5 ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(l_match), 0L ); + } l_match = t_3; } @@ -2667,14 +2670,17 @@ static Obj HdlrFunc7 ( CHECK_BOOL( t_6 ) t_5 = t_6; } - else { - CHECK_FUNC( l_cats ) + else if (IS_FILTER( l_cats ) ) { t_8 = GC_FILTERS; CHECK_BOUND( t_8, "FILTERS" ) C_ELM_LIST_FPL( t_7, t_8, l_i ) - CHECK_FUNC( t_7 ) t_5 = NewAndFilter( l_cats, t_7 ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(l_cats), 0L ); + } l_cats = t_5; /* rank := rank - RankFilter( FILTERS[i] ); */ @@ -3201,13 +3207,16 @@ static Obj HdlrFunc15 ( t_3 = (EQ( t_4, a_key ) ? True : False); t_1 = t_3; } - else { - CHECK_FUNC( t_2 ) + else if (IS_FILTER( t_2 ) ) { C_ELM_LIST_FPL( t_5, l_known, l_i ) t_4 = (EQ( t_5, a_key ) ? True : False); - CHECK_FUNC( t_4 ) t_1 = NewAndFilter( t_2, t_4 ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } RES_BRK_CURR_STAT(); SWITCH_TO_OLD_FRAME(oldFrame); return t_1; diff --git a/src/c_type1.c b/src/c_type1.c index d9c53c9d86..90e693f6b2 100644 --- a/src/c_type1.c +++ b/src/c_type1.c @@ -237,11 +237,14 @@ static Obj HdlrFunc2 ( CHECK_BOOL( a_tester ) t_5 = a_tester; } - else { - CHECK_FUNC( t_6 ) - CHECK_FUNC( a_tester ) + else if (IS_FILTER( t_6 ) ) { t_5 = NewAndFilter( t_6, a_tester ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_6), 0L ); + } SET_ELM_PLIST( t_4, 1, t_5 ); CHANGED_BAG( t_4 ); t_5 = GC_GETTER__FLAGS; diff --git a/src/compiler.c b/src/compiler.c index 49a2ab095c..92c70585fa 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -1312,13 +1312,18 @@ CVar CompAnd ( Emit( "}\n" ); /* emit the code for the case that the left value is a filter */ - Emit( "else {\n" ); - CompCheckFunc( left ); + Emit( "else if (IS_FILTER( %c ) ) {\n", left ); right2 = CompExpr(READ_EXPR(expr, 1)); - CompCheckFunc( right2 ); Emit( "%c = NewAndFilter( %c, %c );\n", val, left, right2 ); Emit( "}\n" ); + /* signal an error */ + Emit( "else {\n" ); + Emit( "ErrorQuit(\n" + "\" must be 'true' or 'false' or a filter (not a %%s)\",\n" + "(Int)TNAM_OBJ(%c), 0L );\n", left ); + Emit( "}\n" ); + /* we know precious little about the result */ MergeInfoCVars( INFO_FEXP(CURR_FUNC()), only_left ); SetInfoCVar( val, W_BOUND ); diff --git a/src/exprs.c b/src/exprs.c index e7947f7e4b..646b0eeec8 100644 --- a/src/exprs.c +++ b/src/exprs.c @@ -186,14 +186,7 @@ Obj EvalAnd ( else if (IS_FILTER(opL)) { tmp = READ_EXPR(expr, 1); opR = EVAL_EXPR( tmp ); - if (IS_FILTER(opR)) { - return NewAndFilter( opL, opR ); - } - else { - ErrorQuit( - " must be a filter (not a %s)", - (Int)TNAM_OBJ(opL), 0L ); - } + return NewAndFilter(opL, opR); } /* signal an error */ diff --git a/src/hpc/c_oper1.c b/src/hpc/c_oper1.c index 817174a234..46cb5aeddc 100644 --- a/src/hpc/c_oper1.c +++ b/src/hpc/c_oper1.c @@ -922,17 +922,20 @@ static Obj HdlrFunc3 ( t_4 = (EQ( t_5, t_6 ) ? True : False); t_3 = t_4; } - else { - CHECK_FUNC( l_match ) + else if (IS_FILTER( l_match ) ) { C_SUM_FIA( t_8, l_k, l_j ) C_SUM_FIA( t_7, t_8, INTOBJ_INT(1) ) CHECK_INT_POS( t_7 ) C_ELM_LIST_FPL( t_6, l_methods, t_7 ) C_ELM_LIST_FPL( t_7, a_flags, l_j ) t_5 = (EQ( t_6, t_7 ) ? True : False); - CHECK_FUNC( t_5 ) t_3 = NewAndFilter( l_match, t_5 ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(l_match), 0L ); + } l_match = t_3; } @@ -2726,14 +2729,17 @@ static Obj HdlrFunc7 ( CHECK_BOOL( t_6 ) t_5 = t_6; } - else { - CHECK_FUNC( l_cats ) + else if (IS_FILTER( l_cats ) ) { t_8 = GC_FILTERS; CHECK_BOUND( t_8, "FILTERS" ) C_ELM_LIST_FPL( t_7, t_8, l_i ) - CHECK_FUNC( t_7 ) t_5 = NewAndFilter( l_cats, t_7 ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(l_cats), 0L ); + } l_cats = t_5; /* rank := rank - RankFilter( FILTERS[i] ); */ @@ -3264,13 +3270,16 @@ static Obj HdlrFunc15 ( t_3 = (EQ( t_4, a_key ) ? True : False); t_1 = t_3; } - else { - CHECK_FUNC( t_2 ) + else if (IS_FILTER( t_2 ) ) { C_ELM_LIST_FPL( t_5, l_known, l_i ) t_4 = (EQ( t_5, a_key ) ? True : False); - CHECK_FUNC( t_4 ) t_1 = NewAndFilter( t_2, t_4 ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } RES_BRK_CURR_STAT(); SWITCH_TO_OLD_FRAME(oldFrame); return t_1; diff --git a/src/hpc/c_type1.c b/src/hpc/c_type1.c index bf124fd60f..aeb8d4d0d2 100644 --- a/src/hpc/c_type1.c +++ b/src/hpc/c_type1.c @@ -276,11 +276,14 @@ static Obj HdlrFunc2 ( CHECK_BOOL( a_tester ) t_5 = a_tester; } - else { - CHECK_FUNC( t_6 ) - CHECK_FUNC( a_tester ) + else if (IS_FILTER( t_6 ) ) { t_5 = NewAndFilter( t_6, a_tester ); } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_6), 0L ); + } SET_ELM_PLIST( t_4, 1, t_5 ); CHANGED_BAG( t_4 ); t_5 = GC_GETTER__FLAGS; diff --git a/src/intrprtr.c b/src/intrprtr.c index c22b0f6196..adfa612d65 100644 --- a/src/intrprtr.c +++ b/src/intrprtr.c @@ -1370,14 +1370,7 @@ void IntrAnd ( void ) /* handle the 'and' of two filters */ else if (IS_FILTER(opL)) { - if (IS_FILTER(opR)) { - PushObj( NewAndFilter( opL, opR ) ); - } - else { - ErrorQuit( - " must be a filter (not a %s)", - (Int)TNAM_OBJ(opL), 0L ); - } + PushObj(NewAndFilter(opL, opR)); } /* signal an error */ diff --git a/src/opers.c b/src/opers.c index 2326fce41c..0ebd1bb9fd 100644 --- a/src/opers.c +++ b/src/opers.c @@ -1248,6 +1248,14 @@ Obj NewAndFilter ( Obj str; char* s; + if (!IS_FILTER(oper1)) + ErrorQuit(" must be a filter (not a %s)", (Int)TNAM_OBJ(oper1), + 0); + + if (!IS_FILTER(oper2)) + ErrorQuit(" must be a filter (not a %s)", (Int)TNAM_OBJ(oper2), + 0); + if ( oper1 == ReturnTrueFilter ) return oper2; diff --git a/tst/test-compile/and_filter.g b/tst/test-compile/and_filter.g new file mode 100644 index 0000000000..ace5467109 --- /dev/null +++ b/tst/test-compile/and_filter.g @@ -0,0 +1,18 @@ +runtest := function() + +Print(false and 1, "\n"); +Print(true or 1, "\n"); +Print(function() return false and 1; end(), "\n"); +Print(function() return true or 1; end(), "\n"); +Print(IsAssociative and IsAssociative, "\n"); + +# ensure we don't abort after an error +BreakOnError := false; + +# trigger error 1: +CALL_WITH_CATCH({} -> Center and IsAssociative, []); + +# trigger error 2: +CALL_WITH_CATCH({} -> IsAssociative and Center, []); + +end; diff --git a/tst/test-compile/and_filter.g.dynamic.c b/tst/test-compile/and_filter.g.dynamic.c new file mode 100644 index 0000000000..1834ec0b7d --- /dev/null +++ b/tst/test-compile/and_filter.g.dynamic.c @@ -0,0 +1,504 @@ +/* C file produced by GAC */ +#include "compiled.h" +#define FILE_CRC "-49920958" + +/* global variables used in handlers */ +static GVar G_Print; +static Obj GF_Print; +static GVar G_CALL__WITH__CATCH; +static Obj GF_CALL__WITH__CATCH; +static GVar G_runtest; +static GVar G_IsAssociative; +static Obj GC_IsAssociative; +static GVar G_BreakOnError; +static GVar G_Center; +static Obj GC_Center; + +/* record names used in handlers */ + +/* information for the functions */ +static Obj NameFunc[7]; +static Obj FileName; + +/* handler for function 3 */ +static Obj HdlrFunc3 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return false and 1; */ + t_2 = False; + if ( t_2 == False ) { + t_1 = t_2; + } + else if ( t_2 == True ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_1 = INTOBJ_INT(1); + } + else if (IS_FILTER( t_2 ) ) { + t_1 = NewAndFilter( t_2, INTOBJ_INT(1) ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 4 */ +static Obj HdlrFunc4 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return true or 1; */ + t_3 = True; + t_2 = (Obj)(UInt)(t_3 != False); + t_1 = (t_2 ? True : False); + if ( t_1 == False ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_3 = (Obj)(UInt)(INTOBJ_INT(1) != False); + t_1 = (t_3 ? True : False); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 5 */ +static Obj HdlrFunc5 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Obj t_4 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return Center and IsAssociative; */ + t_2 = GC_Center; + CHECK_BOUND( t_2, "Center" ) + if ( t_2 == False ) { + t_1 = t_2; + } + else if ( t_2 == True ) { + t_3 = GC_IsAssociative; + CHECK_BOUND( t_3, "IsAssociative" ) + CHECK_BOOL( t_3 ) + t_1 = t_3; + } + else if (IS_FILTER( t_2 ) ) { + t_4 = GC_IsAssociative; + CHECK_BOUND( t_4, "IsAssociative" ) + t_1 = NewAndFilter( t_2, t_4 ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 6 */ +static Obj HdlrFunc6 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Obj t_4 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return IsAssociative and Center; */ + t_2 = GC_IsAssociative; + CHECK_BOUND( t_2, "IsAssociative" ) + if ( t_2 == False ) { + t_1 = t_2; + } + else if ( t_2 == True ) { + t_3 = GC_Center; + CHECK_BOUND( t_3, "Center" ) + CHECK_BOOL( t_3 ) + t_1 = t_3; + } + else if (IS_FILTER( t_2 ) ) { + t_4 = GC_Center; + CHECK_BOUND( t_4, "Center" ) + t_1 = NewAndFilter( t_2, t_4 ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 2 */ +static Obj HdlrFunc2 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Obj t_4 = 0; + Obj t_5 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* Print( false and 1, "\n" ); */ + t_1 = GF_Print; + t_3 = False; + if ( t_3 == False ) { + t_2 = t_3; + } + else if ( t_3 == True ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_2 = INTOBJ_INT(1); + } + else if (IS_FILTER( t_3 ) ) { + t_2 = NewAndFilter( t_3, INTOBJ_INT(1) ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_3), 0L ); + } + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( true or 1, "\n" ); */ + t_1 = GF_Print; + t_4 = True; + t_3 = (Obj)(UInt)(t_4 != False); + t_2 = (t_3 ? True : False); + if ( t_2 == False ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_4 = (Obj)(UInt)(INTOBJ_INT(1) != False); + t_2 = (t_4 ? True : False); + } + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( function ( ) + return false and 1; + end( ), "\n" ); */ + t_1 = GF_Print; + t_3 = NewFunction( NameFunc[3], 0, 0, HdlrFunc3 ); + SET_ENVI_FUNC( t_3, STATE(CurrLVars) ); + t_4 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_4, 5); + SET_ENDLINE_BODY(t_4, 5); + SET_FILENAME_BODY(t_4, FileName); + SET_BODY_FUNC(t_3, t_4); + CHANGED_BAG( STATE(CurrLVars) ); + t_2 = CALL_0ARGS( t_3 ); + CHECK_FUNC_RESULT( t_2 ) + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( function ( ) + return true or 1; + end( ), "\n" ); */ + t_1 = GF_Print; + t_3 = NewFunction( NameFunc[4], 0, 0, HdlrFunc4 ); + SET_ENVI_FUNC( t_3, STATE(CurrLVars) ); + t_4 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_4, 6); + SET_ENDLINE_BODY(t_4, 6); + SET_FILENAME_BODY(t_4, FileName); + SET_BODY_FUNC(t_3, t_4); + CHANGED_BAG( STATE(CurrLVars) ); + t_2 = CALL_0ARGS( t_3 ); + CHECK_FUNC_RESULT( t_2 ) + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( IsAssociative and IsAssociative, "\n" ); */ + t_1 = GF_Print; + t_3 = GC_IsAssociative; + CHECK_BOUND( t_3, "IsAssociative" ) + if ( t_3 == False ) { + t_2 = t_3; + } + else if ( t_3 == True ) { + t_4 = GC_IsAssociative; + CHECK_BOUND( t_4, "IsAssociative" ) + CHECK_BOOL( t_4 ) + t_2 = t_4; + } + else if (IS_FILTER( t_3 ) ) { + t_5 = GC_IsAssociative; + CHECK_BOUND( t_5, "IsAssociative" ) + t_2 = NewAndFilter( t_3, t_5 ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_3), 0L ); + } + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* BreakOnError := false; */ + t_1 = False; + AssGVar( G_BreakOnError, t_1 ); + + /* CALL_WITH_CATCH( function ( ) + return Center and IsAssociative; + end, [ ] ); */ + t_1 = GF_CALL__WITH__CATCH; + t_2 = NewFunction( NameFunc[5], 0, 0, HdlrFunc5 ); + SET_ENVI_FUNC( t_2, STATE(CurrLVars) ); + t_3 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_3, 13); + SET_ENDLINE_BODY(t_3, 13); + SET_FILENAME_BODY(t_3, FileName); + SET_BODY_FUNC(t_2, t_3); + CHANGED_BAG( STATE(CurrLVars) ); + t_3 = NEW_PLIST( T_PLIST, 0 ); + SET_LEN_PLIST( t_3, 0 ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* CALL_WITH_CATCH( function ( ) + return IsAssociative and Center; + end, [ ] ); */ + t_1 = GF_CALL__WITH__CATCH; + t_2 = NewFunction( NameFunc[6], 0, 0, HdlrFunc6 ); + SET_ENVI_FUNC( t_2, STATE(CurrLVars) ); + t_3 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_3, 16); + SET_ENDLINE_BODY(t_3, 16); + SET_FILENAME_BODY(t_3, FileName); + SET_BODY_FUNC(t_2, t_3); + CHANGED_BAG( STATE(CurrLVars) ); + t_3 = NEW_PLIST( T_PLIST, 0 ); + SET_LEN_PLIST( t_3, 0 ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 1 */ +static Obj HdlrFunc1 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* runtest := function ( ) + Print( false and 1, "\n" ); + Print( true or 1, "\n" ); + Print( function ( ) + return false and 1; + end( ), "\n" ); + Print( function ( ) + return true or 1; + end( ), "\n" ); + Print( IsAssociative and IsAssociative, "\n" ); + BreakOnError := false; + CALL_WITH_CATCH( function ( ) + return Center and IsAssociative; + end, [ ] ); + CALL_WITH_CATCH( function ( ) + return IsAssociative and Center; + end, [ ] ); + return; + end; */ + t_1 = NewFunction( NameFunc[2], 0, 0, HdlrFunc2 ); + SET_ENVI_FUNC( t_1, STATE(CurrLVars) ); + t_2 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_2, 1); + SET_ENDLINE_BODY(t_2, 18); + SET_FILENAME_BODY(t_2, FileName); + SET_BODY_FUNC(t_1, t_2); + CHANGED_BAG( STATE(CurrLVars) ); + AssGVar( G_runtest, t_1 ); + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* 'PostRestore' restore gvars, rnams, functions */ +static Int PostRestore ( StructInitInfo * module ) +{ + + /* global variables used in handlers */ + G_Print = GVarName( "Print" ); + G_CALL__WITH__CATCH = GVarName( "CALL_WITH_CATCH" ); + G_runtest = GVarName( "runtest" ); + G_IsAssociative = GVarName( "IsAssociative" ); + G_BreakOnError = GVarName( "BreakOnError" ); + G_Center = GVarName( "Center" ); + + /* record names used in handlers */ + + /* information for the functions */ + NameFunc[1] = 0; + NameFunc[2] = 0; + NameFunc[3] = 0; + NameFunc[4] = 0; + NameFunc[5] = 0; + NameFunc[6] = 0; + + /* return success */ + return 0; + +} + + +/* 'InitKernel' sets up data structures, fopies, copies, handlers */ +static Int InitKernel ( StructInitInfo * module ) +{ + + /* global variables used in handlers */ + InitFopyGVar( "Print", &GF_Print ); + InitFopyGVar( "CALL_WITH_CATCH", &GF_CALL__WITH__CATCH ); + InitCopyGVar( "IsAssociative", &GC_IsAssociative ); + InitCopyGVar( "Center", &GC_Center ); + + /* information for the functions */ + InitGlobalBag( &FileName, "and_filter.g:FileName("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc1, "and_filter.g:HdlrFunc1("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[1]), "and_filter.g:NameFunc[1]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc2, "and_filter.g:HdlrFunc2("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[2]), "and_filter.g:NameFunc[2]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc3, "and_filter.g:HdlrFunc3("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[3]), "and_filter.g:NameFunc[3]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc4, "and_filter.g:HdlrFunc4("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[4]), "and_filter.g:NameFunc[4]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc5, "and_filter.g:HdlrFunc5("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[5]), "and_filter.g:NameFunc[5]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc6, "and_filter.g:HdlrFunc6("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[6]), "and_filter.g:NameFunc[6]("FILE_CRC")" ); + + /* return success */ + return 0; + +} + +/* 'InitLibrary' sets up gvars, rnams, functions */ +static Int InitLibrary ( StructInitInfo * module ) +{ + Obj func1; + Obj body1; + + /* Complete Copy/Fopy registration */ + UpdateCopyFopyInfo(); + FileName = MakeImmString( "and_filter.g" ); + PostRestore(module); + + /* create all the functions defined in this module */ + func1 = NewFunction(NameFunc[1],0,0,HdlrFunc1); + SET_ENVI_FUNC( func1, STATE(CurrLVars) ); + CHANGED_BAG( STATE(CurrLVars) ); + body1 = NewBag( T_BODY, sizeof(BodyHeader)); + SET_BODY_FUNC( func1, body1 ); + CHANGED_BAG( func1 ); + CALL_0ARGS( func1 ); + + /* return success */ + return 0; + +} + +/* returns the description of this module */ +static StructInitInfo module = { + .type = MODULE_DYNAMIC, + .name = "and_filter.g", + .crc = -49920958, + .initKernel = InitKernel, + .initLibrary = InitLibrary, + .postRestore = PostRestore, +}; + +StructInitInfo * Init__Dynamic ( void ) +{ + return &module; +} + +/* compiled code ends here */ diff --git a/tst/test-compile/and_filter.g.out b/tst/test-compile/and_filter.g.out new file mode 100644 index 0000000000..7444bf30d1 --- /dev/null +++ b/tst/test-compile/and_filter.g.out @@ -0,0 +1,7 @@ +false +true +false +true + +Error, must be 'true' or 'false' or a filter (not a function) +Error, must be a filter (not a function) diff --git a/tst/test-compile/and_filter.g.static.c b/tst/test-compile/and_filter.g.static.c new file mode 100644 index 0000000000..1fd5a0befa --- /dev/null +++ b/tst/test-compile/and_filter.g.static.c @@ -0,0 +1,504 @@ +/* C file produced by GAC */ +#include "compiled.h" +#define FILE_CRC "-49920958" + +/* global variables used in handlers */ +static GVar G_Print; +static Obj GF_Print; +static GVar G_CALL__WITH__CATCH; +static Obj GF_CALL__WITH__CATCH; +static GVar G_runtest; +static GVar G_IsAssociative; +static Obj GC_IsAssociative; +static GVar G_BreakOnError; +static GVar G_Center; +static Obj GC_Center; + +/* record names used in handlers */ + +/* information for the functions */ +static Obj NameFunc[7]; +static Obj FileName; + +/* handler for function 3 */ +static Obj HdlrFunc3 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return false and 1; */ + t_2 = False; + if ( t_2 == False ) { + t_1 = t_2; + } + else if ( t_2 == True ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_1 = INTOBJ_INT(1); + } + else if (IS_FILTER( t_2 ) ) { + t_1 = NewAndFilter( t_2, INTOBJ_INT(1) ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 4 */ +static Obj HdlrFunc4 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return true or 1; */ + t_3 = True; + t_2 = (Obj)(UInt)(t_3 != False); + t_1 = (t_2 ? True : False); + if ( t_1 == False ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_3 = (Obj)(UInt)(INTOBJ_INT(1) != False); + t_1 = (t_3 ? True : False); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 5 */ +static Obj HdlrFunc5 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Obj t_4 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return Center and IsAssociative; */ + t_2 = GC_Center; + CHECK_BOUND( t_2, "Center" ) + if ( t_2 == False ) { + t_1 = t_2; + } + else if ( t_2 == True ) { + t_3 = GC_IsAssociative; + CHECK_BOUND( t_3, "IsAssociative" ) + CHECK_BOOL( t_3 ) + t_1 = t_3; + } + else if (IS_FILTER( t_2 ) ) { + t_4 = GC_IsAssociative; + CHECK_BOUND( t_4, "IsAssociative" ) + t_1 = NewAndFilter( t_2, t_4 ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 6 */ +static Obj HdlrFunc6 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Obj t_4 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* return IsAssociative and Center; */ + t_2 = GC_IsAssociative; + CHECK_BOUND( t_2, "IsAssociative" ) + if ( t_2 == False ) { + t_1 = t_2; + } + else if ( t_2 == True ) { + t_3 = GC_Center; + CHECK_BOUND( t_3, "Center" ) + CHECK_BOOL( t_3 ) + t_1 = t_3; + } + else if (IS_FILTER( t_2 ) ) { + t_4 = GC_Center; + CHECK_BOUND( t_4, "Center" ) + t_1 = NewAndFilter( t_2, t_4 ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_2), 0L ); + } + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return t_1; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 2 */ +static Obj HdlrFunc2 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Obj t_3 = 0; + Obj t_4 = 0; + Obj t_5 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* Print( false and 1, "\n" ); */ + t_1 = GF_Print; + t_3 = False; + if ( t_3 == False ) { + t_2 = t_3; + } + else if ( t_3 == True ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_2 = INTOBJ_INT(1); + } + else if (IS_FILTER( t_3 ) ) { + t_2 = NewAndFilter( t_3, INTOBJ_INT(1) ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_3), 0L ); + } + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( true or 1, "\n" ); */ + t_1 = GF_Print; + t_4 = True; + t_3 = (Obj)(UInt)(t_4 != False); + t_2 = (t_3 ? True : False); + if ( t_2 == False ) { + CHECK_BOOL( INTOBJ_INT(1) ) + t_4 = (Obj)(UInt)(INTOBJ_INT(1) != False); + t_2 = (t_4 ? True : False); + } + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( function ( ) + return false and 1; + end( ), "\n" ); */ + t_1 = GF_Print; + t_3 = NewFunction( NameFunc[3], 0, 0, HdlrFunc3 ); + SET_ENVI_FUNC( t_3, STATE(CurrLVars) ); + t_4 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_4, 5); + SET_ENDLINE_BODY(t_4, 5); + SET_FILENAME_BODY(t_4, FileName); + SET_BODY_FUNC(t_3, t_4); + CHANGED_BAG( STATE(CurrLVars) ); + t_2 = CALL_0ARGS( t_3 ); + CHECK_FUNC_RESULT( t_2 ) + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( function ( ) + return true or 1; + end( ), "\n" ); */ + t_1 = GF_Print; + t_3 = NewFunction( NameFunc[4], 0, 0, HdlrFunc4 ); + SET_ENVI_FUNC( t_3, STATE(CurrLVars) ); + t_4 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_4, 6); + SET_ENDLINE_BODY(t_4, 6); + SET_FILENAME_BODY(t_4, FileName); + SET_BODY_FUNC(t_3, t_4); + CHANGED_BAG( STATE(CurrLVars) ); + t_2 = CALL_0ARGS( t_3 ); + CHECK_FUNC_RESULT( t_2 ) + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* Print( IsAssociative and IsAssociative, "\n" ); */ + t_1 = GF_Print; + t_3 = GC_IsAssociative; + CHECK_BOUND( t_3, "IsAssociative" ) + if ( t_3 == False ) { + t_2 = t_3; + } + else if ( t_3 == True ) { + t_4 = GC_IsAssociative; + CHECK_BOUND( t_4, "IsAssociative" ) + CHECK_BOOL( t_4 ) + t_2 = t_4; + } + else if (IS_FILTER( t_3 ) ) { + t_5 = GC_IsAssociative; + CHECK_BOUND( t_5, "IsAssociative" ) + t_2 = NewAndFilter( t_3, t_5 ); + } + else { + ErrorQuit( + " must be 'true' or 'false' or a filter (not a %s)", + (Int)TNAM_OBJ(t_3), 0L ); + } + t_3 = MakeString( "\n" ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* BreakOnError := false; */ + t_1 = False; + AssGVar( G_BreakOnError, t_1 ); + + /* CALL_WITH_CATCH( function ( ) + return Center and IsAssociative; + end, [ ] ); */ + t_1 = GF_CALL__WITH__CATCH; + t_2 = NewFunction( NameFunc[5], 0, 0, HdlrFunc5 ); + SET_ENVI_FUNC( t_2, STATE(CurrLVars) ); + t_3 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_3, 13); + SET_ENDLINE_BODY(t_3, 13); + SET_FILENAME_BODY(t_3, FileName); + SET_BODY_FUNC(t_2, t_3); + CHANGED_BAG( STATE(CurrLVars) ); + t_3 = NEW_PLIST( T_PLIST, 0 ); + SET_LEN_PLIST( t_3, 0 ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* CALL_WITH_CATCH( function ( ) + return IsAssociative and Center; + end, [ ] ); */ + t_1 = GF_CALL__WITH__CATCH; + t_2 = NewFunction( NameFunc[6], 0, 0, HdlrFunc6 ); + SET_ENVI_FUNC( t_2, STATE(CurrLVars) ); + t_3 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_3, 16); + SET_ENDLINE_BODY(t_3, 16); + SET_FILENAME_BODY(t_3, FileName); + SET_BODY_FUNC(t_2, t_3); + CHANGED_BAG( STATE(CurrLVars) ); + t_3 = NEW_PLIST( T_PLIST, 0 ); + SET_LEN_PLIST( t_3, 0 ); + CALL_2ARGS( t_1, t_2, t_3 ); + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* handler for function 1 */ +static Obj HdlrFunc1 ( + Obj self ) +{ + Obj t_1 = 0; + Obj t_2 = 0; + Bag oldFrame; + OLD_BRK_CURR_STAT + + /* allocate new stack frame */ + SWITCH_TO_NEW_FRAME(self,0,0,oldFrame); + REM_BRK_CURR_STAT(); + SET_BRK_CURR_STAT(0); + + /* runtest := function ( ) + Print( false and 1, "\n" ); + Print( true or 1, "\n" ); + Print( function ( ) + return false and 1; + end( ), "\n" ); + Print( function ( ) + return true or 1; + end( ), "\n" ); + Print( IsAssociative and IsAssociative, "\n" ); + BreakOnError := false; + CALL_WITH_CATCH( function ( ) + return Center and IsAssociative; + end, [ ] ); + CALL_WITH_CATCH( function ( ) + return IsAssociative and Center; + end, [ ] ); + return; + end; */ + t_1 = NewFunction( NameFunc[2], 0, 0, HdlrFunc2 ); + SET_ENVI_FUNC( t_1, STATE(CurrLVars) ); + t_2 = NewBag( T_BODY, sizeof(BodyHeader) ); + SET_STARTLINE_BODY(t_2, 1); + SET_ENDLINE_BODY(t_2, 18); + SET_FILENAME_BODY(t_2, FileName); + SET_BODY_FUNC(t_1, t_2); + CHANGED_BAG( STATE(CurrLVars) ); + AssGVar( G_runtest, t_1 ); + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; + + /* return; */ + RES_BRK_CURR_STAT(); + SWITCH_TO_OLD_FRAME(oldFrame); + return 0; +} + +/* 'PostRestore' restore gvars, rnams, functions */ +static Int PostRestore ( StructInitInfo * module ) +{ + + /* global variables used in handlers */ + G_Print = GVarName( "Print" ); + G_CALL__WITH__CATCH = GVarName( "CALL_WITH_CATCH" ); + G_runtest = GVarName( "runtest" ); + G_IsAssociative = GVarName( "IsAssociative" ); + G_BreakOnError = GVarName( "BreakOnError" ); + G_Center = GVarName( "Center" ); + + /* record names used in handlers */ + + /* information for the functions */ + NameFunc[1] = 0; + NameFunc[2] = 0; + NameFunc[3] = 0; + NameFunc[4] = 0; + NameFunc[5] = 0; + NameFunc[6] = 0; + + /* return success */ + return 0; + +} + + +/* 'InitKernel' sets up data structures, fopies, copies, handlers */ +static Int InitKernel ( StructInitInfo * module ) +{ + + /* global variables used in handlers */ + InitFopyGVar( "Print", &GF_Print ); + InitFopyGVar( "CALL_WITH_CATCH", &GF_CALL__WITH__CATCH ); + InitCopyGVar( "IsAssociative", &GC_IsAssociative ); + InitCopyGVar( "Center", &GC_Center ); + + /* information for the functions */ + InitGlobalBag( &FileName, "and_filter.g:FileName("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc1, "and_filter.g:HdlrFunc1("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[1]), "and_filter.g:NameFunc[1]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc2, "and_filter.g:HdlrFunc2("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[2]), "and_filter.g:NameFunc[2]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc3, "and_filter.g:HdlrFunc3("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[3]), "and_filter.g:NameFunc[3]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc4, "and_filter.g:HdlrFunc4("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[4]), "and_filter.g:NameFunc[4]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc5, "and_filter.g:HdlrFunc5("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[5]), "and_filter.g:NameFunc[5]("FILE_CRC")" ); + InitHandlerFunc( HdlrFunc6, "and_filter.g:HdlrFunc6("FILE_CRC")" ); + InitGlobalBag( &(NameFunc[6]), "and_filter.g:NameFunc[6]("FILE_CRC")" ); + + /* return success */ + return 0; + +} + +/* 'InitLibrary' sets up gvars, rnams, functions */ +static Int InitLibrary ( StructInitInfo * module ) +{ + Obj func1; + Obj body1; + + /* Complete Copy/Fopy registration */ + UpdateCopyFopyInfo(); + FileName = MakeImmString( "and_filter.g" ); + PostRestore(module); + + /* create all the functions defined in this module */ + func1 = NewFunction(NameFunc[1],0,0,HdlrFunc1); + SET_ENVI_FUNC( func1, STATE(CurrLVars) ); + CHANGED_BAG( STATE(CurrLVars) ); + body1 = NewBag( T_BODY, sizeof(BodyHeader)); + SET_BODY_FUNC( func1, body1 ); + CHANGED_BAG( func1 ); + CALL_0ARGS( func1 ); + + /* return success */ + return 0; + +} + +/* returns the description of this module */ +static StructInitInfo module = { + .type = MODULE_STATIC, + .name = "and_filter.g", + .crc = -49920958, + .initKernel = InitKernel, + .initLibrary = InitLibrary, + .postRestore = PostRestore, +}; + +StructInitInfo * Init__and__filter ( void ) +{ + return &module; +} + +/* compiled code ends here */ diff --git a/tst/testinstall/boolean.tst b/tst/testinstall/boolean.tst index 7744cd4404..58e0bab7ec 100644 --- a/tst/testinstall/boolean.tst +++ b/tst/testinstall/boolean.tst @@ -80,13 +80,13 @@ Error, must be 'true' or 'false' or a filter (not a function) gap> ReturnTrue and true; Error, must be 'true' or 'false' or a filter (not a function) gap> IsAssociative and ReturnTrue; -Error, must be a filter (not a function) +Error, must be a filter (not a function) gap> IsAssociative and true; -Error, must be a filter (not a function) +Error, must be a filter (not a boolean or fail) gap> IsAssociative and Center; -Error, must be a filter (not a function) +Error, must be a filter (not a function) gap> IsAssociative and FirstOp; -Error, must be a filter (not a function) +Error, must be a filter (not a function) gap> true and IsAssociative; Error, must be 'true' or 'false' (not a function) gap> Center and IsAssociative; @@ -112,13 +112,13 @@ Error, must be 'true' or 'false' or a filter (not a function) gap> function() return ReturnTrue and true; end(); Error, must be 'true' or 'false' or a filter (not a function) gap> function() return IsAssociative and ReturnTrue; end(); -Error, must be a filter (not a function) +Error, must be a filter (not a function) gap> function() return IsAssociative and true; end(); -Error, must be a filter (not a function) +Error, must be a filter (not a boolean or fail) gap> function() return IsAssociative and Center; end(); -Error, must be a filter (not a function) +Error, must be a filter (not a function) gap> function() return IsAssociative and FirstOp; end(); -Error, must be a filter (not a function) +Error, must be a filter (not a function) gap> function() return true and IsAssociative; end(); Error, must be 'true' or 'false' (not a function) gap> function() return Center and IsAssociative; end();