From 5908729bce50a04fdf993905411f279227c8b46a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 30 Apr 2018 21:59:01 +0200 Subject: [PATCH] Improve and test support for custom functions * NamesLocalVariablesFunction actually is a kernel operation, mark it as such * fix a crash caused by infinite recursion when trying to display a function which is not a `T_FUNCTION` * add tests for installing custom methods for NameFunction, NamesLocalVariablesFunction, and NumberArgumentsFunction --- lib/function.g | 21 ++++++++------------- lib/function.gi | 6 +++--- tst/testinstall/callfunc.tst | 21 +++++++++++++++++---- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/function.g b/lib/function.g index fde53d9fb7..d5cd34631b 100644 --- a/lib/function.g +++ b/lib/function.g @@ -162,10 +162,10 @@ DeclareOperationKernel("NameFunction", [IS_OBJECT], NAME_FUNC); ############################################################################# ## -#F SetNameFunction( , ) . . . . . . . .set name of a function +#O SetNameFunction( , ) . . . . . . . .set name of a function ## ## -## +## ## ## ## changes the name of a function. This only changes the name stored in @@ -174,15 +174,12 @@ DeclareOperationKernel("NameFunction", [IS_OBJECT], NAME_FUNC); ## ## ## -#T If objects simulate functions this must become an operation, or an attribute -#T with the above -## DeclareOperationKernel( "SetNameFunction", [IS_OBJECT, IS_STRING], SET_NAME_FUNC ); ############################################################################# ## -#F NumberArgumentsFunction( ) +#O NumberArgumentsFunction( ) ## ## <#GAPDoc Label="NumberArgumentsFunction"> ## @@ -216,7 +213,7 @@ DeclareOperationKernel( "NumberArgumentsFunction", [IS_OBJECT], NARG_FUNC ); ############################################################################# ## -#F NamesLocalVariablesFunction( ) +#O NamesLocalVariablesFunction( ) ## ## <#GAPDoc Label="NamesLocalVariablesFunction"> ## @@ -229,7 +226,7 @@ DeclareOperationKernel( "NumberArgumentsFunction", [IS_OBJECT], NARG_FUNC ); ## func, and the remaining ones are the local variables as given in ## the local statement in func. ## (The number of arguments can be computed with -## .) +## .) ##

## NamesLocalVariablesFunction(function( a, b ) local c; return 1; end); @@ -243,7 +240,7 @@ DeclareOperationKernel( "NumberArgumentsFunction", [IS_OBJECT], NARG_FUNC ); ## ## <#/GAPDoc> ## -BIND_GLOBAL( "NamesLocalVariablesFunction", NAMS_FUNC ); +DeclareOperationKernel( "NamesLocalVariablesFunction", [IS_OBJECT], NAMS_FUNC ); ############################################################################# @@ -368,7 +365,7 @@ end); ############################################################################# ## -#F CallFuncList( , ) . . . . . . . . . . . . . call a function +#O CallFuncList( , ) . . . . . . . . . . . . . call a function ## ## <#GAPDoc Label="CallFuncList"> ## @@ -389,7 +386,7 @@ end); ## 13 ## ]]> ##

-## A more useful application of is for a function +## A more useful application of is for a function ## g that is called in the body of a function f with ## (a sublist of) the arguments of f, where f has been defined ## with a single formal argument arg @@ -441,8 +438,6 @@ end); ## ## <#/GAPDoc> ## -#T If objects simulate functions this must become an operation. -## UNBIND_GLOBAL("CallFuncList"); # was declared 2b defined DeclareOperationKernel( "CallFuncList", [IS_OBJECT, IS_LIST], CALL_FUNC_LIST ); DeclareOperationKernel( "CallFuncListWrap", [IS_OBJECT, IS_LIST], CALL_FUNC_LIST_WRAP ); diff --git a/lib/function.gi b/lib/function.gi index d587e68c06..e0d25bc3cf 100644 --- a/lib/function.gi +++ b/lib/function.gi @@ -10,7 +10,7 @@ ## that they need to be in function.g ## -InstallMethod( ViewString, "for a function", true, [IsFunction], 0, +InstallMethod( ViewString, "for a function", [IsFunction and IsInternalRep], function(func) local locks, nams, narg, i, isvarg, result; result := ""; @@ -60,7 +60,7 @@ function(func) return result; end); -InstallMethod(DisplayString, "for a function, using string stream", [IsFunction], +InstallMethod(DisplayString, "for a function, using string stream", [IsFunction and IsInternalRep], function(fun) local s, stream; s := ""; @@ -71,7 +71,7 @@ function(fun) return MakeImmutable(s); end); -InstallMethod(String, "for a function, with whitespace reduced", [IsFunction], +InstallMethod(String, "for a function, with whitespace reduced", [IsFunction and IsInternalRep], function(fun) local s, str; s := ShallowCopy(DisplayString(fun)); diff --git a/tst/testinstall/callfunc.tst b/tst/testinstall/callfunc.tst index b833333578..f16067356f 100644 --- a/tst/testinstall/callfunc.tst +++ b/tst/testinstall/callfunc.tst @@ -29,12 +29,25 @@ gap> ForAll([0..100], x -> CallFuncListWrap(swallow, List([1..x], y -> [y]) ) = true # test overloading CallFuncList -gap> fam := NewFamily("XYZsFamily");; -gap> cat := NewCategory("IsXYZ",IsObject);; +gap> fam := NewFamily("CustomFunctionFamily");; +gap> cat := NewCategory("IsCustomFunction", IsFunction);; gap> type := NewType(fam, cat and IsPositionalObjectRep);; gap> result := fail;; gap> InstallMethod(CallFuncList,[cat,IsList],function(func,args) result:=args; return args; end); -gap> o := Objectify(type,[]);; +gap> InstallMethod(NameFunction, [cat], f -> f![1]); +gap> InstallMethod(NamesLocalVariablesFunction, [cat], f -> ["arg"]); +gap> InstallMethod(NumberArgumentsFunction, [cat], f -> -1); + +# +gap> o := Objectify(type,["myName"]);; +gap> Display(o); + +gap> NameFunction(o); +"myName" +gap> NamesLocalVariablesFunction(o); +[ "arg" ] +gap> NumberArgumentsFunction(o); +-1 # test dispatch through interpreter / IntrFuncCallEnd gap> o(); @@ -109,7 +122,7 @@ gap> CallFuncList(o, [1,2,3,4,5,6,7]); [ 1, 2, 3, 4, 5, 6, 7 ] # test overloading CallFuncList with a procedure call -gap> cat2 := NewCategory("IsXYZ2",IsObject);; +gap> cat2 := NewCategory("IsCustomFunction2",IsFunction);; gap> type2 := NewType(fam, cat2 and IsPositionalObjectRep);; gap> InstallMethod(CallFuncList,[cat2,IsList],function(func,args) result:=args; end); gap> o2 := Objectify(type2,[]);;