Index: generic/predefined.h =================================================================== diff -u -rf6be532e62dfbe148ebca8205a67688b751298ad -r120f51260309bbe35ba0f142a25e1b18947e3635 --- generic/predefined.h (.../predefined.h) (revision f6be532e62dfbe148ebca8205a67688b751298ad) +++ generic/predefined.h (.../predefined.h) (revision 120f51260309bbe35ba0f142a25e1b18947e3635) @@ -150,14 +150,8 @@ "eval next -childof $slotobject $args}\n" "::xotcl::MetaSlot create ::xotcl::Slot\n" "::xotcl::MetaSlot __invalidateobjectparameter\n" -"proc ::xotcl::parametersFromSlots {obj} {\n" -"set parameterdefinitions [list]\n" -"set slots [::xotcl2::objectInfo slotobjects $obj]\n" -"foreach slot $slots {\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" -"set parameterdefinition \"-$name\"\n" +"proc ::xotcl::parameterFromSlot {slot name} {\n" +"set parameterdefinition $name\n" "set opts [list]\n" "if {[$slot exists required] && [$slot required]} {\n" "lappend opts required}\n" @@ -178,9 +172,16 @@ "if {[llength $opts] > 0} {\n" "append parameterdefinition :[join $opts ,]}\n" "if {[info exists arg]} {\n" -"lappend parameterdefinition $arg\n" -"unset arg}\n" -"lappend parameterdefinitions $parameterdefinition}\n" +"lappend parameterdefinition $arg}\n" +"return $parameterdefinition}\n" +"proc ::xotcl::parametersFromSlots {obj} {\n" +"set parameterdefinitions [list]\n" +"set slots [::xotcl2::objectInfo slotobjects $obj]\n" +"foreach slot $slots {\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" +"lappend parameterdefinitions -[::xotcl::parameterFromSlot $slot $name]}\n" "return $parameterdefinitions}\n" "::xotcl2::Object protected method objectparameter {} {\n" "set parameterdefinitions [::xotcl::parametersFromSlots [self]]\n" @@ -259,8 +260,9 @@ "set :methodname ${:name}}\n" "${:domain} __invalidateobjectparameter\n" "set cl [expr {${:per-object} ? \"Object\" : \"Class\"}]\n" -"::xotcl::dispatch ${:domain} ::xotcl::classes::xotcl2::${cl}::forward \\\n" -"${:name} ${:manager} [list %1 [${:manager} defaultmethods]] %self \\\n" +"::xotcl::forward ${:domain} ${:name} \\\n" +"${:manager} \\\n" +"[list %1 [${:manager} defaultmethods]] %self \\\n" "${:methodname}}}\n" "::xotcl::MetaSlot create ::xotcl::InfoSlot\n" "createBootstrapAttributeSlots ::xotcl::InfoSlot {\n" @@ -350,6 +352,7 @@ ":check_single_value -keep_old_value false $value $predicate $type $obj $var}\n" "::xotcl::setinstvar $obj __oldvalue($var) $value}\n" "::xotcl::Attribute method mk_type_checker {} {\n" +"puts stderr \"[self] [self proc]\"\n" "set __initcmd \"\"\n" "if {[:exists type]} {\n" "if {[::xotcl::is ${:type} class]} {\n" @@ -371,6 +374,15 @@ "\\[list [::xotcl::self] __default_from_cmd \\[::xotcl::self\\] [list [set :initcmd]]\\]\\n\"} elseif [:exists valuecmd] {\n" "append __initcmd \":trace add variable [list ${:name}] read \\\n" "\\[list [::xotcl::self] __value_from_cmd \\[::xotcl::self\\] [list [set :valuecmd]]\\]\"}\n" +"set valueParam [::xotcl::parameterFromSlot [self] \"value\"]\n" +"if {$valueParam ne \"value\"} {\n" +"if {[set :multivalued]} {\n" +":method check_single_value [list $valueParam] {return 1}\n" +":method check_multiple_values list {foreach a $list {:check_single_value $a}}\n" +":method assign [list obj var value] {\n" +":check_multiple_values $value\n" +"::xotcl::setinstvar $obj $var $value}} else {\n" +":method assign [list obj var $valueParam] {::xotcl::setinstvar $obj $var $value}}}\n" "if {[:exists valuechangedcmd]} {\n" "append __initcmd \":trace add variable [list ${:name}] write \\\n" "\\[list [::xotcl::self] __value_changed_cmd \\[::xotcl::self\\] [list [set :valuechangedcmd]]\\]\"}\n" Index: generic/predefined.xotcl =================================================================== diff -u -rf6be532e62dfbe148ebca8205a67688b751298ad -r120f51260309bbe35ba0f142a25e1b18947e3635 --- generic/predefined.xotcl (.../predefined.xotcl) (revision f6be532e62dfbe148ebca8205a67688b751298ad) +++ generic/predefined.xotcl (.../predefined.xotcl) (revision 120f51260309bbe35ba0f142a25e1b18947e3635) @@ -317,6 +317,43 @@ # Provide the a slot based mechanism for building an object # configuration interface from slot definitions +proc ::xotcl::parameterFromSlot {slot name} { + set parameterdefinition $name + set opts [list] + if {[$slot exists required] && [$slot required]} { + lappend opts required + } + if {[$slot exists type]} { + lappend opts [$slot type] + } + if {[$slot exists arg]} { + lappend opts arg=[$slot arg] + } + if {[$slot exists default]} { + set arg [::xotcl::setinstvar $slot default] + # deactivated for now: || [string first {$} $arg] > -1 + if {[string match {*\[*\]*} $arg]} { + lappend opts substdefault + } + } elseif {[$slot exists initcmd]} { + set arg [::xotcl::setinstvar $slot initcmd] + lappend opts initcmd + } + if {[$slot exists methodname]} { + set methodname [::xotcl::setinstvar $slot methodname] + if {$methodname ne $name} { + lappend opts arg=$methodname + } + } + if {[llength $opts] > 0} { + append parameterdefinition :[join $opts ,] + } + if {[info exists arg]} { + lappend parameterdefinition $arg + } + return $parameterdefinition +} + proc ::xotcl::parametersFromSlots {obj} { set parameterdefinitions [list] set slots [::xotcl2::objectInfo slotobjects $obj] @@ -326,41 +363,7 @@ ([$slot name] eq "mixin" || [$slot name] eq "filter") } continue set name [namespace tail $slot] - set parameterdefinition "-$name" - set opts [list] - if {[$slot exists required] && [$slot required]} { - lappend opts required - } - if {[$slot exists type]} { - lappend opts [$slot type] - } - if {[$slot exists arg]} { - lappend opts arg=[$slot arg] - } - if {[$slot exists default]} { - set arg [::xotcl::setinstvar $slot default] - # deactivated for now: || [string first {$} $arg] > -1 - if {[string match {*\[*\]*} $arg]} { - lappend opts substdefault - } - } elseif {[$slot exists initcmd]} { - set arg [::xotcl::setinstvar $slot initcmd] - lappend opts initcmd - } - if {[$slot exists methodname]} { - set methodname [::xotcl::setinstvar $slot methodname] - if {$methodname ne $name} { - lappend opts arg=$methodname - } - } - if {[llength $opts] > 0} { - append parameterdefinition :[join $opts ,] - } - if {[info exists arg]} { - lappend parameterdefinition $arg - unset arg - } - lappend parameterdefinitions $parameterdefinition + lappend parameterdefinitions -[::xotcl::parameterFromSlot $slot $name] } return $parameterdefinitions } @@ -502,9 +505,10 @@ ${:domain} __invalidateobjectparameter set cl [expr {${:per-object} ? "Object" : "Class"}] # since the domain object might be xotcl1 or xotcl2, use dispatch - ::xotcl::dispatch ${:domain} ::xotcl::classes::xotcl2::${cl}::forward \ - ${:name} ${:manager} [list %1 [${:manager} defaultmethods]] %self \ - ${:methodname} + ::xotcl::forward ${:domain} ${:name} \ + ${:manager} \ + [list %1 [${:manager} defaultmethods]] %self \ + ${:methodname} } } @@ -669,6 +673,7 @@ ::xotcl::setinstvar $obj __oldvalue($var) $value } ::xotcl::Attribute method mk_type_checker {} { + puts stderr "[self] [self proc]" set __initcmd "" if {[:exists type]} { if {[::xotcl::is ${:type} class]} { @@ -705,6 +710,21 @@ append __initcmd ":trace add variable [list ${:name}] read \ \[list [::xotcl::self] __value_from_cmd \[::xotcl::self\] [list [set :valuecmd]]\]" } + set valueParam [::xotcl::parameterFromSlot [self] "value"] + if {$valueParam ne "value"} { + if {[set :multivalued]} { + :method check_single_value [list $valueParam] {return 1} + :method check_multiple_values list {foreach a $list {:check_single_value $a}} + #puts stderr "adding multiple assignmethod for [self] with $valueParam" + :method assign [list obj var value] { + :check_multiple_values $value + ::xotcl::setinstvar $obj $var $value + } + } else { + #puts stderr "adding single assignmethod for [self] with $valueParam" + :method assign [list obj var $valueParam] {::xotcl::setinstvar $obj $var $value} + } + } #append __initcmd [:mk_type_checker] if {[:exists valuechangedcmd]} { append __initcmd ":trace add variable [list ${:name}] write \ @@ -727,12 +747,13 @@ :method forward args {::xotcl::next; :optimize} :method init args {::xotcl::next; :optimize} :public method optimize {} { + #puts stderr OPTIMIZER if {[set :multivalued]} return if {[set :defaultmethods] ne {get assign}} return #puts stderr assign=[:info callable -which assign] if {[:info callable -which assign] ne "::xotcl::Slot alias assign ::xotcl::setinstvar"} return if {[:info callable -which get] ne "::xotcl::Slot alias get ::xotcl::setinstvar"} return - #puts stderr "**** optimizing ${:domain} $forwarder ${:name}" + #puts stderr "**** optimizing [${:domain} info method definition ${:name}]" ::xotcl::setter ${:domain} {*}[expr {${:per-object} ? "-per-object" : ""}] ${:name} } } Index: tests/parameters.xotcl =================================================================== diff -u -rf6be532e62dfbe148ebca8205a67688b751298ad -r120f51260309bbe35ba0f142a25e1b18947e3635 --- tests/parameters.xotcl (.../parameters.xotcl) (revision f6be532e62dfbe148ebca8205a67688b751298ad) +++ tests/parameters.xotcl (.../parameters.xotcl) (revision 120f51260309bbe35ba0f142a25e1b18947e3635) @@ -474,15 +474,47 @@ "Value 'o' of mix has not mixin M" \ "does not have mixin M" -# TODO: error messages for failed conversions not consistent -# TODO: setter should perform parameter checking: -# (a) simple approach: make scripted setter methods +# TODO: naming "type" and "mixin" not perfect. +# maybe "type" => "hastype" +# 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 # pass parameter definition +# +# TODO: error messages for failed conversions are not consistent +# should happen, when all kind of parameters finally settled # -# The following test fails currently: -#?? {p o xxx} "Invalid argument: cannot convert 'xxx' to object" +? {p o o} \ + "o" \ + "value is an object" +?? {p o xxx} \ + "Invalid argument: cannot convert 'xxx' to object" \ + "value is not an object" +ParamTest slots { + ::xotcl::Attribute create os -type object -multivalued true +} + +? {p os o} \ + "o" \ + "value is a list of objects (1 element)" +? {p os {o c1 d1}} \ + "o c1 d1" \ + "value is a list of objects (multiple elements)" + +?? {p os {o xxx d1}} \ + "Invalid argument: cannot convert 'xxx' to object" \ + "list with invalid object" + ## TODO regression test for type checking, parameter options (initcmd, ## substdefault, combinations with defaults, ...), etc. puts stderr =====END