Index: TODO =================================================================== diff -u -r761c9758221eb84b88a328e659523c4773aa5dfe -rb6d81c6521d1e1d58f00763f5ab30a0946cc222a --- TODO (.../TODO) (revision 761c9758221eb84b88a328e659523c4773aa5dfe) +++ TODO (.../TODO) (revision b6d81c6521d1e1d58f00763f5ab30a0946cc222a) @@ -1245,6 +1245,12 @@ - added flag -complain to ::nsf::is - removed ::nsf::parametercheck +- new parameter option "convert" to signal that an application + specific parameter checker should convert the value + (takes the result of the methods as conversion result) +- added parameters for slots "allowemtpy" and "convert" +- extended regression test + TODO: - reflect changes in /is/objectproperty/info has/info is/ in migration guide - implement built-in-converter for "baseclass" and "metaclass"? Index: generic/xotcl.c =================================================================== diff -u -r761c9758221eb84b88a328e659523c4773aa5dfe -rb6d81c6521d1e1d58f00763f5ab30a0946cc222a --- generic/xotcl.c (.../xotcl.c) (revision 761c9758221eb84b88a328e659523c4773aa5dfe) +++ generic/xotcl.c (.../xotcl.c) (revision b6d81c6521d1e1d58f00763f5ab30a0946cc222a) @@ -5439,6 +5439,9 @@ if ((pPtr->flags & XOTCL_ARG_ALLOW_EMPTY)) { ParamDefsFormatOption(interp, nameStringObj, "allowempty", &colonWritten, &first); } + if ((pPtr->flags & XOTCL_ARG_IS_CONVERTER)) { + ParamDefsFormatOption(interp, nameStringObj, "convert", &colonWritten, &first); + } if ((pPtr->flags & XOTCL_ARG_INITCMD)) { ParamDefsFormatOption(interp, nameStringObj, "initcmd", &colonWritten, &first); } else if ((pPtr->flags & XOTCL_ARG_METHOD)) { @@ -6534,19 +6537,22 @@ DECR_REF_COUNT(ov[1]); DECR_REF_COUNT(ov[2]); + *outObjPtr = objPtr; + if (result == TCL_OK) { /*fprintf(stderr, "convertViaCmd converts %s to '%s' paramPtr %p\n", ObjStr(objPtr), ObjStr(Tcl_GetObjResult(interp)),pPtr);*/ - *outObjPtr = Tcl_GetObjResult(interp); + if (pPtr->flags & XOTCL_ARG_IS_CONVERTER) { + /* + * If we want to convert, the resulting obj is the result of the + * converter. incr refCount is necessary e.g. for e.g. + * return [expr {$value + 1}] + */ + *outObjPtr = Tcl_GetObjResult(interp); + INCR_REF_COUNT(*outObjPtr); + } *clientData = (ClientData) *outObjPtr; - - /* incr refCount is necessary e.g. for - return [expr {$value + 1}] - */ - INCR_REF_COUNT(*outObjPtr); - } else { - *outObjPtr = objPtr; - } + } return result; } @@ -6615,6 +6621,8 @@ paramPtr->flags |= XOTCL_ARG_SUBST_DEFAULT; } else if (strncmp(option, "allowempty", 10) == 0) { paramPtr->flags |= XOTCL_ARG_ALLOW_EMPTY; + } else if (strncmp(option, "convert", 7) == 0) { + paramPtr->flags |= XOTCL_ARG_IS_CONVERTER; } else if (strncmp(option, "initcmd", 7) == 0) { paramPtr->flags |= XOTCL_ARG_INITCMD; } else if (strncmp(option, "method", 6) == 0) { @@ -6859,10 +6867,14 @@ result = ParamOptionSetConverter(interp, paramPtr, converterNameString, convertViaCmd); } } + if ((paramPtr->flags & XOTCL_ARG_IS_CONVERTER) && paramPtr->converter != convertViaCmd) { + return XOTclVarErrMsg(interp, + "option 'convert' only allowed for application-defined converters", + (char *) NULL); + } if (converterNameObj != paramPtr->converterName) { DECR_REF_COUNT(converterNameObj); } - } /* Index: generic/xotclInt.h =================================================================== diff -u -rd2f17f8dd98fcfa82a8473ed5e299c7c2026a80f -rb6d81c6521d1e1d58f00763f5ab30a0946cc222a --- generic/xotclInt.h (.../xotclInt.h) (revision d2f17f8dd98fcfa82a8473ed5e299c7c2026a80f) +++ generic/xotclInt.h (.../xotclInt.h) (revision b6d81c6521d1e1d58f00763f5ab30a0946cc222a) @@ -374,12 +374,13 @@ #define XOTCL_ARG_RELATION 0x0100 #define XOTCL_ARG_SWITCH 0x0200 #define XOTCL_ARG_HAS_DEFAULT 0x1000 +#define XOTCL_ARG_IS_CONVERTER 0x2000 /* disallowed options */ #define XOTCL_DISALLOWED_ARG_METHOD_PARAMETER (XOTCL_ARG_METHOD|XOTCL_ARG_INITCMD|XOTCL_ARG_RELATION) #define XOTCL_DISALLOWED_ARG_SETTER (XOTCL_ARG_SUBST_DEFAULT|XOTCL_DISALLOWED_ARG_METHOD_PARAMETER) #define XOTCL_DISALLOWED_ARG_OBJECT_PARAMETER 0 -#define XOTCL_DISALLOWED_ARG_VALUEECHECK (XOTCL_ARG_SUBST_DEFAULT|XOTCL_ARG_METHOD|XOTCL_ARG_INITCMD|XOTCL_ARG_RELATION|XOTCL_ARG_SWITCH|XOTCL_ARG_CURRENTLY_UNKNOWN) +#define XOTCL_DISALLOWED_ARG_VALUEECHECK (XOTCL_ARG_SUBST_DEFAULT|XOTCL_ARG_METHOD|XOTCL_ARG_INITCMD|XOTCL_ARG_RELATION|XOTCL_ARG_SWITCH|XOTCL_ARG_CURRENTLY_UNKNOWN|XOTCL_ARG_IS_CONVERTER) /* method types */ Index: library/nx/nx.tcl =================================================================== diff -u -rf20a7f81bcae20a40c4990afd431615ca1914c51 -rb6d81c6521d1e1d58f00763f5ab30a0946cc222a --- library/nx/nx.tcl (.../nx.tcl) (revision f20a7f81bcae20a40c4990afd431615ca1914c51) +++ library/nx/nx.tcl (.../nx.tcl) (revision b6d81c6521d1e1d58f00763f5ab30a0946cc222a) @@ -1294,6 +1294,12 @@ lappend objopts $prefix=${:arg} lappend methodopts $prefix=${:arg} } + foreach att {convert allowempty} { + if {[info exists :$att]} { + lappend objopts $att + lappend methodopts $att + } + } if {[info exists :default]} { set arg ${:default} # deactivated for now: || [string first {$} $arg] > -1 @@ -1617,6 +1623,8 @@ valuecmd valuechangedcmd arg + allowempty + convert } Attribute method __default_from_cmd {obj cmd var sub op} { Index: library/xotcl/tests/slottest.xotcl =================================================================== diff -u -r76fadfb3f603f8f96a6064f4bb5342133923ec53 -rb6d81c6521d1e1d58f00763f5ab30a0946cc222a --- library/xotcl/tests/slottest.xotcl (.../slottest.xotcl) (revision 76fadfb3f603f8f96a6064f4bb5342133923ec53) +++ library/xotcl/tests/slottest.xotcl (.../slottest.xotcl) (revision b6d81c6521d1e1d58f00763f5ab30a0946cc222a) @@ -408,7 +408,7 @@ ? {p2 salary} 1009 Person slots { - Attribute create sex -type "sex" { + Attribute create sex -type "sex" -convert true { :method type=sex {name value} { #puts stderr "[self] slot specific converter" switch -glob $value { @@ -421,7 +421,7 @@ } Person p3 -sex male ? {p3 sex} m -Person method foo {s:sex,slot=::Person::slot::sex} {return $s} +Person method foo {s:sex,slot=::Person::slot::sex,convert} {return $s} ? {p3 foo male} "m" ? {p3 sex male} m Index: tests/parameters.tcl =================================================================== diff -u -r4dc0f6d2bab7c95b74c346604e63cecec770f8fc -rb6d81c6521d1e1d58f00763f5ab30a0946cc222a --- tests/parameters.tcl (.../parameters.tcl) (revision 4dc0f6d2bab7c95b74c346604e63cecec770f8fc) +++ tests/parameters.tcl (.../parameters.tcl) (revision b6d81c6521d1e1d58f00763f5ab30a0946cc222a) @@ -77,6 +77,9 @@ ? {::nsf::is switch 1} {invalid value constraints "switch"} ? {::nsf::is superclass M} {invalid value constraints "superclass"} + # don't allow convert + ? {::nsf::is integer,convert 1} {invalid value constraints "integer,convert"} + # tcl checker ? {::nsf::is upper ABC} 1 ? {::nsf::is upper Abc} 0 @@ -933,11 +936,12 @@ } } Class create C { - :method foo {s:sex,multivalued} {return $s} + :method foo {s:sex,multivalued,convert} {return $s} + :method bar {s:sex,multivalued} {return $s} } C create c1 ? {c1 foo {male female mann frau}} "m f m f" - + ? {c1 bar {male female mann frau}} "male female mann frau" Object create tmpObj tmpObj method type=mType {name value arg:optional} { @@ -966,7 +970,7 @@ } } Object create o { - :method foo {x:integer,slot=::mySlot} { + :method foo {x:integer,slot=::mySlot,convert} { return $x } } @@ -1012,6 +1016,7 @@ Class create Person { :attribute sex { :type "sex" + :convert true :method type=sex {name value} { #puts stderr "[self] slot specific converter" switch -glob $value { @@ -1025,7 +1030,7 @@ Person create p1 -sex male ? {p1 sex} m - Person method foo {s:sex,slot=::Person::slot::sex} {return $s} + Person method foo {s:sex,slot=::Person::slot::sex,convert} {return $s} ? {p1 foo male} m ? {p1 sex male} m }