1 //<Script type="text/javascript">
2 XObject = imports.XObject.XObject;
4 Scope = imports.Scope.Scope;
5 DocComment = imports.DocComment.DocComment;
6 Symbol = imports.Symbol.Symbol;
7 Parser = imports.Parser.Parser;
12 * // FIXME - I need this to do next() without doccomments..
15 Walker2 = XObject.define(
20 this.indexedScopes = {};
22 //this.timer = new Date() * 1;
30 timerPrint: function (str) {
31 var ntime = new Date() * 1;
32 var tdif = ntime -this.timer;
35 if (tdif > 100) { //slower ones..
38 print(pref+'['+tdif+']'+str);
43 //this.warnings.push(s);
44 print("WARNING:" + htmlescape(s) + "<BR>");
46 // defaults should not be initialized here =- otherwise they get duped on new, rather than initalized..
51 mode : "", //"BUILDING_SYMBOL_TREE",
53 indexedScopes : false,
55 symbols: false, /// object store of sumbols..
60 buildSymbolTree : function()
65 this.braceNesting = 0;
69 this.globalScope = new Scope(-1, false, -1, '$global$');
70 indexedScopes = { 0 : this.globalScope };
72 this.mode = 'BUILDING_SYMBOL_TREE';
73 this.parseScope(this.globalScope);
80 //print("<B>LOG:</B>" + htmlescape(str) + "<BR/>\n");
84 //print("<B>LOG:</B>" + str + "<BR/>");
91 parseScope : function(scope, ealiases) // parse a token stream..
93 //this.timerPrint("parseScope EnterScope");
96 var fixAlias = function(str, nomore)
98 var ar = str.split('.');
101 //print(str +"?=" +aliases.toSource());
102 if (aliases[m] == undefined) {
105 var ret = aliases[m] + (ar.length? '.' : '' )+ ar.join('.');
106 if (nomore !== true) {
107 ret = fixAlias(ret, true);
117 if (ealiases != undefined) {
119 for(var i in ealiases) {
120 aliases[i] = ealiases[i];
127 //print("STARTING SCOPE WITH: " + ealiases.toSource());
133 var expressionBraceNesting = this.braceNesting;
134 var bracketNesting = 0;
135 var parensNesting = 0;
138 var l1 = '', l2 = '';
142 var locBraceNest = 0;
143 // determines if we are in object literals...
145 var isObjectLitAr = [ false ];
146 //print("SCOPE: ------------------START ----------------");
147 this.scopesIn(scope);
148 var scopeLen = this.scopes.length;
150 if (this.ts.cursor < 1) {
151 // this.ts.cursor--; // hopeflly this kludge will work
155 //print(JSON.stringify(this.ts, null, 4)); Seed.quit();
157 while (null != (token = this.ts.next())) {
158 print("TOK"+ token.toString());
159 // this.timerPrint("parseScope AFTER lookT: " + token.toString());
161 if (token.is('WHIT')) {
164 if (token.name != 'JSDOC') {
167 if (this.currentDoc) {
168 // add it to the current scope????
170 this.addSymbol('', true);
172 //throw "Unconsumed Doc (TOKwhitespace): " + this.currentDoc.toSource();
176 var newDoc = new DocComment(token.data);
178 // it's a scope changer..
179 if (newDoc.getTag("scope").length) {
180 //print(newDoc.getTag("scope").toSource());
182 scope.ident = '$private$|' + newDoc.getTag("scope")[0].desc;
186 // it's a scope changer..
187 if (newDoc.getTag("scopeAlias").length) {
188 //print(newDoc.getTag("scopeAlias").toSource());
190 var sal = newDoc.getTag("scopeAlias")[0].desc.split("=");
191 aliases[sal[0]] = sal[1];
197 /// got a doc comment..
198 //token.data might be this.??? (not sure though)
199 this.currentDoc = newDoc;
203 // catch the various issues .. - scoe changes or doc actions..
207 // things that stop comments carrying on...??
209 if (this.currentDoc && (
210 token.tokN.data == ';' ||
211 token.tokN.data == '}')) {
212 this.addSymbol('', true);
213 //throw "Unconsumed Doc ("+ token.toString() +"): " + this.currentDoc.toSource();
217 // the rest are scoping issues...
221 if (token.name == 'VAR' &&
223 this.ts.lookTok(1).type == 'NAME' &&
224 this.ts.lookTok(2).data == '-' &&
225 this.ts.lookTok(3).type == 'NAME' &&
226 this.ts.lookTok(4).data == ';'
230 //print("SET ALIAS:" + this.ts.lookTok(1).data +'=' + this.ts.lookTok(3).data);
232 aliases[this.ts.lookTok(1).data] = this.ts.lookTok(3).data;
239 // extends scoping *** not sure if the can be x = Roo.apply(....)
240 // xxx.extends(a,b, {
241 // $this$=b|b.prototype
246 if (token.type = 'NAME') {
248 //print("TOK(ident)"+ token.toString());
254 if (/\.extend$/.test(token.data) &&
255 this.ts.lookTok(1).data == '(' &&
256 this.ts.lookTok(2).type == 'NAME' &&
257 this.ts.lookTok(3).data == ',' &&
258 this.ts.lookTok(4).type == 'NAME' &&
259 this.ts.lookTok(5).data == ',' &&
260 this.ts.lookTok(6).data == '{'
263 // ignore test for ( a and ,
264 this.ts.nextTok(); /// (
265 token = this.ts.nextTok(); // a
266 scopeName = token.data;
268 if (this.currentDoc) {
269 this.addSymbol(scopeName,false,'OBJECT');
272 this.ts.nextTok(); // ,
273 this.ts.nextTok(); // b
276 this.ts.nextTok(); // ,
277 token = this.ts.nextTok(); // {
279 scopeName = fixAlias(scopeName);
281 var fnScope = new Scope(this.braceNesting, scope, token.n,
282 '$this$=' + scopeName + '|'+scopeName+'.prototype');
283 this.indexedScopes[this.ts.cursor] = fnScope;
285 this.scopesIn(fnScope);
288 //print(">>" +locBraceNest);
289 continue; // no more processing..
293 // a = Roo.extend(parentname, {
295 if (/\.extend$/.test(token.data) &&
296 this.ts.lookTok(-2).type == 'NAME' &&
297 this.ts.lookTok(-1).data == '=' &&
298 this.ts.lookTok(1).data == '(' &&
299 this.ts.lookTok(2).type == 'NAME' &&
300 this.ts.lookTok(3).data == ',' &&
301 this.ts.lookTok(4).data == '{'
303 // ignore test for ( a and ,
304 token = this.ts.lookTok(-2);
305 scopeName = token.data;
306 if (this.currentDoc) {
307 this.addSymbol(scopeName,false,'OBJECT');
310 this.ts.nextTok(); /// (
311 this.ts.nextTok(); // parent
313 this.ts.nextTok(); // ,
314 token = this.ts.nextTok(); // {
317 scopeName = fixAlias(scopeName);
318 var fnScope = new Scope(this.braceNesting, scope, token.n,
319 '$this$=' + scopeName + '|'+scopeName+'.prototype');
320 this.indexedScopes[this.ts.cursor] = fnScope;
322 this.scopesIn(fnScope);
325 //print(">>" +locBraceNest);
326 continue; // no more processing..
333 if (/\.(applyIf|apply)$/.test(token.data) &&
334 this.ts.lookTok(1).data == '(' &&
335 this.ts.lookTok(2).type == 'NAME' &&
336 this.ts.lookTok(3).data == ',' &&
337 this.ts.lookTok(4).data == '{'
340 this.ts.nextTok(); /// (
342 //print("GOT : applyIF!");
344 token = this.ts.nextTok(); // b
345 scopeName = token.data;
348 if (this.currentDoc) {
349 this.addSymbol(scopeName,false,'OBJECT');
355 this.ts.nextTok(); /// ,
356 this.ts.nextTok(); // {
357 scopeName = fixAlias(scopeName);
358 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
359 this.indexedScopes[this.ts.cursor] = fnScope;
361 this.scopesIn(fnScope);
364 //print(">>" +locBraceNest);
365 continue; // no more processing..
371 // change scope to xxxx
373 print(JSON.stringify([
374 this.ts.lookTok(1).data
375 this.ts.lookTok(2).name
376 this.ts.lookTok(3).type
377 this.ts.lookTok(4).data
378 this.ts.lookTok(5).data
381 if ( this.ts.lookTok(1).data == '=' &&
382 this.ts.lookTok(2).name == 'NEW' &&
383 this.ts.lookTok(3).type == 'NAME' &&
384 this.ts.lookTok(4).data == '(' &&
385 this.ts.lookTok(5).data == '{'
387 scopeName = token.data;
388 if (this.currentDoc) {
389 this.addSymbol(scopeName,false,'OBJECT');
393 this.ts.nextTok(); /// =
394 this.ts.nextTok(); /// new
395 this.ts.nextTok(); /// yyy
396 this.ts.nextTok(); /// (
397 this.ts.nextTok(); /// {
399 scopeName = fixAlias(scopeName);
400 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
401 this.indexedScopes[this.ts.cursor] = fnScope;
403 this.scopesIn(fnScope);
406 //print(">>" +locBraceNest);
408 continue; // no more processing..
429 // eval can be prefixed with a hint hider for the compresser..
430 if ((token.data == 'eval') || /\.eval$/.test(token.data)) {
431 this.currentDoc = false;
435 if (this.currentDoc) {
436 //print(token.toString());
438 // ident : function ()
439 // ident = function ()
440 var atype = 'OBJECT';
442 if (((this.ts.lookTok(1).data == ':' )|| (this.ts.lookTok(1).data == '=')) &&
443 (this.ts.lookTok(2).name == "FUNCTION")
448 //print("ADD SYM:" + atype + ":" + token.toString() + this.ts.lookTok(1).toString() + this.ts.lookTok(2).toString());
451 this.ts.lookTok(-1).tokN == Script.TOKdot ? token.data : fixAlias(token.data),
458 continue; // dont care about other idents..
461 if (token.type == "STRN") {
462 if (this.currentDoc) {
463 this.addSymbol(token.data.substring(1,token.data.length-1),false,'OBJECT');
468 // really we only have to deal with object constructs and function calls that change the scope...
471 if (token.name == 'FUNCTION') {
473 // see if we have an unconsumed doc...
475 if (this.currentDoc) {
476 print(this.ts.dumpToCur());
477 throw "Unhandled doc (TOKfunction)" + token.toString();
478 //this.addSymbol(this.currentDoc.getTag('class')[0].name, true);
480 //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
487 /// foo = function() {} << really it set's the 'this' scope to foo.prototype
488 //$this$=foo.prototype|$private$|foo.prototype
491 (this.ts.lookTok(-1).data == '=') &&
492 (this.ts.lookTok(-2).type == 'NAME')
494 scopeName = this.ts.lookTok(-2).data;
495 this.ts.balanceN('(');
496 token = this.ts.nextTok(); // should be {
497 //print("FOO=FUNCITON() {}" + this.ts.context() + "\n" + token.toString());
500 scopeName = fixAlias(scopeName);
501 var fnScope = new Scope(this.braceNesting, scope, token.n,
502 '$this$='+scopeName+'.prototype|$private$|'+scopeName+'.prototype');
503 this.indexedScopes[this.ts.cursor] = fnScope;
505 //this.scopesIn(fnScope);
506 this.parseScope(fnScope, aliases);
511 //print(">>" +locBraceNest);
512 continue; // no more processing..
518 // foo = new function() {}
519 // is this actually used much!?!?!
523 (this.ts.lookTok(-1).name == 'NEW') &&
524 (this.ts.lookTok(-2).data == '=') &&
525 (this.ts.lookTok(-3).type = 'FUNCTION')
527 //scopeName = this.ts.look(-3).data;
528 this.ts.balanceN(Script.TOKlparen);
529 token = this.ts.nextTok(); // should be {
530 scopeName = fixAlias(scopeName);
531 var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
532 this.indexedScopes[this.ts.cursor] = fnScope;
534 //this.scopesIn(fnScope);
535 this.parseScope(fnScope, aliases);
538 //print(">>" +locBraceNest);
539 continue; // no more processing..
545 ///==== check/set isObjectLitAr ??
548 // foo: function() {}
549 // no change to scoping..
551 //print("checking for : function() {");
552 //print( [this.ts.lookTok(-3).type , this.ts.lookTok(-2).type , this.ts.lookTok(-1).type ].join(":"));
554 (this.ts.lookTok(-1).data == ':') &&
555 (this.ts.lookTok(-2).type == 'NAME') &&
556 (this.ts.lookTok(-3).data == '(' || this.ts.lookTok(-3).data== ',')
558 //print("got for : function() {");
560 //scopeName = this.ts.look(-3).data;
561 this.ts.balanceN(Script.TOKlparen);
562 //print(token.toString())
563 token = this.ts.nextTok(); // should be {
564 //print(token.toString())
565 scopeName = fixAlias(scopeName);
566 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
567 this.indexedScopes[this.ts.cursor] = fnScope;
569 //this.scopesIn(fnScope);
570 this.parseScope(fnScope, aliases);
572 //print(">>" +locBraceNest);
573 continue; // no more processing..
576 /// function foo() {} << really it set's the 'this' scope to foo.prototype
577 //$this$=foo|$private$
581 (this.ts.lookTok(1).type == 'NAME')
583 //scopeName = this.ts.look(-3).data;
584 this.ts.balanceN('(');
585 token = this.ts.nextTok(); // should be {
587 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
588 this.indexedScopes[this.ts.cursor] = fnScope;
590 //this.scopesIn(fnScope);
591 this.parseScope(fnScope, aliases);
593 //print(">>" +locBraceNest);
594 continue; // no more processing..
599 // foo = new (function() { }
601 // RETURN function(...) {
604 // (this.ts.lookTok(-1).tokN == Script.TOKlparen) &&
605 (this.ts.lookTok(1).name != 'NAME')
607 // (this.ts.lookTok(-2).tokN == Script.TOKnew) &&
608 // (this.ts.lookTok(-3).tokN == Script.TOKassign) &&
609 // (this.ts.lookTok(-4).tokN == Script.TOKidentifier)
611 //scopeName = this.ts.look(-3).data;
612 this.ts.balanceN('(');
613 token = this.ts.nextTok(); // should be {
614 var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
615 this.indexedScopes[this.ts.cursor] = fnScope;
617 //this.scopesIn(fnScope);
618 this.parseScope(fnScope, aliases);
620 //print(">>" +locBraceNest);
621 continue; // no more processing..
627 print(this.ts.context());
628 throw "dont know how to handle function syntax??";
635 } // end checking for TOKfunction
637 if (token.data == '{') {
639 // foo = { // !var!!!
644 (this.ts.lookTok(-1).data == '=') &&
645 (this.ts.lookTok(-2).type == 'NAME') &&
646 (this.ts.lookTok(-3).nane != 'VAR')
649 scopeName = this.ts.look(-2).data;
650 scopeName = fixAlias(scopeName);
651 var fnScope = new Scope(this.braceNesting, scope, token.n,
652 '$this$='+scopeName + '|'+scopeName
654 this.indexedScopes[this.ts.cursor] = fnScope;
656 this.scopesIn(fnScope);
660 //print(">>" +locBraceNest);
661 continue; // no more processing..
666 //print("GOT LBRACE : check for :");
668 (this.ts.lookTok(-1).data == ':') &&
669 (this.ts.lookTok(-2).type == 'NAME') &&
670 (this.ts.lookTok(-3).name != 'VAR')
673 scopeName = this.ts.lookTok(-2).data;
674 scopeName = fixAlias(scopeName);
675 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
676 this.indexedScopes[this.ts.cursor] = fnScope;
678 this.scopesIn(fnScope);
681 //print(">>" +locBraceNest);
682 continue; // no more processing..
684 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
685 this.indexedScopes[this.ts.cursor] = fnScope;
687 this.scopesIn(fnScope);
690 //print(">>" +locBraceNest);
694 if (token.data == '{') {
697 if (this.currentDoc) {
698 this.addSymbol('', true);
700 //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
706 //assert braceNesting >= scope.getBraceNesting();
707 var closescope = this.scopeOut();
708 scope = this.scopes[this.scopes.length-1];
709 //print("<<:" + locBraceNest)
710 //print("<<<<<< " + locBraceNest );
711 if (locBraceNest < 0) {
712 // print("POPED OF END OF SCOPE!");
714 //var ls = this.scopeOut();
715 //ls.getUsedSymbols();
728 addSymbol: function(lastIdent, appendIt, atype )
731 /*if (!this.currentDoc.tags.length) {
734 //print(this.currentDoc.toSource());
735 // this.currentDoc = false;
737 print("SKIP ADD SYM: no tags");
738 print(this.currentDoc.src);
742 if (this.currentDoc.getTag('private').length) {
745 //print(this.currentDoc.toSource());
746 this.currentDoc = false;
747 print("SKIP ADD SYM: it's private");
751 var token = this.ts.cur();
752 if (typeof(appendIt) == 'undefined') {
755 // print(this.currentDoc.toSource(););
756 if (this.currentDoc.getTag('event').length) {
757 //?? why does it end up in desc - and not name/...
758 print(this.currentDoc.getTag('event')[0]);
759 lastIdent = '*' + this.currentDoc.getTag('event')[0].desc;
760 //lastIdent = '*' + lastIdent ;
762 if (!lastIdent.length && this.currentDoc.getTag('property').length) {
763 lastIdent = this.currentDoc.getTag('property')[0].name;
764 //lastIdent = '*' + lastIdent ;
768 if (!/\./.test(_s)) {
770 //print("WALKER ADDsymbol: " + lastIdent);
773 for (var i = 0; i < this.scopes.length;i++) {
774 s.push(this.scopes[i].ident);
778 var s = s.join('|').split('|');
779 print("Walker:ADDSymbol: " + s.join('|') );
784 for (var i = 0; i < s.length;i++) {
789 if ((s[i] == '$private$') || (s[i] == '$global$')) {
793 if (s[i].substring(0,6) == '$this$') {
794 var ts = s[i].split('=');
798 // when to use $this$ (probabl for events)
799 _s += _s.length ? '.' : '';
805 //print("ADDING SYMBOL: "+ s.join('|') +"\n"+ _s + "\n" +Script.prettyDump(this.currentDoc.toSource()));
807 if (appendIt && !lastIdent.length) {
809 // append, and no symbol???
811 // see if it's a @class
812 if (this.currentDoc.getTag('class').length) {
813 _s = this.currentDoc.getTag('class')[0].desc;
814 var symbol = new Symbol(_s, [], "CONSTRUCTOR", this.currentDoc);
815 Parser.addSymbol(symbol);
816 this.symbols[_s] = symbol;
820 // if (this.currentDoc.getTag('property').length) {
821 // print(Script.pretStringtyDump(this.currentDoc.toSource));
822 // throw "Add Prop?";
825 _s = _s.replace(/\.prototype.*$/, '');
826 if (typeof(this.symbols[_s]) == 'undefined') {
827 print("Symbol:" + _s);
828 print(this.currentDoc.src);
830 throw "Trying to append symbol, but no doc available";
833 for (var i =0; i < this.currentDoc.tags.length;i++) {
834 this.symbols[_s].addDocTag(this.currentDoc.tags[i]);
836 this.currentDoc = false;
840 if (typeof(this.symbols[_s]) != 'undefined') {
842 if (this.symbols[_s].comment.hasTags) {
843 // then existing comment doesnt has tags
844 throw "DUPLICATE Symbol " + _s;
846 // otherwise existing comment has tags - overwrite..
850 if (typeof(atype) == "undefined") {
851 atype = 'OBJECT'; //this.currentDoc.getTag('class').length ? 'OBJECT' : 'FUNCTION';;
854 var symbol = new Symbol(_s, [], atype, this.currentDoc);
856 Parser.addSymbol(symbol);
857 this.symbols[_s] = symbol;
859 this.currentDoc = false;
866 scopesIn : function(s)
869 //print(">>>" + this.ts.context() + "\n>>>"+this.scopes.length+":" +this.scopeListToStr());
872 scopeOut : function()
875 // print("<<<" + this.ts.context() + "\n<<<"+this.scopes.length+":" +this.scopeListToStr());
876 return this.scopes.pop();
880 scopeListToStr : function()
883 for (var i = 0; i < this.scopes.length;i++) {
884 s.push(this.scopes[i].ident);
886 return s.join('\n\t');