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;
13 * // FIXME - I need this to do next() without doccomments..
16 Walker2 = XObject.define(
18 XObject.extend(this,opts);
22 this.indexedScopes = {};
24 //this.timer = new Date() * 1;
32 timerPrint: function (str) {
33 var ntime = new Date() * 1;
34 var tdif = ntime -this.timer;
37 if (tdif > 100) { //slower ones..
40 print(pref+'['+tdif+']'+str);
45 * @cfg parser {Parser} instance of parser
50 //this.warnings.push(s);
51 print("WARNING:" + htmlescape(s) + "<BR>");
53 // defaults should not be initialized here =- otherwise they get duped on new, rather than initalized..
58 mode : "", //"BUILDING_SYMBOL_TREE",
60 indexedScopes : false,
65 * @param {Object} symbols object store of sumbols..
70 buildSymbolTree : function()
75 this.braceNesting = 0;
79 this.globalScope = new Scope(-1, false, -1, '$global$');
80 indexedScopes = { 0 : this.globalScope };
82 this.mode = 'BUILDING_SYMBOL_TREE';
83 this.parseScope(this.globalScope);
91 //print("<B>LOG:</B>" + htmlescape(str) + "<BR/>\n");
95 //print("<B>LOG:</B>" + str + "<BR/>");
102 parseScope : function(scope, ealiases) // parse a token stream..
104 //this.timerPrint("parseScope EnterScope");
107 var fixAlias = function(str, nomore)
109 var ar = str.split('.');
112 //print(str +"?=" +aliases.toSource());
113 if (aliases[m] == undefined) {
116 var ret = aliases[m] + (ar.length? '.' : '' )+ ar.join('.');
117 if (nomore !== true) {
118 ret = fixAlias(ret, true);
128 if (ealiases != undefined) {
130 for(var i in ealiases) {
131 aliases[i] = ealiases[i];
138 //print("STARTING SCOPE WITH: " + ealiases.toSource());
144 var expressionBraceNesting = this.braceNesting;
145 var bracketNesting = 0;
146 var parensNesting = 0;
149 var l1 = '', l2 = '';
153 var locBraceNest = 0;
154 // determines if we are in object literals...
156 var isObjectLitAr = [ false ];
157 //print("SCOPE: ------------------START ----------------");
158 this.scopesIn(scope);
159 var scopeLen = this.scopes.length;
161 if (this.ts.cursor < 1) {
162 // this.ts.cursor--; // hopeflly this kludge will work
166 //print(JSON.stringify(this.ts, null, 4)); Seed.quit();
168 while (null != (token = this.ts.next())) {
169 //print("TOK"+ token.toString());
170 // this.timerPrint("parseScope AFTER lookT: " + token.toString());
172 if (token.is('COMM')) {
175 if (token.name != 'JSDOC') {
176 //print("Walker2 : spce is not JSDOC");
179 if (this.currentDoc) {
180 // add it to the current scope????
182 this.addSymbol('', true);
183 //print ( "Unconsumed Doc: " + token.toString())
184 //throw "Unconsumed Doc (TOKwhitespace): " + this.currentDoc.toSource();
187 // print ( "NEW COMMENT: " + token.toString())
188 var newDoc = new DocComment(token.data);
190 // it's a scope changer..
191 if (newDoc.getTag("scope").length) {
192 //print("Walker2 : doctag changes scope");
194 scope.ident = '$private$|' + newDoc.getTag("scope")[0].desc;
198 // it's a scope changer..
199 if (newDoc.getTag("scopeAlias").length) {
200 //print(newDoc.getTag("scopeAlias").toSource());
202 //print("Walker2 : doctag changes scope (alias)");
203 var sal = newDoc.getTag("scopeAlias")[0].desc.split("=");
204 aliases[sal[0]] = sal[1];
210 if (newDoc.getTag("namespace").length) {
211 //print("Walker2 : doctag changes scope");
213 this.namespace = newDoc.getTag("namespace")[0].desc +'.';
217 /// got a doc comment..
218 //token.data might be this.??? (not sure though)
219 //print("Walker2 : setting currentDoc");
220 this.currentDoc = newDoc;
224 // catch the various issues .. - scoe changes or doc actions..
228 // things that stop comments carrying on...??
230 if (this.currentDoc && (
232 token.data == '}')) {
233 this.addSymbol('', true);
234 //throw "Unconsumed Doc ("+ token.toString() +"): " + this.currentDoc.toSource();
238 // the rest are scoping issues...
242 if (token.name == 'VAR' &&
244 this.ts.lookTok(1).type == 'NAME' &&
245 this.ts.lookTok(2).data == '=' &&
246 this.ts.lookTok(3).type == 'NAME' &&
247 this.ts.lookTok(4).data == ';'
251 //print("SET ALIAS:" + this.ts.lookTok(1).data +'=' + this.ts.lookTok(3).data);
253 aliases[this.ts.lookTok(1).data] = this.ts.lookTok(3).data;
258 if ((token.data == 'eval') || /\.eval$/.test(token.data)) {
259 this.currentDoc = false;
263 // extends scoping *** not sure if the can be x = Roo.apply(....)
264 // xxx.extends(a,b, {
265 // $this$=b|b.prototype
270 if (token.type == 'NAME') {
272 //print("TOK(ident)"+ token.toString());
274 if (/\.extend$/.test(token.data) &&
275 this.ts.lookTok(1).data == '(' &&
276 this.ts.lookTok(2).type == 'NAME' &&
277 this.ts.lookTok(3).data == ',' &&
278 this.ts.lookTok(4).type == 'NAME' &&
279 this.ts.lookTok(5).data == ',' &&
280 this.ts.lookTok(6).data == '{'
283 // ignore test for ( a and ,
284 this.ts.nextTok(); /// (
285 token = this.ts.nextTok(); // a
286 scopeName = token.data;
288 if (this.currentDoc) {
289 this.addSymbol(scopeName,false,'OBJECT');
292 this.ts.nextTok(); // ,
293 this.ts.nextTok(); // b
296 this.ts.nextTok(); // ,
297 token = this.ts.nextTok(); // {
299 scopeName = fixAlias(scopeName);
301 var fnScope = new Scope(this.braceNesting, scope, token.n,
302 '$this$=' + scopeName + '|'+scopeName+'.prototype');
303 this.indexedScopes[this.ts.cursor] = fnScope;
305 this.scopesIn(fnScope);
308 //print(">>" +locBraceNest);
309 continue; // no more processing..
313 // a = Roo.extend(parentname, {
315 if (/\.extend$/.test(token.data) &&
316 this.ts.lookTok(-2).type == 'NAME' &&
317 this.ts.lookTok(-1).data == '=' &&
318 this.ts.lookTok(1).data == '(' &&
319 this.ts.lookTok(2).type == 'NAME' &&
320 this.ts.lookTok(3).data == ',' &&
321 this.ts.lookTok(4).data == '{'
323 // ignore test for ( a and ,
324 token = this.ts.lookTok(-2);
325 scopeName = token.data;
326 if (this.currentDoc) {
327 this.addSymbol(scopeName,false,'OBJECT');
330 this.ts.nextTok(); /// (
331 this.ts.nextTok(); // parent
333 this.ts.nextTok(); // ,
334 token = this.ts.nextTok(); // {
337 scopeName = fixAlias(scopeName);
338 var fnScope = new Scope(this.braceNesting, scope, token.n,
339 '$this$=' + scopeName + '|'+scopeName+'.prototype');
340 this.indexedScopes[this.ts.cursor] = fnScope;
342 this.scopesIn(fnScope);
345 //print(">>" +locBraceNest);
346 continue; // no more processing..
353 print(JSON.stringify([
355 this.ts.lookTok(1).data ,
356 this.ts.lookTok(2).type ,
357 this.ts.lookTok(3).data ,
358 this.ts.lookTok(4).data
362 if (/\.(applyIf|apply)$/.test(token.data) &&
363 this.ts.lookTok(1).data == '(' &&
364 this.ts.lookTok(2).type == 'NAME' &&
365 this.ts.lookTok(3).data == ',' &&
366 this.ts.lookTok(4).data == '{'
369 this.ts.nextTok(); /// (
371 //print("GOT : applyIF!");
373 token = this.ts.nextTok(); // b
374 scopeName = token.data;
377 if (this.currentDoc) {
378 this.addSymbol(scopeName,false,'OBJECT');
383 this.ts.nextTok(); /// ,
384 this.ts.nextTok(); // {
385 scopeName = fixAlias(scopeName);
386 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
387 this.indexedScopes[this.ts.cursor] = fnScope;
389 this.scopesIn(fnScope);
392 //print(">>" +locBraceNest);
393 continue; // no more processing..
399 // change scope to xxxx
401 print(JSON.stringify([
402 this.ts.lookTok(1).data ,
403 this.ts.lookTok(2).name ,
404 this.ts.lookTok(3).type ,
405 this.ts.lookTok(4).data ,
406 this.ts.lookTok(5).data
409 if ( this.ts.lookTok(1).data == '=' &&
410 this.ts.lookTok(2).name == 'NEW' &&
411 this.ts.lookTok(3).type == 'NAME' &&
412 this.ts.lookTok(4).data == '(' &&
413 this.ts.lookTok(5).data == '{'
415 scopeName = token.data;
416 if (this.currentDoc) {
417 this.addSymbol(scopeName,false,'OBJECT');
421 this.ts.nextTok(); /// =
422 this.ts.nextTok(); /// new
423 this.ts.nextTok(); /// yyy
424 this.ts.nextTok(); /// (
425 this.ts.nextTok(); /// {
427 scopeName = fixAlias(scopeName);
428 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
429 this.indexedScopes[this.ts.cursor] = fnScope;
431 this.scopesIn(fnScope);
434 //print(">>" +locBraceNest);
436 continue; // no more processing..
439 // AAA = XObject.define( ctr, extends, methods)
441 //print(this.ts.lookTok(2).data);
442 /*print(JSON.stringify([
443 'line:' + token.line,
444 this.ts.lookTok(1).data ,
445 this.ts.lookTok(2).data ,
446 this.ts.lookTok(3).data ,
447 this.ts.lookTok(4).name
451 this.ts.lookTok(1).data == '=' &&
452 this.ts.lookTok(2).data.match(/\.define$/) &&
453 this.ts.lookTok(3).data == '(' &&
454 this.ts.lookTok(4).name == 'FUNCTION'
458 scopeName = this.namespace + token.data;
459 print("GOT NEW SCOPE: " + scopeName);
461 if (this.currentDoc) {
462 this.addSymbol(scopeName,false,'OBJECT');
466 this.ts.nextTok(); /// =
467 this.ts.nextTok(); /// XOBJECT.extend?
468 this.ts.nextTok(); /// (
471 scopeName = fixAlias(scopeName);
472 var fnScope = new Scope(this.braceNesting, scope, token.n,
473 '$this$=' + scopeName + '|'+scopeName+'.prototype');
475 print(fnScope.ident);
476 this.indexedScopes[this.ts.cursor] = fnScope;
478 this.scopesIn(fnScope);
481 //print(">>" +locBraceNest);
483 continue; // no more processing..
490 // eval can be prefixed with a hint hider for the compresser..
493 if (this.currentDoc) {
494 //print(token.toString());
496 // ident : function ()
497 // ident = function ()
498 var atype = 'OBJECT';
500 if (((this.ts.lookTok(1).data == ':' )|| (this.ts.lookTok(1).data == '=')) &&
501 (this.ts.lookTok(2).name == "FUNCTION")
503 // this.ts.nextTok();
504 // this.ts.nextTok();
508 //print("ADD SYM:" + atype + ":" + token.toString() + this.ts.lookTok(1).toString() + this.ts.lookTok(2).toString());
511 this.ts.lookTok(-1).data == '.' ? token.data : fixAlias(token.data),
515 this.currentDoc = false;
521 continue; // dont care about other idents..
525 //print ("NOT NAME");
528 if (token.type == "STRN") { // THIS WILL NOT HAPPEN HERE?!!?
529 if (this.currentDoc) {
530 this.addSymbol(token.data.substring(1,token.data.length-1),false,'OBJECT');
535 // really we only have to deal with object constructs and function calls that change the scope...
538 if (token.name == 'FUNCTION') {
539 //print("GOT FUNCTION");
540 // see if we have an unconsumed doc...
544 /** -- removed as it's killing Xobject parsing...
545 if (this.currentDoc) {
547 name: "ArgumentError",
548 message: this.ts.filename + ": Unhandled doc (TOKfunction)" + token.toString()
551 //this.addSymbol(this.currentDoc.getTag('class')[0].name, true);
553 //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
560 /// foo = function() {} << really it set's the 'this' scope to foo.prototype
561 //$this$=foo.prototype|$private$|foo.prototype
564 (this.ts.lookTok(-1).data == '=') &&
565 (this.ts.lookTok(-2).type == 'NAME')
567 scopeName = this.ts.lookTok(-2).data;
568 this.ts.balance('(');
569 token = this.ts.nextTok(); // should be {
570 //print("FOO=FUNCITON() {}" + this.ts.context() + "\n" + token.toString());
573 scopeName = fixAlias(scopeName);
574 var fnScope = new Scope(this.braceNesting, scope, token.n,
575 '$this$='+scopeName+'.prototype|$private$|'+scopeName+'.prototype');
577 this.indexedScopes[this.ts.cursor] = fnScope;
579 //this.scopesIn(fnScope);
580 this.parseScope(fnScope, aliases);
585 //print(">>" +locBraceNest);
586 continue; // no more processing..
592 // foo = new function() {}
593 // is this actually used much!?!?!
597 (this.ts.lookTok(-1).name == 'NEW') &&
598 (this.ts.lookTok(-2).data == '=') &&
599 (this.ts.lookTok(-3).type = 'FUNCTION')
601 //scopeName = this.ts.look(-3).data;
602 this.ts.balance("(");
603 token = this.ts.nextTok(); // should be {
604 scopeName = fixAlias(scopeName);
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);
612 //print(">>" +locBraceNest);
613 continue; // no more processing..
619 ///==== check/set isObjectLitAr ??
622 // foo: function() {}
623 // no change to scoping..
625 //print("checking for : function() {");
626 //print( [this.ts.lookTok(-3).type , this.ts.lookTok(-2).type , this.ts.lookTok(-1).type ].join(":"));
628 (this.ts.lookTok(-1).data == ':') &&
629 (this.ts.lookTok(-2).type == 'NAME') &&
630 (this.ts.lookTok(-3).data == '(' || this.ts.lookTok(-3).data== ',')
632 //print("got for : function() {");
634 //scopeName = this.ts.look(-3).data;
635 this.ts.balance('(');
636 //print(token.toString())
637 token = this.ts.nextTok(); // should be {
638 //print(token.toString())
639 scopeName = fixAlias(scopeName);
640 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
641 this.indexedScopes[this.ts.cursor] = fnScope;
643 //this.scopesIn(fnScope);
644 this.parseScope(fnScope, aliases);
646 //print(">>" +locBraceNest);
647 continue; // no more processing..
650 /// function foo() {} << really it set's the 'this' scope to foo.prototype
651 //$this$=foo|$private$
655 (this.ts.lookTok(1).type == 'NAME')
657 //scopeName = this.ts.look(-3).data;
658 this.ts.balance('(');
659 token = this.ts.nextTok(); // should be {
661 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
662 this.indexedScopes[this.ts.cursor] = fnScope;
664 //this.scopesIn(fnScope);
665 this.parseScope(fnScope, aliases);
667 //print(">>" +locBraceNest);
668 continue; // no more processing..
673 // foo = new (function() { }
675 // RETURN function(...) {
678 // (this.ts.lookTok(-1).tokN == Script.TOKlparen) &&
679 (this.ts.lookTok(1).name != 'NAME')
681 // (this.ts.lookTok(-2).tokN == Script.TOKnew) &&
682 // (this.ts.lookTok(-3).tokN == Script.TOKassign) &&
683 // (this.ts.lookTok(-4).tokN == Script.TOKidentifier)
685 //scopeName = this.ts.look(-3).data;
686 this.ts.balance('(');
687 token = this.ts.nextTok(); // should be {
688 var fnScope = new Scope(this.braceNesting, scope, token.n, '$private$');
689 this.indexedScopes[this.ts.cursor] = fnScope;
691 //this.scopesIn(fnScope);
692 this.parseScope(fnScope, aliases);
694 //print(">>" +locBraceNest);
695 continue; // no more processing..
702 name: "ArgumentError",
703 message: "dont know how to handle function syntax??\n" +
713 } // end checking for TOKfunction
715 if (token.data == '{') {
717 // foo = { // !var!!!
722 (this.ts.lookTok(-1).data == '=') &&
723 (this.ts.lookTok(-2).type == 'NAME') &&
724 (this.ts.lookTok(-3).name != 'VAR')
727 scopeName = this.ts.look(-2).data;
729 scopeName = fixAlias(scopeName);
731 //print(this.scopes.length);
732 var fnScope = new Scope(this.braceNesting, scope, token.n,
733 '$this$='+scopeName + '|'+scopeName
736 this.indexedScopes[this.ts.cursor] = fnScope;
738 // push the same scope onto the stack..
739 this.scopesIn(fnScope);
740 //this.scopesIn(this.scopes[this.scopes.length-1]);
744 //print(">>" +locBraceNest);
745 continue; // no more processing..
750 //print("GOT LBRACE : check for :");
752 (this.ts.lookTok(-1).data == ':') &&
753 (this.ts.lookTok(-2).type == 'NAME') &&
754 (this.ts.lookTok(-3).name != 'VAR')
757 scopeName = this.ts.lookTok(-2).data;
758 scopeName = fixAlias(scopeName);
759 var fnScope = new Scope(this.braceNesting, scope, token.n, scopeName);
760 this.indexedScopes[this.ts.cursor] = fnScope;
762 this.scopesIn(fnScope);
765 //print(">>" +locBraceNest);
766 continue; // no more processing..
768 var fnScope = new Scope(this.braceNesting, scope, token.n, '');
769 this.indexedScopes[this.ts.cursor] = fnScope;
771 this.scopesIn(fnScope);
774 //print(">>" +locBraceNest);
778 if (token.data == '}') {
781 if (this.currentDoc) {
782 this.addSymbol('', true);
784 //throw "Unconsumed Doc: (TOKrbrace)" + this.currentDoc.toSource();
790 //assert braceNesting >= scope.getBraceNesting();
791 var closescope = this.scopeOut();
792 scope = this.scopes[this.scopes.length-1];
793 //print("<<:" + locBraceNest)
794 //print("<<<<<< " + locBraceNest );
795 if (locBraceNest < 0) {
796 // print("POPED OF END OF SCOPE!");
798 //var ls = this.scopeOut();
799 //ls.getUsedSymbols();
812 addSymbol: function(lastIdent, appendIt, atype )
814 //print("Walker.addSymbol : " + lastIdent);
815 // print("Walker.curdoc: " + JSON.stringify(this.currentDoc, null,4));
817 /*if (!this.currentDoc.tags.length) {
820 //print(this.currentDoc.toSource());
821 // this.currentDoc = false;
823 print("SKIP ADD SYM: no tags");
824 print(this.currentDoc.src);
828 if (this.currentDoc.getTag('private').length) {
831 //print(this.currentDoc.toSource());
832 this.currentDoc = false;
833 //print("SKIP ADD SYM: it's private");
837 var token = this.ts.lookTok(0);
838 if (typeof(appendIt) == 'undefined') {
841 // print(this.currentDoc.toSource(););
842 if (this.currentDoc.getTag('event').length) {
843 //?? why does it end up in desc - and not name/...
844 //print(this.currentDoc.getTag('event')[0]);
845 lastIdent = '*' + this.currentDoc.getTag('event')[0].desc;
846 //lastIdent = '*' + lastIdent ;
848 if (!lastIdent.length && this.currentDoc.getTag('property').length) {
849 lastIdent = this.currentDoc.getTag('property')[0].name;
850 //lastIdent = '*' + lastIdent ;
854 if (!/\./.test(_s)) {
856 //print("WALKER ADDsymbol: " + lastIdent);
859 for (var i = 0; i < this.scopes.length;i++) {
860 s.push(this.scopes[i].ident);
864 //print("FULLSCOPE: " + JSON.stringify(s));
867 var s = s.join('|').split('|');
868 //print("FULLSCOPE: " + s);
869 // print("Walker:ADDSymbol: " + s.join('|') );
874 for (var i = 0; i < s.length;i++) {
879 if ((s[i] == '$private$') || (s[i] == '$global$')) {
883 if (s[i].substring(0,6) == '$this$') {
884 var ts = s[i].split('=');
886 _s = ''; // ??? VERY QUESTIONABLE!!!
889 // when to use $this$ (probabl for events)
890 _s += _s.length ? '.' : '';
893 //print("FULLSCOPE: s , t : " + _s +', ' + _t);
896 //print("ADDING SYMBOL: "+ s.join('|') +"\n"+ _s + "\n" +Script.prettyDump(this.currentDoc.toSource()));
897 //print("Walker.addsymbol - add : " + _s);
898 if (appendIt && !lastIdent.length) {
900 // append, and no symbol???
902 // see if it's a @class
903 if (this.currentDoc.getTag('class').length) {
904 _s = this.currentDoc.getTag('class')[0].desc;
905 var symbol = new Symbol(_s, [], "CONSTRUCTOR", this.currentDoc);
907 this.parser.addSymbol(symbol);
908 this.symbols[_s] = symbol;
912 // if (this.currentDoc.getTag('property').length) {
913 // print(Script.pretStringtyDump(this.currentDoc.toSource));
914 // throw "Add Prop?";
917 _s = _s.replace(/\.prototype.*$/, '');
918 if (typeof(this.symbols[_s]) == 'undefined') {
919 //print("Symbol:" + _s);
920 //print(this.currentDoc.src);
923 // name: "ArgumentError",
924 // message: "Trying to append symbol '" + _s + "', but no doc available\n" +
925 // this.ts.lookTok(0).toString()
927 this.currentDoc = false;
932 for (var i =0; i < this.currentDoc.tags.length;i++) {
933 this.symbols[_s].addDocTag(this.currentDoc.tags[i]);
935 this.currentDoc = false;
939 //print("Walker.addsymbol - chkdup: " + _s);
940 if (typeof(this.symbols[_s]) != 'undefined') {
942 if (this.symbols[_s].comment.hasTags) {
943 // then existing comment doesnt has tags
945 // name: "ArgumentError",
946 // message:"DUPLICATE Symbol " + _s + "\n" + token.toString()
950 // otherwise existing comment has tags - overwrite..
954 //print("Walker.addsymbol - ATYPE: " + _s);
956 if (typeof(atype) == "undefined") {
957 atype = 'OBJECT'; //this.currentDoc.getTag('class').length ? 'OBJECT' : 'FUNCTION';;
960 //print("Walker.addsymbol - add : ");
961 var symbol = new Symbol(_s, [], atype, this.currentDoc);
963 this.parser.addSymbol(symbol);
964 this.symbols[_s] = symbol;
966 this.currentDoc = false;
973 scopesIn : function(s)
976 //print(">>>" + this.ts.context() + "\n>>>"+this.scopes.length+":" +this.scopeListToStr());
979 scopeOut : function()
982 // print("<<<" + this.ts.context() + "\n<<<"+this.scopes.length+":" +this.scopeListToStr());
983 return this.scopes.pop();
987 scopeListToStr : function()
990 for (var i = 0; i < this.scopes.length;i++) {
991 s.push(this.scopes[i].ident);
993 return s.join('\n\t');