c47f66f3e842802d55cd0ca2de9f037e85dfb423
[roobuilder] / src / Palete / VapiParser.vala
1
2
3  // valac -g  --pkg libvala-0.26  --pkg gee-1.0 --pkg json-glib-1.0  --pkg gtk+-3.0   VapiParser.vala Gir.vala GirObject.vala -o /tmp/vdoc
4
5 namespace Palete {
6          
7          public errordomain VapiParserError {
8                 PARSE_FAILED 
9         }
10          
11  
12         public class VapiParser : Vala.CodeVisitor {
13                 
14                 Vala.CodeContext context;
15                  
16                 Project.Gtk project;
17                 
18                 public VapiParser(Project.Gtk project) {
19                         base();
20                         this.project = project;
21                         // should not really happen..
22                         if (project.gir_cache == null) {
23                                 project.gir_cache =       new Gee.HashMap<string,Gir>();
24                         }
25                 }
26                  
27                 
28                 public override void visit_namespace (Vala.Namespace element) 
29                 {
30                         if (element == null) {
31                                 
32                                 return;
33                         }
34                          
35                         
36                         //print("parsing namespace %s\n", element.name);
37                         if (element.name == null) {
38                                 element.accept_children(this); // catch sub namespaces..
39                                 return;
40                         }
41                         this.add_namespace(null, element);
42                 }
43                 public void add_namespace(GirObject? parent, Vala.Namespace element)
44                 {
45                         
46                         
47                         var g = new GirObject("Package",element.name) ;
48                         if (parent == null) {
49                                 this.project.gir_cache.set(element.name, (Gir)g);
50                         } else {
51                                 // we add it as a class of the package.. even though its a namespace..
52                                 parent.classes.set(element.name, g);
53                         }
54                         
55                         
56                         foreach(var c in element.get_classes()) {
57                                 this.add_class(g, c);
58                         }
59                         foreach(var c in element.get_enums()) {
60                                 this.add_enum(g, c);
61                         }
62                         foreach(var c in element.get_interfaces()) {
63                                 this.add_interface(g, c);
64                         }
65                         foreach(var c in element.get_namespaces()) {
66                                 this.add_namespace(g, c);
67                         }
68                         foreach(var c in element.get_methods()) {
69                                 this.add_method(g, c);
70                         }
71                         
72                         foreach(var c in element.get_structs()) {
73                                 this.add_struct(g, c);
74                         }
75                         
76                         element.accept_children(this); // catch sub namespaces..
77                         
78                         
79                 }
80                  
81                 
82                 public void add_enum(GirObject parent, Vala.Enum cls)
83                 {
84                 
85                         var c = new GirObject("Enum",   cls.name);
86                         parent.consts.set(cls.name, c);
87                         c.ns = parent.name;
88                         
89                         c.gparent = parent;
90                         
91                         foreach(var e in cls.get_values()) {
92                                 var em = new GirObject("EnumMember",e.name);
93                                 em.gparent = c;
94                                 em.ns = c.ns;
95                                 
96 #if VALA_0_56
97                                 em.type  = e.type_reference == null ||  e.type_reference.type_symbol == null ? "" : e.type_reference.type_symbol.get_full_name();                       
98 #elif VALA_0_36
99                                 em.type  = e.type_reference == null ||  e.type_reference.data_type == null ? "" : e.type_reference.data_type.get_full_name();
100 #endif                          
101                                 
102                                 
103                                 // unlikely to get value..
104                                 //c.value = element->get_prop("value");
105                                 c.consts.set(e.name,em);
106                         }
107                         
108                          
109                 }
110                 
111                 public void add_interface(GirObject parent, Vala.Interface cls)
112                 {
113                 
114                         var c = new GirObject("Interface", parent.name + "." + cls.name);
115                         parent.classes.set(cls.name, c);
116                         c.ns = parent.name;
117                         //c.parent = cls.base_class == null ? "" : cls.base_class.get_full_name() ;  // extends...
118                         c.gparent = parent;
119                         
120                         foreach(var p in cls.get_properties()) {
121                                 this.add_property(c, p);
122                         }
123                         // methods...
124                         foreach(var p in cls.get_signals()) {
125                                 this.add_signal(c, p);
126                         }
127                         
128                         foreach(var p in cls.get_methods()) {
129                                 // skip static methods..
130                                 if (p.binding != Vala.MemberBinding.INSTANCE &&
131                                         !(p is Vala.CreationMethod)
132                                 ) {
133                                         continue;
134                                 }
135                                 
136                                 this.add_method(c, p);
137                         }
138                         
139                         //if (cls.base_class != null) {
140                         //      c.inherits.add(cls.base_class.get_full_name());
141                         //}
142                         //foreach(var p in cls.get_base_types()) {
143                         //      if (p.data_type != null) {
144                         //              c.implements.add(p.data_type.get_full_name());
145                         //      }
146                         //}
147                           
148                         
149                         
150                          
151                 }
152                 //https://learnxinyminutes.com/docs/vala/ -- see for ctor on structs.
153                 
154                 public void add_struct(GirObject parent, Vala.Struct cls)
155                 {
156                 
157                         var c = new GirObject("Struct", parent.name + "." + cls.name);
158                         parent.classes.set(cls.name, c);
159                           
160                         foreach(var p in cls.get_fields()) {
161                                 this.add_field(c, p);
162                         }
163                         // methods...
164                          
165                           
166                         
167                         if (cls.version.deprecated) { 
168                                 GLib.debug("class %s is deprecated", c.name);
169                                 c.is_deprecated = true;
170                         }
171                         
172                 }
173                 
174                 
175                 
176                 public void add_class(GirObject parent, Vala.Class cls)
177                 {
178                 
179                         var c = new GirObject("Class", parent.name + "." + cls.name);
180                         parent.classes.set(cls.name, c);
181                         c.ns = parent.name;
182                         c.parent = cls.base_class == null ? "" : cls.base_class.get_full_name() ;  // extends...
183                         c.gparent = parent;
184                         c.is_abstract = cls.is_abstract;
185                         foreach(var p in cls.get_properties()) {
186                                 this.add_property(c, p);
187                         }
188                         // methods...
189                         foreach(var p in cls.get_signals()) {
190                                 this.add_signal(c, p);
191                         }
192                         
193                         foreach(var p in cls.get_methods()) {
194                                 // skip static methods..
195                                 if (p.binding != Vala.MemberBinding.INSTANCE &&
196                                         !(p is Vala.CreationMethod)
197                                 ) {
198                                         continue;
199                                 }
200                                 
201                                 this.add_method(c, p);
202                         }
203                         
204                         if (cls.base_class != null) {
205                                 c.inherits.add(cls.base_class.get_full_name());
206                         }
207                         foreach(var p in cls.get_base_types()) {
208 #if VALA_0_56
209                                 if (p.type_symbol != null) {
210                                         c.implements.add(p.type_symbol.get_full_name());
211                                 }
212 #elif VALA_0_36
213                                 if (p.data_type != null) {
214                                         c.implements.add(p.data_type.get_full_name());
215                                 }
216
217 #endif                          
218                                  
219                         }
220                         
221                         if (cls.version.deprecated) { 
222                                 GLib.debug("class %s is deprecated", c.name);
223                                 c.is_deprecated = true;
224                         }
225                         
226                 }
227                 
228                 public GirObject? fqn_to_cls(string fqn)
229                 {
230                         var ar = fqn.split(".");
231                         var pkg = this.project.gir_cache.get(ar[0]);
232                         var cls = pkg != null ? pkg.classes.get(ar[1]) : null;
233                         return cls;
234                 }
235                 
236                 public void augment_inherits_for(GirObject cls, Gee.ArrayList<string> to_check, bool is_top)
237                 {
238                         foreach (var chk_cls in to_check) {
239                                 if (!cls.inherits.contains(chk_cls)) { 
240                                         cls.inherits.add(chk_cls);
241                                         
242                                 } else {
243                                         if (!is_top) {
244                                                 continue;
245                                         }
246                                 }
247                                 
248                                 
249                                 var subcls = this.fqn_to_cls(chk_cls);
250                                 if (subcls == null) {
251                                         continue;
252                                 }
253                                 this.augment_inherits_for(cls, subcls.inherits, false);
254                                 this.augment_implements_for(cls, subcls.implements);
255                         }
256                 
257                 }
258                 public void augment_implements_for(GirObject cls, Gee.ArrayList<string> to_check)
259                 {
260                         foreach (var chk_cls in to_check) {
261                                 if (cls.implements.contains(chk_cls)) { 
262                                         continue;
263                                 }
264                                 cls.implements.add(chk_cls);
265                                 
266                                 var subcls = this.fqn_to_cls(chk_cls);
267                                 if (subcls == null) {
268                                         continue;
269                                 }
270                                 this.augment_implements_for(cls, subcls.implements);
271
272                         }
273                 
274                 }
275                 
276                 // this might miss out interfaces of child classes?
277                 public void augment_all_inheritence()
278                 {
279                         // this works out all the children...
280                         foreach(var pkgname in this.project.gir_cache.keys) {
281                         
282                                 var pkg = this.project.gir_cache.get(pkgname);
283                                 foreach (var clsname in pkg.classes.keys) {
284                                         var cls = pkg.classes.get(clsname);
285                                         this.augment_inherits_for(cls, cls.inherits, true);
286                                         this.augment_implements_for(cls, cls.implements);
287                                 }
288                         }
289                         // now do the implementations
290                         foreach(var pkgname in this.project.gir_cache.keys) {
291                         
292                                 var pkg = this.project.gir_cache.get(pkgname);
293                                 foreach (var clsname in pkg.classes.keys) {
294                                         var cls = pkg.classes.get(clsname);
295                                         foreach(var parentname in cls.inherits) {
296                                                 var parent =  this.fqn_to_cls(parentname);
297                                                 if (parent == null) { 
298                                                         continue;
299                                                 }
300                                                 if (parent.implementations.contains(cls.fqn())) {
301                                                         continue;
302                                                 }
303                                                 parent.implementations.add(cls.fqn());
304                                         
305                                         }
306                                         foreach(var parentname in cls.implements) {
307                                                 var parent =  this.fqn_to_cls(parentname);
308                                                 if (parent == null) { 
309                                                         continue;
310                                                 }
311                                                 if (parent.implementations.contains(cls.fqn())) {
312                                                         continue;
313                                                 }
314                                                 parent.implementations.add(cls.fqn());
315                                         
316                                         }
317                                 }
318                         }
319                         
320                                 
321                 }
322                 
323                  
324                 
325                 public void add_property(GirObject parent, Vala.Property prop)
326                 {
327                         var c = new GirObject("Prop",prop.name);
328                         c.gparent = parent;
329                         c.ns = parent.ns;
330                         c.propertyof = parent.name;
331 #if VALA_0_56
332                         c.type  = prop.property_type.type_symbol == null ? "" : prop.property_type.type_symbol.get_full_name();
333 #elif VALA_0_36
334                         c.type  = prop.property_type.data_type == null ? "" : prop.property_type.data_type.get_full_name();             
335 #endif
336                         c.is_readable = prop.get_accessor != null ?  prop.get_accessor.readable : false;
337                         c.is_writable = prop.get_accessor != null ?  prop.get_accessor.writable : false;
338                         if (prop.version.deprecated) { 
339                                 GLib.debug("class %s is deprecated", c.name);
340                                 c.is_deprecated = true;
341                         }
342                         parent.props.set(prop.name,c);
343
344                         
345                 }
346                 
347                 
348                 public void add_field(GirObject parent, Vala.Field prop)
349                 {
350                         var c = new GirObject("Field",prop.name);
351                         c.gparent = parent;
352                         c.ns = parent.ns;
353                         c.propertyof = parent.name;
354 #if VALA_0_56
355                         c.type  = prop.variable_type.type_symbol == null ? "" : prop.variable_type.type_symbol.get_full_name();
356 #elif VALA_0_36
357                         c.type  = prop.variable_type.data_type == null ? "" : prop.variable_type.data_type.get_full_name();             
358 #endif
359                          
360                         if (prop.version.deprecated) { 
361                                 GLib.debug("class %s is deprecated", c.name);
362                                 c.is_deprecated = true;
363                         }
364                         parent.props.set(prop.name,c);
365
366                         
367                 }
368                 
369                 public void add_signal(GirObject parent, Vala.Signal sig)
370                 {
371                         var c = new GirObject("Signal",sig.name);
372                         c.gparent = parent;
373                         c.ns = parent.ns;
374
375 #if VALA_0_56
376                         var dt  = sig.return_type.type_symbol  ;
377 #elif VALA_0_36
378                         var dt  = sig.return_type.data_type;
379 #endif                  
380                          
381                         
382                         var retval = "";
383                         
384                         if (dt != null) {
385                                 //print("creating return type on signal %s\n", sig.name);
386                                 var cc = new GirObject("Return", "return-value");
387                                 cc.gparent = c;
388                                 cc.ns = c.ns;
389                                 cc.type  =  dt.get_full_name();
390                                 c.return_value = cc;
391                                 
392                                  retval = "\treturn " + cc.type +";";
393                         }
394                         parent.signals.set(sig.name,c);
395                         
396                         var params =  sig.get_parameters() ;
397                         if (params.size < 1) {
398                         
399                                 c.sig = "( ) => {\n\n"+ retval + "\n}\n";
400                         
401                                 return;
402                         }
403                         var cc = new GirObject("Paramset",sig.name); // what's the name on this?
404                         cc.gparent = c;
405                         cc.ns = c.ns;
406                         c.paramset = cc;
407                         
408                         var args = "";                  
409                         foreach(var p in params) {
410                                 this.add_param(cc, p);
411                                 args += args.length > 0 ? ", " : "";
412                                 args += p.name;
413                         }
414                         // add c.sig -> this is the empty 
415                         c.sig = "(" + args + ") => {\n\n"+ retval + "\n}\n";
416                         
417                         
418                         
419                 }       
420                 
421                 public void add_method(GirObject parent, Vala.Method met)
422                 {
423                         var n = met.name == null ? "" : met.name;
424                         var ty  = "Method";
425                         if (met is Vala.CreationMethod) {
426                                 ty = "Ctor";
427                                 if(n == "" || n == ".new") {
428                                         n = "new";
429                                 }
430                                 
431                         }
432                         //print("add_method :  %s\n", n);
433                         
434                         var c = new GirObject(ty,n);
435                         c.gparent = parent;
436                         c.ns = parent.ns;
437 #if VALA_0_56                                           
438                         if (met.return_type.type_symbol != null) {
439 #elif VALA_0_36
440                         if (met.return_type.data_type != null) {
441 #endif  
442                         
443                         
444                                 //print("creating return type on method %s\n", met.name);
445                                 var cc = new GirObject("Return", "return-value");
446                                 cc.gparent = c;
447                                 cc.ns = c.ns;
448
449 #if VALA_0_56                   
450                                 cc.type  =  met.return_type.type_symbol.get_full_name();
451 #elif VALA_0_36
452                                 cc.type  =  met.return_type.data_type.get_full_name();
453 #endif  
454                                 
455                                 
456                                 
457                                 c.return_value = cc;
458                         }
459                         if (met is Vala.CreationMethod) {
460                                 parent.ctors.set(c.name,c);
461                         } else {
462                                 parent.methods.set(met.name,c);
463                         }
464                         
465                         var params =  met.get_parameters() ;
466                         if (params.size < 1) {
467                                 return;
468                         }
469                         var cc = new GirObject("Paramset",met.name); // what's the name on this?
470                         cc.gparent = c;
471                         cc.ns = c.ns;
472                         c.paramset = cc;
473                         c.sig = "(";
474                         
475                         foreach(var p in params) {
476                                 if (p.name == null && !p.ellipsis) {
477                                         continue;
478                                 }
479                                 var pp = this.add_param(cc, p);
480                                 c.sig += (c.sig == "(" ? "" : ",");
481                                 c.sig += " " + (pp.direction == "in" ? "" : pp.direction) + " " + pp.type + " " + pp.name;
482                         }
483                         c.sig += (c.sig == "(" ? ")" : " )");
484                         
485                 }
486                 
487                 public GirObject add_param(GirObject parent, Vala.Parameter pam)
488                 {
489                         
490                         var n = pam.name;
491                         if (pam.ellipsis) {
492                                 n = "___";
493                         }
494                         var c = new GirObject("Param",n);
495                         c.gparent = parent;
496                         c.ns = parent.ns;
497                         c.direction = "??";
498                         switch (pam.direction) {
499                                 case Vala.ParameterDirection.IN:
500                                         c.direction = "in";
501                                         break;
502                                 case Vala.ParameterDirection.OUT:
503                                         c.direction = "out";
504                                         break;
505                                 case Vala.ParameterDirection.REF:
506                                         c.direction = "ref";
507                                         break;
508                         }
509                         
510                         parent.params.add(c);
511                         
512                         if (!pam.ellipsis) {
513 #if VALA_0_56                   
514                                 c.type = pam.variable_type.type_symbol == null ? "" : pam.variable_type.type_symbol.get_full_name();
515 #elif VALA_0_36
516                                 c.type = pam.variable_type.data_type == null ? "" : pam.variable_type.data_type.get_full_name();
517 #endif                          
518                         }
519                         Gir.checkParamOverride(c); 
520                         return c;
521                         
522                 }
523                 
524                 public void create_valac_tree( )
525                 {
526                         // init context:
527                         context = new Vala.CodeContext ();
528                         Vala.CodeContext.push (context);
529                 
530                         context.experimental = false;
531                         context.experimental_non_null = false;
532 #if VALA_0_56
533                         var ver=56;
534 #elif VALA_0_36
535                         var ver=36;
536 #endif
537                         
538                         for (int i = 2; i <= ver; i += 2) {
539                                 context.add_define ("VALA_0_%d".printf (i));
540                         }
541                         
542                          
543                         //var vapidirs = ((Project.Gtk)this.file.project).vapidirs();
544                         // what's the current version of vala???
545                         
546                         
547                         //vapidirs +=  Path.get_dirname (context.get_vapi_path("glib-2.0")) ;
548                          
549                         var vapidirs = context.vapi_directories;
550                         
551                         vapidirs += (BuilderApplication.configDirectory() + "/resources/vapi");
552                         vapidirs += "/usr/share/vala-0.%d/vapi".printf(ver);
553                         vapidirs += "/usr/share/vala/vapi";
554                         context.vapi_directories = vapidirs;
555                         
556                         // or context.get_vapi_path("glib-2.0"); // should return path..
557                         //context.vapi_directories = vapidirs;
558                         context.report.enable_warnings = true;
559                         context.metadata_directories = { };
560                         context.gir_directories = {};
561                         //context.thread = true; 
562                         
563                         
564                         //this.report = new ValaSourceReport(this.file);
565                         //context.report = this.report;
566                         
567                         
568                         context.basedir = "/tmp"; //Posix.realpath (".");
569                 
570                         context.directory = context.basedir;
571                 
572
573                         // add default packages:
574                         //if (settings.profile == "gobject-2.0" || settings.profile == "gobject" || settings.profile == null) {
575 #if VALA_0_56
576                         context.set_target_profile (Vala.Profile.GOBJECT);
577 #elif VALA_0_36
578                         context.profile = Vala.Profile.GOBJECT;
579 #endif
580                          
581                         var ns_ref = new Vala.UsingDirective (new Vala.UnresolvedSymbol (null, "GLib", null));
582                         context.root.add_using_directive (ns_ref);
583                         
584                         
585                         context.add_external_package ("glib-2.0"); 
586                         context.add_external_package ("gobject-2.0");
587                         // user defined ones..
588                         
589                 var dcg = this.project.compilegroups.get("_default_");
590                 for (var i = 0; i < dcg.packages.size; i++) {
591                 
592                         var pkg = dcg.packages.get(i);
593                         // do not add libvala versions except the one that matches the one we are compiled against..
594                         if (Regex.match_simple("^libvala", pkg) && pkg != ("libvala-0." + ver.to_string())) {
595                                 continue;
596                         }
597                                 //valac += " --pkg " + dcg.packages.get(i);
598                                  if (!this.has_vapi(context.vapi_directories, dcg.packages.get(i))) {
599                                  
600                                         continue;
601                                 }
602                                 GLib.debug("ADD vapi '%s'", dcg.packages.get(i));
603                                 context.add_external_package (dcg.packages.get(i));
604                         }                       
605                         
606                         
607                         
608                          
609                         // core packages we are interested in for the builder..
610                         // some of these may fail... - we probalby need a better way to handle this..
611                         /*
612                         context.add_external_package ("gtk+-3.0");
613                         context.add_external_package ("libsoup-2.4");
614                         if (!context.add_external_package ("webkit2gtk-4.0")) {
615                                 context.add_external_package ("webkit2gtk-3.0");
616                         }
617                         // these are supposed to be in the 'deps' file, but it's not getting read..
618                         context.add_external_package ("cogl-1.0");
619                         context.add_external_package ("json-glib-1.0");
620                         context.add_external_package ("clutter-gtk-1.0");
621
622
623                     
624                         context.add_external_package ("gdl-3.0");
625                         context.add_external_package ("gtksourceview-3.0");
626                         context.add_external_package ("vte-2.90"); //??? -- hopefullly that works..
627                         */
628                         //add_documented_files (context, settings.source_files);
629                 
630                         Vala.Parser parser = new Vala.Parser ();
631                         parser.parse (context);
632                         //gir_parser.parse (context);
633                         if (context.report.get_errors () > 0) {
634                                 
635                                 //throw new VapiParserError.PARSE_FAILED("failed parse VAPIS, so we can not write file correctly");
636                                 
637                                 print("parse got errors");
638                                  
639                                 
640                                 Vala.CodeContext.pop ();
641                                 return ;
642                         }
643
644
645                         
646                         // check context:
647                         context.check ();
648                         if (context.report.get_errors () > 0) {
649                                 GLib.error("failed check VAPIS, so we can not write file correctly");
650                                 // throw new VapiParserError.PARSE_FAILED("failed check VAPIS, so we can not write file correctly");
651                                 Vala.CodeContext.pop ();
652                                  
653                                 return;
654                                 
655                         }
656                          
657                         
658                          
659                         context.accept(this);
660                         
661                         context = null;
662                         // dump the tree for Gtk?
663                         
664                         Vala.CodeContext.pop ();
665                         
666                         
667                         this.augment_all_inheritence();
668                         
669                         
670                         
671                         print("ALL OK?\n");
672                  
673                 }
674         //
675                 // startpoint:
676                 //
677          public bool has_vapi(string[] dirs,  string vapi) 
678                 {
679                         for(var i =0 ; i < dirs.length; i++) {
680                                 GLib.debug("check VAPI - %s", dirs[i] + "/" + vapi + ".vapi");
681                                 if (!FileUtils.test( dirs[i] + "/" + vapi + ".vapi", FileTest.EXISTS)) {
682                                         continue;
683                                 }   
684                                 return true;
685                         }
686                         return false;
687                         
688                 }
689         }
690 }
691  /*
692 int main (string[] args) {
693         
694         var g = Palete.Gir.factoryFqn("Gtk.SourceView");
695         print("%s\n", g.asJSONString());
696         
697         return 0;
698 }
699  
700
701 */