Index: generic/gentclAPI.decls =================================================================== diff -u -r12f68a7ade25ae2bb0fccb8a88583fc0d22edda0 -r4a478eb598eea7cc8dec70222777d114c55f1ff8 --- generic/gentclAPI.decls (.../gentclAPI.decls) (revision 12f68a7ade25ae2bb0fccb8a88583fc0d22edda0) +++ generic/gentclAPI.decls (.../gentclAPI.decls) (revision 4a478eb598eea7cc8dec70222777d114c55f1ff8) @@ -138,6 +138,10 @@ {-argName "-per-object"} {-argName "methodName" -required 1} } +xotclCmd valuecheck XOTclValuecheckCmd { + {-argName "param" -type tclobj} + {-argName "value" -required 0 -type tclobj} +} # # object methods # Index: generic/tclAPI.h =================================================================== diff -u -rfe19549734064c3a57866e7e47743ec787f647e5 -r4a478eb598eea7cc8dec70222777d114c55f1ff8 --- generic/tclAPI.h (.../tclAPI.h) (revision fe19549734064c3a57866e7e47743ec787f647e5) +++ generic/tclAPI.h (.../tclAPI.h) (revision 4a478eb598eea7cc8dec70222777d114c55f1ff8) @@ -186,6 +186,7 @@ static int XOTclRelationCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int XOTclSetInstvarCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int XOTclSetterCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int XOTclValuecheckCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int XOTclCheckBooleanArgs(Tcl_Interp *interp, char *name, Tcl_Obj *value); static int XOTclCheckRequiredArgs(Tcl_Interp *interp, char *name, Tcl_Obj *value); @@ -268,6 +269,7 @@ static int XOTclRelationCmd(Tcl_Interp *interp, XOTclObject *object, int relationtype, Tcl_Obj *value); static int XOTclSetInstvarCmd(Tcl_Interp *interp, XOTclObject *object, Tcl_Obj *variable, Tcl_Obj *value); static int XOTclSetterCmd(Tcl_Interp *interp, XOTclObject *object, int withPer_object, char *methodName); +static int XOTclValuecheckCmd(Tcl_Interp *interp, Tcl_Obj *param, Tcl_Obj *value); enum { XOTclCheckBooleanArgsIdx, @@ -350,7 +352,8 @@ XOTclQualifyObjCmdIdx, XOTclRelationCmdIdx, XOTclSetInstvarCmdIdx, - XOTclSetterCmdIdx + XOTclSetterCmdIdx, + XOTclValuecheckCmdIdx } XOTclMethods; @@ -1959,6 +1962,25 @@ } } +static int +XOTclValuecheckCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + parseContext pc; + + if (ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[XOTclValuecheckCmdIdx].paramDefs, + method_definitions[XOTclValuecheckCmdIdx].nrParameters, + &pc) != TCL_OK) { + return TCL_ERROR; + } else { + Tcl_Obj *param = (Tcl_Obj *)pc.clientData[0]; + Tcl_Obj *value = (Tcl_Obj *)pc.clientData[1]; + + parseContextRelease(&pc); + return XOTclValuecheckCmd(interp, param, value); + + } +} + static methodDefinition method_definitions[] = { {"::xotcl::cmd::ParameterType::type=boolean", XOTclCheckBooleanArgsStub, 2, { {"name", 1, 0, convertToString}, @@ -2320,6 +2342,10 @@ {"object", 1, 0, convertToObject}, {"-per-object", 0, 0, convertToString}, {"methodName", 1, 0, convertToString}} +}, +{"::xotcl::valuecheck", XOTclValuecheckCmdStub, 2, { + {"param", 0, 0, convertToTclobj}, + {"value", 0, 0, convertToTclobj}} },{NULL} }; Index: generic/xotcl.c =================================================================== diff -u -r4ce2a0659cf44b3dbb7262f63fadb3333c968751 -r4a478eb598eea7cc8dec70222777d114c55f1ff8 --- generic/xotcl.c (.../xotcl.c) (revision 4ce2a0659cf44b3dbb7262f63fadb3333c968751) +++ generic/xotcl.c (.../xotcl.c) (revision 4a478eb598eea7cc8dec70222777d114c55f1ff8) @@ -12061,6 +12061,86 @@ } return result; } + +static void ParamFreeInternalRep(register Tcl_Obj *objPtr); +static int ParamSetFromAny(Tcl_Interp *interp, register Tcl_Obj *objPtr); +static Tcl_ObjType paramObjType = { + "xotclParam", /* name */ + ParamFreeInternalRep, /* freeIntRepProc */ + NULL, /* dupIntRepProc */ + NULL, /* updateStringProc */ + ParamSetFromAny /* setFromAnyProc */ +}; + +static void +ParamFreeInternalRep( + register Tcl_Obj *objPtr) /* Param structure object with internal + * representation to free. */ +{ + XOTclParam *paramPtr = (XOTclParam *) objPtr->internalRep.twoPtrValue.ptr1; + if (paramPtr != NULL) { + /*fprintf(stderr, "freeing %p\n",paramPtr);*/ + ParamsFree(paramPtr); + } +} + +static int +ParamSetFromAny( + Tcl_Interp *interp, /* Used for error reporting if not NULL. */ + register Tcl_Obj *objPtr) /* The object to convert. */ +{ + XOTclParam *paramPtr; + Tcl_Obj *fullParamObj = Tcl_NewStringObj("value:", 6); + int result, possibleUnknowns = 0, plainParams = 0; + + paramPtr = ParamsNew(1); + /*fprintf(stderr, "allocating %p\n",paramPtr);*/ + + Tcl_AppendToObj(fullParamObj, ObjStr(objPtr), -1); + INCR_REF_COUNT(fullParamObj); + result = ParamParse(interp, "valuecheck", fullParamObj, + XOTCL_ARG_METHOD_PARAMETER /* allowed options */, + paramPtr, &possibleUnknowns, &plainParams); + if (result == TCL_OK) { + TclFreeIntRep(objPtr); + objPtr->internalRep.twoPtrValue.ptr1 = (void *)paramPtr; + objPtr->internalRep.twoPtrValue.ptr2 = NULL; + objPtr->typePtr = ¶mObjType; + } + + DECR_REF_COUNT(fullParamObj); + return result; +} + +/* +xotclCmd valuecheck XOTclValuecheckCmd { + {-argName "param" -type tclobj} + {-argName "value" -required 0 -type tclobj} + } */ +static int XOTclValuecheckCmd(Tcl_Interp *interp, Tcl_Obj *objPtr, Tcl_Obj *value) { + /* xxxx */ + ClientData checkedData; + XOTclParam *paramPtr; + int result; + + if (objPtr->typePtr == ¶mObjType) { + paramPtr = (XOTclParam *) objPtr->internalRep.twoPtrValue.ptr1; + } else { + result = ParamSetFromAny(interp, objPtr); + if (result == TCL_OK) { + paramPtr = (XOTclParam *) objPtr->internalRep.twoPtrValue.ptr1; + } else { + return XOTclVarErrMsg(interp, + "invalid value constraints \"", ObjStr(objPtr), "\"", + (char *) NULL); + } + } + + result = ArgumentCheck(interp, value, paramPtr, &checkedData); + Tcl_SetIntObj(Tcl_GetObjResult(interp), (result == TCL_OK)); + return TCL_OK; +} + /*************************** * End generated XOTcl commands ***************************/ Index: tests/parameters.xotcl =================================================================== diff -u -r4ce2a0659cf44b3dbb7262f63fadb3333c968751 -r4a478eb598eea7cc8dec70222777d114c55f1ff8 --- tests/parameters.xotcl (.../parameters.xotcl) (revision 4ce2a0659cf44b3dbb7262f63fadb3333c968751) +++ tests/parameters.xotcl (.../parameters.xotcl) (revision 4a478eb598eea7cc8dec70222777d114c55f1ff8) @@ -7,6 +7,29 @@ ::xotcl::use xotcl2 +####################################################### +# valuecheck +####################################################### +Test case valuecheck +Test parameter count 10000 +#Test parameter count 10 +Object create o1 +? {::xotcl::valuecheck object o1} 1 +? {::xotcl::is o1 object} 1 +? {::xotcl::valuecheck class o1} 0 +? {::xotcl::valuecheck class Test} 1 +? {::xotcl::valuecheck object,multivalued [list o1 Test]} 1 +? {::xotcl::valuecheck integer 1} 1 +? {::xotcl::valuecheck integer,multivalued [list 1 2 3]} 1 +? {::xotcl::valuecheck integer,multivalued [list 1 2 3 a]} 0 +? {::xotcl::valuecheck in1 aaa} {invalid value constraints "in1"} + +####################################################### +# objectparameter +####################################################### +Test case objectparameter + +Test parameter count 10 Class create C -parameter {a {b:boolean} {c 1}} C create c1 ? {C eval {:objectparameter}} "-object-mixin:relation -mixin:relation,arg=class-mixin\ @@ -18,9 +41,10 @@ "-a -b:boolean {-c 1} -mixin:relation,arg=object-mixin -filter:relation\ -class:relation -noinit:method,optional,noarg -volatile:method,optional,noarg\ arg:initcmd,optional" -# + +####################################################### # reclass to Object, no need to do anything on caching -# +####################################################### Test case reclass c1 class Object ? {c1 eval :objectparameter} "-mixin:relation,arg=object-mixin -filter:relation\ @@ -35,9 +59,9 @@ -class:relation -noinit:method,optional,noarg -volatile:method,optional,noarg\ arg:initcmd,optional" -# +####################################################### # Add mixin -# +####################################################### Test case objparam-mixins Class create M -parameter {m1 m2 b} Class create M2 -parameter {b2} @@ -77,9 +101,9 @@ arg:initcmd,optional" -# +####################################################### # test passed arguments -# +####################################################### Test case passed-arguments ? {catch {D create d1 -d 123}} 0 "create d1 with required argument given" @@ -131,9 +155,9 @@ {Parameter option 'relation' not allowed} \ "don't allow relation option as method parameter" -# +####################################################### # non required positional arguments -# +####################################################### Test case non-reg-args D method foo {a b:optional c:optional} { @@ -149,9 +173,9 @@ ? {d1 foo 1 2} "1-1-0-1" "omit optional argument" ? {d1 foo 1} "1-0-0-1" "omit optional arguments" -# +####################################################### # non required positional arguments -# +####################################################### Test case multivalued Object create o @@ -184,9 +208,9 @@ ? {foo ints add 0} "0 1 2" ? {foo ints add a} {expected integer but got "a"} -# +####################################################### # subst default tests -# +####################################################### Test case subst-default D method bar { @@ -269,9 +293,9 @@ "a 1 b 1 c 1 end 1" \ "query arguments with default, no paramdefs needed" -# +####################################################### # Query method parameter -# +####################################################### Test case query-method-parameter ? {D info method parameter foo} \ @@ -296,9 +320,9 @@ # "query instparams for info method 'params' method" -# +####################################################### # user defined parameter types -# +####################################################### Test case user-types # @@ -396,9 +420,9 @@ ? {d1 foo -a 2 10} "a=2,b=10" -# +####################################################### # testing object types in method parameters -# +####################################################### Test case mp-object-types Class create M D create d1 -d 1 @@ -481,9 +505,9 @@ "o not of type ::C" -# +####################################################### # testing object types in object parameters -# +####################################################### Test case op-object-types Class create M D create d1 -d 1 @@ -513,12 +537,6 @@ # maybe "mixin" => "hasmixin" # => effects as well ::xotcl::is # -# TODO: It looks, as if we need multivalues as well on object -# parameters. If a slot has multivalued set, objectparameter -# must honor it. This would allow general checking of e.g. list -# of integers, list of objects, etc. Therefore, we would not -# need to duplicate this functionality on the slots. -# # TODO (optimization): optimizer can improve parameter checking: # (a) simple approach: make scripted setter methods on domain # (b) maybe nicer: provide arguments to c-setter to