Index: TODO =================================================================== diff -u -r11911b4cef79513ac212b56be4270d1fb7a78ad6 -r138d0f863712bcafd8732a3a40cef60cc80e8737 --- TODO (.../TODO) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) +++ TODO (.../TODO) (revision 138d0f863712bcafd8732a3a40cef60cc80e8737) @@ -1639,6 +1639,11 @@ - documented functions in nfsStack.c - removed obsolete CallStackGetFrame(), replaced by CallStackGetTopFrame() +- push stack frame before calling the defaultcmd of an ensemble object to + make implementation more simple. +- simplified EnsembleObject.defaultcmd and EnsembleObject.unknown significantly, + scripted support methods are removed. + TODO: - cleanup of xotcl-aol Index: generic/nsf.c =================================================================== diff -u -r11911b4cef79513ac212b56be4270d1fb7a78ad6 -r138d0f863712bcafd8732a3a40cef60cc80e8737 --- generic/nsf.c (.../nsf.c) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) +++ generic/nsf.c (.../nsf.c) (revision 138d0f863712bcafd8732a3a40cef60cc80e8737) @@ -6452,7 +6452,10 @@ * The client data cp is still the obj of the called method */ if (objc < 2) { + Tcl_CallFrame frame, *framePtr = &frame; + Nsf_PushFrameCsc(interp, cscPtr, framePtr); result = DispatchDefaultMethod(cp, interp, objc, objv, NSF_CSC_IMMEDIATE); + Nsf_PopFrameCsc(interp, framePtr); } else { Tcl_CallFrame frame, *framePtr = &frame; NsfObject *self = (NsfObject *)cp; Index: library/nx/nx.tcl =================================================================== diff -u -r11911b4cef79513ac212b56be4270d1fb7a78ad6 -r138d0f863712bcafd8732a3a40cef60cc80e8737 --- library/nx/nx.tcl (.../nx.tcl) (revision 11911b4cef79513ac212b56be4270d1fb7a78ad6) +++ library/nx/nx.tcl (.../nx.tcl) (revision 138d0f863712bcafd8732a3a40cef60cc80e8737) @@ -369,7 +369,7 @@ # only method registered on the object are resolved (ensemble # methods). Only for the methods "unknown" and "defaultmethod", # self is actually the ensemble object. These methods are - # maintenance methods. We have to be careful ... + # maintenance methods. We have to be careful here ... # # a) not to interfere between "maintenance methods" and "ensemble # methods" within the maintenance methods. This is achieved @@ -382,93 +382,24 @@ # in nsf when calling e.g. "unknwown" (such that a subcmd # "unknown" does not interfere with the method "unknown"). # - :method subcmdName {} { - # - # Compute the name of a subcmd and the object, on which it is - # registed, given an Ensemble object. - # - set self [::nsf::current object] - set parent [::nsf::dispatch $self ::nsf::methods::object::info::parent] - set grandparent [::nsf::dispatch $parent ::nsf::methods::object::info::parent] - set tail [namespace tail $parent] - if {$tail eq "slot" && [::nsf::is class $grandparent]} { - set aliases [::nsf::dispatch $grandparent ::nsf::methods::class::info::methods -methodtype alias] - foreach alias $aliases { - set def [::nsf::dispatch $grandparent ::nsf::methods::class::info::method definition $alias] - if {[lindex $def end] eq $self} { - return [list name [lindex $def 3] regobj ] - } - } - } - return [list name [namespace tail $self] regobj $parent] - } - - :method methodPath {} { - # - # Compute the composite path of a given ensemble object, - # containing its parent ensemble objects. - # - set o [::nsf::current object] - array set "" [$o ::nsf::classes::nx::EnsembleObject::subcmdName] - set path $(name) - while {1} { - set o [::nsf::dispatch $o ::nsf::methods::object::info::parent] - if {![::nsf::dispatch $o ::nsf::methods::object::info::hastype ::nx::EnsembleObject]} break - array set "" [$o ::nsf::classes::nx::EnsembleObject::subcmdName] - set path "$(name) $path" - } - return [list regobj $(regobj) path $path] - } - - :method subMethods {} { - # - # Compute pairs of method names and ensemble (sub)objects - # contained in the current object. - # - set result [list] - set self [::nsf::current object] - set methods [lsort [::nsf::dispatch $self ::nsf::methods::object::info::methods]] - array set "" [$self ::nsf::classes::nx::EnsembleObject::subcmdName] - foreach m $methods { - set type [::nsf::dispatch $self ::nsf::methods::object::info::method type $m] - if {$type eq "object"} { - foreach {obj submethod} \ - [::nsf::dispatch ${self}::$m ::nsf::classes::nx::EnsembleObject::subMethods] { - lappend result $obj $submethod - } - } else { - lappend result $self $m - } - } - return $result - } - - # - # The methods "unknown" and "defaultmethod" are called internally - # :method unknown {obj m args} { set path [current methodpath] - #puts stderr "+++ UNKNOWN $self obj $obj '$m' $args // path '[current methodpath]'" + #puts stderr "+++ UNKNOWN obj $obj '$m' $args // path '[current methodpath]'" if {[catch {set valid [$obj ::nsf::methods::object::info::lookupmethods -expand "$path *"]} errorMsg]} { set valid "" puts stderr "+++ UNKNOWN raises error $errorMsg" } set ref "\"[lindex $args 0]\" of $obj $path" - error "Unable to dispatch sub-method $ref; valid are:\n[join [lsort $valid] {, }]" + error "Unable to dispatch sub-method $ref; valid are: [join [lsort $valid] {, }]" } :method defaultmethod {} { - #puts uplevel-method=[uplevel {nx::current method}]-[uplevel nx::self] - set self [current object] - set methods [lsort [::nsf::dispatch $self ::nsf::methods::object::info::methods]] - array set "" [$self ::nsf::classes::nx::EnsembleObject::subcmdName] - set pairs [$self ::nsf::classes::nx::EnsembleObject::subMethods] - foreach {obj m} $pairs { - array set "" [$obj ::nsf::classes::nx::EnsembleObject::methodPath] - set cmd [::nsf::dispatch $obj ::nsf::methods::object::info::method parametersyntax $m] - puts stderr "$(regobj) $(path) $m $cmd" - } - return $methods + set obj [uplevel {current object}] + set path [current methodpath] + set l [string length $path] + set submethods [$obj ::nsf::methods::object::info::lookupmethods -expand "$path *"] + foreach sm $submethods {set results([lindex [string range $sm $l+1 end] 0]) 1} + error "Valid submethods of $obj $path: [lsort [array names results]]" } # end of EnsembleObject Index: tests/submethods.tcl =================================================================== diff -u -r448c0563adb3705d6686bdb37dc316f37b325474 -r138d0f863712bcafd8732a3a40cef60cc80e8737 --- tests/submethods.tcl (.../submethods.tcl) (revision 448c0563adb3705d6686bdb37dc316f37b325474) +++ tests/submethods.tcl (.../submethods.tcl) (revision 138d0f863712bcafd8732a3a40cef60cc80e8737) @@ -35,14 +35,12 @@ ? {o string length 1} length ? {o string tolower 2} tolower ? {o string toupper 2} \ - {Unable to dispatch sub-method "toupper" of ::o string; valid are: -string info, string length, string tolower} + {Unable to dispatch sub-method "toupper" of ::o string; valid are: string info, string length, string tolower} ? {o foo a x} "x" ? {o foo a y} "y" ? {o foo a z} \ - {Unable to dispatch sub-method "z" of ::o foo a; valid are: -foo a defaultmethod, foo a subcmdName, foo a unknown, foo a x, foo a y} + {Unable to dispatch sub-method "z" of ::o foo a; valid are: foo a defaultmethod, foo a subcmdName, foo a unknown, foo a x, foo a y} ? {o info method type string} object # the following is a problem, when string has subcmd "info" @@ -51,14 +49,12 @@ ? {o string length aaa} "length" ? {o string info class} "info" ? {o string hugo} \ - {Unable to dispatch sub-method "hugo" of ::o string; valid are: -string info, string length, string tolower} + {Unable to dispatch sub-method "hugo" of ::o string; valid are: string info, string length, string tolower} Foo create f1 ? {f1 baz a m1 10} m1 ? {f1 baz a m3 10} \ - {Unable to dispatch sub-method "m3" of ::f1 baz a; valid are: -baz a m1, baz a m2} + {Unable to dispatch sub-method "m3" of ::f1 baz a; valid are: baz a m1, baz a m2} #unable to dispatch method baz a m3; valid subcommands of a: m1 m2} # @@ -85,12 +81,12 @@ :create f1 } - ? {o string} "info length tolower" - ? {o foo} "a b" + ? {o string} "Valid submethods of ::o string: info length tolower" + ? {o foo} "Valid submethods of ::o foo: a b" - ? {f1 bar} "m1 m2" - ? {f1 baz} "a b" - ? {f1 baz a} "m1 m2" + ? {f1 bar} "Valid submethods of ::f1 bar: m1 m2" + ? {f1 baz} "Valid submethods of ::f1 baz: a b" + ? {f1 baz a} "Valid submethods of ::f1 baz a: m1 m2" } # @@ -189,9 +185,7 @@ return something } :method "info has something better" {} { - puts stderr "... better calls NEXT" nx::next - puts stderr "... better calls NEXT DONE" return better } } @@ -207,15 +201,26 @@ # call a submethod, which is nowhere defined ? {o1 info has typo M} \ - {Unable to dispatch sub-method "typo" of ::o1 info has; valid are: -info has mixin, info has namespace, info has something better, info has something else, info has type} + {Unable to dispatch sub-method "typo" of ::o1 info has; valid are: info has mixin, info has namespace, info has something better, info has something else, info has type} # call a submethod, which is only defined in the mixin ? {o1 info has something else} something # call a submethod, which is only defined in the mixin, and which # does a next (which should not complain) ? {o1 info has something better} better + + # yet another missing case + ? {o1 info has something wrong} \ + {Unable to dispatch sub-method "wrong" of ::o1 info has something; valid are: info has something better, info has something else} + + # call defaultcmds on ensembles + ? {lsort [o1 info has something]} "Valid submethods of ::o1 info has something: better else" + + # defaultcmd has to return also subcmds of other shadowed ensembles + ? {lsort [o1 info has]} "Valid submethods of ::o1 info has: mixin namespace something type" + ? {lsort [o1 info]} "Valid submethods of ::o1 info: children class filter forward has info is lookup method methods mixin parent precedence slots unknown vars" + } #