Index: generic/predefined.h =================================================================== diff -u -rf4e75c452cf99c87ad8705c954cb9548652873fa -r3ecb613fe4ef3fd510e73792cdf0764a1d1489ab --- generic/predefined.h (.../predefined.h) (revision f4e75c452cf99c87ad8705c954cb9548652873fa) +++ generic/predefined.h (.../predefined.h) (revision 3ecb613fe4ef3fd510e73792cdf0764a1d1489ab) @@ -148,62 +148,6 @@ "::xotcl::MetaSlot create ::xotcl::Slot\n" "::xotcl::MetaSlot create ::xotcl::ObjectParameterSlot\n" "::xotcl::relation ::xotcl::ObjectParameterSlot superclass ::xotcl::Slot\n" -"::xotcl::MetaSlot __invalidateobjectparameter\n" -"::xotcl::ObjectParameterSlot method toParameterSyntax {name} {\n" -"set objparamdefinition $name\n" -"set methodparamdefinition \"\"\n" -"set objopts [list]\n" -"set methodopts [list]\n" -"if {[info exists :required] && ${:required}} {\n" -"lappend objopts required\n" -"lappend methodopts required}\n" -"if {[info exists :type]} {\n" -"if {[string match ::* ${:type}]} {\n" -"lappend objopts object type=${:type}\n" -"lappend methodopts object type=${:type}} else {\n" -"lappend objopts ${:type}\n" -"lappend methodopts ${:type}}}\n" -"if {[info exists :multivalued] && ${:multivalued}} {\n" -"if {!([info exists :type] && ${:type} eq \"relation\")} {\n" -"lappend objopts multivalued} else {}}\n" -"if {[info exists :arg]} {\n" -"lappend objopts arg=${:arg}\n" -"lappend methodopts arg=${:arg}}\n" -"if {[info exists :default]} {\n" -"set arg ${:default}\n" -"if {[string match {*\\[*\\]*} $arg]} {\n" -"lappend objopts substdefault}} elseif {[info exists :initcmd]} {\n" -"set arg ${:initcmd}\n" -"lappend objopts initcmd}\n" -"if {[info exists :methodname]} {\n" -"if {${:methodname} ne ${:name}} {\n" -"lappend objopts arg=${:methodname}\n" -"lappend methodopts arg=${:methodname}}}\n" -"if {[llength $objopts] > 0} {\n" -"append objparamdefinition :[join $objopts ,]}\n" -"if {[llength $methodopts] > 0} {\n" -"set methodparamdefinition [join $methodopts ,]}\n" -"if {[info exists arg]} {\n" -"lappend objparamdefinition $arg}\n" -"return [list oparam $objparamdefinition mparam $methodparamdefinition]}\n" -"proc ::xotcl::parametersFromSlots {obj} {\n" -"set parameterdefinitions [list]\n" -"foreach slot [::xotcl2::objectInfo slotobjects $obj] {\n" -"if {[::xotcl::is $obj type ::xotcl::Object] &&\n" -"([$slot name] eq \"mixin\" || [$slot name] eq \"filter\")} continue\n" -"set name [namespace tail $slot]\n" -"array set \"\" [$slot toParameterSyntax $name]\n" -"lappend parameterdefinitions -$(oparam)}\n" -"return $parameterdefinitions}\n" -"::xotcl2::Object protected method objectparameter {} {\n" -"set parameterdefinitions [::xotcl::parametersFromSlots [self]]\n" -"if {[::xotcl::is [self] class]} {\n" -"lappend parameterdefinitions -parameter:method,optional}\n" -"lappend parameterdefinitions \\\n" -"-noinit:method,optional,noarg \\\n" -"-volatile:method,optional,noarg \\\n" -"arg:initcmd,optional\n" -"return $parameterdefinitions}\n" "::xotcl::MetaSlot create ::xotcl::MethodParameterSlot\n" "::xotcl::relation ::xotcl::MethodParameterSlot superclass ::xotcl::Slot\n" "foreach cmd [info command ::xotcl::cmd::MethodParameterSlot::*] {\n" @@ -224,9 +168,10 @@ "if {[info exists default]} {\n" "foreach i [::xotcl::cmd::ClassInfo::instances $class] {\n" "if {![$i exists $att]} {\n" -"if {[string match {*[*]*} $default]} {\n" -"set default [::xotcl::dispatch $i -objscope ::eval subst $default]}\n" -"::xotcl::setinstvar $i $att $default}}\n" +"if {[string match {*\\[*\\]*} $default]} {\n" +"set value [::xotcl::dispatch $i -objscope ::eval subst $default]} else {\n" +"set value $default}\n" +"::xotcl::setinstvar $i $att $value}}\n" "unset default}}\n" "$class __invalidateobjectparameter}\n" "createBootstrapAttributeSlots ::xotcl::Slot {\n" @@ -278,6 +223,66 @@ "${:manager} \\\n" "[list %1 [${:manager} defaultmethods]] %self \\\n" "${:methodname}}}\n" +"::xotcl::MetaSlot __invalidateobjectparameter\n" +"::xotcl::ObjectParameterSlot method toParameterSyntax {{name:substdefault ${:name}}} {\n" +"set objparamdefinition $name\n" +"set methodparamdefinition \"\"\n" +"set objopts [list]\n" +"set methodopts [list]\n" +"set type \"\"\n" +"if {[info exists :required] && ${:required}} {\n" +"lappend objopts required\n" +"lappend methodopts required}\n" +"if {[info exists :type]} {\n" +"if {[string match ::* ${:type}]} {\n" +"set type [expr {[::xotcl::is ${:type} metaclass] ? \"class\" : \"object\"}]\n" +"lappend objopts type=${:type}\n" +"lappend methodopts type=${:type}} else {\n" +"set type ${:type}}}\n" +"if {[info exists :multivalued] && ${:multivalued}} {\n" +"if {!([info exists :type] && ${:type} eq \"relation\")} {\n" +"lappend objopts multivalued} else {}}\n" +"if {[info exists :arg]} {\n" +"set prefix [expr {$type eq \"object\" || $type eq \"class\" ? \"type\" : \"arg\"}]\n" +"lappend objopts $prefix=${:arg}\n" +"lappend methodopts $prefix=${:arg}}\n" +"if {[info exists :default]} {\n" +"set arg ${:default}\n" +"if {[string match {*\\[*\\]*} $arg]} {\n" +"lappend objopts substdefault}} elseif {[info exists :initcmd]} {\n" +"set arg ${:initcmd}\n" +"lappend objopts initcmd}\n" +"if {[info exists :methodname]} {\n" +"if {${:methodname} ne ${:name}} {\n" +"lappend objopts arg=${:methodname}\n" +"lappend methodopts arg=${:methodname}}}\n" +"if {$type ne \"\"} {\n" +"set objopts [linsert $objopts 0 $type]\n" +"set methodopts [linsert $methodopts 0 $type]}\n" +"if {[llength $objopts] > 0} {\n" +"append objparamdefinition :[join $objopts ,]}\n" +"if {[llength $methodopts] > 0} {\n" +"set methodparamdefinition [join $methodopts ,]}\n" +"if {[info exists arg]} {\n" +"lappend objparamdefinition $arg}\n" +"return [list oparam $objparamdefinition mparam $methodparamdefinition]}\n" +"proc ::xotcl::parametersFromSlots {obj} {\n" +"set parameterdefinitions [list]\n" +"foreach slot [::xotcl2::objectInfo slotobjects $obj] {\n" +"if {[::xotcl::is $obj type ::xotcl::Object] &&\n" +"([$slot name] eq \"mixin\" || [$slot name] eq \"filter\")} continue\n" +"array set \"\" [$slot toParameterSyntax]\n" +"lappend parameterdefinitions -$(oparam)}\n" +"return $parameterdefinitions}\n" +"::xotcl2::Object protected method objectparameter {} {\n" +"set parameterdefinitions [::xotcl::parametersFromSlots [self]]\n" +"if {[::xotcl::is [self] class]} {\n" +"lappend parameterdefinitions -parameter:method,optional}\n" +"lappend parameterdefinitions \\\n" +"-noinit:method,optional,noarg \\\n" +"-volatile:method,optional,noarg \\\n" +"arg:initcmd,optional\n" +"return $parameterdefinitions}\n" "::xotcl::MetaSlot create ::xotcl::RelationSlot\n" "createBootstrapAttributeSlots ::xotcl::RelationSlot {\n" "{multivalued true}\n" Index: generic/predefined.xotcl =================================================================== diff -u -r5a0750dc422574bc5ae91d9b58c64b8f5713d405 -r3ecb613fe4ef3fd510e73792cdf0764a1d1489ab --- generic/predefined.xotcl (.../predefined.xotcl) (revision 5a0750dc422574bc5ae91d9b58c64b8f5713d405) +++ generic/predefined.xotcl (.../predefined.xotcl) (revision 3ecb613fe4ef3fd510e73792cdf0764a1d1489ab) @@ -309,109 +309,7 @@ ::xotcl::MetaSlot create ::xotcl::ObjectParameterSlot ::xotcl::relation ::xotcl::ObjectParameterSlot superclass ::xotcl::Slot - # We have no working objectparameter yet. So invalidate MetaSlot to - # avoid caching. - ::xotcl::MetaSlot __invalidateobjectparameter - - #foreach o {::xotcl::MetaSlot ::xotcl2::ObjectParameterSlot} { - # foreach r {object class metaclass} { - # puts stderr "$o $r=[::xotcl::is $o $r]" - # } - #} - # Provide the a slot based mechanism for building an object - # configuration interface from slot definitions - ::xotcl::ObjectParameterSlot method toParameterSyntax {name} { - set objparamdefinition $name - set methodparamdefinition "" - set objopts [list] - set methodopts [list] - if {[info exists :required] && ${:required}} { - lappend objopts required - lappend methodopts required - } - if {[info exists :type]} { - if {[string match ::* ${:type}]} { - lappend objopts object type=${:type} - lappend methodopts object type=${:type} - } else { - lappend objopts ${:type} - lappend methodopts ${:type} - } - } - # TODO: remove multivalued check on relations by handling multivalued - # not in relation, but in the converters - if {[info exists :multivalued] && ${:multivalued}} { - if {!([info exists :type] && ${:type} eq "relation")} { - lappend objopts multivalued - } else { - #puts stderr "ignore multivalued for $name in relation" - } - } - if {[info exists :arg]} { - lappend objopts arg=${:arg} - lappend methodopts arg=${:arg} - } - if {[info exists :default]} { - set arg ${:default} - # deactivated for now: || [string first {$} $arg] > -1 - if {[string match {*\[*\]*} $arg]} { - lappend objopts substdefault - } - } elseif {[info exists :initcmd]} { - set arg ${:initcmd} - lappend objopts initcmd - } - if {[info exists :methodname]} { - if {${:methodname} ne ${:name}} { - lappend objopts arg=${:methodname} - lappend methodopts arg=${:methodname} - #puts stderr "..... setting arg for methodname: $slot has arg arg=${:methodname}" - } - } - if {[llength $objopts] > 0} { - append objparamdefinition :[join $objopts ,] - } - if {[llength $methodopts] > 0} { - set methodparamdefinition [join $methodopts ,] - } - if {[info exists arg]} { - lappend objparamdefinition $arg - } - #puts stderr "[self proc] ${name} returns [list oparam $objparamdefinition mparam $methodparamdefinition]" - return [list oparam $objparamdefinition mparam $methodparamdefinition] - } - - proc ::xotcl::parametersFromSlots {obj} { - set parameterdefinitions [list] - foreach slot [::xotcl2::objectInfo slotobjects $obj] { - # Skip some slots for xotcl1; - # TODO: maybe different parameterFromSlots for xotcl1? - if {[::xotcl::is $obj type ::xotcl::Object] && - ([$slot name] eq "mixin" || [$slot name] eq "filter") - } continue - set name [namespace tail $slot] - array set "" [$slot toParameterSyntax $name] - lappend parameterdefinitions -$(oparam) - } - return $parameterdefinitions - } - - ::xotcl2::Object protected method objectparameter {} { - set parameterdefinitions [::xotcl::parametersFromSlots [self]] - if {[::xotcl::is [self] class]} { - lappend parameterdefinitions -parameter:method,optional - } - lappend parameterdefinitions \ - -noinit:method,optional,noarg \ - -volatile:method,optional,noarg \ - arg:initcmd,optional - # for the time being, use: - #lappend parameterdefinitions args - #puts stderr "*** parameter definition for [self]: $parameterdefinitions" - return $parameterdefinitions - } - # # create class and object for method parameter slots ::xotcl::MetaSlot create ::xotcl::MethodParameterSlot @@ -441,25 +339,29 @@ ::xotcl::setter $class $att } - # do a second round to ensure that the already defined objects - # have the appropriate default values + # + # Perform a second round to set default values for already defined + # objects. + # foreach att $definitions { if {[llength $att]>1} {foreach {att default} $att break} if {[info exists default]} { + # checking subclasses is not required during bootstrap - # todo: do we really need $class twice? foreach i [::xotcl::cmd::ClassInfo::instances $class] { if {![$i exists $att]} { - if {[string match {*[*]*} $default]} { - #set default [$i eval subst $default] - set default [::xotcl::dispatch $i -objscope ::eval subst $default] - } - ::xotcl::setinstvar $i $att $default + if {[string match {*\[*\]*} $default]} { + set value [::xotcl::dispatch $i -objscope ::eval subst $default] + } else { + set value $default + } + ::xotcl::setinstvar $i $att $value } } unset default } } + #puts stderr "Bootstrapslot for $class calls __invalidateobjectparameter" $class __invalidateobjectparameter } @@ -508,7 +410,7 @@ if {$p>-1} {::xotcl::setinstvar $obj $prop [lreplace $old $p $p]} else { error "$value is not a $prop of $obj (valid are: $old)" } -} + } ::xotcl::ObjectParameterSlot method unknown {method args} { set methods [list] @@ -545,6 +447,115 @@ } } + ################################################################# + # We have no working objectparameter yet, since it requires a + # minimal slot infrastructure to build object parameters from + # slots. The above definitions should be sufficient. We provide the + # definition here before we refine the slot definitions. + # + # Invalidate previously defined object parameter. + ::xotcl::MetaSlot __invalidateobjectparameter + + # Provide the a slot based mechanism for building an object + # configuration interface from slot definitions + ::xotcl::ObjectParameterSlot method toParameterSyntax {{name:substdefault ${:name}}} { + set objparamdefinition $name + set methodparamdefinition "" + set objopts [list] + set methodopts [list] + set type "" + if {[info exists :required] && ${:required}} { + lappend objopts required + lappend methodopts required + } + if {[info exists :type]} { + if {[string match ::* ${:type}]} { + set type [expr {[::xotcl::is ${:type} metaclass] ? "class" : "object"}] + lappend objopts type=${:type} + lappend methodopts type=${:type} + } else { + set type ${:type} + } + } + # TODO: remove multivalued check on relations by handling multivalued + # not in relation, but in the converters + if {[info exists :multivalued] && ${:multivalued}} { + if {!([info exists :type] && ${:type} eq "relation")} { + lappend objopts multivalued + } else { + #puts stderr "ignore multivalued for $name in relation" + } + } + if {[info exists :arg]} { + set prefix [expr {$type eq "object" || $type eq "class" ? "type" : "arg"}] + lappend objopts $prefix=${:arg} + lappend methodopts $prefix=${:arg} + } + if {[info exists :default]} { + set arg ${:default} + # deactivated for now: || [string first {$} $arg] > -1 + if {[string match {*\[*\]*} $arg]} { + lappend objopts substdefault + } + } elseif {[info exists :initcmd]} { + set arg ${:initcmd} + lappend objopts initcmd + } + if {[info exists :methodname]} { + if {${:methodname} ne ${:name}} { + lappend objopts arg=${:methodname} + lappend methodopts arg=${:methodname} + #puts stderr "..... setting arg for methodname: $slot has arg arg=${:methodname}" + } + } + if {$type ne ""} { + set objopts [linsert $objopts 0 $type] + set methodopts [linsert $methodopts 0 $type] + } + if {[llength $objopts] > 0} { + append objparamdefinition :[join $objopts ,] + } + if {[llength $methodopts] > 0} { + set methodparamdefinition [join $methodopts ,] + } + if {[info exists arg]} { + lappend objparamdefinition $arg + } + #puts stderr "[self proc] ${name} returns [list oparam $objparamdefinition mparam $methodparamdefinition]" + return [list oparam $objparamdefinition mparam $methodparamdefinition] + } + + proc ::xotcl::parametersFromSlots {obj} { + set parameterdefinitions [list] + foreach slot [::xotcl2::objectInfo slotobjects $obj] { + # Skip some slots for xotcl1; + # TODO: maybe different parameterFromSlots for xotcl1? + if {[::xotcl::is $obj type ::xotcl::Object] && + ([$slot name] eq "mixin" || [$slot name] eq "filter") + } continue + array set "" [$slot toParameterSyntax] + lappend parameterdefinitions -$(oparam) + } + return $parameterdefinitions + } + + ::xotcl2::Object protected method objectparameter {} { + #puts stderr "... objectparameter [self]" + set parameterdefinitions [::xotcl::parametersFromSlots [self]] + if {[::xotcl::is [self] class]} { + lappend parameterdefinitions -parameter:method,optional + } + lappend parameterdefinitions \ + -noinit:method,optional,noarg \ + -volatile:method,optional,noarg \ + arg:initcmd,optional + # for the time being, use: + #lappend parameterdefinitions args + #puts stderr "*** parameter definition for [self]: $parameterdefinitions" + return $parameterdefinitions + } + + ############################################ # RelationSlot ############################################ Index: generic/xotcl.c =================================================================== diff -u -r7afa0b7f3e63e10eb45a65a7360285ba9590f514 -r3ecb613fe4ef3fd510e73792cdf0764a1d1489ab --- generic/xotcl.c (.../xotcl.c) (revision 7afa0b7f3e63e10eb45a65a7360285ba9590f514) +++ generic/xotcl.c (.../xotcl.c) (revision 3ecb613fe4ef3fd510e73792cdf0764a1d1489ab) @@ -6221,22 +6221,26 @@ static int convertToNothing(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { return TCL_OK; } + static int convertToBoolean(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { int result, bool; result = Tcl_GetBooleanFromObj(interp, objPtr, &bool); if (result == TCL_OK) *clientData = (ClientData)INT2PTR(bool); return result; } + static int convertToInteger(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { int result, i; result = Tcl_GetIntFromObj(interp, objPtr, &i); if (result == TCL_OK) *clientData = (ClientData)INT2PTR(i); return result; } + static int convertToSwitch(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { return convertToBoolean(interp, objPtr, pPtr, clientData); } -static int objectOfType(Tcl_Interp *interp, XOTclObject *object, Tcl_Obj *objPtr, XOTclParam CONST *pPtr) { + +static int objectOfType(Tcl_Interp *interp, XOTclObject *object, char *what, Tcl_Obj *objPtr, XOTclParam CONST *pPtr) { XOTclClass *cl; Tcl_DString ds, *dsPtr = &ds; @@ -6249,7 +6253,8 @@ } DSTRING_INIT(dsPtr); - Tcl_DStringAppend(dsPtr, "object of type ", -1); + Tcl_DStringAppend(dsPtr, what, -1); + Tcl_DStringAppend(dsPtr, " of type ", -1); Tcl_DStringAppend(dsPtr, ObjStr(pPtr->converterArg), -1); XOTclObjErrType(interp, objPtr, Tcl_DStringValue(dsPtr)); DSTRING_FREE(dsPtr); @@ -6259,14 +6264,14 @@ static int convertToObject(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { if (GetObjectFromObj(interp, objPtr, (XOTclObject **)clientData) == TCL_OK) { - return objectOfType(interp, (XOTclObject *)*clientData, objPtr, pPtr); + return objectOfType(interp, (XOTclObject *)*clientData, "object", objPtr, pPtr); } return XOTclObjErrType(interp, objPtr, "object"); } static int convertToClass(Tcl_Interp *interp, Tcl_Obj *objPtr, XOTclParam CONST *pPtr, ClientData *clientData) { if (GetClassFromObj(interp, objPtr, (XOTclClass **)clientData, 0) == TCL_OK) { - return objectOfType(interp, (XOTclObject *)*clientData, objPtr, pPtr); + return objectOfType(interp, (XOTclObject *)*clientData, "class", objPtr, pPtr); } return XOTclObjErrType(interp, objPtr, "class"); } Index: tests/parameters.xotcl =================================================================== diff -u -r7afa0b7f3e63e10eb45a65a7360285ba9590f514 -r3ecb613fe4ef3fd510e73792cdf0764a1d1489ab --- tests/parameters.xotcl (.../parameters.xotcl) (revision 7afa0b7f3e63e10eb45a65a7360285ba9590f514) +++ tests/parameters.xotcl (.../parameters.xotcl) (revision 3ecb613fe4ef3fd510e73792cdf0764a1d1489ab) @@ -71,10 +71,9 @@ # # tclObj + converterArg (alnum..xdigit) Attribute ... -type alnum # object + converterArg (some class, e.g. ::C) Attribute ... -type ::C Attribute -type object -arg ::C -# class + converterArg (some metaclass, e.g. ::M) Attribute -type class -arg ::M +# class + converterArg (some metaclass, e.g. ::M) Attribute -type class -arg ::M # -# todo: get rid of convertToObjectOfType() merge to convertToClass/Object - +# #::xotcl::Slot { # {name "[namespace tail [::xotcl::self]]"} # {methodname} @@ -595,15 +594,18 @@ # testing object types in object parameters ####################################################### Test case op-object-types +Class create MC -superclass Class +MC create MC1 Class create M D create d1 -d 1 C create c1 -mixin M Object create o -puts stderr ===== +#puts stderr ===== Class create ParamTest -parameter { o:object c:class + c1:class,type=::MC d:object,type=::C d1:object,type=C m:metaclass @@ -621,32 +623,49 @@ return $(oparam) } +#puts stderr =====2 ? {parameterFromSlot ParamTest o} "o:object" +? {parameterFromSlot ParamTest c} "c:class" +? {parameterFromSlot ParamTest c1} "c1:class,type=::MC" ? {parameterFromSlot ParamTest d} "d:object,type=::C" ? {parameterFromSlot ParamTest d1} "d1:object,type=::C" ? {parameterFromSlot ParamTest mix} "mix:mixin,arg=M" ? {parameterFromSlot ParamTest x} "x:object,multivalued o" ? {parameterFromSlot ParamTest u} "u:upper" ? {parameterFromSlot ParamTest us} "us:upper,multivalued" +#puts stderr =====3 ? {ParamTest create p -o o} ::p ? {ParamTest create p -o xxx} \ {expected object but got "xxx"} \ "not an object" -? {ParamTest create p -mix c1} ::p -? {ParamTest create p -mix o} \ - "Value 'o' of mix has not mixin M" \ - "does not have mixin M" +? {ParamTest create p -c C} ::p "class" +? {ParamTest create p -c o} \ + {expected class but got "o"} \ + "not a class" +? {ParamTest create p -c1 MC1} ::p "instance of meta-class MC" +? {ParamTest create p -c1 C} \ + {expected class of type ::MC but got "C"} \ + "not an instance of meta-class MC" + ? {ParamTest create p -d d1} ::p ? {ParamTest create p -d1 d1} ::p ? {ParamTest create p -d c1} ::p ? {ParamTest create p -d o} \ {expected object of type ::C but got "o"} \ "o not of type ::C" + +? {ParamTest create p -mix c1} ::p +? {ParamTest create p -mix o} \ + "Value 'o' of mix has not mixin M" \ + "does not have mixin M" + ? {ParamTest create p -u A} ::p ? {ParamTest create p -u c1} {expected upper but got "c1"} +? {ParamTest create p -us {A B c}} \ + {invalid value in "A B c": expected upper but got "c"} ? {ParamTest create p -us {A B}} ::p ? {p us add C end} "A B C"