Index: TODO =================================================================== diff -u -rab02510271f298ae1c4b3aa585a018badc84b013 -re90e59865348906790e496aa960ef57837456e9e --- TODO (.../TODO) (revision ab02510271f298ae1c4b3aa585a018badc84b013) +++ TODO (.../TODO) (revision e90e59865348906790e496aa960ef57837456e9e) @@ -2681,14 +2681,27 @@ - nx.tcl: replace loops ::nsf::methods::[object|class]::* by explict command registrations +- nsf.c: + * added NsfClassListNoDup() to allow just single inserts + * added NsfClassListPrint() for debugging + * info heritage returns no duplicates + * added prototype for NsfNoCurrentObjectError() + * report "no current object" when no object is + passed to a method. + * code cleanup +- extended regression test + + TODO: -- the last two results of "info heritage" in info-method.test are not - what we want (e.g. ::M3 ::B ::M3 ::nx::Object); would not be surprised - if the same problem occursn somewhere else -- if the tests on the last two tests fails, we get an exception (should - go away, when the duplicates are eliminated). +- check again, of the nodup elimination in + MixinComputeOrderFullList() is ok, maybe the duplicate elimination + in info heritage should be based on something like + MixinComputeOrder() based on CmdListAdd() +- if the check on eg. info-heritage-circular in test/info.method.tcl + fails, we get an exception. + - what to do with "info heritage" a) keep the new version (slightly incompatible in XOTcl) b) provide a scripted compatible version in "info superclass" Index: generic/nsf.c =================================================================== diff -u -r5c464365425434543edd13f1674e1dd2d7f17a71 -re90e59865348906790e496aa960ef57837456e9e --- generic/nsf.c (.../nsf.c) (revision 5c464365425434543edd13f1674e1dd2d7f17a71) +++ generic/nsf.c (.../nsf.c) (revision e90e59865348906790e496aa960ef57837456e9e) @@ -1330,6 +1330,46 @@ /* *---------------------------------------------------------------------- + * NsfClassListNoDup -- + * + * Add class list entry to the specified list without duplicates. In case + * the initial list is empty, *firstPtrPtr is updated as well. + * + * Results: + * Returns address of next pointer. + * + * Side effects: + * New list element is allocated. + * + *---------------------------------------------------------------------- + */ + +static NsfClasses ** +NsfClassListNoDup(NsfClasses **firstPtrPtr, NsfClass *cl, ClientData clientData, int *new) { + NsfClasses *l = *firstPtrPtr, *element = NULL, **newPtr = &element; + + if (l) { + for (; l->nextPtr && l->cl != cl; l = l->nextPtr); + newPtr = &l->nextPtr; + } else { + newPtr = firstPtrPtr; + } + + if (l == NULL || l->cl != cl) { + if (new) *new = 1; + element = NEW(NsfClasses); + element->cl = cl; + element->clientData = clientData; + element->nextPtr = NULL; + *newPtr = element; + } else { + if (new) *new = 0; + } + return newPtr; +} + +/* + *---------------------------------------------------------------------- * NsfClassListFind -- * * Find an element in the class list and return it if found. @@ -1350,6 +1390,22 @@ return classList; } +#if 1 +/* debugging purposes only */ +static void +NsfClassListPrint(CONST char *title, NsfClasses *clsList) { + if (title) { + fprintf(stderr, "%s", title); + } + fprintf(stderr, " %p: ", clsList); + while (clsList) { + fprintf(stderr, "%p %s ", clsList->cl, ClassName(clsList->cl)); + clsList = clsList->nextPtr; + } + fprintf(stderr, "\n"); +} +#endif + #if defined(CHECK_ACTIVATION_COUNTS) /* *---------------------------------------------------------------------- @@ -4423,21 +4479,21 @@ NsfCommandRelease(del); } -#if 0 +#if 1 /** for debug purposes only */ static void CmdListPrint(Tcl_Interp *interp, CONST char *title, NsfCmdList *cmdList) { - if (cmdList) { - fprintf(stderr, title); + if (title) { + fprintf(stderr, "%s %p:\n", title, cmdList); } while (cmdList) { fprintf(stderr, " CL=%p, cmdPtr=%p %s, clorobj %p, clientData=%p\n", cmdList, cmdList->cmdPtr, - in ? Tcl_GetCommandName(interp, cmdList->cmdPtr) : "", + interp ? Tcl_GetCommandName(interp, cmdList->cmdPtr) : "", cmdList->clorobj, cmdList->clientData); - cmdList = cmdList->next; + cmdList = cmdList->nextPtr; } } #endif @@ -5011,39 +5067,46 @@ NsfClass *mCl = NsfGetClassFromCmdPtr(m->cmdPtr); if (mCl) { for (pl = ComputeOrder(mCl, mCl->order, Super); pl; pl = pl->nextPtr) { - /*fprintf(stderr, " %s, ", ObjStr(pl->cl->object.cmdName));*/ + //fprintf(stderr, " %s, ", ClassName(pl->cl)); if ((pl->cl->object.flags & NSF_IS_ROOT_CLASS) == 0) { NsfClassOpt *opt = pl->cl->opt; if (opt && opt->classmixins) { /* - * compute transitively the (class) mixin classes of this - * added class + * Compute transitively the (class) mixin classes of this + * added class. */ + /*fprintf(stderr, "find %p %s in checklist %p\n", pl->cl, ClassName(pl->cl), *checkList);*/ if (!NsfClassListFind(*checkList, pl->cl)) { NsfClassListAdd(checkList, pl->cl, NULL); - /*fprintf(stderr, "+++ transitive %s\n", - ObjStr(pl->cl->object.cmdName));*/ + /*fprintf(stderr, "+++ transitive %s\n", ClassName(pl->cl));*/ MixinComputeOrderFullList(interp, &opt->classmixins, mixinClasses, checkList, level+1); - } + } else { + /*fprintf(stderr, "+++ dont add %s\n", ClassName(pl->cl));*/ + } } - /* fprintf(stderr, "+++ add to mixinClasses %p path: %s clPtr %p\n", - mixinClasses, ObjStr(pl->cl->object.cmdName), clPtr);*/ - clPtr = NsfClassListAdd(clPtr, pl->cl, m->clientData); + /*fprintf(stderr, "+++ add to mixinClasses %p path: %s clPtr %p\n", + mixinClasses, ClassName(pl->cl), clPtr);*/ + clPtr = NsfClassListNoDup(clPtr, pl->cl, m->clientData, NULL); } } } } + + //NsfClassListPrint("MixinComputeOrderFullList final", *mixinClasses); + //NsfClassListPrint("MixinComputeOrderFullList check", *checkList); + if (level == 0 && *checkList) { NsfClassListFree(*checkList); *checkList = NULL; } + } static void MixinResetOrder(NsfObject *object) { - /*fprintf(stderr, "removeList %s \n", ObjectName(object));*/ + /*fprintf(stderr, "MixinResetOrder for object %s \n", ObjectName(object));*/ CmdListRemoveList(&object->mixinOrder, NULL /*GuardDel*/); object->mixinOrder = NULL; } @@ -5072,7 +5135,7 @@ NsfClassOpt *clopt = pl->cl->opt; if (clopt && clopt->classmixins) { MixinComputeOrderFullList(interp, &clopt->classmixins, - classList, checkList, 0); + classList, checkList, 1); } } } @@ -5103,11 +5166,18 @@ /* append per-obj mixins */ if (object->opt) { MixinComputeOrderFullList(interp, &object->opt->mixins, &mixinClasses, - &checkList, 0); + &checkList, 1); } + /*fprintf(stderr, "%s ", ObjectName(object)); + NsfClassListPrint("MixinComputeOrder poms", mixinClasses);*/ /* append per-class mixins */ NsfClassListAddPerClassMixins(interp, object->cl, &mixinClasses, &checkList); + + /*fprintf(stderr, "%s ", ObjectName(object)); + NsfClassListPrint("MixinComputeOrder poms+pcms", mixinClasses); + CmdListPrint(interp, "mixinOrder", object->mixinOrder);*/ + NsfClassListFree(checkList); fullList = mixinClasses; @@ -5118,27 +5188,34 @@ */ while (mixinClasses) { NsfClass *cl = mixinClasses->cl; + + /*fprintf(stderr, "--- Work on %s\n", ClassName(cl)); + CmdListPrint(interp, "mixinOrder", object->mixinOrder);*/ checker = nextCl = mixinClasses->nextPtr; - /* fprintf(stderr, "--- checking %s\n", ObjStr(cl->object.cmdName));*/ - checker = NsfClassListFind(checker, cl); + /*fprintf(stderr, "--- checking %s found %p \n", ClassName(cl), checker);*/ + /* * if checker is set, it is a duplicate and ignored */ if (checker == NULL) { /* check object->cl hierachy */ checker = NsfClassListFind(ComputeOrder(object->cl, object->cl->order, Super), cl); + /*fprintf(stderr, "--- checking 2 %s found %p \n", ClassName(cl), checker);*/ /* * if checker is set, it was found in the class hierarchy and it is ignored */ } if (checker == NULL) { /* add the class to the mixinOrder list */ NsfCmdList *new; - /* fprintf(stderr, "--- adding to mixinlist %s\n", - ObjStr(cl->object.cmdName));*/ + + /*fprintf(stderr, "--- adding to mixinOrder %s to cmdlist %p of object %s\n", + ClassName(cl), object->mixinOrder, ObjectName(object));*/ new = CmdListAdd(&object->mixinOrder, cl->object.id, NULL, /*noDuplicates*/ 0); + /*CmdListPrint(interp, "mixinOrder", object->mixinOrder);*/ + /* * We require the first matching guard of the full list in the new * client data @@ -5333,7 +5410,7 @@ "nsPtr->flags %.6x (instance of %s)\n", inst, inst->flags, inst->activationCount, ObjectName(inst), inst->id, cmdPtr->flags, cmdPtr->nsPtr ? cmdPtr->nsPtr->flags : 0, - ObjStr(startCl->object.cmdName));*/ + ClassName(startCl));*/ Tcl_CreateHashEntry(destTablePtr, ObjectName(inst), &new); @@ -5449,7 +5526,7 @@ pattern, matchObject); if (rc) {return rc;} } - /*fprintf(stderr, "check subclasses of %s done\n", ObjStr(startCl->object.cmdName));*/ + /*fprintf(stderr, "check subclasses of %s done\n", ClassName(startCl));*/ if (startCl->opt) { NsfCmdList *m; @@ -5461,12 +5538,11 @@ cl = NsfGetClassFromCmdPtr(m->cmdPtr); assert(cl); - /*fprintf(stderr, "check %s mixinof %s\n", - ClassName(cl), ObjStr(startCl->object.cmdName));*/ + /*fprintf(stderr, "check %s mixinof %s\n", ClassName(cl), ClassName((startCl)));*/ rc = GetAllObjectMixinsOf(interp, destTablePtr, cl, isMixin, appendResult, pattern, matchObject); /* fprintf(stderr, "check %s mixinof %s done\n", - ClassName(cl), ObjStr(startCl->object.cmdName));*/ + ClassName(cl), ClassName(startCl));*/ if (rc) {return rc;} } } @@ -5639,7 +5715,7 @@ if (new) { /* fprintf(stderr, "class mixin GetAllClassMixins for: %s (%s)\n", - ClassName(cl), ObjStr(startCl->object.cmdName)); */ + ClassName(cl), ClassName(startCl)); */ rc = GetAllClassMixins(interp, destTablePtr, cl, withGuards, pattern, matchObject); if (rc) {return rc;} @@ -5653,7 +5729,7 @@ */ for (sc = startCl->super; sc; sc = sc->nextPtr) { /* fprintf(stderr, "Superclass GetAllClassMixins for %s (%s)\n", - ObjStr(sc->cl->object.cmdName), ObjStr(startCl->object.cmdName)); */ + ClassName(sc->cl), ClassName(startCl)); */ rc = GetAllClassMixins(interp, destTablePtr, sc->cl, withGuards, pattern, matchObject); if (rc) {return rc;} @@ -5743,8 +5819,7 @@ Tcl_HashSearch hSrch; Tcl_HashEntry *hPtr; - /*fprintf(stderr, "invalidating instances of class %s\n", - ObjStr(clPtr->cl->object.cmdName));*/ + /*fprintf(stderr, "invalidating instances of class %s\n", ClassName(clPtr->cl));*/ /* Here we should check, whether this class is used as an object or class mixin somewhere else and invalidate the objects of these as @@ -5807,7 +5882,7 @@ /* reset mixin order for all objects having this class as per object mixin */ ResetOrderOfClassesUsedAsMixins(clPtr->cl); - /* fprintf(stderr, "invalidating instances of class %s\n", ObjStr(clPtr->cl->object.cmdName)); + /* fprintf(stderr, "invalidating instances of class %s\n", ClassName(clPtr)); */ instanceTablePtr = &clPtr->cl->instances; for (hPtr = Tcl_FirstHashEntry(instanceTablePtr, &hSrch); hPtr; @@ -5832,7 +5907,7 @@ for (hPtr = Tcl_FirstHashEntry(commandTable, &hSrch); hPtr; hPtr = Tcl_NextHashEntry(&hSrch)) { NsfClass *ncl = (NsfClass *)Tcl_GetHashKey(commandTable, hPtr); - /*fprintf(stderr, "Got %s, reset for ncl %p\n", ncl?ObjStr(ncl->object.cmdName):"NULL", ncl);*/ + /*fprintf(stderr, "Got %s, reset for ncl %p\n", ncl?ClassName(ncl):"NULL", ncl);*/ if (ncl) { MixinResetOrderForInstances(ncl); /* this place seems to be sufficient to invalidate the computed object parameter definitions */ @@ -6589,7 +6664,7 @@ if (pi) { CmdListAdd(filterList, pi, pl->cl, /*noDuplicates*/ 0); /* - fprintf(stderr, " %s::%s, ", ObjStr(pl->cl->object.cmdName), simpleName); + fprintf(stderr, " %s::%s, ", ClassName(pl->cl), simpleName); */ } } @@ -15429,7 +15504,7 @@ NsfColonCmd(Tcl_Interp *interp, int nobjc, Tcl_Obj *CONST nobjv[]) { NsfObject *self = GetSelfObj(interp); if (!self) { - NsfNoCurrentObjectError(interp, ObjStr(nobjv[0])); + return NsfNoCurrentObjectError(interp, ObjStr(nobjv[0])); } /* fprintf(stderr, "Colon dispatch %s.%s\n", ObjectName(self),ObjStr(nobjv[0]));*/ return ObjectDispatch(self, interp, nobjc, nobjv, NSF_CM_NO_SHIFT); @@ -15886,7 +15961,7 @@ int result; if (!self) { - NsfNoCurrentObjectError(interp, ObjStr(nobjv[0])); + return NsfNoCurrentObjectError(interp, ObjStr(nobjv[0])); } if (withLocal) { @@ -17972,7 +18047,7 @@ /*fprintf(stderr, "+++ createspecifiedName '%s', nameString '%s', newObject=%p ismeta(%s) %d, ismeta(%s) %d\n", specifiedName, nameString, newObject, ClassName(cl), IsMetaClass(interp, cl, 1), - newObject ? ObjStr(newObject->cl->object.cmdName) : "NULL", + newObject ? ClassName(newObject->cl) : "NULL", newObject ? IsMetaClass(interp, newObject->cl, 1) : NULL );*/ Index: generic/nsf.h =================================================================== diff -u -r211c77c1a94a47be185a8bfb12c89512937b1901 -re90e59865348906790e496aa960ef57837456e9e --- generic/nsf.h (.../nsf.h) (revision 211c77c1a94a47be185a8bfb12c89512937b1901) +++ generic/nsf.h (.../nsf.h) (revision e90e59865348906790e496aa960ef57837456e9e) @@ -259,7 +259,10 @@ extern int NsfDispatchClientDataError(Tcl_Interp *interp, ClientData clientData, CONST char *what, CONST char *methodName); +extern int +NsfNoCurrentObjectError(Tcl_Interp *interp, CONST char *what); + #define NSF_LOG_NOTICE 2 #define NSF_LOG_WARN 1 Index: generic/nsfError.c =================================================================== diff -u -r5c464365425434543edd13f1674e1dd2d7f17a71 -re90e59865348906790e496aa960ef57837456e9e --- generic/nsfError.c (.../nsfError.c) (revision 5c464365425434543edd13f1674e1dd2d7f17a71) +++ generic/nsfError.c (.../nsfError.c) (revision e90e59865348906790e496aa960ef57837456e9e) @@ -32,8 +32,7 @@ */ extern void -NsfDStringPrintf(Tcl_DString *dsPtr, CONST char *fmt, va_list apSrc) -{ +NsfDStringPrintf(Tcl_DString *dsPtr, CONST char *fmt, va_list apSrc) { int result, avail = dsPtr->spaceAvl, offset = dsPtr->length; va_list ap; @@ -70,8 +69,7 @@ *---------------------------------------------------------------------- */ extern void -NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *CONST objv[]) -{ +NsfDStringArgv(Tcl_DString *dsPtr, int objc, Tcl_Obj *CONST objv[]) { int i; for (i=0; iobject with a value ? {::o x} "::o" # check, if missing object is still detected - ? ::o::x "Method x not dispatched on valid object ; don't call aliased methods via namespace paths!" + ? ::o::x "No current object; x called outside the context of a Next Scripting method" ? self "No current object; command called outside the context of a Next Scripting method" } \ No newline at end of file