Index: generic/nsf.c =================================================================== diff -u -N -ree323da025db17a708fcfbf7228b3011ce649d07 -r3ab1e160c5e9832a4d69c6f999a63d9706c4c956 --- generic/nsf.c (.../nsf.c) (revision ee323da025db17a708fcfbf7228b3011ce649d07) +++ generic/nsf.c (.../nsf.c) (revision 3ab1e160c5e9832a4d69c6f999a63d9706c4c956) @@ -8493,22 +8493,22 @@ /*fprintf(stderr, "... method %p %s csc %p\n", cmd, methodName, cscPtr); */ if (cmd) { /* - * In order to allow next to be called on the - * ensemble-method, a call-frame entry is needed. The - * associated calltype is flagged as an ensemble to be - * able to distinguish frames during next. + * In order to allow [next] to be called in an ensemble method, + * an extra callframe is needed. This CSC frame is typed as + * NSF_CSC_TYPE_ENSEMBLE. Note that the associated call is flagged + * additionally (NSF_CSC_CALL_IS_ENSEMBLE; see above) to be able + * to identify ensemble-specific frames during [next] execution. * - * The invocation requires NSF_CSC_IMMEDIATE to ensure, - * that scripted methods are executed before the ensemble - * ends. If they would be exeecuted lated, their parent - * frame (CMETHOD) would have disappeared from the stack - * already. + * The dispatch requires NSF_CSC_IMMEDIATE to be set, ensuring + * that scripted methods are executed before the ensemble ends. If + * they were executed later, they would find their parent frame + * (CMETHOD) being popped from the stack already. */ - /*fprintf(stderr, ".... ensemble dispatch on %s.%s cscPtr %p base flags %.6x\n", - ObjectName(object),methodName, cscPtr, (0xFF & cscPtr->flags));*/ + /*fprintf(stderr, ".... ensemble dispatch on %s.%s cscPtr %p base flags %.6x cl %s\n", + ObjectName(object),methodName, cscPtr, (0xFF & cscPtr->flags),cscPtr->cl?ObjStr(cscPtr->cl->object.cmdName):NULL);*/ result = MethodDispatch(object, interp, objc-1, objv+1, - cmd, object, NULL, methodName, + cmd, object, cscPtr->cl, methodName, cscPtr->frameType|NSF_CSC_TYPE_ENSEMBLE, (cscPtr->flags & 0xFF)|NSF_CSC_IMMEDIATE); goto obj_dispatch_ok; @@ -11810,12 +11810,9 @@ * locate the appropriate callstack content and continue next on * that. */ - fprintf(stderr,">>> input framePtr %p input cscPtr %p\n",framePtr,cscPtr); cscPtr = CallStackFindEnsembleCsc(framePtr, &framePtr); assert(cscPtr); inEnsemble = 1; - fprintf(stderr,">>> framePtr %p cscPtr %p\n",framePtr,cscPtr); - fprintf(stderr,"cscPtr->objv[0] %s\n",cscPtr->objv[0]?ObjStr(cscPtr->objv[0]):NULL); *methodNamePtr = ObjStr(cscPtr->objv[0]); } else { inEnsemble = 0; @@ -12060,8 +12057,8 @@ * handle this case. */ - /*fprintf(stderr, "--- no cmd, csc %p frameType %.6x callType %.6x endOfFilterChain %d\n", - cscPtr, cscPtr->frameType, cscPtr->flags, endOfFilterChain);*/ + /*fprintf(stderr, "--- no cmd, csc %p frameType %.6x callType %.6x endOfFilterChain %d NSF_CSC_CALL_IS_ENSEMBLE %d\n", + cscPtr, cscPtr->frameType, cscPtr->flags, endOfFilterChain,(cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE)!=0);*/ rst->unknown = endOfFilterChain || (cscPtr->flags & NSF_CSC_CALL_IS_ENSEMBLE); /*fprintf(stderr, "******** setting unknown to %d\n", rst->unknown );*/ } Index: generic/nsfStack.c =================================================================== diff -u -N -ree323da025db17a708fcfbf7228b3011ce649d07 -r3ab1e160c5e9832a4d69c6f999a63d9706c4c956 --- generic/nsfStack.c (.../nsfStack.c) (revision ee323da025db17a708fcfbf7228b3011ce649d07) +++ generic/nsfStack.c (.../nsfStack.c) (revision 3ab1e160c5e9832a4d69c6f999a63d9706c4c956) @@ -601,6 +601,7 @@ /* * Append all ensemble names to the specified list obj */ + for (/* Skipping the starting frame, assumingly a "leaf" frame in an ensemle dispatch */ framePtr = Tcl_CallFrame_callerPtr(framePtr), elements = 0; Tcl_CallFrame_isProcCallFrame(framePtr) & (FRAME_IS_NSF_CMETHOD|FRAME_IS_NSF_METHOD); Index: tests/disposition.test =================================================================== diff -u -N -ree323da025db17a708fcfbf7228b3011ce649d07 -r3ab1e160c5e9832a4d69c6f999a63d9706c4c956 --- tests/disposition.test (.../disposition.test) (revision ee323da025db17a708fcfbf7228b3011ce649d07) +++ tests/disposition.test (.../disposition.test) (revision 3ab1e160c5e9832a4d69c6f999a63d9706c4c956) @@ -798,12 +798,13 @@ # A depth-1 submethod ... C public method "FOO foo" {} { - set :msg "[::nsf::current]--[::nsf::current methodpath]--[::nsf::current method]" + # next + append :msg "[::nsf::current]--[::nsf::current methodpath]--[::nsf::current method]" } # A depth-2 submethod ... C public method "BAR BOO buu" {} { - set :msg "[::nsf::current]--[::nsf::current methodpath]--[::nsf::current method]" + append :msg "[::nsf::current]--[::nsf::current methodpath]--[::nsf::current method]" } @@ -847,7 +848,152 @@ C setObjectParams [list FOO:alias] ? { [C create c2 foo] eval {set :msg}; # N - } "::c2--FOO--foo" + } "::c2--FOO--foo" + + # + # 1) Interleaving @Type(INACTIVE) frames through indirection + # + # a) Ahead of the ensemble "root" frame (i.e., indirection at the + # level the receiver object) + # + + Class create M1 { + :public method FOO args { + next + } + } + + C mixin M1 + + # N+4 |:CscFrame @Type(ENSEMBLE) | <-- foo (leaf) + # N+3 |:CscFrame @Call(ENSEMBLE) | <-- FOO (root) + # N+2 |:CscFrame @INACTIVE| <-- M1.FOO + # N+1 |:TclFrame| + + C setObjectParams [list] + ? { + [C create c1] FOO foo; # N + c1 eval {set :msg} + } "::c1--FOO--foo" + + # N+6 |:CscFrame @Type(ENSEMBLE)| <-- foo (leaf) + # N+5 |:CscFrame @Call(ENSEMBLE)| <-- FOO (root) + # N+4 |:CscFrame @INACTIVE| <-- M1.FOO + # N+3 |:CscFrame @INACTIVE| <-- (INNER configure() frame) + # N+2 |:ObjFrame| <-- ::c2 (OUTER configure() frame) + # N+1 |:TclFrame| + + C setObjectParams [list FOO:alias] + ? { + [C create c2 foo] eval {set :msg}; # N + } "::c2--FOO--foo" + + # ... the filter variant ... + C mixin {} + C public method intercept args { + next + } + C filter intercept + + # N+4 |:CscFrame @Type(ENSEMBLE) | <-- foo (leaf) + # N+3 |:CscFrame @Call(ENSEMBLE) | <-- FOO (root) + # N+2 |:CscFrame @INACTIVE| <-- intercept + # N+1 |:TclFrame| + C setObjectParams [list] + ? { + [C create c1] FOO foo; # N + c1 eval {set :msg} + } "::c1--FOO--foo" + + # N+6 |:CscFrame @Type(ENSEMBLE)| <-- foo (leaf) + # N+5 |:CscFrame @Call(ENSEMBLE)| <-- FOO (root) + # N+4 |:CscFrame @INACTIVE| <-- intercept + # N+3 |:CscFrame @INACTIVE| <-- (INNER configure() frame) + # N+2 |:ObjFrame| <-- ::c2 (OUTER configure() frame) + # N+1 |:TclFrame| + + C setObjectParams [list FOO:alias] + ? { + [C create c2 foo] eval {set :msg}; # N + } "::c2--FOO--foo" + + + C filter "" + # / / / / / / / / / / / / / / / / / / / / / / / / / / / / / + # b) Between root and intermittent or inbetween the set of + # intermittent frames (i.e., indirection at the level of + # container/ensemble objects) + + # NOTE: Filters and mixins registered for the container object do + # not interleave in ensemble dispatches ... the dispatch lookup + # (along the next path) always starts at the top-level + # (calling) object. As a result, there are no intermediate frames to + # be expected ... + Class create M2 { + :public method foo args { + return "[current class]--[next]" + } + } + + C::slot::__FOO mixin M2 + ? {C::slot::__FOO foo} "::M2--::C::slot::__FOO----foo" + C::slot::__FOO eval {unset :msg} + + C setObjectParams [list] + ? { + [C create c1] FOO foo; # N + c1 eval {set :msg} + } "::c1--FOO--foo" + + C::slot::__FOO mixin {} + C::slot::__FOO public method intercept {} { + return "[current]--[next]" + } + C::slot::__FOO filter intercept + ? {C::slot::__FOO foo} "::C::slot::__FOO--::C::slot::__FOO----foo" + + C setObjectParams [list] + ? { + [C create c1] FOO foo; # N + c1 eval {set :msg} + } "::c1--FOO--foo" + + # -- + + Class create M2 { + :public method "FOO foo" args { + append :msg "(1)--[current next]" + next + puts stderr ++++++++++++++++++ + append :msg "--(3)--[current class]--[current methodpath]--[current]" + puts stderr ++++++++++++++++++ + } + } + + C mixin M2 + + # N+4 |:CscFrame @Type(ENSEMBLE) | <-- C.FOO.foo (leaf) + # N+2 |:CscFrame @Call(ENSEMBLE) | <-- C.FOO (root) + # N+3 |:CscFrame @INACTIVE @Type(ENSEMBLE)| <-- M2.FOO.foo + # N+2 |:CscFrame @INACTIVE @Call(ENSEMBLE) | <-- M2.FOO + # N+1 |:TclFrame| + C setObjectParams [list] + ? { + puts stderr "/ / / / / / / / / / / " + [C create c1] FOO foo; # N + puts stderr "/ / / / / / / / / / / " + c1 eval {set :msg} + } "(1)--::c1--FOO--foo--(3)--::M2--FOO--::c1" + + C mixin {} + + # + # TODO: [current class] in M2 FOO foo does not resolve! + # + # TODO: ensemble next (in submethod) + container filter -> leads to unknown ... + # + exit + } nx::Test case dispo-configure-transparency { Index: tests/submethods.test =================================================================== diff -u -N -r53e092b1dceccab3bbd0045bd5b14c1ddedaf68d -r3ab1e160c5e9832a4d69c6f999a63d9706c4c956 --- tests/submethods.test (.../submethods.test) (revision 53e092b1dceccab3bbd0045bd5b14c1ddedaf68d) +++ tests/submethods.test (.../submethods.test) (revision 3ab1e160c5e9832a4d69c6f999a63d9706c4c956) @@ -338,5 +338,48 @@ ? {obj foo} ::nx::Object } +nx::Test case submethods-as-filters { + # + # submethods as filters? + # + #set h [C public method "BAR bar" args { + # next + #}] + #C filter {{BAR bar}} +} +nx::Test case submethods-current-introspection { + # + # [current] & [current class] + # + Object create o + o public method "FOO foo" {} { + return "-[current]-[current class]-" + } + ? {o FOO foo} -::o-- + + Class create C + C public method "FOO foo" {} { + return "-[current]-[current class]-" + } + C create c + ? {c FOO foo} -::c-::C- + C mixin [Class create M1 { + :public method "FOO foo" {} { + return "-[current]-[current class][next]" + } + }] + + ? {c FOO foo} -::c-::M1-::c-::C- + + o mixin ::M1 + ? {o FOO foo} -::o-::M1-::o-- + + # + # TODO: [current callingmethod], [current calledmethod] + # +} + + +