JSDOC/Collapse.js
[app.jsdoc] / JSDOC / Collapse.js
1 //<script type="text/javscript">
2 XObject = imports.XObject.XObject;
3
4  
5 console     = imports.console.console; 
6
7 // make sure parent is loaded..
8 TokenStream = imports.TokenStream.TokenStream;
9  
10 /**
11  * 
12  */
13
14 /**
15  * @scope JSDOC
16  * @class Collapse
17  * @extends JSDOC.TokenStream
18  * base class for parsing segments of token array..
19  * 
20  * 
21  * We want to make parsing the whole thing easy..
22  * 
23  * so we do various tricks:
24  * 
25  * 
26  * a) white space collased
27  *    wsPrefix 
28  * b)  toks
29  *     { } - collapse into first element.
30        ( ) - collapse into first element.
31        [ ] - collapse into first element.
32  * c) items = , seperation within the above..
33  * d) props = for  { xx: ... , yy: ....}
34  * 
35  * 
36  * usage:
37  *  x = new Collapse({
38  *      srcFile : ....
39  *  })
40  *  x.collapse();
41  * 
42  * 
43  * @param {Object} array tokens
44      
45  */ 
46  
47 Collapse = XObject.define(
48     
49     function (cfg)
50     {
51         Collapse.superclass.constructor.call(this, cfg);
52         
53         
54         this.allJSDOC = [];
55        // console.dump(ar);
56         
57     }, 
58     TokenStream, 
59     {
60         
61         /**
62          * @cfg {Boolean} collapseTop make statements array of top level tokens.
63          */
64         collapseTop : false,
65         
66         /**
67          * @type {Array} top level statements
68          */
69         statements : false,
70         
71         /**
72          * @cfg {Boolean} createJSDOC    create .jsdoc properties on tokens.
73          */
74         createJSDOC : false,
75         
76         /**
77          * @type {Array} allJSDOC if createJSDOC is set, then all the files JSDOC comments
78          *                        are stored here, in theory to verify that all have been used up..
79          */
80         allJSDOC : false,
81         
82         /**
83          * collapse the token array
84          * if collapseTop is set, then statments is set to the array statements (which is an array of tokens)
85          * otherwise this.tokens is set..
86          */
87         collapse : function(ar) {
88            
89             ar = ar || this.tokens ;
90             this.rewind();
91             ar = this.spaces(ar);
92             ar = this._collapse(ar);
93         
94             if (this.collapseTop) {
95                 //print(JSON.stringify(ar, null,4));
96                 
97                 return this.toItems(ar, [ ';', '{'] );
98                 
99             }
100             return ar;
101         },
102         
103         /**
104          * Add all the comments to the closed token.
105          * adds :
106          *   token.comments = [] (array of COMMENTS)
107          *   token.comment = combined string
108          *   token.jsdoc = last comment (as DocComment)
109          *
110          *
111          */
112         spaces : function (toks)
113         {
114             this.tokens = toks;
115             this.rewind();
116             var ar = [];
117             var pref = [];
118             
119             var tok;
120             var jsdoc;
121             var _this = this;
122             
123             for (var i = 0; i < this.tokens.length; i ++) {
124                 tok = this.tokens[i];
125                 
126                 if (this.createJSDOC) {
127                     tok.jsdoc = false;
128                 }
129                 
130                 if (tok.is("COMM") || tok.is("WHIT")) {
131                     pref.push(tok);
132                     continue;
133                 }
134                 tok.prefix = '';
135                 if (pref.length) {
136                     tok.comments = [];
137                     pref.forEach( function(e) {
138                         if (!e) {
139                             return;
140                         }
141                         if (e.name == "JSDOC") {
142                             tok.comment = e.data;
143                             if (_this.createJSDOC) { 
144                                 tok.jsdoc = new imports.DocComment.DocComment(tok.comment);
145                                 _this.allJSDOC.push(tok.jsdoc); 
146                             }
147                         }
148                         // kludge for private..
149                         if (e.is("COMM") && e.data.match(/\/\/\s+private/)) {
150                             tok.comment = '/** @private */';
151                             if (_this.createJSDOC) { 
152                                 tok.jsdoc = new imports.DocComment.DocComment(tok.comment);
153                                 _this.allJSDOC.push(tok.jsdoc); 
154                             }
155                         }
156                         
157                         tok.prefix += e.data;
158                         
159                     })
160                 }
161                 
162                 ar.push(tok);
163                 pref=  [];
164                 
165             }
166             return ar;
167             
168         },
169         
170         
171              
172         _collapse : function(ar, depth) {
173             
174             depth = depth || 0;
175             var st = new  TokenStream({ tokens : ar });
176             var ret = [];
177             
178             while (true) {
179                 var  tok = st.look(1,true);
180                 tok.depth = depth;
181                 if (!tok || !tok.is) {
182                   //  Seed.print(TokenStream.toString(ret));
183                     return ret;
184                 }
185                 // console.log(tok.data);
186                 switch(tok.type) {
187                     case "VOID": 
188                         return ret; //EOF
189                         
190                         
191                     case "KEYW": 
192                     case "TOKN":
193                     case "NAME":
194                     case "STRN":
195                     case "NUMB":
196                     case "REGX":
197                         ret.push(st.next(1));
198                         continue;
199                         
200                     case "PUNC":
201                         switch (tok.data) {
202                             case "[":
203                             case "{":
204                             case "(":
205                                 
206                                 var start = st.cursor;
207                                 st.next(1);
208                                 var add = st.balance(tok.data);
209                                 if (!add) {
210                                     console.dump(tok);
211                                     console.dump(start + '...' + st.cursor);
212                                     console.dump(st.tokens);
213                                  
214                                 }
215                                 if (add) {
216                                     add.shift();
217                                 }
218                                 //Seed.print("ADD");
219                                 //Seed.print(JSON.stringify(add, null,4));
220                                 
221                                 
222                                 
223                                 var toks = add ? this._collapse(add, depth+1) : [];
224                                 tok.items = false;
225                                 tok.props = false;
226                                 
227                                 
228                                 
229                                 if (tok.data != '{') {
230                                     // paramters or array elements..
231                                     tok.items = this.toItems(toks, [',']);
232                                     tok.args = [];
233                                     tok.items.forEach(function(tar) {
234                                         if (tar[0].is('NAME')) {
235                                             tok.args.push(tar[0].data);
236                                         }
237                                     });
238                                     
239                                     
240                                         
241                                     ret.push(tok);
242                                     
243                                     continue;
244                                     
245                                     
246                                 }  
247                                     // check for types.. it could be a list of statements.. or object
248                                     
249                                 var ost = new  TokenStream({tokens : toks});
250                                 //console.dump(ost.look(2,true) );
251                                 if (ost.look(2,true) && ost.look(2,true).data == ":") {
252                                     tok.props = this.toProps(toks);
253                                 } else {
254                                     // list of statemetns..
255                                     tok.items = this.toItems(toks,[ ';', '{'] ); 
256                                 }
257                                 
258                                    
259                                 
260                                 //Seed.print(" ADD : " + add.length  +  " ITEMS: " + tok.items.length);
261                                 
262                                 ret.push(tok);
263                                 
264                                 continue;
265                    
266                             default:
267                                 ret.push(st.next(1));
268                                 continue;
269                         }
270                         Seed.print("OOPS");
271                         continue;
272                     default : 
273                         Seed.print("OOPS" + tok.type);
274                         continue;
275                 }
276             }
277                 
278                 
279             
280             
281             
282             
283             
284             
285             
286             
287         },
288         toItems : function(ar,sep)
289         {
290             var ret = [];
291             var g = [];
292               
293             for (var i = 0; i < ar.length; i ++) {
294                 if (sep.indexOf(ar[i].data) < 0) {
295                     g.push(ar[i]);
296                     continue;
297                 }
298                 // var a=..., b =...
299                 if ((ar[i].data != ';') && g.length && (g[0].name == "VAR")) {;
300                     g.push(ar[i]);
301                     continue;
302                 }
303                 
304                 g.push(ar[i]);
305                 ret.push(g);
306                 g = [];
307                 
308             }
309             // last..
310             if (g.length) {
311                 ret.push(g);
312             }
313             return ret;
314             
315         },
316         toProps : function(ar)
317         {
318             
319             var ret = { }
320                
321             var g = { key : '', val: [] }
322                
323             
324             var k = '';
325             var state = 0;
326             for (var i = 0; i < ar.length; i ++) {
327                 
328                 switch(state) {
329                     case 0:
330                         k = ar[i].data;
331                         g.key = ar[i];
332                         state = 1;
333                         continue;
334                     case 1:
335                         state =2; // should be ':'
336                         continue;
337                     case 2:
338                         g.val.push(ar[i]);
339                         if (ar[i].data != ',') {
340                             continue;
341                         }
342                         ret[k] = g;
343                         g = { key : '', val: [] }
344                         state = 0;
345                         continue;
346                    
347                 }
348             }
349              // last.. - if g.val.length is 0 then it's a trailing ','...
350              // we should really throw a syntax error in that case..
351             if (k.length && g.val.length) {
352                 ret[k] = g;
353             }
354             return ret;
355             
356             
357         }
358
359     
360     
361 });