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