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  * @namespace JSDOC
16  * @class Collapse
17  * @extends 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                                     
233                                     
234                                 } else {
235                                     // check for types.. it could be a list of statements.. or object
236                                     
237                                     var ost = new  TokenStream(toks);
238                                     //console.dump(ost.look(2,true) );
239                                     if (ost.look(2,true) && ost.look(2,true).data == ":") {
240                                         tok.props = this.toProps(toks);
241                                     } else {
242                                         // list of statemetns..
243                                         tok.items = this.toItems(toks,[ ';', '{'] ); 
244                                     }
245                                     
246                                     
247                                 }
248                                  
249                                 
250                                 
251                                 
252                                 
253                                 
254                                 
255                                 //Seed.print(" ADD : " + add.length  +  " ITEMS: " + tok.items.length);
256                                 
257                                 ret.push(tok);
258                                 
259                                 continue;
260                    
261                             default:
262                                 ret.push(st.next(1));
263                                 continue;
264                         }
265                         Seed.print("OOPS");
266                         continue;
267                     default : 
268                         Seed.print("OOPS" + tok.type);
269                         continue;
270                 }
271             }
272                 
273                 
274             
275             
276             
277             
278             
279             
280             
281             
282         },
283         toItems : function(ar,sep)
284         {
285             var ret = [];
286             var g = [];
287               
288             for (var i = 0; i < ar.length; i ++) {
289                 if (sep.indexOf(ar[i].data) < 0) {
290                     g.push(ar[i]);
291                     continue;
292                 }
293                 // var a=..., b =...
294                 if ((ar[i].data != ';') && g.length && (g[0].name == "VAR")) {;
295                     g.push(ar[i]);
296                     continue;
297                 }
298                 
299                 g.push(ar[i]);
300                 ret.push(g);
301                 g = [];
302                 
303             }
304             // last..
305             if (g.length) {
306                 ret.push(g);
307             }
308             return ret;
309             
310         },
311         toProps : function(ar)
312         {
313             
314             var ret = { }
315                
316             var g = { key : '', val: [] }
317                
318             
319             var k = '';
320             var state = 0;
321             for (var i = 0; i < ar.length; i ++) {
322                 
323                 switch(state) {
324                     case 0:
325                         k = ar[i].data;
326                         g.key = ar[i];
327                         state = 1;
328                         continue;
329                     case 1:
330                         state =2; // should be ':'
331                         continue;
332                     case 2:
333                         g.val.push(ar[i]);
334                         if (ar[i].data != ',') {
335                             continue;
336                         }
337                         ret[k] = g;
338                         g = { key : '', val: [] }
339                         state = 0;
340                         continue;
341                    
342                 }
343             }
344              // last.. - if g.val.length is 0 then it's a trailing ','...
345              // we should really throw a syntax error in that case..
346             if (k.length && g.val.length) {
347                 ret[k] = g;
348             }
349             return ret;
350             
351             
352         }
353
354     
355     
356 });