JsParser.js
[app.Builder.js] / JsParser.js
1 //<script type="text/javscript">
2
3 XObject = imports.XObject.XObject;
4 console     = imports.console.console;
5 Collapse = imports.JSDOC.Collapse.Collapse;
6 /**
7  * 
8  * this takes our collased file, and turns it into the config array..
9  * 
10  * @see rconv.js (our tester file)
11  * 
12  * STATUS:
13  *
14  *  - Pman.Tab.* appears to work.
15  * .. next up ..Dialog...
16  *
17  *
18  *
19  * Current issues:
20  *  - xtype is combined on generated files. (not xns + xtype)
21  *  - listeners are prefixed with '|' ... 
22  *
23  * 
24  */
25
26 JsParser  =  XObject.define(
27     function (ar)
28     {
29         JsParser.superclass.constructor.call(this, ar);
30        // console.log("STARTING OUTPUT");
31         
32          
33
34     },
35     Collapse, 
36     {
37         
38         cfg : { },
39
40         parse: function()
41         {
42             // standard pman dialog
43             if (this.tokens[0].data == 'Pman.on') {
44                 this.parsePmanLayout();
45                 return;
46             }
47          
48             
49             // Standard Pman Dialog - 
50             if (this.tokens[2].props && typeof(this.tokens[2].props.create) != 'undefined') {
51                 this.parsePmanDialog();
52                 return;
53             }
54             
55             
56             // Seed Gtk XObject application. 
57             if (this.tokens.length > 2 && this.tokens[2].data.match(/^imports\./)) {
58                 this.parseXObject();
59                 return;
60             }
61             
62             Seed.print("Unknown format");
63             Seed.print(JSON.stringify(this.tokens,null,4));
64             Seed.quit();
65             
66             
67             
68             
69             
70             
71             
72             
73             // perfect for dialogs... - is this our 'generic, non-pman code?'
74             
75             
76             var pos = this.lookFor( 'function');
77             
78             // XXXXX = function(
79             var cfg = {};
80             
81             if (pos > -1 && (this.tokens[pos-1].data == '=') && (this.tokens[pos-2].type == 'NAME')) {
82                 
83                 this.cfg = {
84                     '*class' : this.tokens[pos-2].data,
85                     '*extends' : '',
86                     '//constructor' :  this.tokens[pos-2].prefix,
87                     '|constructor' : 'function ' + this.tokens[pos+1].toRaw() + 
88                             this.tokens[pos+2].toRaw()
89                     
90                 };
91                 this.cursor = pos+2;
92                 
93             }
94             
95             if (pos < 0) {
96                 // no function - we have a static one...
97                 pos = this.lookFor( '=');
98                 if (pos > 1 && 
99                     (this.tokens[pos-1].type == 'NAME') &&
100                     (this.tokens[pos+1].data == '{')
101                 ) {
102                     this.cfg = {
103                         '*class' : this.tokens[pos-1].data,
104                         '//*class' :  this.tokens[pos-1].prefix
105                         
106                         
107                     };
108                     XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].props));
109                     return;
110                     
111                 }
112                 
113                 
114                 
115             }
116             
117             
118               // Roo.apply (l
119             var pos = this.lookFor( 'Roo.apply');
120             //console.dump(this.tokens);
121             
122             
123             if (
124                 (pos > -1) &&
125                 (this.tokens[pos+1].items[0][0].data  == this.cfg['*class'] + '.prototype')
126             ) {
127                 // XXXXXx.prototype = {
128                 
129                 
130                     
131                 XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[1][0].props));
132                 return;
133                 
134             }
135             
136             
137             var pos = this.lookFor('new');
138             
139             if (pos > -1 && 
140                 (this.tokens[pos-2].type == 'NAME') &&
141                 (this.tokens[pos-1].data == '=') && 
142                 (this.tokens[pos+1].type == 'NAME') &&
143                 (this.tokens[pos+2].data == '(') 
144             ) {
145                 
146                 this.cfg = {
147                     '//*class' : this.tokens[pos-2].prefix,
148                     '*class' : this.tokens[pos-2].data,
149                     '*extends' : this.tokens[pos+1].data
150                 };
151                     
152                 XObject.extend(this.cfg, this.parseProps(this.tokens[pos+2].items[0][0].props));
153                 
154                 return;
155                 
156             }
157             
158             ///Builder.Provider.ProjectManager = new Roo.Observable({
159                 
160             
161             
162             var pos = this.lookFor( 'Roo.extend');
163             if (pos > -1) {
164                 
165                 this.cfg['*extends'] = this.tokens[pos+1].items[1][0].data;
166                 XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[2][0].props));
167                 
168                 // no more..
169                 return;
170             }
171             
172              
173                 
174             var pos = this.lookFor( 'Roo.extend');
175             if (pos > -1) {
176                 
177                 this.cfg['*extends'] = this.tokens[pos+1].items[1][0].data;
178                 XObject.extend(this.cfg, this.parseProps(this.tokens[pos+1].items[2][0].props));
179                 
180                 // no more..
181                 return;
182             }
183             
184             
185             
186             //console.dump(cfg);
187             //Seed.quit();
188             
189             
190             
191             // other type of layout
192           //  console.dump(this.tokens);
193             
194             // this type of file..
195             // xxxx.xxx = function
196             // -> into |constructor..
197             // -> extend + prototype
198              
199             
200             
201                 
202         },
203         
204         
205         parsePmanLayout : function()
206         {
207                 // then it's a layout style..
208             
209             //Seed.quit();
210             
211             
212             //console.dump(this.tokens);
213             //              the list of statements inside of function..?
214             
215             
216             var stmts =  this.tokens[1].items[1][2].items;
217             
218             // look for register..
219             var topp = false;
220             stmts.map( function(s, i) {
221                 if (s[0].data == 'Pman.register') {
222                     topp = brace = s[1].items[0][0].props;
223                 }
224             });
225             if (!topp) {
226                 console.dump(this.tokens);
227                 throw "could not find top props...";
228                 
229             }
230             
231             this.cfg = this.parseProps(topp);
232             this.cfg.name = this.tokens[3].data;
233             this.cfg.type = 'Roo';
234             
235             //                  (            {          add    { this.panel (  {
236             var cfg = this.tokens[7].items[0][0].props.add.val[2].items[2][3].items[0][0].props;
237             this.cfg.items = [ this.parseProps(cfg) ];
238             //console.dump(this.cfg); 
239         },
240         
241         
242         parsePmanDialog : function() {
243             
244             //console.dump(this.tokens);
245             this.cfg.name = this.tokens[0].data;
246             
247             
248             
249             var cfg = this.tokens[2].props.create.val[2].items[1][3].items[0][0].props;
250             his.cfg.type = 'Roo';
251             //console.dump(this.tokens);
252             //print(JSON.stringify(cfg,null,4)); Seed.quit();
253             
254            // print("Trying standard dialog");Seed.quit();;
255             
256             this.cfg.items = [ this.parseProps(cfg) ];
257             return;
258             
259         },
260         
261         // Seed xobject file.
262         parseXObject : function() {
263             
264             this.parseImports();
265               
266             var pos = this.lookFor('XObject');
267             if (pos < 0)  {
268                 throw "Can not find XObject";
269             }
270             this.cfg.name = this.tokens[pos-3].data;
271             this.cfg.type = 'Gtk';
272             var cfg = this.tokens[pos+1].items[0][0].props;
273             this.cfg.items = [ this.parseProps(cfg) ];
274             
275             //print(JSON.stringify(this.tokens[pos]));
276             
277             //print(JSON.stringify(this.tokens,null,4)); Seed.quit();
278             //Seed.quit();
279             
280         },
281         
282         
283         
284         /**
285          *  parse Imports lines.
286          *
287          */
288         
289         parseImports : function()
290         {
291            // console.dump(this.tokens);
292             this.cfg.giImports = [];
293             this.cfg.imports= [];
294             while (true) {
295                 var pos = this.lookFor('=');
296                 if (pos < 0)  {
297                     break;
298                 }
299                 this.cursor = pos;
300                 var k = this.look(-1, true);
301                 var v = this.look(1, true);
302                // Seed.print(k.data + " => " + v.data);
303                
304                 /// finish!!! - not an import ...
305                
306                 if (!v.data.match(/^imports/)) {
307                     return; ///
308                     
309                     this.cursor++;
310                     continue;
311                 }
312                 if (v.data.match(/^imports\.gi/)) {
313                     // gi import..
314                     this.cfg.giImports.push(v.data.replace(/imports\.gi\./, ''));
315                     
316                     this.cursor++;
317                     continue;
318                 }
319                   
320                 // two types of import left
321                 // imports.xnew
322                 if (v.data.match(/^imports\./)) {
323                     this.cfg.imports[k.data] = v.data.replace(/imports\./, '') + '.js';
324                     this.cursor++;
325                     continue;
326                 }
327                 // imports[.....]
328                 this.cursor++;
329                 if (this.lookFor('[') > this.lookFor('=')) {
330                     continue;
331                 }
332                 var bpos = this.lookFor('[');
333                // console.dump(this.tokens[bpos]);
334                 
335                 this.cfg.imports[k.data] = this.tokens[bpos].items[0][0].toJS();
336                 
337                 this.cursor++;
338                 
339             }
340         //    console.dump(this.giImports);
341           //  console.dump(this.imports);
342             //Seed.quit();
343             
344         },
345         
346         ///------------------- GENERIC PARSING ------------------
347         
348         
349         
350         
351         
352         
353         parseProps:  function(o)
354         {
355             //print(JSON.stringify(o,null,4));
356             
357             var ret = { };
358             var fakeItems =  [];
359             for(var k in o) {
360                 
361                 //print( "parsing prop: " + k);
362                 if (o[k].key.data == '}') {
363                     // typo trailing comma in object def.
364                     continue;
365                 }
366                 
367                 var kv = k;
368                 if (o[k].key.type == 'STRN') {
369                     kv = o[k].key.toJS();
370                 }
371                 if (!o[k].val.length) {
372                     console.dump(o[k]);
373                 }
374                 
375                 //console.dump(o[k]);
376                 if (o[k].val[0].data == "function") {
377                     // add comments..
378                   //   console.dump(o[k].key.prefix); 
379                     var pr = typeof(o[k].key.prefix) == 'undefined' ? '' : o[k].key.prefix ;
380                     pr = this.clean_prefix( pr) ;
381                     if (pr.length) {
382                         ret['//' +kv ] =  pr;
383                     }
384                     //print("running expand");
385                     ret['|' +kv ] =  this.clean_body( this.expand(o[k].val));
386                     continue;
387                 }
388                 
389                 
390                 if (o[k].val[0].data == "[") {
391                     
392                     if (o[k].val[0].items[0][0].data == '{') {
393                         // array of objects..
394                         
395                         // this works for items..
396                         
397                         // used elsewhere for buttons: -> in which case we have a fake xtype
398                         
399                         
400                         
401                         // if K is not ITEMS - we need to add '*prop' -> and add it to the items array..
402                         var add = this.parseArray(o[k].val[0].items);
403                         if (kv == 'items') {
404                             ret[kv] = add;
405                             continue;
406                         }
407                         var fake_array = {
408                             xtype : 'Array.' + kv,
409                             '*prop' : kv,
410                             items : add
411                         }
412                         fakeItems.push(fake_array);
413                         continue;
414                     } 
415                     // raw array 
416                     
417                     
418                     ret['|' +kv ] =  this.clean_body(this.expand(o[k].val)); // remove ','...
419                     continue;
420                 }
421                 if (o[k].val[0].data == "(") {
422                     ret['|' +kv ] =  this.expand(o[k].val);
423                     continue;
424                 }
425                 // value is an object..
426                 
427                 if (o[k].val[0].data == "{") {
428                     
429                     // things that can be property of object type:
430                     // listeners, set, 
431                     var add = this.parseProps(o[k].val[0].props);
432                     
433                     
434                     
435                     if (kv == 'set' || kv =='listeners') {
436                         ret[kv ] = add;
437                         continue;
438                     }
439                     if ((typeof(add.xtype) != 'undefined') ||  ['sortInfo', 'center', 'east', 'west', 'north', 'south'].indexOf(kv) > -1) {
440                         add['*prop'] =  kv;
441                         fakeItems.push(add);
442                         continue;
443                     }
444                     
445                     
446                     ret[ '|' + kv ] =  this.expand(o[k].val);
447                     
448                     
449                     // this hsould be added to 'items', with a *prop element..
450                     continue;
451                 }
452                 //console.dump(o[k].val);
453                 
454                 if (o[k].val[1].data == ',' || o[k].val[1].data == '}') {
455                     // single item piece of data...
456                     var t1= o[k].val[0];
457                     switch(o[k].val[0].type) {
458                         case 'STRN':
459                         case 'NUMB':
460                         case 'KEYW':
461                             ret[  kv ]  = t1.toJS();
462                             continue;
463                         case 'NAME':
464                             ret[ '|' + kv ] =  t1.data;
465                             continue;
466                         
467                     }
468                 }
469                
470                 ret[ '|' + kv ] =  this.expand(o[k].val);
471                 
472             }
473             if (!ret.items && fakeItems.length) {
474                 ret.items = [];
475             }
476             fakeItems.forEach(  function(e) {
477                 ret.items.push(e);
478             });
479             // merge fakeItems;
480             //console.dump(ret);
481             
482             return ret;
483         },
484         parseArray: function(ar) {
485           // console.dump(ar);
486            // Seed.quit();
487             var ret = [];
488             ar.map(function (e) {
489                 // has no props...
490                 if (typeof(e[0].props) == 'undefined') {
491                     return;
492                 }
493                
494                 
495                 ret.push( this.parseProps(e[0].props));
496                      
497             },this);
498              
499             return ret;
500           
501         },
502         
503         /**
504          * convert a function call token array back into a string
505          */
506         expand: function(ar)
507         {
508             var ret = '';
509             //print(JSON.stringify(ar,null,4));
510              
511             for(var i =0 ; i < ar.length -1; i++) {
512                 ret += ar[i].toRaw();
513             }
514             
515             return ret;
516             
517             
518         },
519         
520         /***
521          * change the indentation on a function 
522          *
523          */
524         clean_body : function(str)
525         {
526             var lns = str.split("\n");
527             var mindent = -1;
528             lns.map( function(l, i) {
529                 if (!i || !l.length || l.match(/^\s+$/)) {
530                     return;
531                 }
532                 
533                 var spc = l.match(/\s+/);
534                 if (!spc || !spc[0].length) {
535                     return;
536                 }
537                 mindent = mindent < 0 ? spc[0].length : Math.min(spc[0].length, mindent);
538                 
539             });
540             //console.log(mindent + ":" + lns[0]);
541             var ar = [];
542             if (mindent < 0) {
543                 return str;
544             }
545             lns.map( function(l,i) {
546                 if (!i) {
547                     ar.push(l.replace(/^\s+/, ''));
548                     return;
549                 }
550                 ar.push(l.substring(mindent));
551             });
552             print(str);
553             print(JSON.stringify(ar,null,4));
554             
555             
556             return ar.join("\n");
557         },
558         clean_prefix: function(str) {
559             
560             
561             
562             if (!str.length) {
563                 return '';
564             }
565             var ret = str.replace(/^\s+/gm, "\n").replace(/\n+/gm, "\n");
566             return ret == "\n" ? '' : ret;
567             
568         }    
569              
570     
571 });