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
157 while (false != (token = this.ts.next())) {
158 //print("TOK"+ token.toString());
159 // this.timerPrint("parseScope AFTER lookT: " + token.toString());
161 if (token.tokN == Script.TOKwhitespace) {
167 if (this.currentDoc) {
168 // add it to the current scope????
170 this.addSymbol('', true);
173 //throw "Unconsumed Doc (TOKwhitespace): " + this.currentDoc.toSource();
177 var newDoc = new DocComment(token.data);
179 // it's a scope changer..
180 if (newDoc.getTag("scope").length) {
181 //print(newDoc.getTag("scope").toSource());
183 scope.ident = '$private$|' + newDoc.getTag("scope")[0].desc;
187 // it's a scope changer..
188 if (newDoc.getTag("scopeAlias").length) {
189 //print(newDoc.getTag("scopeAlias").toSource());
191 var sal = newDoc.getTag("scopeAlias")[0].desc.split("=");
192 aliases[sal[0]] = sal[1];
198 /// got a doc comment..
199 //token.data might be this.??? (not sure though)
200 this.currentDoc = newDoc;
204 // catch the various issues .. - scoe changes or doc actions..
208 // things that stop comments carrying on...??
210 if (this.currentDoc && (
211 token.tokN == Script.TOKsemicolon ||
212 token.tokN == Script.TOKrbrace)) {
213 this.addSymbol('', true);
214 //throw "Unconsumed Doc ("+ token.toString() +"): " + this.currentDoc.toSource();
218 // the rest are scoping issues...
222 if (token.tokN == Script.TOKvar &&
224 this.ts.lookT(1).tokN == Script.TOKidentifier &&
225 this.ts.lookT(2).tokN == Script.TOKassign &&
226 this.ts.lookT(3).tokN == Script.TOKidentifier &&
227 this.ts.lookT(4).tokN == Script.TOKsemicolon
231 //print("SET ALIAS:" + this.ts.lookT(1).data +'=' + this.ts.lookT(3).data);
233 aliases[this.ts.lookT(1).data] = this.ts.lookT(3).data;
240 // extends scoping *** not sure if the can be x = Roo.apply(....)
241 // xxx.extends(a,b, {
242 // $this$=b|b.prototype
247 if (token.tokN == Script.TOKidentifier) {
249 //print("TOK(ident)"+ token.toString());
255 if (/\.extend$/.test(token.data) &&
256 this.ts.lookT(1).tokN == Script.TOKlparen &&
257 this.ts.lookT(2).tokN == Script.TOKidentifier &&
258 this.ts.lookT(3).tokN == Script.TOKcomma &&
259 this.ts.lookT(4).tokN == Script.TOKidentifier &&
260 this.ts.lookT(5).tokN == Script.TOKcomma &&
261 this.ts.lookT(6).tokN == Script.TOKlbrace
263 // ignore test for ( a and ,
264 this.ts.nextT(); /// (
265 token = this.ts.nextT(); // a
266 scopeName = token.data;
268 if (this.currentDoc) {
269 this.addSymbol(scopeName,false,'OBJECT');
272 this.ts.nextT(); // ,
273 this.ts.nextT(); // b
276 this.ts.nextT(); // ,
277 token = this.ts.nextT(); // {
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.lookT(-2).tokN == Script.TOKidentifier &&
297 this.ts.lookT(-1).tokN == Script.TOKassign &&
298 this.ts.lookT(1).tokN == Script.TOKlparen &&
299 this.ts.lookT(2).tokN == Script.TOKidentifier &&
300 this.ts.lookT(3).tokN == Script.TOKcomma &&
301 this.ts.lookT(4).tokN == Script.TOKlbrace
303 // ignore test for ( a and ,
304 token = this.ts.lookT(-2);
305 scopeName = token.data;
306 if (this.currentDoc) {
307 this.addSymbol(scopeName,false,'OBJECT');
310 this.ts.nextT(); /// (
311 this.ts.nextT(); // parent
313 this.ts.nextT(); // ,
314 token = this.ts.nextT(); // {
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..
332 if (/\.(applyIf|apply)$/.test(token.data) &&
333 this.ts.lookT(1).tokN == Script.TOKlparen &&
334 this.ts.lookT(2).tokN == Script.TOKidentifier &&
335 this.ts.lookT(3).tokN == Script.TOKcomma &&
336 this.ts.lookT(4).tokN == Script.TOKlbrace
339 this.ts.nextT(); /// (
341 //print("GOT : applyIF!");
343 token = this.ts.nextT(); // b
344 scopeName = token.data;
347 if (this.currentDoc) {
348 this.addSymbol(scopeName,false,'OBJECT');
354 this.ts.nextT(); /// ,
355 this.ts.nextT(); // {
356 scopeName = fixAlias(scopeName);
357 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
358 this.indexedScopes[this.ts.cursor] = fnScope;
360 this.scopesIn(fnScope);
363 //print(">>" +locBraceNest);
364 continue; // no more processing..
370 // change scope to xxxx
372 if ( this.ts.lookT(1).tokN == Script.TOKassign &&
373 this.ts.lookT(2).tokN == Script.TOKnew &&
374 this.ts.lookT(3).tokN == Script.TOKidentifier &&
375 this.ts.lookT(4).tokN == Script.TOKlparen &&
376 this.ts.lookT(5).tokN == Script.TOKlbrace
378 scopeName = token.data;
379 if (this.currentDoc) {
380 this.addSymbol(scopeName,false,'OBJECT');
384 this.ts.nextT(); /// =
385 this.ts.nextT(); /// new
386 this.ts.nextT(); /// yyy
387 this.ts.nextT(); /// (
388 this.ts.nextT(); /// {
390 scopeName = fixAlias(scopeName);
391 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
392 this.indexedScopes[this.ts.cursor] = fnScope;
394 this.scopesIn(fnScope);
397 //print(">>" +locBraceNest);
399 continue; // no more processing..
420 // eval can be prefixed with a hint hider for the compresser..
421 if ((token.data == 'eval') || /\.eval$/.test(token.data)) {
422 this.currentDoc = false;
426 if (this.currentDoc) {
427 //print(token.toString());
429 // ident : function ()
430 // ident = function ()
431 var atype = 'OBJECT';
433 if (((this.ts.lookT(1).tokN == Script.TOKcolon )|| (this.ts.lookT(1).tokN == Script.TOKassign)) &&
434 (this.ts.lookT(2).tokN == Script.TOKfunction)
439 //print("ADD SYM:" + atype + ":" + token.toString() + this.ts.lookT(1).toString() + this.ts.lookT(2).toString());
442 this.ts.lookT(-1).tokN == Script.TOKdot ? token.data : fixAlias(token.data),
449 continue; // dont care about other idents..
452 if (token.tokN == Script.TOKstring) {
453 if (this.currentDoc) {
454 this.addSymbol(token.data.substring(1,token.data.length-1),false,'OBJECT');
459 // really we only have to deal with object constructs and function calls that change the scope...
462 if (token.tokN == Script.TOKfunction) {
464 // see if we have an unconsumed doc...
466 if (this.currentDoc) {
467 print(this.ts.dumpToCur());
468 throw "Unhandled doc (TOKfunction)" + token.toString();
469 //this.addSymbol(this.currentDoc.getTag('class')[0].name, true);
471 //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
478 /// foo = function() {} << really it set's the 'this' scope to foo.prototype
479 //$this$=foo.prototype|$private$|foo.prototype
482 (this.ts.lookT(-1).tokN == Script.TOKassign) &&
483 (this.ts.lookT(-2).tokN == Script.TOKidentifier)
485 scopeName = this.ts.lookT(-2).data;
486 this.ts.balanceN(Script.TOKlparen);
487 token = this.ts.nextT(); // should be {
488 //print("FOO=FUNCITON() {}" + this.ts.context() + "\n" + token.toString());
491 scopeName = fixAlias(scopeName);
492 var fnScope = new Scope(this.braceNesting, scope, token.n,
493 '$this$='+scopeName+'.prototype|$private$|'+scopeName+'.prototype');
494 this.indexedScopes[this.ts.cursor] = fnScope;
496 //this.scopesIn(fnScope);
497 this.parseScope(fnScope, aliases);
502 //print(">>" +locBraceNest);
503 continue; // no more processing..
509 // foo = new function() {}
510 // is this actually used much!?!?!
514 (this.ts.lookT(-1).tokN == Script.TOKnew) &&
515 (this.ts.lookT(-2).tokN == Script.TOKassign)
516 (this.ts.lookT(-3).tokN == Script.TOKidentifier)
518 //scopeName = this.ts.look(-3).data;
519 this.ts.balanceN(Script.TOKlparen);
520 token = this.ts.nextT(); // should be {
521 scopeName = fixAlias(scopeName);
522 var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
523 this.indexedScopes[this.ts.cursor] = fnScope;
525 //this.scopesIn(fnScope);
526 this.parseScope(fnScope, aliases);
529 //print(">>" +locBraceNest);
530 continue; // no more processing..
536 ///==== check/set isObjectLitAr ??
539 // foo: function() {}
540 // no change to scoping..
542 //print("checking for : function() {");
543 //print( [this.ts.lookT(-3).type , this.ts.lookT(-2).type , this.ts.lookT(-1).type ].join(":"));
545 (this.ts.lookT(-1).tokN == Script.TOKcolon) &&
546 (this.ts.lookT(-2).tokN == Script.TOKidentifier) &&
547 (this.ts.lookT(-3).tokN == Script.TOKlbrace || this.ts.lookT(-3).tokN == Script.TOKcomma)
549 //print("got for : function() {");
551 //scopeName = this.ts.look(-3).data;
552 this.ts.balanceN(Script.TOKlparen);
553 //print(token.toString())
554 token = this.ts.nextT(); // should be {
555 //print(token.toString())
556 scopeName = fixAlias(scopeName);
557 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
558 this.indexedScopes[this.ts.cursor] = fnScope;
560 //this.scopesIn(fnScope);
561 this.parseScope(fnScope, aliases);
563 //print(">>" +locBraceNest);
564 continue; // no more processing..
567 /// function foo() {} << really it set's the 'this' scope to foo.prototype
568 //$this$=foo|$private$
572 (this.ts.lookT(1).tokN == Script.TOKidentifier)
574 //scopeName = this.ts.look(-3).data;
575 this.ts.balanceN(Script.TOKlparen);
576 token = this.ts.nextT(); // should be {
578 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
579 this.indexedScopes[this.ts.cursor] = fnScope;
581 //this.scopesIn(fnScope);
582 this.parseScope(fnScope, aliases);
584 //print(">>" +locBraceNest);
585 continue; // no more processing..
590 // foo = new (function() { }
592 // RETURN function(...) {
595 // (this.ts.lookT(-1).tokN == Script.TOKlparen) &&
596 (this.ts.lookT(1).tokN != Script.TOKidentifier)
598 // (this.ts.lookT(-2).tokN == Script.TOKnew) &&
599 // (this.ts.lookT(-3).tokN == Script.TOKassign) &&
600 // (this.ts.lookT(-4).tokN == Script.TOKidentifier)
602 //scopeName = this.ts.look(-3).data;
603 this.ts.balanceN(Script.TOKlparen);
604 token = this.ts.nextT(); // should be {
605 var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
606 this.indexedScopes[this.ts.cursor] = fnScope;
608 //this.scopesIn(fnScope);
609 this.parseScope(fnScope, aliases);
611 //print(">>" +locBraceNest);
612 continue; // no more processing..
618 print(this.ts.context());
619 throw "dont know how to handle function syntax??";
626 } // end checking for TOKfunction
628 if (token.tokN == Script.TOKlbrace) {
630 // foo = { // !var!!!
635 (this.ts.lookT(-1).tokN == Script.TOKassign) &&
636 (this.ts.lookT(-2).tokN == Script.TOKidentifier) &&
637 (this.ts.lookT(-3).tokN != Script.TOKvar)
640 scopeName = this.ts.look(-2).data;
641 scopeName = fixAlias(scopeName);
642 var fnScope = new Scope(this.braceNesting, scope, token.n,
643 '$this$='+scopeName + '|'+scopeName
645 this.indexedScopes[this.ts.cursor] = fnScope;
647 this.scopesIn(fnScope);
651 //print(">>" +locBraceNest);
652 continue; // no more processing..
657 //print("GOT LBRACE : check for :");
659 (this.ts.lookT(-1).tokN == Script.TOKcolon) &&
660 (this.ts.lookT(-2).tokN == Script.TOKidentifier) &&
661 (this.ts.lookT(-3).tokN != Script.TOKvar)
664 scopeName = this.ts.lookT(-2).data;
665 scopeName = fixAlias(scopeName);
666 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
667 this.indexedScopes[this.ts.cursor] = fnScope;
669 this.scopesIn(fnScope);
672 //print(">>" +locBraceNest);
673 continue; // no more processing..
675 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
676 this.indexedScopes[this.ts.cursor] = fnScope;
678 this.scopesIn(fnScope);
681 //print(">>" +locBraceNest);
685 if (token.tokN == Script.TOKrbrace) {
688 if (this.currentDoc) {
689 this.addSymbol('', true);
691 //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
697 //assert braceNesting >= scope.getBraceNesting();
698 var closescope = this.scopeOut();
699 scope = this.scopes[this.scopes.length-1];
700 //print("<<:" + locBraceNest)
701 //print("<<<<<< " + locBraceNest );
702 if (locBraceNest < 0) {
703 // print("POPED OF END OF SCOPE!");
705 //var ls = this.scopeOut();
706 //ls.getUsedSymbols();
719 addSymbol: function(lastIdent, appendIt, atype )
722 /*if (!this.currentDoc.tags.length) {
725 //print(this.currentDoc.toSource());
726 // this.currentDoc = false;
728 print("SKIP ADD SYM: no tags");
729 print(this.currentDoc.src);
733 if (this.currentDoc.getTag('private').length) {
736 //print(this.currentDoc.toSource());
737 this.currentDoc = false;
738 print("SKIP ADD SYM: it's private");
742 var token = this.ts.cur();
743 if (typeof(appendIt) == 'undefined') {
746 // print(this.currentDoc.toSource(););
747 if (this.currentDoc.getTag('event').length) {
748 //?? why does it end up in desc - and not name/...
749 print(this.currentDoc.getTag('event')[0]);
750 lastIdent = '*' + this.currentDoc.getTag('event')[0].desc;
751 //lastIdent = '*' + lastIdent ;
753 if (!lastIdent.length && this.currentDoc.getTag('property').length) {
754 lastIdent = this.currentDoc.getTag('property')[0].name;
755 //lastIdent = '*' + lastIdent ;
759 if (!/\./.test(_s)) {
761 //print("WALKER ADDsymbol: " + lastIdent);
764 for (var i = 0; i < this.scopes.length;i++) {
765 s.push(this.scopes[i].ident);
769 var s = s.join('|').split('|');
770 print("Walker:ADDSymbol: " + s.join('|') );
775 for (var i = 0; i < s.length;i++) {
780 if ((s[i] == '$private$') || (s[i] == '$global$')) {
784 if (s[i].substring(0,6) == '$this$') {
785 var ts = s[i].split('=');
789 // when to use $this$ (probabl for events)
790 _s += _s.length ? '.' : '';
796 //print("ADDING SYMBOL: "+ s.join('|') +"\n"+ _s + "\n" +Script.prettyDump(this.currentDoc.toSource()));
798 if (appendIt && !lastIdent.length) {
800 // append, and no symbol???
802 // see if it's a @class
803 if (this.currentDoc.getTag('class').length) {
804 _s = this.currentDoc.getTag('class')[0].desc;
805 var symbol = new Symbol(_s, [], "CONSTRUCTOR", this.currentDoc);
806 Parser.addSymbol(symbol);
807 this.symbols[_s] = symbol;
811 // if (this.currentDoc.getTag('property').length) {
812 // print(Script.pretStringtyDump(this.currentDoc.toSource));
813 // throw "Add Prop?";
816 _s = _s.replace(/\.prototype.*$/, '');
817 if (typeof(this.symbols[_s]) == 'undefined') {
818 print("Symbol:" + _s);
819 print(this.currentDoc.src);
821 throw "Trying to append symbol, but no doc available";
824 for (var i =0; i < this.currentDoc.tags.length;i++) {
825 this.symbols[_s].addDocTag(this.currentDoc.tags[i]);
827 this.currentDoc = false;
831 if (typeof(this.symbols[_s]) != 'undefined') {
833 if (this.symbols[_s].comment.hasTags) {
834 // then existing comment doesnt has tags
835 throw "DUPLICATE Symbol " + _s;
837 // otherwise existing comment has tags - overwrite..
841 if (typeof(atype) == "undefined") {
842 atype = 'OBJECT'; //this.currentDoc.getTag('class').length ? 'OBJECT' : 'FUNCTION';;
845 var symbol = new Symbol(_s, [], atype, this.currentDoc);
847 Parser.addSymbol(symbol);
848 this.symbols[_s] = symbol;
850 this.currentDoc = false;
857 scopesIn : function(s)
860 //print(">>>" + this.ts.context() + "\n>>>"+this.scopes.length+":" +this.scopeListToStr());
863 scopeOut : function()
866 // print("<<<" + this.ts.context() + "\n<<<"+this.scopes.length+":" +this.scopeListToStr());
867 return this.scopes.pop();
871 scopeListToStr : function()
874 for (var i = 0; i < this.scopes.length;i++) {
875 s.push(this.scopes[i].ident);
877 return s.join('\n\t');