Index: TODO =================================================================== diff -u -r4de992d3115042b8f0ad2d49d37505ad2666b6fa -r5016c5d2fee323133f57ad401f1aa4f9d927cd2a --- TODO (.../TODO) (revision 4de992d3115042b8f0ad2d49d37505ad2666b6fa) +++ TODO (.../TODO) (revision 5016c5d2fee323133f57ad401f1aa4f9d927cd2a) @@ -2666,10 +2666,22 @@ * nsf works with OpenACS again (requires new nstrace.tcl, aolserver-openacs.tcl, and 01-debug-procs.tcl). -- nsf.c: factor out ClassListAddPerClassMixins() +- nsf.c: + * factor out NsfClassListAddPerClassMixins() + * factor out NsfClassListFind() + * let result of "cls info heritage" return per-class mixins + as well, otherwise it would be useless, since + "cls info superclass -closure" would return the same 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). + +- there are probably many more places, where NsfClassListFind() could be used. - ::nsf::method::exists /handle/ -> check, if handle is a handle of a registered method (to be be used in serializer alias-dependency) - profiling missing when NSF_INVOKE_SHADOWED_TRADITIONAL is turned off. Index: generic/nsf.c =================================================================== diff -u -r4de992d3115042b8f0ad2d49d37505ad2666b6fa -r5016c5d2fee323133f57ad401f1aa4f9d927cd2a --- generic/nsf.c (.../nsf.c) (revision 4de992d3115042b8f0ad2d49d37505ad2666b6fa) +++ generic/nsf.c (.../nsf.c) (revision 5016c5d2fee323133f57ad401f1aa4f9d927cd2a) @@ -1328,6 +1328,28 @@ return &(element->nextPtr); } +/* + *---------------------------------------------------------------------- + * NsfClassListFind -- + * + * Find an element in the class list and return it if found. + * + * Results: + * Found element or NULL + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ +static NsfClasses * +NsfClassListFind(NsfClasses *classList, NsfClass *cl) { + for (; classList; classList = classList->nextPtr) { + if (classList->cl == cl) break; + } + return classList; +} + #if defined(CHECK_ACTIVATION_COUNTS) /* *---------------------------------------------------------------------- @@ -4998,8 +5020,7 @@ NsfClasses *cls; int i, found = 0; for (i=0, cls = *checkList; cls; i++, cls = cls->nextPtr) { - /* fprintf(stderr, "+++ c%d: %s\n", i, - ClassName(cls->cl));*/ + /* fprintf(stderr, "+++ c%d: %s\n", i, ClassName(cls->cl));*/ if (pl->cl == cls->cl) { found = 1; break; @@ -5036,23 +5057,22 @@ /* *---------------------------------------------------------------------- - * ClassListAddPerClassMixins -- + * NsfClassListAddPerClassMixins -- * - * Append the class mixins to the proivded list. Check list is used to + * Append the class mixins to the proivded list. CheckList is used to * eliminate potential duplicates. * * Results: * void * * Side effects: - * Appends potentially elements classList and checkList + * Appends potentially elements to classList and checkList * *---------------------------------------------------------------------- */ static void -ClassListAddPerClassMixins(Tcl_Interp *interp, NsfClass *cl, +NsfClassListAddPerClassMixins(Tcl_Interp *interp, NsfClass *cl, NsfClasses **classList, NsfClasses **checkList) { - /* append per-class mixins */ NsfClasses *pl; for (pl = ComputeOrder(cl, cl->order, Super); pl; pl = pl->nextPtr) { @@ -5069,7 +5089,7 @@ * MixinComputeOrder -- * * Compute a duplicate-free linearized order of per-object and per-class - * mixins and the class inheritance. The precendence rule is that the last + * mixins and the class inheritance. The precendence rule is that the last * occurence makes it into the final list. * * Results: @@ -5080,7 +5100,6 @@ * *---------------------------------------------------------------------- */ - static void MixinComputeOrder(Tcl_Interp *interp, NsfObject *object) { NsfClasses *fullList, *checkList = NULL, *mixinClasses = NULL, *nextCl, @@ -5095,49 +5114,45 @@ } /* append per-class mixins */ - ClassListAddPerClassMixins(interp, object->cl, &mixinClasses, &checkList); + NsfClassListAddPerClassMixins(interp, object->cl, &mixinClasses, &checkList); NsfClassListFree(checkList); fullList = mixinClasses; - /* use no duplicates & no classes of the precedence order - on the resulting list */ + /* + * Don't add duplicates or classes of the precedence order to the resulting + * list. + */ while (mixinClasses) { + NsfClass *cl = mixinClasses->cl; + checker = nextCl = mixinClasses->nextPtr; - /* fprintf(stderr, "--- checking %s\n", - ObjStr(mixinClasses->cl->object.cmdName));*/ + /* fprintf(stderr, "--- checking %s\n", ObjStr(cl->object.cmdName));*/ - while (checker) { - if (checker->cl == mixinClasses->cl) break; - checker = checker->nextPtr; - } - /* if checker is set, it is a duplicate and ignored */ - + checker = NsfClassListFind(checker, cl); + /* + * if checker is set, it is a duplicate and ignored + */ if (checker == NULL) { - /* check obj->cl hierachy */ - for (checker = ComputeOrder(object->cl, object->cl->order, Super); checker; checker = checker->nextPtr) { - if (checker->cl == mixinClasses->cl) { - break; - } - } - /* if checker is set, it was found in the class hierarchy - and it is ignored */ + /* check object->cl hierachy */ + checker = NsfClassListFind(ComputeOrder(object->cl, object->cl->order, Super), cl); + /* + * 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(mixinClasses->cl->object.cmdName));*/ - new = CmdListAdd(&object->mixinOrder, mixinClasses->cl->object.id, NULL, - /*noDuplicates*/ 0); - - /* in the client data of the order list, we require the first - matching guard ... scan the full list for it. */ - for (guardChecker = fullList; guardChecker; guardChecker = guardChecker->nextPtr) { - if (guardChecker->cl == mixinClasses->cl) { - new->clientData = guardChecker->clientData; - break; - } + ObjStr(cl->object.cmdName));*/ + new = CmdListAdd(&object->mixinOrder, cl->object.id, NULL, /*noDuplicates*/ 0); + /* + * We require the first matching guard of the full list in the new + * client data + */ + guardChecker = NsfClassListFind(fullList, cl); + if (guardChecker) { + new->clientData = guardChecker->clientData; } } mixinClasses = nextCl; @@ -5147,7 +5162,6 @@ NsfClassListFree(fullList); /*CmdListPrint(interp, "mixin order\n", obj->mixinOrder);*/ - } /* @@ -11979,7 +11993,7 @@ int hasMCM = 0; /* has the class metaclass mixed in? */ - ClassListAddPerClassMixins(interp, cl, &mixinClasses, &checkList); + NsfClassListAddPerClassMixins(interp, cl, &mixinClasses, &checkList); for (mc = mixinClasses; mc; mc = mc->nextPtr) { if (IsMetaClass(interp, mc->cl, 0)) { @@ -18850,13 +18864,32 @@ */ static int NsfClassInfoHeritageMethod(Tcl_Interp *interp, NsfClass *cl, CONST char *pattern) { - NsfClasses *pl = ComputeOrder(cl, cl->order, Super); + NsfClasses *pl, *intrinsic; + int withMixins = 1; + NsfClasses *checkList = NULL, *mixinClasses = NULL; Tcl_ResetResult(interp); - if (pl) pl=pl->nextPtr; - for (; pl; pl = pl->nextPtr) { - AppendMatchingElement(interp, pl->cl->object.cmdName, pattern); + + intrinsic = ComputeOrder(cl, cl->order, Super); + + if (withMixins) { + NsfClassListAddPerClassMixins(interp, cl, &mixinClasses, &checkList); + for (pl = mixinClasses; pl; pl = pl->nextPtr) { + if (!NsfClassListFind(intrinsic, pl->cl)) { + AppendMatchingElement(interp, pl->cl->object.cmdName, pattern); + } + } } + + if (intrinsic) { + for (pl = intrinsic->nextPtr; pl; pl = pl->nextPtr) { + AppendMatchingElement(interp, pl->cl->object.cmdName, pattern); + } + } + + NsfClassListFree(mixinClasses); + NsfClassListFree(checkList); + return TCL_OK; } Index: tests/info-method.test =================================================================== diff -u -re02cb00ae815bd6f8561a6a03fceacc13fd91903 -r5016c5d2fee323133f57ad401f1aa4f9d927cd2a --- tests/info-method.test (.../info-method.test) (revision e02cb00ae815bd6f8561a6a03fceacc13fd91903) +++ tests/info-method.test (.../info-method.test) (revision 5016c5d2fee323133f57ad401f1aa4f9d927cd2a) @@ -408,4 +408,39 @@ ? {::nx::Object info method parametersyntax ::nx::next} "?arguments?" ? {::nx::Object info method parametersyntax ::nsf::xotclnext} "?--noArgs? ?arg ...?" +} + +nx::Test case info-heritage { + Class create A + Class create B -superclass A + Class create M1 + Class create M2 -superclass A + Class create M3 + + ? {A info heritage} "::nx::Object" + ? {B info heritage} "::A ::nx::Object" + ? {M1 info heritage} "::nx::Object" + ? {M2 info heritage} "::A ::nx::Object" + + B mixin add M1 + + ? {A info heritage} "::nx::Object" + ? {B info heritage} "::M1 ::A ::nx::Object" + + B mixin M2 + ? {A info heritage} "::nx::Object" + ? {B info heritage} "::M2 ::A ::nx::Object" + + B mixin A + ? {A info heritage} "::nx::Object" + ? {B info heritage} "::A ::nx::Object" + + M3 mixin B + ? {B info heritage} "::A ::nx::Object" + + A mixin M3 + ? {A info heritage} "::M3 ::B ::M3 ::nx::Object" + + B mixin M3 + ? {B info heritage} "::M3 ::M3 ::M3 ::M3 ::M3 ::M3 ::A ::nx::Object" } \ No newline at end of file Index: tests/mixinof.test =================================================================== diff -u -re02cb00ae815bd6f8561a6a03fceacc13fd91903 -r5016c5d2fee323133f57ad401f1aa4f9d927cd2a --- tests/mixinof.test (.../mixinof.test) (revision e02cb00ae815bd6f8561a6a03fceacc13fd91903) +++ tests/mixinof.test (.../mixinof.test) (revision 5016c5d2fee323133f57ad401f1aa4f9d927cd2a) @@ -281,71 +281,74 @@ ########################################### # testing simple per class mixins with redefinition ########################################### -Test case pcm-redefine -Class create A -Class create B -mixin A -Class create C -superclass B -C create c1 +Test case pcm-redefine { + Class create A + Class create B -mixin A + Class create C -superclass B + C create c1 + + ? {B mixin} ::A + ? {B info mixin classes} ::A + ? {A info mixinof -scope class} ::B + ? {c1 info precedence} "::A ::C ::B ::nx::Object" + ? {B info superclass -closure} "::nx::Object" + ? {C info superclass -closure} "::B ::nx::Object" + ? {B info heritage} "::A ::nx::Object" + ? {C info heritage} "::A ::B ::nx::Object" + + Class create B -mixin A + + ? {B info superclass -closure} "::nx::Object" + ? {C info superclass -closure} "::nx::Object" + ? {B info heritage} "::A ::nx::Object" + ? {C info heritage} "::nx::Object" + ? {B mixin} ::A + ? {B info mixin classes} ::A + ? {A info mixinof} ::B + ? {c1 info precedence} "::C ::nx::Object" + + B destroy + ? {A info mixinof} "" + ? {c1 info precedence} "::C ::nx::Object" +} -? {B mixin} ::A -? {B info mixin classes} ::A -? {A info mixinof -scope class} ::B -? {c1 info precedence} "::A ::C ::B ::nx::Object" -? {B info heritage} "::nx::Object" -? {C info heritage} "::B ::nx::Object" -Class create B -mixin A - -? {B info heritage} "::nx::Object" -? {C info heritage} "::nx::Object" -? {B mixin} ::A -? {B info mixin classes} ::A -? {A info mixinof} ::B -? {c1 info precedence} "::C ::nx::Object" - -B destroy -? {A info mixinof} "" -? {c1 info precedence} "::C ::nx::Object" - -A destroy -C destroy -c1 destroy - - ########################################### # testing simple per class mixins with # redefinition and softrecreate ########################################### -Test case pcm-redefine-soft -::nsf::configure softrecreate true -Class create A -Class create B -mixin A -Class create C -superclass B -C create c1 +Test case pcm-redefine-soft { + ::nsf::configure softrecreate true + Class create A + Class create B -mixin A + Class create C -superclass B + C create c1 + + ? {B mixin} ::A + ? {B info mixin classes} ::A + ? {A info mixinof -scope class} ::B + ? {c1 info precedence} "::A ::C ::B ::nx::Object" + ? {B info superclass -closure} "::nx::Object" + ? {C info superclass -closure} "::B ::nx::Object" + ? {B info heritage} "::A ::nx::Object" + ? {C info heritage} "::A ::B ::nx::Object" + + Class create B -mixin A -? {B mixin} ::A -? {B info mixin classes} ::A -? {A info mixinof -scope class} ::B -? {c1 info precedence} "::A ::C ::B ::nx::Object" -? {C info heritage} "::B ::nx::Object" -? {B info heritage} "::nx::Object" + ? {B info superclass -closure} "::nx::Object" + ? {C info superclass -closure} "::B ::nx::Object" + ? {B info heritage} "::A ::nx::Object" + ? {C info heritage} "::A ::B ::nx::Object" + ? {B info mixin classes} ::A + ? {A info mixinof -scope class} ::B + ? {c1 info precedence} "::A ::C ::B ::nx::Object" + + B destroy + ? {A info mixinof -scope class} "" + ? {c1 info precedence} "::C ::nx::Object" -Class create B -mixin A -? {C info heritage} "::B ::nx::Object" -? {B info heritage} "::nx::Object" -? {B info mixin classes} ::A -? {A info mixinof -scope class} ::B -? {c1 info precedence} "::A ::C ::B ::nx::Object" +} -B destroy -? {A info mixinof -scope class} "" -? {c1 info precedence} "::C ::nx::Object" - -A destroy -C destroy -c1 destroy - - ########################################### # test of recreate with same superclass, # with softrecreate off