Index: Makefile.in =================================================================== diff -u -r0c7e47e58354106c6810812efe41008ce5ae939b -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- Makefile.in (.../Makefile.in) (revision 0c7e47e58354106c6810812efe41008ce5ae939b) +++ Makefile.in (.../Makefile.in) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -394,6 +394,7 @@ $(TCLSH) $(src_test_dir_native)/protected.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/forwardtest.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) $(TCLSH) $(src_test_dir_native)/mixinoftest.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) + $(TCLSH) $(src_test_dir_native)/coroutines.tcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) test-xotcl: $(TCLSH_PROG) $(TCLSH) $(xotcl_src_test_dir)/testo.xotcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) Index: TODO =================================================================== diff -u -r79c263a13be8850014d056153956f5a83dfbb639 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- TODO (.../TODO) (revision 79c263a13be8850014d056153956f5a83dfbb639) +++ TODO (.../TODO) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -1452,11 +1452,16 @@ - added temporary routine ::nsf::yieldcheck for coro debugging - renamed Tcl85showStack() to TclShowStack() +- Big internal changes for handling nre-enabled procs in more + situations. Handles now all nx regression tests, but fails in + testx.xotcl (just nre-enabled) + TODO: -- coro cleanup, when really working -- coro regression test +- major coro cleanup, when working +- extend coro regression test + - subcmd * handle sucmd for other method factories * handle absence of -create flag in resolve_method_path (for introspection) Index: generic/nsf.c =================================================================== diff -u -r79c263a13be8850014d056153956f5a83dfbb639 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- generic/nsf.c (.../nsf.c) (revision 79c263a13be8850014d056153956f5a83dfbb639) +++ generic/nsf.c (.../nsf.c) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -175,8 +175,10 @@ static int NsfODestroyMethod(Tcl_Interp *interp, NsfObject *object); static int NsfOResidualargsMethod(Tcl_Interp *interp, NsfObject *object, int objc, Tcl_Obj *CONST objv[]); static int DispatchDestroyMethod(Tcl_Interp *interp, NsfObject *object, int flags); +static int DispatchUnknownMethod(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[], + Tcl_Obj *methodObj, int flags); - NSF_INLINE static int ObjectDispatch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int flags); @@ -189,6 +191,7 @@ static void PrimitiveCDestroy(ClientData clientData); static void PrimitiveODestroy(ClientData clientData); static void PrimitiveDestroy(ClientData clientData); +static void NsfCleanupObject(NsfObject *object, char *string); /* prototypes for object lookup */ static NsfObject *GetObjectFromString(Tcl_Interp *interp, CONST char *name); @@ -401,7 +404,7 @@ TEOV_callback *rootPtr = TOP_CB(interp); #endif - result = ObjectDispatch(clientData, interp, objc, tov, flags); + result = ObjectDispatch(clientData, interp, objc, tov, flags|NSF_CM_IMMEDIATE); #if defined(NRE) /* @@ -436,7 +439,7 @@ /*fprintf(stderr, "%%%% CallMethodWithArg cmdname=%s, method=%s, objc=%d\n", ObjStr(tov[0]), ObjStr(tov[1]), objc);*/ - result = ObjectDispatch(clientData, interp, objc, tov, flags); + result = ObjectDispatch(clientData, interp, objc, tov, flags|NSF_CM_IMMEDIATE); FREE_ON_STACK(Tcl_Obj*, tov); return result; @@ -558,9 +561,11 @@ return nsPtr ? nsPtr->fullName : ""; } +// TODO: remove string static void -NsfCleanupObject(NsfObject *object) { +NsfCleanupObject(NsfObject *object, char *string) { NsfObjectRefCountDecr(object); + /* fprintf(stderr, "obj refCount of %p after decr %d (%s)\n",object,object->refCount, string);*/ if (object->refCount <= 0) { /*fprintf(stderr, "NsfCleanupObject %p refcount %d\n", object, object->refCount);*/ @@ -1458,6 +1463,7 @@ key, obj, obj && !NsfObjectIsClass(object)); */ if (object && !NsfObjectIsClass(object) && !(object->flags & NSF_DESTROY_CALLED)) { + DispatchDestroyMethod(interp, object, 0); } } @@ -2237,9 +2243,8 @@ /*fprintf(stderr, "... check %p %s\n", object, object ? objectName(object) : "(null)");*/ - if (object) { - /*fprintf(stderr, " ... child %s %p -- %s\n", oname, object, object ? objectName(object):"(null)");*/ - /*fprintf(stderr, " ... obj=%s flags %.4x\n", objectName(object), object->flags);*/ + /* delete here just true children */ + if (object && object->id == cmd) { /* in the exit handler physical destroy --> directly call destroy */ if (RUNTIME_STATE(interp)->exitHandlerDestroyRound @@ -2751,15 +2756,6 @@ * Next Scripting CallStack */ -static void -CallStackRestoreSavedFrames(Tcl_Interp *interp, callFrameContext *ctx) { - if (ctx->framesSaved) { - Tcl_Interp_varFramePtr(interp) = (CallFrame *)ctx->varFramePtr; - /*RUNTIME_STATE(interp)->varFramePtr = ctx->varFramePtr;*/ - - } -} - NSF_INLINE static void CallStackDoDestroy(Tcl_Interp *interp, NsfObject *object) { Tcl_Command oid; @@ -2786,8 +2782,9 @@ from Tcl. We make sure via refcounting that the object structure is kept until after DeleteCommandFromToken(). */ - object->refCount ++; + /*fprintf(stderr, "obj refCount of %p after incr %d (CallStackDoDestroy) dodestroy\n", + object,object->refCount);*/ /*fprintf(stderr, "CallStackDoDestroy %p after refCount ++ %d teardown %p\n", object, object->refCount, object->teardown);*/ @@ -2804,7 +2801,7 @@ Tcl_SetObjResult(interp, savedObjResult); DECR_REF_COUNT(savedObjResult); } - NsfCleanupObject(object); + NsfCleanupObject(object, "CallStackDoDestroy"); } } @@ -3431,6 +3428,8 @@ static int MixinStackPush(NsfObject *object) { register NsfMixinStack *h = NEW(NsfMixinStack); + // TODO: are all mixin push and pop ops really needed? + //fprintf(stderr, "MixinStackPush %s\n", objectName(object)); h->currentCmdPtr = NULL; h->nextPtr = object->mixinStack; object->mixinStack = h; @@ -3443,6 +3442,7 @@ static void MixinStackPop(NsfObject *object) { register NsfMixinStack *h = object->mixinStack; + //fprintf(stderr, "MixinStackPop %s\n", objectName(object)); object->mixinStack = h->nextPtr; FREE(NsfMixinStack, h); } @@ -4275,10 +4275,10 @@ */ static int MixinSearchProc(Tcl_Interp *interp, NsfObject *object, CONST char *methodName, - NsfClass **cl, Tcl_Command *currentCmdPtr, Tcl_Command *cmdPtr) { + NsfClass **clPtr, Tcl_Command *currentCmdPtr, Tcl_Command *cmdPtr) { Tcl_Command cmd = NULL; NsfCmdList *cmdList; - NsfClass *cls; + NsfClass *cl; int result = TCL_OK; assert(object); @@ -4290,29 +4290,29 @@ cmdList = SeekCurrent(object->mixinStack->currentCmdPtr, object->mixinOrder); RUNTIME_STATE(interp)->cmdPtr = cmdList ? cmdList->cmdPtr : NULL; - /* fprintf(stderr, "MixinSearch searching for '%s' %p\n", methodName, cmdList); */ + //fprintf(stderr, "MixinSearch searching for '%s' %p\n", methodName, cmdList); /*CmdListPrint(interp, "MixinSearch CL = \n", cmdList);*/ for (; cmdList; cmdList = cmdList->nextPtr) { if (Tcl_Command_cmdEpoch(cmdList->cmdPtr)) { continue; } - cls = NsfGetClassFromCmdPtr(cmdList->cmdPtr); - assert(cls); + cl = NsfGetClassFromCmdPtr(cmdList->cmdPtr); + assert(cl); /* fprintf(stderr, "+++ MixinSearch %s->%s in %p cmdPtr %p clientData %p\n", objectName(object), methodName, cmdList, cmdList->cmdPtr, cmdList->clientData); */ - cmd = FindMethod(cls->nsPtr, methodName); + cmd = FindMethod(cl->nsPtr, methodName); if (cmd == NULL) { continue; } if (Tcl_Command_flags(cmd) & NSF_CMD_CLASS_ONLY_METHOD) { /*fprintf(stderr, "we found class specific method %s on class %s object %s, isclass %d\n", - methodName, className(cls), objectName(object), NsfObjectIsClass(object));*/ + methodName, className(cl), objectName(object), NsfObjectIsClass(object));*/ if (!NsfObjectIsClass(object)) { /* the command is not for us; skip it */ cmd = NULL; @@ -4322,16 +4322,18 @@ if (cmdList->clientData) { if (!RUNTIME_STATE(interp)->guardCount) { - result = GuardCall(object, cls, (Tcl_Command) cmd, interp, + fprintf(stderr, "guardcall\n"); + result = GuardCall(object, cl, (Tcl_Command) cmd, interp, (Tcl_Obj*)cmdList->clientData, NULL); } } if (result == TCL_OK) { /* * on success: compute mixin call data */ - *cl = cls; + *clPtr = cl; *currentCmdPtr = cmdList->cmdPtr; + /* fprintf(stderr, "mixinsearch returns %p (cl %s)\n",cmd, className(cl)); */ break; } else if (result == TCL_ERROR) { break; @@ -5391,13 +5393,28 @@ return NsfUnsetInstVar2(object, interp, name, NULL, flgs); } + +/* + *---------------------------------------------------------------------- + * CheckVarName -- + * + * Check, whether the provided name is free of namepace markup. + * + * Results: + * Tcl result code. + * + * Side effects: + * none + * + *---------------------------------------------------------------------- + */ static int CheckVarName(Tcl_Interp *interp, const char *varNameString) { /* - * Check, whether the provided name is save to be used in the - * resolver. We do not want to get interferences with namespace - * resolver and such. In an first attempt, we disallowed occurances - * of "::", but we have to deal as well with e.g. arrayName(::x::y) + * We want to have a plain variable name, since we do not want to + * get interferences with namespace resolver and such. In an first + * attempt, we disallowed occurances of "::", but we have to deal as + * well with e.g. arrayName(::x::y) * * TODO: more general and efficient solution to disallow e.g. a::b * (check for :: until parens) @@ -5526,16 +5543,23 @@ } /* - PushProcCallFrame() compiles conditionally a proc and pushes a - callframe. Interesting fields: - - clientData: Record describing procedure to be interpreted. - isLambda: 1 if this is a call by ApplyObjCmd: it needs special rules for error msg - + *---------------------------------------------------------------------- + * PushProcCallFrame -- + * + * Set up and push a new call frame for the procedure invocation. + * callframe. The proc is passed via clientData. + * + * Results: + * Tcl result code + * + * Side effects: + * compiles body conditionally + * + *---------------------------------------------------------------------- */ - static int -PushProcCallFrame(ClientData clientData, register Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], +PushProcCallFrame(ClientData clientData, register Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[], NsfCallStackContent *cscPtr) { Proc *procPtr = (Proc *) clientData; CallFrame *framePtr; @@ -5573,14 +5597,13 @@ fprintf(stderr, " put csc %p into frame %p flags %.4x\n", cscPtr, framePtr, framePtr->isProcCallFrame); #endif framePtr->clientData = (ClientData)cscPtr; - return ByteCompiled(interp, procPtr, TclGetString(objv[0])); } static void GetVarAndNameFromHash(Tcl_HashEntry *hPtr, Var **val, Tcl_Obj **varNameObj) { - *val = VarHashGetValue(hPtr); - *varNameObj = VarHashGetKey(*val); + *val = VarHashGetValue(hPtr); + *varNameObj = VarHashGetKey(*val); } void @@ -5811,22 +5834,28 @@ } + /* * method dispatch */ +// prototype +NSF_INLINE static void ObjectDispatchFinalize(NsfObject *object, int flags); + #if defined(NRE) static int -FinalizeProcMethod(ClientData data[], Tcl_Interp *interp, int result) { +ProcMethodDispatchFinalize(ClientData data[], Tcl_Interp *interp, int result) { ParseContext *pcPtr = data[0]; NsfCallStackContent *cscPtr = data[1]; CONST char *methodName = data[2]; NsfObject *object = cscPtr->self; + int flags = cscPtr->callType; // TODO move down? NsfObjectOpt *opt = object->opt; NsfParamDefs *paramDefs; int rc; - /*fprintf(stderr, "---- FinalizeProcMethod result %d, csc %p, pcPtr %p, obj %p %s.%s\n", + /*fprintf(stderr, "ProcMethodDispatchFinalize result %d, csc %p, pcPtr %p, obj %p %s.%s\n", result, cscPtr, pcPtr, object, objectName(object), methodName);*/ + # if defined(TCL85STACK_TRACE) fprintf(stderr, "POP FRAME (implicit) csc %p obj %s obj refcount %d %d\n", cscPtr, objectName(object), @@ -5862,20 +5891,39 @@ } } +#if 0 + // TODO move declation up + NsfRuntimeState *rst = RUNTIME_STATE(interp); + fprintf(stderr, "ProcMethodDispatchFinalize unknown %d\n", rst->unknown); + if (rst->unknown) { + fprintf(stderr, "call UNKNOWN? ProcMethodDispatchFinalize cscPtr->objv %p\n", cscPtr->objv); + if (cscPtr->objv == NULL) { + TclShowStack(interp); + } else { + int r1 = DispatchUnknownMethod(object, interp, cscPtr->objc, cscPtr->objv, + cscPtr->objv[0], NSF_CM_IMMEDIATE); + } + fprintf(stderr, "after UNKNOWN\n"); + } +#endif + if (pcPtr) { # if defined(TCL_STACK_ALLOC_TRACE) - fprintf(stderr, "---- FinalizeProcMethod calls releasePc, stackFree %p\n", pcPtr); + fprintf(stderr, "---- ProcMethodDispatchFinalize calls releasePc, stackFree %p\n", pcPtr); # endif ParseContextRelease(pcPtr); TclStackFree(interp, pcPtr); } # if defined(TCL_STACK_ALLOC_TRACE) - fprintf(stderr, "---- FinalizeProcMethod calls pop, csc free %p method %s\n", cscPtr, methodName); + fprintf(stderr, "---- ProcMethodDispatchFinalize calls pop, csc free %p method %s\n", cscPtr, methodName); # endif CscFinish(interp, cscPtr); TclStackFree(interp, cscPtr); + // any dependencies on cscPtr? + ObjectDispatchFinalize(object, flags); + return result; } #endif @@ -5896,6 +5944,9 @@ assert(object); assert(object->teardown); +#if defined(NRE) + assert(cscPtr->callType & NSF_CSC_CALL_IS_NRE); +#endif #if defined(TCL85STACK_TRACE) fprintf(stderr, "+++ ProcMethodDispatch %s, cscPtr %p, frametype %d, teardown %p\n", @@ -5985,6 +6036,7 @@ result = ProcessMethodArguments(pcPtr, interp, object, 1, paramDefs, methodName, objc, objv); cscPtr->objc = objc; cscPtr->objv = (Tcl_Obj **)objv; + if (result == TCL_OK) { releasePc = 1; result = PushProcCallFrame(cp, interp, pcPtr->objc, pcPtr->full_objv, cscPtr); @@ -6024,8 +6076,9 @@ /* TODO: cleanup, when really working */ //TEOV_callback *rootPtr = TOP_CB(interp); /*fprintf(stderr, "CALL TclNRInterpProcCore %s method '%s'\n", objectName(object), ObjStr(objv[0]));*/ - Tcl_NRAddCallback(interp, FinalizeProcMethod, + Tcl_NRAddCallback(interp, ProcMethodDispatchFinalize, releasePc ? pcPtr : NULL, cscPtr, methodName, NULL); + cscPtr->callType |= NSF_CSC_CALL_IS_NRE; result = TclNRInterpProcCore(interp, objv[0], 1, &MakeProcError); /*fprintf(stderr, ".... run callbacks rootPtr = %p, result %d methodName %s\n", rootPtr, result, methodName);*/ //fprintf(stderr, "NO TclNRRunCallbacks rootPtr = %p, result %d methodName %s\n", rootPtr, result, methodName); @@ -6083,6 +6136,9 @@ assert(object); assert(object->teardown); +#if defined(NRE) + assert(!cscPtr || cscPtr->callType == 0); +#endif #if defined(TCL85STACK_TRACE) fprintf(stderr, "+++ CmdMethodDispatchCheck %s, obj %p %s, cscPtr %p, teardown %p\n", @@ -6191,7 +6247,6 @@ * *---------------------------------------------------------------------- */ - static int DispatchDefaultMethod(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int result; @@ -6201,7 +6256,9 @@ Tcl_Obj *tov[2]; tov[0] = objv[0]; tov[1] = methodObj; - result = ObjectDispatch(clientData, interp, 2, tov, NSF_CM_NO_UNKNOWN); + fprintf(stderr, "DispatchDefaultMethod\n"); + // maybe we can relax NSF_CM_IMMEDIATE if we handle it in ensemble... + result = ObjectDispatch(clientData, interp, 2, tov, NSF_CM_NO_UNKNOWN|NSF_CM_IMMEDIATE); } else { result = TCL_OK; } @@ -6242,8 +6299,8 @@ ) return TCL_OK; - /*fprintf(stderr, " DispatchDestroyMethod obj %p flags %.6x active %d\n", object, object->flags, - object->activationCount);*/ + /*fprintf(stderr, " DispatchDestroyMethod obj %p flags %.6x active %d\n", + object, object->flags, object->activationCount); */ PRINTOBJ("DispatchDestroyMethod", object); @@ -6316,7 +6373,8 @@ } flags &= ~NSF_CM_NO_SHIFT; - result = ObjectDispatch(clientData, interp, objc+2, tov, flags | NSF_CM_NO_UNKNOWN); + //fprintf(stderr, "DispatchUnknownMethod\n"); + result = ObjectDispatch(clientData, interp, objc+2, tov, flags|NSF_CM_NO_UNKNOWN); FREE_ON_STACK(Tcl_Obj*, tov); } else { /* no unknown called, this is the built-in unknown handler */ @@ -6330,6 +6388,276 @@ return result; } +#if 1 +// zzzzz mmmm +// new method dispatch + +// TODO remove last arg of methoddispatch +static int +MethodDispatch(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[], + Tcl_Command cmd, NsfObject *object, NsfClass *cl, + CONST char *methodName, int frameType, int flags, int call); + +static int +MethodDispatchCsc(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[], + NsfCallStackContent *cscPtr, + CONST char *methodName, int flags) { + + // not needed when no client data + //CscInit(cscPtr, object, cl, cmd, frameType); + // do we need to split cscPtr up? + Tcl_Command cmd = cscPtr->cmdPtr; + NsfObject *object = cscPtr->self; + ClientData cp = Tcl_Command_objClientData(cmd); + register Tcl_ObjCmdProc *proc = Tcl_Command_objProc(cmd); + int result; + + assert (object->teardown); + /*fprintf(stderr, "MethodDispatch method '%s' cmd %p cp=%p objc=%d\n", methodName, cmd, cp, objc);*/ + + if (proc == TclObjInterpProc) { + /* + * The cmd is a scripted method + */ + + //TODO simplify ifdefs + { +#if defined(NRE) + TEOV_callback *rootPtr = TOP_CB(interp); +#endif + // object, cl, cmd goub be gotten from cscPtr + result = ProcMethodDispatch(cp, interp, objc, objv, methodName, + cscPtr->self, cscPtr->cl, cmd, cscPtr); + +#if defined(NRE) + if ((flags & NSF_CM_IMMEDIATE)) { + fprintf(stderr, ".... manual run callbacks rootPtr = %p, result %d methodName %s.%s\n", + rootPtr, result, cscPtr->cl?className(cscPtr->cl):"NULL", methodName); + + /* TODO: we should need this only for scriped stuff; maybe it can harm otherwise for coros */ + result = TclNRRunCallbacks(interp, result, rootPtr, 0); + } else { + fprintf(stderr, ".... don't run callbacks rootPtr = %p, result %d methodName %s.%s\n", + rootPtr, result, cscPtr->cl?className(cscPtr->cl):"NULL", methodName); + } + + /* CscFinish() is performed by the callbacks or in error case base ProcMethodDispatch */ + /*fprintf(stderr, "no pop/CscFinish for %s\n", methodName);*/ +#else + //CscFinish(interp, cscPtr); +#endif + } + + return result; + + } else if (cp || Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD) { + /* + * The cmd has client data or is an aliased method + */ + if (proc == NsfObjDispatch) { + /* + * invoke an aliased object (ensemble object) via method interface + */ + NsfRuntimeState *rst = RUNTIME_STATE(interp); + NsfObject *invokeObj = (NsfObject *)cp; + + if (invokeObj->flags & NSF_DELETED) { + /* + * When we try to call a deleted object, the cmd (alias) is + * automatically removed. + */ + Tcl_DeleteCommandFromToken(interp, cmd); + NsfCleanupObject(invokeObj, "alias-delete1"); + return NsfVarErrMsg(interp, "Trying to dispatch deleted object via method '", + methodName, "'", (char *) NULL); + } + + /* + * The client data cp is still the obj of the called method + */ + if (objc < 2) { + result = DispatchDefaultMethod(cp, interp, objc, objv); + } else { + Tcl_CallFrame frame, *framePtr = &frame; + NsfObject *self = (NsfObject *)cp; + char *methodName = ObjStr(objv[1]); + + // doppelt? + //CscInit(cscPtr, object, cscPtr->cl, cscPtr->cmdPtr, cscPtr->frameType); + cscPtr->objc = objc; + cscPtr->objv = (Tcl_Obj **)objv; + cscPtr->callType |= NSF_CSC_CALL_IS_ENSEMBLE; /*zzzz*/ + Nsf_PushFrameCsc(interp, cscPtr, framePtr); + + /*fprintf(stderr, "save self %p %s (ns %p) object %p %s\n", + self, objectName(self), self->nsPtr, object, objectName(object));*/ + if (self->nsPtr) { + cmd = FindMethod(self->nsPtr, methodName); + /* 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. + * + * The invocation requires NSF_CM_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. + */ + + /*fprintf(stderr, ".... ensemble dispatch on %s.%s csc %p\n", + objectName(object),methodName, cscPtr);*/ + result = MethodDispatch(object, interp, objc-1, objv+1, + cmd, object, NULL, methodName, + cscPtr->frameType|NSF_CSC_TYPE_ENSEMBLE, + cscPtr->callType|NSF_CM_IMMEDIATE, 1); + goto obj_dispatch_ok; + } + } + + /* + * The method to be called was not part of this ensemble. Call + * next to try to call such methods along the next path. + */ + fprintf(stderr, "call next instead of unknown %s.%s \n", + objectName(cscPtr->self),methodName); + { + Tcl_CallFrame *framePtr1; + NsfCallStackContent *cscPtr1 = CallStackGetTopFrame(interp, &framePtr1); + + if ((cscPtr1->frameType & NSF_CSC_TYPE_ENSEMBLE)) { + /* + * We are in an ensemble method. The next works here not on the + * actual methodName + frame, but on the ensemble above it. We + * locate the appropriate callstack content and continue next on + * that. + */ + cscPtr1 = CallStackFindEnsembleCsc(framePtr1, &framePtr1); + assert(cscPtr1); + } + fprintf(stderr, "call NextSearchAndInvoke with ov %p could use %p // cscPtr %p flags %.6x\n", + cscPtr1->objv, objv, cscPtr1, cscPtr1->callType); + result = NextSearchAndInvoke(interp, ObjStr(cscPtr1->objv[0]), + cscPtr1->objc, cscPtr1->objv, cscPtr1); + } + + fprintf(stderr, "==> next %s csc %p returned %d unknown %d\n", + methodName, cscPtr, result, rst->unknown); + if (rst->unknown) { + result = DispatchUnknownMethod(self, interp, objc-1, objv+1, + objv[1], NSF_CM_NO_OBJECT_METHOD|NSF_CM_IMMEDIATE); + // TODO: check need for immediate in Unknown Default Destroy Method + } + obj_dispatch_ok: + Nsf_PopFrameCsc(interp, framePtr); + // doppelt? + //CscFinish(interp, cscPtr); + + } + return result; + + } else if (proc == NsfForwardMethod || + proc == NsfObjscopedMethod || + proc == NsfSetterMethod + ) { + TclCmdClientData *tcd = (TclCmdClientData *)cp; + tcd->object = object; + assert((CmdIsProc(cmd) == 0)); + } else if (cp == (ClientData)NSF_CMD_NONLEAF_METHOD) { + cp = clientData; + assert((CmdIsProc(cmd) == 0)); + } + //CscInit(cscPtr, object, cl, cmd, frameType); + + } else { + /* + * The cmd has no client data + */ + /*fprintf(stderr, "cmdMethodDispatch %s %s, nothing stacked\n",objectName(object), methodName);*/ + return CmdMethodDispatch(clientData, interp, objc, objv, methodName, object, cmd, NULL); + } + + result = CmdMethodDispatch(cp, interp, objc, objv, methodName, object, cmd, cscPtr); + /* + * Make sure, that csc is still in the scope; therefore, csc is + * currently on the top scope of this function + */ + //CscFinish(interp, cscPtr); + + return result; +} + +static NsfCallStackContent * +CscAlloc(Tcl_Interp *interp, NsfCallStackContent *cscPtr, Tcl_ObjCmdProc *proc) { + +#if defined(NRE) + if (proc == TclObjInterpProc) { + cscPtr = (NsfCallStackContent *) TclStackAlloc(interp, sizeof(NsfCallStackContent)); +# if defined(TCL_STACK_ALLOC_TRACE) + fprintf(stderr, "---- csc alloc %p method %s\n", cscPtr, methodName); +# endif + cscPtr->callType = NSF_CSC_CALL_IS_NRE; + } else { + cscPtr->callType = 0; + } +#else + cscPtr->callType = 0; +#endif + + return cscPtr; +} + +static void +CscCleanup(Tcl_Interp *interp, NsfCallStackContent *cscPtr) { + +#if defined(NRE) + if ((cscPtr->callType & NSF_CSC_CALL_IS_NRE) == 0) { + CscFinish(interp, cscPtr); + } +#else + CscFinish(interp, cscPtr); +#endif +} + +static int +MethodDispatch(ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[], + Tcl_Command cmd, NsfObject *object, NsfClass *cl, + CONST char *methodName, int frameType, int flags, int call) { + NsfCallStackContent csc, *cscPtr; + int result; + //ClientData cp = Tcl_Command_objClientData(cmd); + //register Tcl_ObjCmdProc *proc = Tcl_Command_objProc(cmd); + + assert (object->teardown); + + //fprintf(stderr, "MethodDispatch method '%s.%s' objc %d flags %.6x call %d\n", + // objectName(object),methodName, objc, flags, call); + + cscPtr = CscAlloc(interp, &csc, Tcl_Command_objProc(cmd)); + + /* + * We would not need CscInit when + * cp == NULL && !(Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD) + */ + CscInit(cscPtr, object, cl, cmd, frameType); + + result = MethodDispatchCsc(clientData, interp, objc, objv, + cscPtr, methodName, flags); + + CscCleanup(interp, cscPtr); + + return result; +} + +#else +// old method dispatch +//###### ORIGINAL /* * MethodDispatch() calls an Next Scripting method. It calls either a * Tcl-implemented method (via ProcMethodDispatch()) or a C-implemented @@ -6339,22 +6667,26 @@ static int MethodDispatch(ClientData clientData, Tcl_Interp *interp, - int objc, Tcl_Obj *CONST objv[], - Tcl_Command cmd, NsfObject *object, NsfClass *cl, - CONST char *methodName, int frameType) { + int objc, Tcl_Obj *CONST objv[], + Tcl_Command cmd, NsfObject *object, NsfClass *cl, + CONST char *methodName, int frameType, int flags, int call) { ClientData cp = Tcl_Command_objClientData(cmd); NsfCallStackContent csc, *cscPtr; register Tcl_ObjCmdProc *proc = Tcl_Command_objProc(cmd); int result; assert (object->teardown); - /*fprintf(stderr, "MethodDispatch method '%s' cmd %p cp=%p objc=%d\n", methodName, cmd, cp, objc);*/ + //fprintf(stderr, "MethodDispatch method '%s' cmd %p cp=%p objc=%d\n", methodName, cmd, cp, objc); + fprintf(stderr, "MethodDispatch method '%s.%s' objc %d call %d\n", objectName(object),methodName, objc, call); if (proc == TclObjInterpProc) { /* - The cmd is a scripted method - */ + * The cmd is a scripted method + */ + + //TODO simplify ifdefs + #if defined(NRE) cscPtr = (NsfCallStackContent *) TclStackAlloc(interp, sizeof(NsfCallStackContent)); # if defined(TCL_STACK_ALLOC_TRACE) @@ -6364,13 +6696,32 @@ cscPtr = &csc; #endif CscInit(cscPtr, object, cl, cmd, frameType); - result = ProcMethodDispatch(cp, interp, objc, objv, methodName, object, cl, cmd, cscPtr); + + { #if defined(NRE) - /* CscFinish() is performed by the callbacks or in error case base ProcMethodDispatch */ - /*fprintf(stderr, "no pop for %s\n", methodName);*/ + TEOV_callback *rootPtr = TOP_CB(interp); +#endif + result = ProcMethodDispatch(cp, interp, objc, objv, methodName, object, cl, cmd, cscPtr); + +#if defined(NRE) + if ((flags & NSF_CM_IMMEDIATE)) { + fprintf(stderr, ".... manual run callbacks rootPtr = %p, result %d methodName %s\n", + rootPtr, result, methodName); + + /* TODO: we should need this only for scriped stuff; maybe it can harm otherwise for coros */ + result = TclNRRunCallbacks(interp, result, rootPtr, 0); + } else { + fprintf(stderr, ".... don't run callbacks rootPtr = %p, result %d methodName %s\n", + rootPtr, result, methodName); + } + + /* CscFinish() is performed by the callbacks or in error case base ProcMethodDispatch */ + /*fprintf(stderr, "no pop/CscFinish for %s\n", methodName);*/ #else - CscFinish(interp, cscPtr); + CscFinish(interp, cscPtr); #endif + } + return result; } else if (cp || Tcl_Command_flags(cmd) & NSF_CMD_NONLEAF_METHOD) { @@ -6394,7 +6745,7 @@ * automatically removed. */ Tcl_DeleteCommandFromToken(interp, cmd); - NsfCleanupObject(invokeObj); + NsfCleanupObject(invokeObj, "alias-delete2"); return NsfVarErrMsg(interp, "Trying to dispatch deleted object via method '", methodName, "'", (char *) NULL); } @@ -6426,13 +6777,19 @@ * ensemble-method, a call-frame entry is needed. The * associated calltype is flagged as an ensemble to be * able to distinguish frames during next. + * + * The invocation requires NSF_CM_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. */ /*fprintf(stderr, ".... ensemble dispatch on %s.%s csc %p\n", objectName(object),methodName, cscPtr);*/ result = MethodDispatch(object, interp, objc-1, objv+1, cmd, object, NULL, methodName, - frameType|NSF_CSC_TYPE_ENSEMBLE); + frameType|NSF_CSC_TYPE_ENSEMBLE, flags|NSF_CM_IMMEDIATE, 2); goto obj_dispatch_ok; } } @@ -6461,8 +6818,8 @@ cscPtr1->objc, cscPtr1->objv, cscPtr1); } - /*fprintf(stderr, "==> next %s csc %p returned %d unknown %d\n", - methodName, cscPtr, result, rst->unknown); */ + fprintf(stderr, "==> next %s csc %p returned %d unknown %d\n", + methodName, cscPtr, result, rst->unknown); if (rst->unknown) { result = DispatchUnknownMethod(self, interp, objc-1, objv+1, objv[1], NSF_CM_NO_OBJECT_METHOD); @@ -6504,23 +6861,45 @@ return result; } +// old method dispatch +#endif +NSF_INLINE static void +ObjectDispatchFinalize(NsfObject *object, int flags) { + + /* fprintf(stderr, "ObjectDispatchFinalize %p flags %.6x\n", object, flags);*/ + +#ifdef DISPATCH_TRACE + PrintExit(interp, "DISPATCH", objc, objv, result); +#endif + + /*fprintf(stderr, "mixinStackPushed %d frametype %d eq %d\n",mixinStackPushed, + flags & NSF_CSC_MIXIN_STACK_PUSHED, + mixinStackPushed == ((flags & NSF_CSC_MIXIN_STACK_PUSHED) != 0));*/ + + if ((flags & NSF_CSC_MIXIN_STACK_PUSHED) && object->mixinStack) { + MixinStackPop(object); + } + if ((flags & NSF_CSC_FILTER_STACK_PUSHED) && object->filterStack) + FilterStackPop(object); +} + NSF_INLINE static int ObjectDispatch(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int flags) { register NsfObject *object = (NsfObject*)clientData; int result = TCL_OK, mixinStackPushed = 0, - filterStackPushed = 0, unknown = 0, objflags, shift, + filterStackPushed = 0, unknown = 0, isNRE = 0, objflags, shift, frameType = NSF_CSC_TYPE_PLAIN; CONST char *methodName; NsfClass *cl = NULL; Tcl_Command cmd = NULL; NsfRuntimeState *rst = RUNTIME_STATE(interp); Tcl_Obj *cmdName = object->cmdName, *methodObj, *cmdObj; + NsfCallStackContent csc, *cscPtr = NULL; + register Tcl_ObjCmdProc *proc = Tcl_Command_objProc(cmd); - assert(objc>0); - if (flags & NSF_CM_NO_SHIFT) { shift = 0; cmdObj = object->cmdName; @@ -6549,12 +6928,16 @@ /* make sure, cmdName and obj survive this method until the end */ INCR_REF_COUNT(cmdName); object->refCount ++; + /*fprintf(stderr, "obj refCount of %p after incr %d (ObjectDispatch) %s\n", + object,object->refCount, methodName);*/ if (!(objflags & NSF_FILTER_ORDER_VALID)) { FilterComputeDefined(interp, object); objflags = object->flags; } + //fprintf(stderr, "dispatch %s objflags %.6x mixin_order_valid %d\n", methodName, objflags, + // (objflags & NSF_MIXIN_ORDER_VALID)); if (!(objflags & NSF_MIXIN_ORDER_VALID)) { MixinComputeDefined(interp, object); objflags = object->flags; @@ -6569,42 +6952,69 @@ methodName, objflags, NSF_FILTER_ORDER_DEFINED_AND_VALID, rst->doFilters, rst->guardCount);*/ + //fprintf(stderr,"ObjectDispatch flags %.6x\n", flags); + assert((flags & (NSF_CSC_MIXIN_STACK_PUSHED|NSF_CSC_FILTER_STACK_PUSHED)) == 0); + if (((objflags & NSF_FILTER_ORDER_DEFINED_AND_VALID) == NSF_FILTER_ORDER_DEFINED_AND_VALID) && rst->doFilters && !rst->guardCount) { - NsfCallStackContent *cscPtr = CallStackGetTopFrame(interp, NULL); + NsfCallStackContent *cscPtr1 = CallStackGetTopFrame(interp, NULL); - /*fprintf(stderr, "... check ok, cscPtr = %p\n", cscPtr); - if (!cscPtr) { + /*fprintf(stderr, "... check ok, cscPtr1 %p\n", cscPtr1); + if (!cscPtr1) { TclShowStack(interp); }*/ - if (!cscPtr || (object != cscPtr->self || - cscPtr->frameType != NSF_CSC_TYPE_ACTIVE_FILTER)) { + // assert(cscPtr1); + if (!cscPtr1 || (object != cscPtr1->self + //|| ((cscPtr1->frameType & NSF_CSC_TYPE_ACTIVE_FILTER) == 0) + //|| (cscPtr1->frameType & NSF_CSC_TYPE_INACTIVE) + || (cscPtr1->frameType != NSF_CSC_TYPE_ACTIVE_FILTER) + )) { + // just assert + //if (cscPtr1 && (object == cscPtr1->self)) { + //fprintf(stderr, "frameType %.6x\n", cscPtr1->frameType); + //assert((cscPtr1->frameType != NSF_CSC_TYPE_ACTIVE_FILTER)); + //} + filterStackPushed = FilterStackPush(interp, object, methodObj); + if ((flags & NSF_CSC_FILTER_STACK_PUSHED)) { + fprintf(stderr, "already NSF_CSC_FILTER_STACK_PUSHED\n"); + } else { + //filterStackPushed = FilterStackPush(interp, object, methodObj); + } + flags |= NSF_CSC_FILTER_STACK_PUSHED; + cmd = FilterSearchProc(interp, object, &object->filterStack->currentCmdPtr, &cl); if (cmd) { /*fprintf(stderr, "filterSearchProc returned cmd %p\n", cmd);*/ frameType = NSF_CSC_TYPE_ACTIVE_FILTER; methodName = (char *)Tcl_GetCommandName(interp, cmd); } else { /*fprintf(stderr, "filterSearchProc returned no cmd\n");*/ - FilterStackPop(object); - filterStackPushed = 0; + //FilterStackPop(object); + //filterStackPushed = 0; } } } - /* check if a mixin is to be called. - don't use mixins on next method calls, since normally it is not - intercepted (it is used as a primitive command). - don't use mixins on init calls, since init is invoked on mixins - during mixin registration (in NsfOMixinMethod) - */ - if ((objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) == NSF_MIXIN_ORDER_DEFINED_AND_VALID) { + /* + * Check if a mixed in method has to be called. + */ + //fprintf(stderr, "dispatch %s objflags %.6x NSF_MIXIN_ORDER_DEFINED_AND_VALID %d\n", + // methodName, objflags, + // (objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID)); + + if ((objflags & NSF_MIXIN_ORDER_DEFINED_AND_VALID) == NSF_MIXIN_ORDER_DEFINED_AND_VALID) { + // remove next block? + if ((flags & NSF_CSC_MIXIN_STACK_PUSHED)) { + fprintf(stderr, "already NSF_CSC_MIXIN_STACK_PUSHED\n"); + } mixinStackPushed = MixinStackPush(object); + flags |= NSF_CSC_MIXIN_STACK_PUSHED; if (frameType != NSF_CSC_TYPE_ACTIVE_FILTER) { + result = MixinSearchProc(interp, object, methodName, &cl, &object->mixinStack->currentCmdPtr, &cmd); if (result != TCL_OK) { @@ -6613,12 +7023,14 @@ if (cmd) { frameType = NSF_CSC_TYPE_ACTIVE_MIXIN; } else { /* the else branch could be deleted */ - MixinStackPop(object); - mixinStackPushed = 0; + //fprintf(stderr, "MixinStackPop 1 %s\n", objectName(object)); + //MixinStackPop(object); + //mixinStackPushed = 0; } } - } + } + /* check if an absolute method name was provided */ if (*methodName == ':') { cmd = Tcl_GetCommandFromObj(interp, methodObj); @@ -6681,22 +7093,46 @@ } if (!unknown) { - result = MethodDispatch(clientData, interp, objc-shift, objv+shift, cmd, object, cl, - methodName, frameType); + //result = MethodDispatch(clientData, interp, objc-shift, objv+shift, cmd, object, cl, + // methodName, frameType, flags); - /*fprintf(stderr, "MethodDispatch %s returns %d unknown %d\n", - methodName, result, rst->unknown);*/ + cscPtr = CscAlloc(interp, &csc, Tcl_Command_objProc(cmd)); + CscInit(cscPtr, object, cl, cmd, frameType); + + // TODO testing, just for the time being + if ((frameType & NSF_CSC_TYPE_ACTIVE_FILTER)) { + // run filters not NRE enabled + flags |= NSF_CM_IMMEDIATE; + // testing with NRE-enabled filters, to invoke UNKNOWN from ProcMethodDispatchFinalize() + //cscPtr->objc = objc-shift; + //cscPtr->objv = objv+shift; + } else if ((frameType & NSF_CSC_TYPE_ACTIVE_MIXIN)) { + //flags |= NSF_CM_IMMEDIATE; + } + result = MethodDispatchCsc(clientData, interp, objc-shift, objv+shift, + cscPtr, methodName, flags); + +#if defined(NRE) + if ((cscPtr->callType & NSF_CSC_CALL_IS_NRE) == 0) { + CscCleanup(interp, cscPtr); + } else { + isNRE = 1; + } +#else + CscCleanup(interp, cscPtr); +#endif + if (result == TCL_ERROR) { /*fprintf(stderr, "Call ErrInProc cl = %p, cmd %p, flags %.6x\n", cl, cl ? cl->object.id : NULL, cl ? cl->object.flags : 0);*/ result = NsfErrInProc(interp, cmdName, - cl && cl->object.teardown ? cl->object.cmdName : NULL, - methodName); + cl && cl->object.teardown ? cl->object.cmdName : NULL, + methodName); } if (rst->unknown && (frameType & NSF_CSC_TYPE_ACTIVE_FILTER)) { - /*fprintf(stderr, "use saved unknown %d frameType %.6x\n", + /*fprintf(stderr, "ObjectDispatch use saved unknown %d frameType %.6x\n", RUNTIME_STATE(interp)->unknown, frameType);*/ unknown = 1; } else { @@ -6708,35 +7144,53 @@ unknown = 1; } - /* fprintf(stderr, "cmd %p unknown %d result %d\n", cmd, unknown, result);*/ + /*fprintf(stderr, "ObjectDispatch %s.%s isNRE %d cmd %p unknown %d result %d\n", + objectName(object), methodName, isNRE, cmd, unknown, result);*/ if (result == TCL_OK) { /*fprintf(stderr, "after doCallProcCheck unknown == %d\n", unknown);*/ if (unknown) { + // just pass IMMEDIATE flag ; TODO: maybe pass it always? + + /*fprintf(stderr, "ObjectDispatch calling unknown flags %.6x\n", flags);*/ + result = DispatchUnknownMethod(clientData, interp, - objc-shift, objv+shift, methodObj, flags); + objc-shift, objv+shift, methodObj, flags&NSF_CM_IMMEDIATE); + /*fprintf(stderr, "ObjectDispatch UNKNOWN returns %d\n", result);*/ } } /* be sure to reset unknown flag */ if (unknown && (frameType & NSF_CSC_TYPE_ACTIVE_FILTER) == 0) { - /*fprintf(stderr, "**** rst->unknown set to 0 flags %.6x frameType %.6x\n",flags,frameType);*/ + /*fprintf(stderr, "ObjectDispatch **** rst->unknown set to 0 flags %.6x frameType %.6x\n", + flags,frameType);*/ rst->unknown = 0; } exit_dispatch: -#ifdef DISPATCH_TRACE - PrintExit(interp, "DISPATCH", objc, objv, result); + /* + if (cscPtr) { +#if defined(NRE) + if ((cscPtr->callType & NSF_CSC_CALL_IS_NRE) == 0) { + CscCleanup(interp, cscPtr); + } #endif + CscCleanup(interp, cscPtr); + }*/ +#if defined(NRE) + if (!isNRE) { + ObjectDispatchFinalize(object, flags); + } +#else + ObjectDispatchFinalize(object, flags); +#endif - if (mixinStackPushed && object->mixinStack) - MixinStackPop(object); - - if (filterStackPushed && object->filterStack) - FilterStackPop(object); + /*fprintf(stderr, "ObjectDispatch %s.%s returns %d\n", + objectName(object), methodName, result);*/ - NsfCleanupObject(object); + NsfCleanupObject(object, "ObjectDispatchFinalize"); /*fprintf(stderr, "ObjectDispatch call NsfCleanupObject %p DONE\n", object);*/ DECR_REF_COUNT(cmdName); /* must be after last dereferencing of obj */ + return result; } @@ -6753,7 +7207,7 @@ #endif if (objc > 1) { - /* normal dispatch */ + /* normal dispatch; we cannot use NSF_CM_IMMEDIATE here, otherwise coroutines won't work */ result = ObjectDispatch(clientData, interp, objc, objv, 0); } else { result = DispatchDefaultMethod(clientData, interp, objc, objv); @@ -7836,9 +8290,9 @@ */ NSF_INLINE static int NextSearchMethod(NsfObject *object, Tcl_Interp *interp, NsfCallStackContent *cscPtr, - NsfClass **clPtr, CONST char **methodNamePtr, Tcl_Command *cmd, + NsfClass **clPtr, CONST char **methodNamePtr, Tcl_Command *cmdPtr, int *isMixinEntry, int *isFilterEntry, - int *endOfFilterChain, Tcl_Command *currentCmd) { + int *endOfFilterChain, Tcl_Command *currentCmdPtr) { int endOfChain = 0, objflags; /* @@ -7854,11 +8308,11 @@ if ((objflags & NSF_FILTER_ORDER_VALID) && object->filterStack && object->filterStack->currentCmdPtr) { - *cmd = FilterSearchProc(interp, object, currentCmd, clPtr); + *cmdPtr = FilterSearchProc(interp, object, currentCmdPtr, clPtr); /* fprintf(stderr, "EndOfChain? cmd=%p\n",*cmd);*/ /* NsfCallStackDump(interp); NsfStackDump(interp);*/ - if (*cmd == NULL) { + if (*cmdPtr == NULL) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_FILTER) { /* * Reset the information to the values of method, clPtr @@ -7871,7 +8325,7 @@ /*fprintf(stderr, "EndOfChain resetting cl\n");*/ } } else { - *methodNamePtr = (char *) Tcl_GetCommandName(interp, *cmd); + *methodNamePtr = (char *) Tcl_GetCommandName(interp, *cmdPtr); *endOfFilterChain = 0; *isFilterEntry = 1; return TCL_OK; @@ -7884,16 +8338,17 @@ assert(objflags & NSF_MIXIN_ORDER_VALID); /* otherwise: MixinComputeDefined(interp, object); */ - /*fprintf(stderr, "nextsearch: mixinorder valid %d stack=%p\n", - obj->flags & NSF_MIXIN_ORDER_VALID, obj->mixinStack);*/ + //fprintf(stderr, "nextsearch: mixinorder valid %d stack %p\n", + // object->flags & NSF_MIXIN_ORDER_VALID, object->mixinStack); - if ((objflags & NSF_MIXIN_ORDER_VALID) && object->mixinStack) { - int result = MixinSearchProc(interp, object, *methodNamePtr, clPtr, currentCmd, cmd); + if ((objflags & NSF_MIXIN_ORDER_VALID) && object->mixinStack) { + int result = MixinSearchProc(interp, object, *methodNamePtr, clPtr, currentCmdPtr, cmdPtr); if (result != TCL_OK) { return result; } - /*fprintf(stderr, "nextsearch: mixinsearch cmd %p, currentCmd %p\n",*cmd, *currentCmd);*/ - if (*cmd == NULL) { + //fprintf(stderr, "nextsearch: mixinsearch cmd %p, frameType %.6x isactivemixin %d\n", + // *cmdPtr, cscPtr->frameType, cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_MIXIN); + if (*cmdPtr == NULL) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_MIXIN) { endOfChain = 1; *clPtr = NULL; @@ -7904,24 +8359,29 @@ } } + //fprintf(stderr, "nextsearch: object %s nsPtr %p endOfChain %d\n", + // objectName(object), object->nsPtr, endOfChain); + /* - * otherwise: normal method dispatch + * Otherwise: normal method dispatch * - * if we are already in the precedence ordering, then advance - * past our last point; otherwise (if clPtr==0) begin from the start + * If we are already in the precedence ordering, then advance + * past our last point; otherwise (if clPtr==0) begin from the start. + * + * When a mixin or filter chain reached its end, we have to search + * the obj-specific methods as well. */ - /* if a mixin or filter chain has ended -> we have to search - the obj-specific methods as well */ - if (object->nsPtr && endOfChain) { - *cmd = FindMethod(object->nsPtr, *methodNamePtr); + *cmdPtr = FindMethod(object->nsPtr, *methodNamePtr); } else { - *cmd = NULL; + *cmdPtr = NULL; } + //fprintf(stderr, "NEXT methodName %s *clPtr %p %s *cmd %p\n", + // *methodNamePtr, *clPtr, className((*clPtr)), *cmdPtr); - if (!*cmd) { + if (!*cmdPtr) { NsfClasses *pl; for (pl = ComputeOrder(object->cl, object->cl->order, Super); *clPtr && pl; pl = pl->nextPtr) { @@ -7933,8 +8393,9 @@ /* * search for a further class method */ - *clPtr = SearchPLMethod(pl, *methodNamePtr, cmd); - /*fprintf(stderr, "zzz new clPtr %p %s cmd %p\n",*clPtr, className((*clPtr)), cmd);*/ + //fprintf(stderr, "zzz start at pl %p\n",pl); + *clPtr = SearchPLMethod(pl, *methodNamePtr, cmdPtr); + //fprintf(stderr, "zzz new clPtr %p %s *cmd %p\n",*clPtr, className((*clPtr)), *cmdPtr); } else { *clPtr = NULL; } @@ -7996,6 +8457,9 @@ *methodNamePtr = Tcl_GetCommandName(interp, cscPtr->cmdPtr); } + /*fprintf(stderr, "NextGetArguments oc %d objc %d inEnsemble %d objv %p\n", + oc, objc, inEnsemble, cscPtr->objv);*/ + if (objc > -1) { int methodNameLength; /* @@ -8087,8 +8551,8 @@ cl = cscPtr->cl; result = NextSearchMethod(object, interp, cscPtr, &cl, &methodName, &cmd, &isMixinEntry, &isFilterEntry, &endOfFilterChain, ¤tCmd); - /*fprintf(stderr, "NEXT search on %s.%s givencl %p cl %p returned %p / %p, %d\n", - objectName(object), *methodNamePtr, givenCl, *clPtr, cmd, currentCmd, result);*/ + //fprintf(stderr, "NEXT search on %s.%s cl %p cmd %p endOfFilterChain %d result %d\n", + // objectName(object), methodName, cl, cmd, endOfFilterChain, result); if (result != TCL_OK) { return result; @@ -8114,7 +8578,7 @@ */ if (object->mixinStack) { if (cscPtr->frameType == NSF_CSC_TYPE_ACTIVE_MIXIN) - cscPtr->frameType = NSF_CSC_TYPE_INACTIVE_MIXIN; + cscPtr->frameType = NSF_CSC_TYPE_INACTIVE; /* otherwise move the command pointer forward */ if (isMixinEntry) { @@ -8144,8 +8608,11 @@ */ cscPtr->callType |= NSF_CSC_CALL_IS_NEXT; rst->unknown = 0; + // fprintf(stderr, "calling method %s\n",methodName); + // TODO: Maybe NSF_CM_IMMEDIATE result = MethodDispatch((ClientData)object, interp, objc, objv, cmd, - object, cl, methodName, frameType); + object, cl, methodName, frameType, NSF_CM_IMMEDIATE, 3); + //fprintf(stderr, "calling method %s DONE\n",methodName); cscPtr->callType &= ~NSF_CSC_CALL_IS_NEXT; if (cscPtr->frameType == NSF_CSC_TYPE_INACTIVE_FILTER) @@ -8211,6 +8678,9 @@ result = NextGetArguments(interp, oc, ov, &cscPtr, &methodName, &nobjc, &nobjv, &freeArgumentVector); if (result == TCL_OK) { + //fprintf(stderr, "NsfNextCmd NextSearchAndInvoke with ov %p // cscPtr %p flags %.6x\n", + // nobjv, cscPtr, cscPtr->callType); + //fprintf(stderr, "NsfNextCmd oc %d ov[0] %p\n", nobjc, nobjv[0]); result = NextSearchAndInvoke(interp, methodName, nobjc, nobjv, cscPtr); } @@ -8640,7 +9110,7 @@ ObjTrace("ODestroy", object); DECR_REF_COUNT(object->cmdName); - NsfCleanupObject(object); + NsfCleanupObject(object, "PrimitiveODestroy"); } @@ -9376,6 +9846,7 @@ int NsfDeleteObject(Tcl_Interp *interp, Nsf_Object *object1) { NsfObject *object = (NsfObject *) object1; + return DispatchDestroyMethod(interp, object, 0); } @@ -9866,14 +10337,17 @@ Nsf_PushFrameObj(interp, object, framePtr); } if (tcd->objProc) { -#if 1 || !defined(NRE) - result = (*tcd->objProc)(tcd->clientData, interp, objc, objv); -#else + /* fprintf(stderr, "CallForwarder Tcl_NRCallObjProc %p\n", clientData);*/ result = Tcl_NRCallObjProc(interp, tcd->objProc, tcd->clientData, objc, objv); -#endif } else if (IsNsfTclObj(interp, tcd->cmdName, (NsfObject**)&clientData)) { - /*fprintf(stderr, "Nsf object %s, objc=%d\n", ObjStr(tcd->cmdName), objc);*/ - result = NsfObjDispatch(clientData, interp, objc, objv); + /*fprintf(stderr, "CallForwarder NsfObjDispatch object %s, objc=%d\n", + ObjStr(tcd->cmdName), objc);*/ + if (objc > 1) { + result = ObjectDispatch(clientData, interp, objc, objv, NSF_CM_IMMEDIATE); + } else { + result = DispatchDefaultMethod(clientData, interp, objc, objv); + } + //result = NsfObjDispatch(clientData, interp, objc, objv); } else { /*fprintf(stderr, "CallForwarder: no nsf object %s\n", ObjStr(tcd->cmdName));*/ result = Tcl_EvalObjv(interp, objc, objv, 0); @@ -10038,11 +10512,13 @@ #endif OV[0] = tcd->cmdName; + result = CallForwarder(tcd, interp, objc, ov); if (tcd->prefix) {DECR_REF_COUNT(ov[1]);} exitforwardmethod: if (freeList) {DECR_REF_COUNT(freeList);} + FREE_ON_STACK(int,objvmap); FREE_ON_STACK(Tcl_Obj*,OV); } @@ -10081,7 +10557,7 @@ (char *) NULL); } return MethodDispatch((ClientData)self, interp, objc, objv, tcd->aliasedCmd, self, tcd->class, - methodName, 0); + methodName, 0, 0, 4); } static int @@ -11460,6 +11936,7 @@ } + /* *---------------------------------------------------------------------- * AliasDeleteObjectReference -- @@ -11490,7 +11967,7 @@ */ /*fprintf(stderr, "remove alias %s to %s\n", Tcl_GetCommandName(interp, cmd), objectName(referencedObject));*/ - NsfCleanupObject(referencedObject); + NsfCleanupObject(referencedObject, "AliasDeleteObjectReference"); Nsf_DeleteCommandFromToken(interp, cmd); return 1; } @@ -11955,7 +12432,7 @@ nobjc+1, nobjv-1, cmd, object, NULL /*NsfClass *cl*/, Tcl_GetCommandName(interp,cmd), - NSF_CSC_TYPE_PLAIN); + NSF_CSC_TYPE_PLAIN, 0, 5); if (withObjscope) { Nsf_PopFrameObj(interp, framePtr); } @@ -11996,8 +12473,9 @@ return NsfVarErrMsg(interp, "Cannot resolve 'self', probably called outside the context of an Next Scripting Object", (char *) NULL); } - /*fprintf(stderr, "Colon dispatch %s on %s\n", ObjStr(nobjv[0]), objectName(self));*/ + //fprintf(stderr, "Colon dispatch %s on %s\n", ObjStr(nobjv[0]), objectName(self)); + /* we could use NSF_CM_IMMEDIATE here */ return ObjectDispatch(self, interp, nobjc, nobjv, NSF_CM_NO_SHIFT); } @@ -12009,10 +12487,12 @@ */ static int NsfExistsVarCmd(Tcl_Interp *interp, NsfObject *object, CONST char *varName) { + if (CheckVarName(interp, varName) != TCL_OK) { return TCL_ERROR; } Tcl_SetIntObj(Tcl_GetObjResult(interp), VarExists(interp, object, varName, NULL, 1, 1)); + return TCL_OK; } @@ -12432,7 +12912,7 @@ (char *) NULL); } result = MethodDispatch((ClientData)self, interp, nobjc+2, nobjv, cmd, self, cl, - methodName, 0); + methodName, 0, 0, 6); } else { result = CallMethod((ClientData)self, interp, methodObj, nobjc+2, nobjv, 0); } @@ -13165,9 +13645,11 @@ */ static int NsfSetVarCmd(Tcl_Interp *interp, NsfObject *object, Tcl_Obj *variable, Tcl_Obj *valueObj) { + if (CheckVarName(interp, ObjStr(variable)) != TCL_OK) { return TCL_ERROR; } + return SetInstVar(interp, object, variable, valueObj); } @@ -14349,7 +14831,7 @@ if (callDirectly) { result = NsfCCreateMethod(interp, cl, ObjStr(fullnameObj), objc+2, ov+1); } else { - result = ObjectDispatch((ClientData)cl, interp, objc+3, ov, 0); + result = ObjectDispatch((ClientData)cl, interp, objc+3, ov, NSF_CM_IMMEDIATE); } FREE_ON_STACK(Tcl_Obj *, ov); @@ -15468,6 +15950,9 @@ fprintf(stderr, "\n"); object->refCount = 1; } + + + //fprintf(stderr, "FinalObjectDeletion obj %s activationcount %d\n", objectName(object), object->activationCount); assert(object->activationCount == 0); /*fprintf(stderr, "FinalObjectDeletion obj %p activationcount %d\n", object, object->activationCount);*/ if (object->id) { Index: generic/nsfInt.h =================================================================== diff -u -r51a8a78d1718e0335a692661f7d1d84f19ba0601 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- generic/nsfInt.h (.../nsfInt.h) (revision 51a8a78d1718e0335a692661f7d1d84f19ba0601) +++ generic/nsfInt.h (.../nsfInt.h) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -240,13 +240,6 @@ use app-specific return codes */ #define NSF_CHECK_FAILED 6 -/* flags for call method */ -#define NSF_CM_NO_UNKNOWN 1 -#define NSF_CM_NO_SHIFT 2 -#define NSF_CM_NO_PROTECT 4 -#define NSF_CM_NO_OBJECT_METHOD 8 -#define NSF_CM_DELGATE 0x10 - /* * * Next Scripting Structures @@ -350,8 +343,8 @@ #define NSF_IS_CLASS 0x0040 #define NSF_IS_ROOT_META_CLASS 0x0080 #define NSF_IS_ROOT_CLASS 0x0100 + #define NSF_TCL_DELETE 0x0200 -/* DESTROYED set, when object is physically destroyed with PrimitiveODestroy */ /*#define NSF_CMD_NOT_FOUND 0x1000*/ #define NSF_DURING_DELETE 0x2000 #define NSF_DELETED 0x4000 @@ -622,19 +615,30 @@ unsigned short callType; } NsfCallStackContent; -#define NSF_CSC_TYPE_PLAIN 0 -#define NSF_CSC_TYPE_ACTIVE_MIXIN 1 -#define NSF_CSC_TYPE_ACTIVE_FILTER 2 -#define NSF_CSC_TYPE_INACTIVE 4 -#define NSF_CSC_TYPE_INACTIVE_MIXIN 5 -#define NSF_CSC_TYPE_INACTIVE_FILTER 6 -#define NSF_CSC_TYPE_GUARD 0x10 -#define NSF_CSC_TYPE_ENSEMBLE 0x20 +#define NSF_CSC_TYPE_PLAIN 0 +#define NSF_CSC_TYPE_ACTIVE_MIXIN 1 +#define NSF_CSC_TYPE_ACTIVE_FILTER 2 +#define NSF_CSC_TYPE_INACTIVE 4 +#define NSF_CSC_TYPE_INACTIVE_MIXIN 5 +#define NSF_CSC_TYPE_INACTIVE_FILTER 6 +#define NSF_CSC_TYPE_GUARD 0x10 +#define NSF_CSC_TYPE_ENSEMBLE 0x20 -#define NSF_CSC_CALL_IS_NEXT 1 -#define NSF_CSC_CALL_IS_GUARD 2 -#define NSF_CSC_CALL_IS_ENSEMBLE 4 /*TODO: needed?*/ +#define NSF_CSC_CALL_IS_NEXT 1 +#define NSF_CSC_CALL_IS_GUARD 2 +#define NSF_CSC_CALL_IS_ENSEMBLE 4 /*TODO: needed?*/ +#define NSF_CSC_CALL_IS_NRE 8 /*TODO: needed?*/ +#define NSF_CSC_MIXIN_STACK_PUSHED 0x100 /*TODO: needed?*/ +#define NSF_CSC_FILTER_STACK_PUSHED 0x200 /*TODO: needed?*/ +/* flags for call method */ +#define NSF_CM_NO_UNKNOWN 1 +#define NSF_CM_NO_SHIFT 2 +#define NSF_CM_NO_PROTECT 4 +#define NSF_CM_NO_OBJECT_METHOD 8 +#define NSF_CM_DELGATE 0x10 +#define NSF_CM_IMMEDIATE 0x20 + #if defined(NSF_PROFILE) typedef struct NsfProfile { long int overallTime; Index: generic/nsfStack.c =================================================================== diff -u -r79c263a13be8850014d056153956f5a83dfbb639 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- generic/nsfStack.c (.../nsfStack.c) (revision 79c263a13be8850014d056153956f5a83dfbb639) +++ generic/nsfStack.c (.../nsfStack.c) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -1,6 +1,5 @@ -static TclVarHashTable *VarHashTableCreate(); -static void NsfCleanupObject(NsfObject *object); +//static TclVarHashTable *VarHashTableCreate(); void TclShowStack(Tcl_Interp *interp) { Tcl_CallFrame *framePtr; @@ -54,7 +53,7 @@ */ static void Nsf_PushFrameObj(Tcl_Interp *interp, NsfObject *object, Tcl_CallFrame *framePtr) { - /*fprintf(stderr,"PUSH OBJECT_FRAME (Nsf_PushFrame) frame %p\n",framePtr);*/ + /*fprintf(stderr,"PUSH OBJECT_FRAME (Nsf_PushFrameObj) frame %p\n",framePtr);*/ if (object->nsPtr) { /*fprintf(stderr,"Nsf_PushFrame frame %p with object->nsPtr %p\n", framePtr, object->nsPtr);*/ Tcl_PushCallFrame(interp, framePtr, object->nsPtr, @@ -77,27 +76,25 @@ } static void Nsf_PopFrameObj(Tcl_Interp *interp, Tcl_CallFrame *framePtr) { - /*fprintf(stderr,"POP OBJECT_FRAME (Nsf_PopFrame) frame %p, vartable %p set to NULL, already %d\n", - framePtr, Tcl_CallFrame_varTablePtr(framePtr), Tcl_CallFrame_varTablePtr(framePtr) == NULL);*/ + /*fprintf(stderr,"POP OBJECT_FRAME (Nsf_PopFrameObj) frame %p, vartable %p set to NULL, already %d\n", + framePtr, Tcl_CallFrame_varTablePtr(framePtr), Tcl_CallFrame_varTablePtr(framePtr) == NULL);*/ Tcl_CallFrame_varTablePtr(framePtr) = NULL; Tcl_PopCallFrame(interp); } static void Nsf_PushFrameCsc(Tcl_Interp *interp, NsfCallStackContent *cscPtr, Tcl_CallFrame *framePtr) { CallFrame *varFramePtr = Tcl_Interp_varFramePtr(interp); + /*fprintf(stderr,"PUSH CMETHOD_FRAME (Nsf_PushFrameCsc) frame %p cscPtr %p methodName %s\n", + framePtr, cscPtr, Tcl_GetCommandName(interp,cscPtr->cmdPtr));*/ - /*fprintf(stderr,"PUSH CMETHOD_FRAME (Nsf_PushFrame) frame %p object->nsPtr %p interp ns %p\n", - framePtr,object->nsPtr, - Tcl_CallFrame_nsPtr(varFramePtr));*/ - Tcl_PushCallFrame(interp, framePtr, Tcl_CallFrame_nsPtr(varFramePtr), 1|FRAME_IS_NSF_CMETHOD); Tcl_CallFrame_clientData(framePtr) = (ClientData)cscPtr; Tcl_CallFrame_procPtr(framePtr) = &RUNTIME_STATE(interp)->fakeProc; } static void Nsf_PopFrameCsc(Tcl_Interp *interp, Tcl_CallFrame *framePtr) { - /*fprintf(stderr,"POP CMETHOD_FRAME (Nsf_PopFrame) frame %p, varTable = %p\n", + /*fprintf(stderr,"POP CMETHOD_FRAME (Nsf_PopFrameCsc) frame %p, varTable = %p\n", framePtr, Tcl_CallFrame_varTablePtr(framePtr));*/ Tcl_PopCallFrame(interp); } @@ -258,11 +255,20 @@ ctx->framesSaved = 0; } else { ctx->varFramePtr = inFramePtr; + /*fprintf(stderr, "CallStackUseActiveFrames stores %p\n",framePtr);*/ Tcl_Interp_varFramePtr(interp) = (CallFrame *)framePtr; ctx->framesSaved = 1; } } +static void +CallStackRestoreSavedFrames(Tcl_Interp *interp, callFrameContext *ctx) { + if (ctx->framesSaved) { + /*fprintf(stderr, "CallStackRestoreSavedFrames drops %p restores %p\n", + Tcl_Interp_varFramePtr(interp), ctx->varFramePtr);*/ + Tcl_Interp_varFramePtr(interp) = (CallFrame *)ctx->varFramePtr; + } +} static NsfCallStackContent * CallStackFindActiveFilter(Tcl_Interp *interp) { @@ -444,7 +450,7 @@ * track object activations */ object->activationCount ++; - + //fprintf(stderr, "activationCount ++ (%s) --> %d\n",objectName(object), object->activationCount); /* * track class activations */ @@ -467,7 +473,7 @@ cscPtr->cl = cl; cscPtr->cmdPtr = cmd; cscPtr->frameType = frameType; - cscPtr->callType = 0; + //cscPtr->callType = 0; /* initialized in CscAlloc() cscPtr->filterStackEntry = frameType == NSF_CSC_TYPE_ACTIVE_FILTER ? object->filterStack : NULL; cscPtr->objv = NULL; @@ -510,6 +516,8 @@ tracking activations of objects */ object->activationCount --; + + //fprintf(stderr, "activationCount -- (%s) --> %d\n",objectName(object), object->activationCount); /*fprintf(stderr, "decr activationCount for %s to %d cscPtr->cl %p\n", objectName(cscPtr->self), cscPtr->self->activationCount, cscPtr->cl);*/ @@ -553,7 +561,7 @@ nsPtr->fullName, nsPtr->activationCount, nsPtr->flags, nsPtr->refCount);*/ if ((nsPtr->refCount == 0) && (nsPtr->flags & NS_DEAD)) { - /* the namspace refcound has reached 0, we have to free + /* the namespace refcount has reached 0, we have to free it. unfortunately, NamespaceFree() is not exported */ /* TODO: remove me finally */ fprintf(stderr, "HAVE TO FREE %p\n",nsPtr); Index: library/nx/nx.tcl =================================================================== diff -u -r02226155f55d727ec7c7ef92e8d47387e8a4ea38 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- library/nx/nx.tcl (.../nx.tcl) (revision 02226155f55d727ec7c7ef92e8d47387e8a4ea38) +++ library/nx/nx.tcl (.../nx.tcl) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -209,7 +209,6 @@ return [::nsf::dispatch [::nsf::current object] ::nsf::cmd::Object::$what {*}$args] } } - # define unknown handler for class :method unknown {m args} { error "Method '$m' unknown for [::nsf::current object].\ @@ -219,6 +218,7 @@ ::nsf::methodproperty [::nsf::current object] unknown protected true } + Object eval { # method modifier "public" @@ -275,6 +275,7 @@ # tries to resolve the class again. This meachnism is used e.g. by # the ::ttrace mechanism for partial loading by Zoran. # + Class protected class-object method __unknown {name} {} # Add alias methods. cmdName for a method can be added via @@ -291,6 +292,7 @@ {*}[expr {${nonleaf} ? "-nonleaf" : ""}] \ $cmd } + Class public method alias {-nonleaf:switch -objscope:switch methodName cmd} { array set "" [:__resolve_method_path -create -verbose $methodName] #puts "class alias $(object).$(methodName) $cmd" @@ -1517,4 +1519,5 @@ unset bootstrap } +puts stderr =======NX-done Index: tests/coroutines.tcl =================================================================== diff -u --- tests/coroutines.tcl (revision 0) +++ tests/coroutines.tcl (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -0,0 +1,33 @@ +package require nx +package require nx::test + +# just 8.6 or similar +if {[info command yield] eq ""} return + +Test case generator { + # =================================== + # nx coro + # =================================== + nx::Object create numbers { + :public method ++ {} { + puts stderr BEFORE-yield-[nx::self] + #::nsf::yieldcheck + yield + puts stderr AFTER-yield-[nx::self] + set i 0 + while 1 { + yield $i + incr i 2 + } + } + } + + coroutine nextNumber numbers ++ + set ::j 0 + for {set i 0} {$i < 10} {incr i} { + incr ::j [nextNumber] + } + rename nextNumber {} + + ? {set ::j} 90 +} Index: tests/interceptor-slot.tcl =================================================================== diff -u -r29ea21bd3f28ea7effaca6039e59a8a3499f8fd8 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- tests/interceptor-slot.tcl (.../interceptor-slot.tcl) (revision 29ea21bd3f28ea7effaca6039e59a8a3499f8fd8) +++ tests/interceptor-slot.tcl (.../interceptor-slot.tcl) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -144,6 +144,7 @@ # define nx unknown handler in case it does not exist ::nx::Object protected method unknown {m args} { + puts stderr XXXXX error "[::nsf::current object]: unable to dispatch method '$m'" } @@ -155,7 +156,9 @@ # create through filter ? {Foo create ob} ::ob # unknown through filter +puts stderr ======a ? {ob bar1} {::ob: unable to dispatch method 'bar1'} +puts stderr ======b ? {ob baz} {} # deactivate nx unknown handler in case it exists @@ -164,10 +167,14 @@ # create through filter ? {Foo create ob2} ::ob2 # unknown through filter +puts stderr ======c ? {ob2 bar2} {::ob2: unable to dispatch method 'bar2'} +puts stderr ======d ? {ob2 baz} {} } +puts stderr ======EXIT + Index: tests/object-system.tcl =================================================================== diff -u -r89376e0f64856bb395fdb4407c9646787545a08b -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- tests/object-system.tcl (.../object-system.tcl) (revision 89376e0f64856bb395fdb4407c9646787545a08b) +++ tests/object-system.tcl (.../object-system.tcl) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -105,8 +105,8 @@ ? {::nsf::isobject C::slot} 1 ? {C info children} ::C::slot - C copy X +puts stderr ===after ? {::nsf::isobject X} 1 ? {X info vars} "" ? {C info vars} "" Index: tests/parameters.tcl =================================================================== diff -u -r29ea21bd3f28ea7effaca6039e59a8a3499f8fd8 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- tests/parameters.tcl (.../parameters.tcl) (revision 29ea21bd3f28ea7effaca6039e59a8a3499f8fd8) +++ tests/parameters.tcl (.../parameters.tcl) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -438,12 +438,13 @@ } ? {Foo create foo -ints {1 2}} "::foo" ? {Foo create foo -ints {1 a 2}} {invalid value in "1 a 2": expected integer but got "a" for parameter -ints} - + # make slot incremental Foo::slot::ints eval { set :incremental 1 :optimize } + Foo create foo -ints {1 2} ? {foo ints add 0} "0 1 2" ? {foo ints add a} {expected integer but got "a" for parameter value} Index: tests/submethods.tcl =================================================================== diff -u -r29ea21bd3f28ea7effaca6039e59a8a3499f8fd8 -rd1ed482555d4d28dbb41fb9ca2723eabb5e01221 --- tests/submethods.tcl (.../submethods.tcl) (revision 29ea21bd3f28ea7effaca6039e59a8a3499f8fd8) +++ tests/submethods.tcl (.../submethods.tcl) (revision d1ed482555d4d28dbb41fb9ca2723eabb5e01221) @@ -36,7 +36,7 @@ ? {o string tolower 2} tolower ? {o string toupper 2} \ {unable to dispatch method ::o string toupper; valid subcommands of string: info length tolower} - + ? {o foo a x} "x" ? {o foo a y} "y" ? {o foo a z} {unable to dispatch method ::o foo a z; valid subcommands of a: defaultmethod subcmdName unknown x y}