JSDOC/Scope.js
[app.jsdoc] / JSDOC / Scope.js
1 //<Script type="text/javascript">
2
3
4 Identifier = imports.Identifier.Identifier
5 XObject = imports.XObject.XObject; 
6
7
8 /**
9 * Scope stuff
10 * @scope JSDOC
11 * @class Scope;
12 * // FIXME - I need this to do next() without doccomments..
13 */
14
15
16 function Scope(braceN, parent, startTokN, lastIdent, token)
17 {
18     if (lastIdent.length) {
19        //  println("NEW SCOPE: " + lastIdent);
20     }
21     
22     this.braceN = braceN
23     this.parent = parent;
24     this.id = startTokN;
25     this.identifiers = { };
26     this.subScopes = [];
27     this.hints = { };
28     this.ident = lastIdent;
29     this.gid = Scope.gid++;
30     this.token = token;
31     //print("ADD SCOPE(" + this.gid + ") TO "+ (parent ? this.parent.gid : 'TOP') + ' : ' + 
32     //    (token ? token.toString() : ''));
33     
34     if (parent) {
35         this.parent.subScopes.push(this);
36     } 
37     
38 }
39
40
41
42
43
44
45
46 Scope.prototype = {
47     
48     id : 0,
49     braceN : -1,
50     parent : false,
51     subScopes : false,
52     identifiers : false,  // map of identifiers to {Identifier} objects
53     hints: false, 
54     mungeM : true, 
55     ident: '',
56     
57     munged : false,
58     protectedVars : {}, // only used by to parent..
59     
60     /**
61      * dump the scope to StdOut...
62      * 
63      */
64     dump : function(indent) 
65     {
66         indent = indent || '';
67         print(
68             indent +  "Scope: " + this.id + "\n" +
69             indent + "Started: " + ( this.token ? this.token.line  : 'TOP' ) + "\n" +
70             indent + "- " + XObject.keys(this.identifiers).join(", ") + "\n"
71         );
72         this.subScopes.forEach(function(s) {
73             s.dump(indent + ' ');
74         });
75         
76         
77     },
78     
79     
80     declareIdentifier : function(symbol, token) 
81     {
82         
83         //print("SCOPE : " + this.gid +  " :SYM: " + symbol + " " + token.toString()+"");
84         
85         if (typeof(this.identifiers[symbol])== 'undefined') {
86             
87             this.identifiers[symbol] =  new Identifier(symbol, this);
88             
89         }
90         if (typeof(token) != 'undefined') { // shoudl this happen?
91             token.identifier = this.identifiers[symbol];
92             
93         }
94         if (this.braceN < 0) {
95                 // then it's global... 
96                 this.identifiers[symbol].toMunge  = false;
97         }
98          
99         
100         this.addToParentScope(symbol);
101         return this.identifiers[symbol];
102     },
103     getIdentifier : function(symbol, token) {
104         if (typeof(this.identifiers[symbol])== 'undefined') {
105             if (['String', 'Date'].indexOf(symbol)> -1) {
106                 return false;
107             }
108             
109             //print("SCOPE : " + this.gid +" = SYMBOL NOT FOUND?" + token.toString());
110             return false;
111         }
112          //print("SCOPE : " + this.gid +" = FOUND:" + token.toString());
113         return this.identifiers[symbol];
114     },
115     
116     addHint : function(varName, varType) {
117         this.hint[varName] = varType;
118     },
119     preventMunging : function() {
120         this.mungeM = false;
121     },
122
123     usedsymcache : false,
124     
125     getUsedSymbols : function() {
126         
127         var result = [];
128        // if (this.usedsymcache !== false) {
129         //    return this.usedsymcache;
130         //}
131         
132         var idents = this.identifiers;
133         for(var i in idents) { 
134             //println('<b>'+i+'</b>='+typeof(idents[i]) +'<br/>');
135             var identifier = this.identifiers[i];
136             var mungedValue = identifier.mungedValue
137             if (!mungedValue.length) {
138                 //println(identifier.toSource());
139                 mungedValue = identifier.name;
140             }
141             result.push(mungedValue);
142         }
143         //println("Symbols for ("+ this.id +"): <B>" + result.join(',') + "</B><BR/>");
144         //this.usedsymcache = result;
145         return result;
146     },
147
148     getAllUsedSymbols :function() {
149         var result = this.getUsedSymbols();
150         var scope = this.parent;
151         while (scope !== false) {
152             //println("addused:"+scope.id);
153             result = result.concat(scope.getUsedSymbols());
154             scope = scope.parent;
155         }
156          //println("Done - addused");
157         return result;
158     },
159     /** - we need to register short vairalbes so they never get munged into.. */
160     addToParentScope: function(ident) 
161     {
162         if (ident.length > 2) {
163             return;
164         }
165         var scope = this.parent;
166         while (scope !== false) {
167             //println("addused:"+scope.id);
168             if (!scope.parent) {
169                 scope.protectedVars[ident] = true;
170             }
171             scope = scope.parent;
172         }
173         
174     },
175     isProtectedVar: function(ident)
176     {
177         if (ident.length > 2) {
178             return false;
179         }
180         var scope = this.parent;
181         while (scope !== false) {
182             //println("addused:"+scope.id);
183             if (!scope.parent) {
184                 if (typeof(scope.protectedVars[ident])  != 'undefined') return true;
185             }
186             scope = scope.parent;
187         }
188         return false;
189     },
190     
191     /**
192      * set's all the munged values on the identifiers.
193      * 
194      * 
195      */
196
197     munge :function() 
198     {
199
200         if (!this.mungeM) {
201             // Stop right here if this scope was flagged as unsafe for munging.
202            // println("MUNGE: SKIP -  Scope" + this.id+"</BR>");
203             return;
204         }
205         if (this.munged) {
206             return;
207         }
208         
209
210         
211         
212         var pickFromSet = 1;
213
214         // Do not munge symbols in the global scope!
215         if (this.parent) {
216             
217             var all = [];
218             for (var ii in this.identifiers) {
219                 all.push(ii);
220             }
221             //print("MUNGE: " + all.join(', '));
222             
223             //println("MUNGE: Building FreeSyms:" + this.id+"</BR>");
224             
225             var freeSymbols = [];
226             var sy = this.getAllUsedSymbols();
227             
228             var addSyms=function(batch)
229             {
230                 for(var i =0;i<batch.length;i++) {
231                     if (sy.indexOf(batch[i]) > -1) {
232                         continue;
233                     }
234                     freeSymbols.push(batch[i]);
235                 }
236             }
237              
238             addSyms(Scope.ones); 
239              
240             var repsym = '';
241             //println(freeSymbols.toSource());
242             
243             //println("MUNGE: Replacing " + this.id+"</BR>");
244             for (var i in  this.identifiers) {
245                 
246                 // is the identifer in the global scope!?!!?
247                 
248                 
249                 if (!this.identifiers[i].toMunge) {
250                     //print("SKIP toMunge==false : " + i)
251                     continue;
252                 }
253                 
254                 if (this.isProtectedVar(i)) {
255                     //print("SKIP PROTECTED: " + i)
256                     continue; // 
257                 }
258                 
259                 
260                 
261                 //if (this.identifiers[i].constructor !=  Identifier) {
262                 //    print("SKIP NOT IDENTIFIER : " + i)
263                 //    continue;
264                // }
265                // println("IDENT:" +i+'</BR>');
266                 
267                 if (!repsym.length) {
268                     if (!freeSymbols.length) {
269                         addSyms(Scope.twos); 
270                     }
271                     repsym = freeSymbols.shift(); // pop off beginngin???
272                 }
273                 
274                 var identifier = this.identifiers[i]; 
275                 //println(typeof(identifier.name));
276                 var mungedValue = identifier.name; 
277                 
278                 //println([     repsym,mungedValue ]);
279                 
280                 if (this.mungeM && repsym.length < mungedValue.length) {
281                     //print("REPLACE:"+ mungedValue +" with " + repsym );    
282                     mungedValue = repsym;
283                     repsym = '';
284                 }
285                 
286                 identifier.mungedValue =  mungedValue;
287             }
288             //println("MUNGE: Done " + this.id+"</BR>");
289         }
290         this.munged = true;
291         //println("Doing sub scopes");
292         for (var j = 0; j < this.subScopes.length; j++) {
293             var ss = this.subScopes[j];
294             ss.munge();
295         }
296     }
297  
298
299 };
300
301
302
303
304
305 XObject.extend(Scope, {
306     
307     builtin : ["NaN","top"],
308     skips : [  'as', 'is', 'do', 'if', 'in', 'for', 'int', 'new', 'try', 'use', 'var', "NaN","top"],
309      
310     ones : [],
311     twos : [],
312     threes : [],
313     init : function () {
314         /* cache it later?
315         if (File.exists('/tmp/var_list_ones.js')) {
316             eval("JSDOC.Scope.ones = " + File.read('/tmp/var_list_ones.js'));
317             eval("JSDOC.Scope.twos = " + File.read('/tmp/var_twos_ones.js'));
318             eval("JSDOC.Scope.threes = " + File.read('/tmp/var_threes_ones.js'));
319         }
320         */
321         this.ones = 'A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z'.split(',');
322         var a = this.ones;
323         var n = a.concat( '0,1,2,3,4,5,6,7,8,9'.split(','));
324         for(var i = 0; i < a.length; i++) {
325             for(var j = 0; j < n.length; j++) {
326                 var tw = a[i] + n[j];
327                 if (this.skips.indexOf(tw) < 0) {
328                     this.twos.push(tw);
329                 }
330                     
331                 /*
332                 for(var k = 0; k < n.length; k++) {
333                     var thr = a[i] + n[j] + n[k];
334                     //println("thr="+ thr + ":iOf="+this.skips.indexOf(thr) );
335                     if (this.skips.indexOf(thr)  < 0) {
336                         //println("+"+thr);
337                         this.threes.push(thr);
338                        }
339                     
340                 }
341                 */
342             }
343         }
344         //println("done creating var list");
345         //println("threes="+ this.threes.toSource());
346         //throw "DONE";
347         
348        
349     }
350 })
351 // init the scope constants..
352 Scope.init();
353 Scope.gid = 0;