Index: TODO =================================================================== diff -u -r17880e63ccb02577a5c856aaa6344cd83028a07b -rdedef29f68094a6083cbc91cb0803c3b1f0c0e68 --- TODO (.../TODO) (revision 17880e63ccb02577a5c856aaa6344cd83028a07b) +++ TODO (.../TODO) (revision dedef29f68094a6083cbc91cb0803c3b1f0c0e68) @@ -3019,12 +3019,39 @@ - preliminary fix for volatile called through redsidual args - new regression test file volatile.test +- fix the comparison with "unknown" in residual args + (2 places marked with "//yyyy" ) TODO: -- fix the comparison with "unknown" in residual args - (2 places marked with "//yyyy" ) +- Revise callstack introspection/intercession, i.e., [current + activelevel] vs. [current callinglevel] vs. uplevel()/upvar(): + + Currently, there are some inconsistencies when comparing activelevel + and callinglevel: + + 1. Both skip INACTIVE frames: This has implications for the notion + of an "activelevel" introspection as such (especially when comparing + with their semantics in XOTcl 1.*); also, we cannot access INACTIVE + (mixin, filter) frames anymore using uplevel|upvar (whether this is + needed is another issue, but at least, this breaks XOTcl 1.* + semantics, as callinglevel resolved to such INACTIVE frame contexts). + 2. The uplevel()/upvar() methods default to uplevel+callinglevel + semantics, so they borrow their issues from 1) + 3. For now, we do not support callstack-transparent upleveling into + non-NSF frames, such as Tcl namespace + proc (apply) frames. + Approaches: + a) Revise the current [current] subcmd scheme: callinglevel + vs. activelevel vs. ...? + b) Provide a more generic, filter-based [current callinglevel] (?) + subcmd which allows for applying different bitmask filters + c) Provide the necessary callstack info in [info frame] and make + replacements for [current activelevel] & [current callinglevel] + scriptable ... + d) support for out/inout argument parsing strategies (however, this + would rather replace [upvar], what about [uplevel] indirection?) + - extend mongo::gridfs::store_file with a switch -metadata to pass metadata together at gridfs file creation time Index: generic/nsf.c =================================================================== diff -u -r904617ff17027dc9b2d99f1507feab0dc99cce0c -rdedef29f68094a6083cbc91cb0803c3b1f0c0e68 --- generic/nsf.c (.../nsf.c) (revision 904617ff17027dc9b2d99f1507feab0dc99cce0c) +++ generic/nsf.c (.../nsf.c) (revision dedef29f68094a6083cbc91cb0803c3b1f0c0e68) @@ -18767,7 +18767,7 @@ Tcl_Obj *newValue, *initMethodObj; CONST char *initString; ParseContext pc; - CallFrame frame, *framePtr = &frame, *callSiteVarFramePtr; + CallFrame frame, *framePtr = &frame, *uplevelVarFramePtr; #if 0 fprintf(stderr, "NsfOConfigureMethod %s %2d ",ObjectName(object), objc); @@ -18809,15 +18809,15 @@ concerning the call frame contexts is updated, effectively losing the info about any preceding uplevel. This loss would result in misbehaviour when crawling the callstack, with the callstack traversals taking the - current var frame as starting point. + current variable frame as starting point. Therefore, we record a) whether there was a preceding uplevel (identifiable through deviating interp->framePtr and interp->varFramePtr) and, in case, b) the ruling variable frame context. The preserved call frame reference can later be used to restore the uplevel'ed call frame context. */ - callSiteVarFramePtr = ((CallFrame *)Tcl_Interp_varFramePtr(interp) != + uplevelVarFramePtr = ((CallFrame *)Tcl_Interp_varFramePtr(interp) != (CallFrame *)Tcl_Interp_framePtr(interp)) ? Tcl_Interp_varFramePtr(interp) : NULL; @@ -18934,21 +18934,20 @@ int oc = 0; /* - Restore the var frame context as found at the original call site of + Restore the variable frame context as found at the original call site of configure(). Note that we do not have to revert this context change when leaving this configure() context because a surrounding [uplevel] will correct the callstack context for us ... */ - if (callSiteVarFramePtr) { - Tcl_Interp_varFramePtr(interp) = callSiteVarFramePtr; + if (uplevelVarFramePtr) { + Tcl_Interp_varFramePtr(interp) = uplevelVarFramePtr; } /* - * Mark the current frame as inactive such that e.g. volatile - * does not use this as a base frame, and methods like - * activelevel ignore it. - */ + * Mark the intermittent CSC frame as INACTIVE, so that, e.g., + * callstack traversals seeking active frames ignore it. + */ cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; /* @@ -19070,6 +19069,12 @@ oc ++; } + /* + * Mark the intermittent CSC frame as INACTIVE, so that, e.g., + * callstack traversals seeking active frames ignore it. + */ + cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; + result = NsfForwardMethod(tcd, interp, oc, ov); ForwardCmdDeleteProc(tcd); } Index: tests/disposition.test =================================================================== diff -u -r3ab1e160c5e9832a4d69c6f999a63d9706c4c956 -rdedef29f68094a6083cbc91cb0803c3b1f0c0e68 --- tests/disposition.test (.../disposition.test) (revision 3ab1e160c5e9832a4d69c6f999a63d9706c4c956) +++ tests/disposition.test (.../disposition.test) (revision dedef29f68094a6083cbc91cb0803c3b1f0c0e68) @@ -502,6 +502,121 @@ } namespace delete __ } + + # + # TODO: Test missing elements for method declarations: + # /cls/ public class {} {} ... + # + + # / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / + # Test the ACTIVE/INACTIVE transparency for the method-variants of + # uplevel|upvar + # + + Callee public class method run {} { + set self [self] + set objparams [:objectparameter] + # + # The ? helper by default performs a [namespace eval] in the :: + # namespace, so the uplevel|upvar would happen in a different, + # non-testable callstack branch. Therefore, we have to build the + # tests around this limitation (for now) + # + ? [list set _ [info exists X]] 0 + ? [list set _ [info exists ix]] 0 + $self new + ? [list set _ [info exists ix]] 1 "after 1. uplevel/upvar calls ('$objparams')" + ? [list set _ [set X]] 1 "after 1. uplevel/upvar calls ('$objparams')" + $self new + ? [list set _ [info exists X]] 1 "after 2. uplevel/upvar calls ('$objparams')" + $self new + ? [list set _ [set X]] 3 "after 3. uplevel/upvar calls ('$objparams')" + $self new + ? [list set _ [set ix]] X "after 4. uplevel/upvar calls ('$objparams')" + $self new -ah X X; + ? [list set _ [set ix]] X "after 5. uplevel/upvar calls ('$objparams')" + ? [list set _ [set X]] 6 "after 5. uplevel/upvar calls ('$objparams')" + ? [list set _ [info exists Y]] 0 + $self new -ah X Y; + ? [list set _ [set Y]] 1 "after 6. uplevel/upvar calls ('$objparams')" + ? [list set _ [set X]] 7 "after 6. uplevel/upvar calls ('$objparams')" + ? [list set _ [set ix]] Y + } + + # {{{-ah:forward,method=uplevel %self call -level 1}} {{call:forward,method=uplevel %self %method -level 1} X}} + + # + # a) NSF/Nx methods upvar() and uplevel() + # + + Callee public method call {x} { + :uplevel [list set ix $x] + :upvar $x _ + incr _ + } + + + foreach dispoSpec { + {-ah:alias,method=call {call:alias X}} + {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} + } { + Callee setObjectParams $dispoSpec + Callee run + } + + # + # b) [current callinglevel] + # + # ... with [uplevel [current callinglevel]] being equivalent to + # using NSF/Nx methods upvar() and uplevel() directly. + # + + Callee public method call {x} { + # ::nsf::__db_show_stack + uplevel [current callinglevel] [list set ix $x] + upvar [current callinglevel] $x _ + incr _ + } + + foreach dispoSpec { + {-ah:alias,method=call {call:alias X}} + {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} + } { + Callee setObjectParams $dispoSpec + Callee run + } + + # + # c) [current activelevel] + # + # ... Currently, in the current testing scenario, there is no + # effective difference between #activelevel and #callinglevel, both + # skip INACTIVE frames. + + Callee mixin [Class new {:public method call args { next }}] + + foreach dispoSpec { + {-ah:alias,method=call {call:alias X}} + {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} + } { + Callee setObjectParams $dispoSpec + Callee run + } + + Callee public method call {x} { + uplevel [current activelevel] [list set ix $x] + upvar [current activelevel] $x _ + incr _ + } + + foreach dispoSpec { + {-ah:alias,method=call {call:alias X}} + {{{-ah:forward,method=%self call}} {{call:forward,method=%self %method} X}} + } { + Callee setObjectParams $dispoSpec + Callee run + } + } nx::Test case alias-noarg { @@ -992,7 +1107,6 @@ # # TODO: ensemble next (in submethod) + container filter -> leads to unknown ... # - exit } @@ -1207,9 +1321,8 @@ ? {T create tt ""} "::obj: unable to dispatch method ''" "sending the msg: tt->z->{}()" ::obj mixin UnknownHandler ? {T create tt ""} "CURRENT-::obj-DELEGATOR-::tt-UNKNOWNMETHOD--PATH-z" "sending the msg: tt->z->{}()" - exit T setObjectParams [list -z:alias] - ? {T create tt -z ""} ::tt "sending the msg: tt->z()" + ? {T create tt -z ""} "CURRENT-::obj-DELEGATOR-::tt-UNKNOWNMETHOD--PATH-z" "sending the msg: tt->z()" # # ISSUE: Any direct dispatch with a FQ selector is forbidden, why? @@ -1250,8 +1363,6 @@ } -exit - # # check xotcl with residual args # @@ -1301,6 +1412,38 @@ ? {c1 eval {set :y}} 1 } -# TODO: what todo with object parameter inspection for names with alias, forward... "names" do not always correspond with vars set. -#puts stderr ===exit +nx::Test case xotcl-residualargs-upleveling { + # + # Test callstack resolution for upvar/uplevel in + # parameter-dispatched methods under residualargs() ... + # + package req XOTcl + xotcl::Class C -proc onTheFly {name args} { + ? [list set _ [info exists ix]] 0 + ? [list set _ [info exists Y]] 0 + set c [[self] $name {*}$args] + ? [list set _ [info exists ix]] 1 + ? [list set _ [set ix]] Y + ? [list set _ [info exists Y]] 1 + ? [list set _ [set Y]] 1 + return $c + } -instproc call {x} { + # ::nsf::__db_show_stack + my uplevel [list set ix $x] + my upvar $x _ + incr _ + } -instproc call2 {x} { + # ::nsf::__db_show_stack + uplevel [self callinglevel] [list set ix $x] + upvar [self callinglevel] $x _ + incr _ + } + + C onTheFly c1 -call Y + C onTheFly c1 -call2 Y +} + +# TODO: what todo with object parameter inspection for names with +# alias, forward... "names" do not always correspond with vars set. + Index: tests/volatile.test =================================================================== diff -u -r17880e63ccb02577a5c856aaa6344cd83028a07b -rdedef29f68094a6083cbc91cb0803c3b1f0c0e68 --- tests/volatile.test (.../volatile.test) (revision 17880e63ccb02577a5c856aaa6344cd83028a07b) +++ tests/volatile.test (.../volatile.test) (revision dedef29f68094a6083cbc91cb0803c3b1f0c0e68) @@ -82,4 +82,4 @@ nx::Test case procs-procs { ::foox ::foon -} +} \ No newline at end of file