| #charset "us-ascii" | |
| /* | |
| * Copyright (c) 2008 by Kevin Forchione. All rights reserved. | |
| * | |
| * This file is part of the TADS 3 Absolute Source Text Order | |
| * | |
| * asto.t | |
| * | |
| * Version 2.0 | |
| * | |
| * Adds the property absSourceTextOrder to each non-class object, and sets | |
| * the property to an integer giving the "absolute" order of the object | |
| * definition in the program source. | |
| * | |
| * This property is useful because it lets you reliably determine the | |
| * order of objects in the program source. | |
| * | |
| * In addition, this module provides object statistics with | |
| * the AstoSequencer.display() method. | |
| * | |
| * The module also includes a function, forEachAsto() that will loop | |
| * over all objects defining an absolute source text order. The parameters | |
| * are similar to the forEachInstance() function provided by _main.t. | |
| * | |
| * THIS MODULE REQUIRES THAT YOU COMPILE EACH APPLICABLE MODULE | |
| * WITH THE | |
| * | |
| * #pragma sourceTextGroup(on) | |
| * | |
| * OR COMPILE WITH THE "-Gstg" OPTION. | |
| */ | |
| #include <tads.h> | |
| #pragma sourceTextGroup(off) | |
| /* | |
| */ | |
| AstoSequencer: PreinitObject | |
| { | |
| objCount = 0 | |
| classCount = 0 | |
| modsCount = 0 | |
| astoCount = 0 | |
| noStgCount = 0 | |
| stgLu = static (new LookupTable()) | |
| baseStoLu = static (new LookupTable()) | |
| astoVec = static (new Vector(10)) | |
| display() | |
| { | |
| local sortedKeys; | |
| "\b@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ "; | |
| "\b"; | |
| "\nObject Sequence Analysis: "; | |
| "\b\t- Total: <<objCount>> "; | |
| "\b\t- Non-sequenced objects: <<noStgCount>> "; | |
| "\n\t\t- classes: <<classCount>> "; | |
| "\n\t\t- objects: <<noStgCount - classCount>> "; | |
| "\b\t- Sequenced definitions: <<astoCount>> "; | |
| "\n\t\t- internals: <<modsCount>> "; | |
| "\n\t\t- objects: <<astoCount - modsCount>> "; | |
| "\bSource Text Group Definitions "; | |
| sortedKeys = stgLu.keysToList().sort(nil, new function(k1, k2) | |
| { | |
| if (k1[2] < k2[2]) | |
| return -1; | |
| else if (k1[2] > k2[2]) | |
| return 1; | |
| else return 0; | |
| }); | |
| "(<<sortedKeys.length()>> groups): "; | |
| foreach (local key in sortedKeys) | |
| { | |
| "\n\tGroup <<key[2]>> (<<key[1]>>):\t<<stgLu[key]>> "; | |
| } | |
| "\bObject Seequence: "; | |
| forEachAsto(Object, nil, new function(o) | |
| { | |
| "\n\t<<o.absSourceTextOrder>> | |
| \t\t<<o.sourceTextGroupName>>: | |
| <<o.sourceTextSymName>> "; | |
| }); | |
| "\b@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ "; | |
| "\b"; | |
| } | |
| execute() | |
| { | |
| local key, value, prev, symLu, strLu, sortedKeys, symName; | |
| /* | |
| * Buld Global Symbol and String Lookups for sourceTextSymName | |
| */ | |
| symLu = t3GetGlobalSymbols(); | |
| strLu = new LookupTable(); | |
| symLu.forEachAssoc(new function(key, value) | |
| { | |
| strLu[value] = key; | |
| }); | |
| /* | |
| * Loop over all Object instances and classes | |
| */ | |
| for (local o = firstObj(Object, ObjAll); o != nil; o = nextObj(o, Object, ObjAll)) | |
| { | |
| /* | |
| * Count all objects | |
| */ | |
| objCount++; | |
| /* | |
| * If the object doesn't define sourceTExtGroup then | |
| * count it and continue looping. | |
| */ | |
| if (o.propDefined(&sourceTextGroup, PropDefDirectly) == nil) | |
| { | |
| noStgCount++; | |
| /* | |
| * If the object is a class, count it and continue looping | |
| */ | |
| if (o.isClass()) | |
| { | |
| classCount++; | |
| } | |
| continue; | |
| } | |
| /* | |
| * If the object is a modification count it | |
| */ | |
| if (o.isClass()) | |
| { | |
| modsCount++; | |
| } | |
| astoVec.append(o); | |
| /* | |
| * Count this object as an "absolute" source text order object | |
| */ | |
| astoCount++; | |
| /* | |
| * Build key for source text group and base source text order | |
| * lookup tables. | |
| */ | |
| key = [o.sourceTextGroup.sourceTextGroupName, | |
| o.sourceTextGroup.sourceTextGroupOrder]; | |
| /* | |
| * Retrieve the value from the source text group lookup | |
| * for this key. | |
| */ | |
| value = stgLu[key]; | |
| /* | |
| * If we have a value, compare it with the value | |
| * of the object's source text order. If the object | |
| * has a greater value then store it in the table. | |
| */ | |
| if (value) | |
| { | |
| if (o.sourceTextOrder > value) | |
| stgLu[key] = o.sourceTextOrder; | |
| } | |
| /* | |
| * Store the object's source text order in the lookup. | |
| */ | |
| else stgLu[key] = o.sourceTextOrder; | |
| } | |
| /* | |
| * Sort the source text group lookup keys | |
| */ | |
| sortedKeys = stgLu.keysToList.sort(nil, new function(k1, k2) | |
| { | |
| if (k1[2] < k2[2]) | |
| return -1; | |
| else if (k1[2] > k2[2]) | |
| return 1; | |
| else return 0; | |
| }); | |
| /* | |
| * Build the base Source Text Order Lookup. | |
| */ | |
| prev = 0; | |
| foreach (local key in sortedKeys) | |
| { | |
| value = stgLu[key]; | |
| baseStoLu[key] = prev; | |
| prev += value; | |
| } | |
| /* | |
| * Loop over each object again and set its "absolute" | |
| * source text order (if appropriate). | |
| */ | |
| for (local o = firstObj(Object, ObjAll); o != nil; o = nextObj(o, Object, ObjAll)) | |
| { | |
| if (o.propDefined(&sourceTextGroup, PropDefDirectly)) | |
| { | |
| key = [o.sourceTextGroup.sourceTextGroupName, | |
| o.sourceTextGroup.sourceTextGroupOrder]; | |
| value = baseStoLu[key]; | |
| value += o.sourceTextOrder; | |
| o.absSourceTextOrder = value; | |
| /* | |
| * Set the object's source text group order from | |
| * its source text group object. | |
| */ | |
| setSourceTextGroupOrder(o, o.sourceTextGroup.sourceTextGroupOrder); | |
| /* | |
| * Set the object's source text group name from | |
| * its source text group object. | |
| */ | |
| setSourceTextGroupName(o, o.sourceTextGroup.sourceTextGroupName); | |
| /* | |
| * Set the object's source text sym name from | |
| * the symbol and string lookup table. | |
| */ | |
| symName = strLu[o]; | |
| if (symName == nil) | |
| { | |
| local scList; | |
| symName = '* '; | |
| scList = o.getSuperclassList(); | |
| for (local index = 1; index <= scList.length(); ++index) | |
| { | |
| symName += strLu[scList[index]]; | |
| if (index < scList.length()) | |
| symName += ', '; | |
| } | |
| symName += ' *'; | |
| } | |
| else if (toInteger(symName)) | |
| { | |
| local sc, cName; | |
| cName = symName; | |
| __modsLoop: | |
| while(toInteger(cName)) | |
| { | |
| for (local c = firstObj(Object, ObjAll); c != nil; c = nextObj(c, Object, ObjAll)) | |
| { | |
| if (c.getSuperclassList().car() == o) | |
| { | |
| cName = strLu[c]; | |
| break __modsLoop; | |
| } | |
| } | |
| } | |
| symName += ( ' (' + cName + ')'); | |
| } | |
| setSourceTextSymName(o, symName); | |
| /* | |
| * Clear the object's source text group. | |
| */ | |
| clearSourceTextGroup(o); | |
| } | |
| } | |
| astoVec.sort(nil, new function(a, b) | |
| { | |
| if (a.absSourceTextOrder < b.absSourceTextOrder) | |
| return -1; | |
| else if (a.absSourceTextOrder > b.absSourceTextOrder) | |
| return 1; | |
| else return 0; | |
| }); | |
| } | |
| setSourceTextGroupOrder(obj, value) { obj.sourceTextGroupOrder = value; } | |
| setSourceTextGroupName(obj, value) { obj.sourceTextGroupName = value; } | |
| setSourceTextSymName(obj, value) { obj.sourceTextSymName = value; } | |
| clearSourceTextGroup(obj) { obj.sourceTextGroup = nil; } | |
| } | |
| /* ------------------------------------------------------------------------ */ | |
| /* | |
| * For convenience, a simple object iterator function. This function | |
| * invokes a callback function for each instance of the given class | |
| * having an "absolute" source text order. The order of iteration is | |
| * either in descending or ascending order of "absolute" source text order. | |
| * | |
| * The callback is invoked with one argument, which gives the current | |
| * instance. The callback can "break" out of the loop by throwing a | |
| * BreakLoopSignal, which can be done conveniently using the breakLoop | |
| * macro. | |
| */ | |
| forEachAsto(cls, desc, func) | |
| { | |
| local vector = new Vector(AstoSequencer.astoCount); | |
| try | |
| { | |
| vector = AstoSequencer.astoVec.subset(new function(obj) | |
| { | |
| return obj.ofKind(cls) || obj == cls; | |
| }); | |
| vector.sort(desc, new function(a, b) | |
| { | |
| if (a.absSourceTextOrder < b.absSourceTextOrder) | |
| return -1; | |
| else | |
| if (a.absSourceTextOrder > b.absSourceTextOrder) | |
| return 1; | |
| else return 0; | |
| }); | |
| vector.forEach(func); | |
| } | |
| catch (BreakLoopSignal sig) | |
| { | |
| /* | |
| * ignore the signal - it simply means we want to terminate the | |
| * loop and return to the caller | |
| */ | |
| } | |
| } | |
| /* ------------------------------------------------------------------------ */ | |
| /* | |
| * For convenience, a simple object iterator function. This function | |
| * invokes a callback function for each instance of the given class | |
| * having a source text group and source text order property. The | |
| * order of iteration is determined by the sort order of both properties. | |
| * | |
| * The callback is invoked with one argument, which gives the current | |
| * instance. The callback can "break" out of the loop by throwing a | |
| * BreakLoopSignal, which can be done conveniently using the breakLoop | |
| * macro. | |
| */ | |
| forEachStgSto(cls, stgOrder, stoOrder, func) | |
| { | |
| local vector, stgLu, stgo, sortedKeys, sortedList; | |
| try | |
| { | |
| stgLu = new LookupTable(); | |
| vector = AstoSequencer.astoVec.subset(new function(obj) | |
| { | |
| return obj.ofKind(cls) || obj == cls; | |
| }); | |
| /* loop over all asto of the given class */ | |
| foreach (local obj in vector.toList()) | |
| { | |
| if (obj.propDefined(&absSourceTextOrder, PropDefDirectly)) | |
| { | |
| stgo = obj.sourceTextGroupOrder; | |
| if (stgLu.isKeyPresent(obj.sourceTextGroupOrder)) | |
| stgLu[stgo] = (stgLu[stgo] + obj); | |
| else | |
| stgLu[stgo] = ([] + obj); | |
| } | |
| } | |
| sortedKeys = stgLu.keysToList().sort(stgOrder); | |
| foreach (local key in sortedKeys) | |
| { | |
| sortedList = stgLu[key].sort(stoOrder, new function(a, b) | |
| { | |
| if (a.sourceTextOrder < b.sourceTextOrder) | |
| return -1; | |
| else if (a.sourceTextOrder > b.sourceTextOrder) | |
| return 1; | |
| else return 0; | |
| }); | |
| foreach (local obj in sortedList) | |
| func(obj); | |
| } | |
| } | |
| catch (BreakLoopSignal sig) | |
| { | |
| /* | |
| * ignore the signal - it simply means we want to terminate the | |
| * loop and return to the caller | |
| */ | |
| } | |
| } |
Xet Storage Details
- Size:
- 12.4 kB
- Xet hash:
- f71faf8394dea22105123fd6ceb883aba30732f249b5a6b5b03fd0a0548ae642
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.