src/Palete/ValaSource.vala
[app.Builder.js] / src / Palete / ValaSource.vala
1
2 // valac TreeBuilder.vala --pkg libvala-0.24 --pkg posix -o /tmp/treebuilder
3
4 namespace Palete {
5         
6         public errordomain ValaSourceError {
7                 INVALID_FORMAT 
8         }
9         
10         public delegate  void ValaSourceResult(Json.Object res);
11         
12         public class ValaSourceReport  : Vala.Report {
13
14                 public string filepath;
15                 
16                 public string tmpname;
17                 
18                 //public Gee.ArrayList<ValaSourceNotice> notices;
19                 public Json.Object result;
20                  
21                 //public Gee.HashMap<int,string> line_errors;
22                 
23                 public void  compile_notice(string type, string filename, int line, string message) {
24                          
25                          if (!this.result.has_member(type+"-TOTAL")) {
26                                  this.result.set_int_member(type+"-TOTAL", 1);
27                          } else {
28                                 this.result.set_int_member(type+"-TOTAL", 
29                                         this.result.get_int_member(type+"-TOTAL") +1 
30                                 );
31                          }
32                          
33                          
34                          if (!this.result.has_member(type)) {
35                                  this.result.set_object_member(type, new Json.Object());
36                          }
37                          var t = this.result.get_object_member(type);
38                          if (!t.has_member(filename)) {
39                                  t.set_object_member(filename, new Json.Object());
40                          }
41                          var tt = t.get_object_member(filename);
42                          if (!tt.has_member(line.to_string())) {
43                                  tt.set_array_member(line.to_string(), new Json.Array());
44                          }
45                          var tl = tt.get_array_member(line.to_string());
46                          tl.add_string_element(message);
47                          
48                 }
49                 
50                 
51          
52                 public ValaSourceReport(string filepath, string tmpname)
53                 {
54                         base();
55                         this.filepath = filepath;
56                         this.tmpname = tmpname;
57                         this.result = new Json.Object();
58                         this.result.set_boolean_member("success", true);
59                         this.result.set_string_member("message", "");
60                         
61                         
62                         
63                         //this.line_errors = new Gee.HashMap<int,string> ();
64                         //this.notices = new Gee.ArrayList<ValaSourceNotice>();
65                 }
66                 
67                 public override void warn (Vala.SourceReference? source, string message) {
68                          
69                         if (source == null) {
70                                 return;
71                                 //stderr.printf ("My error: %s\n", message);
72                         }
73                         
74                         if (source.file.filename != this.tmpname) {
75                                 this.compile_notice("WARN", source.file.filename , source.begin.line, message);
76                                 return;
77                         }
78                         this.compile_notice("WARN", this.filepath, source.begin.line, message);
79                         
80                 }
81                 public override void depr (Vala.SourceReference? source, string message) {
82                          
83                         if (source == null) {
84                                 return;
85                                 //stderr.printf ("My error: %s\n", message);
86                         }
87                         
88                         if (source.file.filename != this.tmpname) {
89                                 this.compile_notice("DEPR", source.file.filename, source.begin.line, message);
90                                 return;
91                         }
92                         this.compile_notice("DEPR",  this.filepath, source.begin.line, message);
93                         
94                 }
95                 
96                 public override void err (Vala.SourceReference? source, string message) {
97                         errors++;
98                         if (source == null) {
99                                 return;
100                                 //stderr.printf ("My error: %s\n", message);
101                         }
102                         if (source.file.filename != this.tmpname) {
103                                 this.compile_notice("ERR", source.file.filename, source.begin.line, message);
104                                 GLib.debug ("Other file: Got error error: %d:  %s\n", source.begin.line, message);
105                                 return;
106                         }
107                          
108                          
109                         this.compile_notice("ERR", this.filepath, source.begin.line, message);
110                         GLib.debug ("Test file: Got error error: %d: %s\n", source.begin.line, message);
111                 }
112                 /*
113                 public void dump()
114                 {
115                         var iter = this.line_errors.map_iterator();
116                         while (iter.next()) {
117                                 print ("%d : %s\n\n", iter.get_key(), iter.get_value());
118                         }
119                 }
120                 */
121
122         }
123
124         public class ValaSource : Object {
125
126                 public static void jerr(string str)
127                 {
128                         var ret = new Json.Object(); 
129                         ret.set_boolean_member("success", false);
130                         ret.set_string_member("message", str);
131                         
132                         var  generator = new Json.Generator ();
133                         var  root = new Json.Node(Json.NodeType.OBJECT);
134                         root.init_object(ret);
135                         generator.set_root (root);
136                          
137                         generator.pretty = true;
138                         generator.indent = 4;
139                  
140
141                         print("%s\n",  generator.to_data (null));
142                         GLib.Process.exit(Posix.EXIT_FAILURE);
143                         
144                 }
145
146                 public static void buildApplication()
147                 {
148                         //print("build based on Application settings\n");
149                         
150                         if (BuilderApplication.opt_compile_target == null) {
151                                 jerr("missing compile target --target");
152                         }
153                         
154                         Project.Project.loadAll();
155                         var proj = Project.Project.getProjectByHash(BuilderApplication.opt_compile_project);
156                         
157                         if (proj == null) {
158                                 jerr("could not load test project %s".printf( BuilderApplication.opt_compile_project));
159                         }
160                         
161                         if (proj.xtype != "Gtk") {
162                                 jerr("%s is not a Gtk Project".printf( BuilderApplication.opt_compile_project));
163                         }
164                         var gproj = (Project.Gtk)proj;
165                         
166                         
167                         if (!gproj.compilegroups.has_key(BuilderApplication.opt_compile_target)) {
168                                 jerr("missing compile target %s".printf(BuilderApplication.opt_compile_target));
169                         }
170                         var skip_file = "";
171                         if (BuilderApplication.opt_compile_skip != null) {
172                                 skip_file = BuilderApplication.opt_compile_skip;
173                         }
174                         var add_file = "";
175                         if (BuilderApplication.opt_compile_add != null) {
176                                 add_file = BuilderApplication.opt_compile_add;
177                         }
178                         
179                         
180                         var vs = new ValaSource(gproj,  add_file, BuilderApplication.opt_compile_target,   skip_file);
181                         vs.compile();
182                         
183                         
184                 }
185
186                 Vala.CodeContext context;
187                 ValaSourceReport report;
188                 Project.Gtk project;
189                 public string build_module;
190                 public string filepath;
191                 public string original_filepath;
192                 public int line_offset = 0;
193                 
194                 // file.project , file.path, file.build_module, ""
195                 public ValaSource(Project.Gtk project, string filepath, string build_module, string original_filepath) {
196                         base();
197                         //this.file = file;
198                         this.filepath = filepath;
199                         this.build_module = build_module;
200                         this.original_filepath = original_filepath;
201                         this.project =  project;
202                         
203                 }
204                 public void dumpCode(string str) 
205                 {
206                         var ls = str.split("\n");
207                         for (var i=0;i < ls.length; i++) {
208                                 print("%d : %s\n", i+1, ls[i]);
209                         }
210                 }
211                 
212                 //public Gee.HashMap<int,string> checkFile()
213                 //{
214                 //      return this.checkString(JsRender.NodeToVala.mungeFile(this.file));
215                 //}
216
217                 public void checkFileWithNodePropChange(
218                                         JsRender.JsRender file,
219                                         JsRender.Node node, 
220                                         string prop,
221                                         string ptype,
222                                         string val,
223                                         ValaSourceResult result_cb)
224                 {
225                         
226                         
227                         
228                         Gee.HashMap<int,string> ret = new Gee.HashMap<int,string> ();
229                         var hash = ptype == "listener" ? node.listeners : node.props;
230                         
231                         // untill we get a smarter renderer..
232                         // we have some scenarios where changing the value does not work
233                         if (prop == "* xns" || prop == "xtype") {
234                                 result_callback(new Json.Object());
235                                 return ;
236                         }
237                                 
238                         
239                         var old = hash.get(prop);
240                         var newval = "/*--VALACHECK-START--*/ " + val ;
241                         
242                         hash.set(prop, newval);
243                         var tmpstring = JsRender.NodeToVala.mungeFile(file);
244                         hash.set(prop, old);
245                         //print("%s\n", tmpstring);
246                         var bits = tmpstring.split("/*--VALACHECK-START--*/");
247                         var offset =0;
248                         if (bits.length > 0) {
249                                 offset = bits[0].split("\n").length +1;
250                         }
251                         
252                         this.line_offset = offset;
253                         
254                         //this.dumpCode(tmpstring);
255                         //print("offset %d\n", offset);
256                         this.result_callback = result_cb;
257                         this.checkStringSpawn(tmpstring );
258                         
259                         // modify report
260                         
261                         
262                         
263                 }
264                 Spawn compiler;
265                 ValaSourceResult result_callback;
266                 public void checkStringSpawn(
267                                         string contents 
268                                 )
269                 {
270                         
271                         FileIOStream iostream;
272                         var tmpfile = File.new_tmp ("test-XXXXXX.vala", out iostream);
273                         tmpfile.ref();
274
275                         OutputStream ostream = iostream.output_stream;
276                         DataOutputStream dostream = new DataOutputStream (ostream);
277                         dostream.put_string (contents);
278                         
279                         
280                         string[] args = {};
281                         args += FileUtils.read_link("/proc/self/exe");
282                         args += "--project";
283                         args += this.project.fn;
284                         args += "--target";
285                         args += this.build_module;
286                         args += "--add-file";
287                         args +=  tmpfile.get_path();
288                         args += "--skip-file";
289                         args += this.filepath;
290                         
291                          
292                         
293                         this.compiler = new Spawn("/tmp", args);
294                         
295                         try {
296                                 this.compiler.run(spawnResult); 
297                         } catch (Error e) {
298                                 var ret = new Json.Object();
299                                 ret.set_boolean_member("success", false);
300                                 ret.set_string_member("message", e.message);
301                                 this.result_callback(ret);
302                         }
303                          
304                 }
305                 public void spawnResult(int res, string output, string stderr)
306                 {
307                          
308                                 
309                         try { 
310                                 GLib.debug("GOT output %s", output);
311                                 
312                                 var pa = new Json.Parser();
313                                 pa.load_from_data(output);
314                                 var node = pa.get_root();
315
316                                 if (node.get_node_type () != Json.NodeType.OBJECT) {
317                                         throw new ValaSourceError.INVALID_FORMAT ("Unexpected element type %s", node.type_name ());
318                                 }
319                                 var ret = node.get_object ();
320                                 ret.set_int_member("line_offset", this.line_offset);
321                                 if (result_callback == null) {
322                                         print ("no callback?");
323                                         return;
324                                 }
325                                 this.result_callback(ret);
326                                 
327                                 
328                         } catch (Error e) {
329                                 var ret = new Json.Object();
330                                 ret.set_boolean_member("success", false);
331                                 ret.set_string_member("message", e.message);
332                                 this.result_callback(ret);
333                         }
334                         //compiler.unref();
335                         //tmpfile.unref();
336                          
337                         
338                         
339                 }
340                 
341                 public void compile( )
342                 {
343                         // init context:
344                         var valac = "valac " ;
345                         
346                         context = new Vala.CodeContext ();
347                         Vala.CodeContext.push (context);
348                 
349                         context.experimental = false;
350                         context.experimental_non_null = false;
351                         
352 #if VALA_0_28
353                         var ver=28;
354 #elif VALA_0_26 
355                         var ver=26;
356 #elif VALA_0_24
357                         var ver=24;
358 #elif VALA_0_22 
359                         var ver=22;
360 #endif
361                         
362                         for (int i = 2; i <= ver; i += 2) {
363                                 context.add_define ("VALA_0_%d".printf (i));
364                         }
365                         
366                         
367                         
368                          
369                         var vapidirs = this.project.vapidirs();
370                          vapidirs +=  Path.get_dirname (context.get_vapi_path("glib-2.0")) ; // usr/share/vala-XXX/vapi
371                          vapidirs +=  Path.get_dirname (context.get_vapi_path("gee-1.0")) ; //usr/share/vala/vapi 
372                                 
373                         for(var i =0 ; i < vapidirs.length; i++) {
374                                 valac += " --vapidir=" + vapidirs[i];
375                         }
376                                 
377                         
378                         context.vapi_directories = vapidirs;
379                         context.report.enable_warnings = true;
380                         context.metadata_directories = { };
381                         context.gir_directories = {};
382                         context.thread = true;
383                          
384                         
385                         this.report = new ValaSourceReport(this.original_filepath, this.filepath);
386                         context.report = this.report;
387                         
388                         
389                         context.basedir = "/tmp"; //Posix.realpath (".");
390                 
391                         context.directory = context.basedir;
392                 
393
394                         // add default packages:
395                         //if (settings.profile == "gobject-2.0" || settings.profile == "gobject" || settings.profile == null) {
396                         context.profile = Vala.Profile.GOBJECT;
397                          
398                         var ns_ref = new Vala.UsingDirective (new Vala.UnresolvedSymbol (null, "GLib", null));
399                         context.root.add_using_directive (ns_ref);
400
401                         var source_file = new Vala.SourceFile (
402                                 context, 
403                                 Vala.SourceFileType.SOURCE, 
404                                         this.filepath 
405                         );
406                         source_file.add_using_directive (ns_ref);
407                         context.add_source_file (source_file);
408                         
409                 // add all the files (except the current one) - this.file.path
410                 var pr = this.project;
411                 if (this.build_module.length > 0) {
412                                 var cg =  pr.compilegroups.get(this.build_module);
413                                 for (var i = 0; i < cg.sources.size; i++) {
414                                         var path = pr.resolve_path(
415                                                         pr.resolve_path_combine_path(pr.firstPath(),cg.sources.get(i)));
416                                                         
417                                         if (!FileUtils.test(path, FileTest.EXISTS)) {
418                                                 continue;
419                                         }       
420                         // skip thie original
421                                         if (path == this.original_filepath.replace(".bjs", ".vala")) {
422                                                 valac += " " + path;
423                                                 continue;
424                                         }
425                                         if (FileUtils.test(path, FileTest.IS_DIR)) {
426                                                 continue;
427                                         }
428                                         //print("Add source file %s\n", path);
429                                         
430                                         valac += " " + path;
431                                         
432                                         if (Regex.match_simple("\\.c$", path)) {
433                                                 context.add_c_source_file(path);
434                                                 continue;
435                                         }
436                                         
437                                         
438                                         var xsf = new Vala.SourceFile (
439                                                 context,
440                                                 Vala.SourceFileType.SOURCE, 
441                                                 path
442                                         );
443                                         xsf.add_using_directive (ns_ref);
444                                         context.add_source_file(xsf);
445                                         
446                                 }
447                         }
448                         // default.. packages..
449                         context.add_external_package ("glib-2.0"); 
450                         context.add_external_package ("gobject-2.0");
451                         // user defined ones..
452                         
453                 var dcg = pr.compilegroups.get("_default_");
454                 for (var i = 0; i < dcg.packages.size; i++) {
455                                 valac += " --pkg " + dcg.packages.get(i);
456                                 if (!this.has_vapi(context.vapi_directories, dcg.packages.get(i))) {
457                                         GLib.debug("Skip vapi '%s' - does not exist", dcg.packages.get(i));
458                                         continue;
459                                 }
460                                 
461                                 context.add_external_package (dcg.packages.get(i));
462                         }
463                 
464                          //Vala.Config.PACKAGE_SUFFIX.substring (1)
465                         
466                         // add the modules...
467                         
468                         context.output = "/tmp/testbuild";
469                         valac += " -o " +context.output;
470                         GLib.debug("%s", valac);
471                         
472                         
473  
474                 
475                         //add_documented_files (context, settings.source_files);
476                 
477                         Vala.Parser parser = new Vala.Parser ();
478                         parser.parse (context);
479                         //gir_parser.parse (context);
480                         if (context.report.get_errors () > 0) {
481                                 Vala.CodeContext.pop ();
482                                 GLib.debug("parse got errors");
483                                 //((ValaSourceReport)context.report).dump();
484                                 this.report.result.set_boolean_member("success", false);
485                                 this.report.result.set_string_member("message", "Parse failed");
486                                 
487                                 this.outputResult();
488                                 return;
489                         }
490
491
492                         
493                         // check context:
494                         context.check ();
495                         if (context.report.get_errors () > 0) {
496                                 Vala.CodeContext.pop ();
497                                 GLib.debug("check got errors");
498                                 //((ValaSourceReport)context.report).dump();
499                                 this.report.result.set_boolean_member("success", false);
500                                 this.report.result.set_string_member("message", "Check failed");
501                                 
502                                 this.outputResult();
503                                 return;
504                         }
505                         
506                         //context.codegen = new Vala.GDBusServerModule ();
507                         
508                          
509                         
510                         //context.codegen.emit (context);
511                         /*
512                         var ccompiler = new Vala.CCodeCompiler ();
513                         var cc_command = Environment.get_variable ("CC");
514                         var pkg_config_command = Environment.get_variable ("PKG_CONFIG");
515 #if VALA_0_28
516                         ccompiler.compile (context, cc_command, new string[] { }, pkg_config_command);
517 #else
518                         ccompiler.compile (context, cc_command, new string[] { });
519 #endif
520                         */
521  
522                         Vala.CodeContext.pop ();
523                         this.outputResult();
524                 
525                 }
526                 public bool has_vapi(string[] dirs,  string vapi) 
527                 {
528                         for(var i =0 ; i < dirs.length; i++) {
529                                 GLib.debug("check VAPI - %s", dirs[i] + "/" + vapi + ".vapi");
530                                 if (!FileUtils.test( dirs[i] + "/" + vapi + ".vapi", FileTest.EXISTS)) {
531                                         continue;
532                                 }   
533                                 return true;
534                         }
535                         return false;
536                         
537                 }
538                 
539                 public void outputResult()
540                 {
541                         var generator = new Json.Generator ();
542                     generator.indent = 1;
543                     generator.pretty = true;
544                     var node = new Json.Node(Json.NodeType.OBJECT);
545                     node.set_object(this.report.result);
546                     
547                     generator.set_root(node);
548                          
549                         generator.pretty = true;
550                         generator.indent = 4;
551                  
552
553                         print("%s\n",  generator.to_data (null));
554                         GLib.Process.exit(Posix.EXIT_SUCCESS);
555                         
556                          
557                 }
558 /*              
559                 
560                 
561                 public Gee.HashMap<int,string> checkString(string contents)
562                 {
563                         // init context:
564                         var valac = "valac " ;
565                         
566                         context = new Vala.CodeContext ();
567                         Vala.CodeContext.push (context);
568                 
569                         context.experimental = false;
570                         context.experimental_non_null = false;
571                         
572 #if VALA_0_28
573                         var ver=28;
574 #elif VALA_0_26 
575                         var ver=26;
576 #elif VALA_0_24
577                         var ver=24;
578 #elif VALA_0_22 
579                         var ver=22;
580 #endif
581                         
582                         for (int i = 2; i <= ver; i += 2) {
583                                 context.add_define ("VALA_0_%d".printf (i));
584                         }
585                         
586                         
587                         
588                         
589                         
590                         
591                         
592                         var vapidirs = ((Project.Gtk)this.file.project).vapidirs();
593                         // what's the current version of vala???
594                         
595                         
596                         vapidirs +=  Path.get_dirname (context.get_vapi_path("glib-2.0")) ;
597                         
598                         for(var i =0 ; i < vapidirs.length; i++) {
599                                 valac += " --vapidir=" + vapidirs[i];
600                         }
601                                 
602                         
603                         // or context.get_vapi_path("glib-2.0"); // should return path..
604                         context.vapi_directories = vapidirs;
605                         context.report.enable_warnings = true;
606                         context.metadata_directories = { };
607                         context.gir_directories = {};
608                         context.thread = true;
609                         
610                         
611                         this.report = new ValaSourceReport(this.file.path);
612                         context.report = this.report;
613                         
614                         
615                         context.basedir = "/tmp"; //Posix.realpath (".");
616                 
617                         context.directory = context.basedir;
618                 
619
620                         // add default packages:
621                         //if (settings.profile == "gobject-2.0" || settings.profile == "gobject" || settings.profile == null) {
622                         context.profile = Vala.Profile.GOBJECT;
623                          
624                         var ns_ref = new Vala.UsingDirective (new Vala.UnresolvedSymbol (null, "GLib", null));
625                         context.root.add_using_directive (ns_ref);
626
627                         var source_file = new Vala.SourceFile (
628                                 context, 
629                                 Vala.SourceFileType.SOURCE, 
630                                         "~~~~~testfile.vala",
631                                         contents
632                         );
633                         source_file.add_using_directive (ns_ref);
634                         context.add_source_file (source_file);
635                         
636                 // add all the files (except the current one) - this.file.path
637                 var pr = ((Project.Gtk)this.file.project);
638                 if (this.file.build_module.length > 0) {
639                                 var cg =  pr.compilegroups.get(this.file.build_module);
640                                 for (var i = 0; i < cg.sources.size; i++) {
641                                         var path = pr.resolve_path(
642                                                         pr.resolve_path_combine_path(pr.firstPath(),cg.sources.get(i)));
643                                                         
644                                         if (!FileUtils.test(path, FileTest.EXISTS)) {
645                                                 continue;
646                                         }       
647                          
648                                         if (path == this.file.path.replace(".bjs", ".vala")) {
649                                                 valac += " " + path;
650                                                 continue;
651                                         }
652                                         if (FileUtils.test(path, FileTest.IS_DIR)) {
653                                                 continue;
654                                         }
655                                         //print("Add source file %s\n", path);
656                                         
657                                         valac += " " + path;
658                                         
659                                         if (Regex.match_simple("\\.c$", path)) {
660                                                 context.add_c_source_file(path);
661                                                 continue;
662                                         }
663                                         
664                                         
665                                         var xsf = new Vala.SourceFile (
666                                                 context,
667                                                 Vala.SourceFileType.SOURCE, 
668                                                 path
669                                         );
670                                         xsf.add_using_directive (ns_ref);
671                                         context.add_source_file(xsf);
672                                         
673                                 }
674                         }
675                         // default.. packages..
676                         context.add_external_package ("glib-2.0"); 
677                         context.add_external_package ("gobject-2.0");
678                         // user defined ones..
679                         
680                 var dcg = pr.compilegroups.get("_default_");
681                 for (var i = 0; i < dcg.packages.size; i++) {
682                                 valac += " --pkg " + dcg.packages.get(i);
683                                 context.add_external_package (dcg.packages.get(i));
684                         }
685                 
686                          //Vala.Config.PACKAGE_SUFFIX.substring (1)
687                         
688                         // add the modules...
689                         
690                         
691                         
692                         //context.add_external_package ("libvala-0.24");
693                         
694                         this.report.compile_notice("START", "", 0, "");
695
696                 
697                         //add_documented_files (context, settings.source_files);
698                 
699                         Vala.Parser parser = new Vala.Parser ();
700                         parser.parse (context);
701                         //gir_parser.parse (context);
702                         if (context.report.get_errors () > 0) {
703                                 print("parse got errors");
704                                 ((ValaSourceReport)context.report).dump();
705                                 
706                                 Vala.CodeContext.pop ();
707                                 this.report.compile_notice("END", "", 0, "");
708                                 return this.report.line_errors;
709                         }
710
711
712                         
713                         // check context:
714                         context.check ();
715                         if (context.report.get_errors () > 0) {
716                                 print("check got errors");
717                                 ((ValaSourceReport)context.report).dump();
718                                 Vala.CodeContext.pop ();
719                                 this.report.compile_notice("END", "", 0, "");
720                                 return this.report.line_errors;
721                                 
722                         }
723                         
724                         //context.codegen = new Vala.GDBusServerModule ();
725                         
726                          
727                         context.output = "/tmp/testbuild";
728                         valac += " -o " +context.output;
729                         //context.codegen.emit (context);
730                          odeContext.pop ();
731                         //(new Vala.CodeNode()).get_error_types().clear();
732                         //(new Vala.NullType()).get_type_arguments().clear();
733                         (new Vala.NullType(null)).get_type_arguments().clear();
734                         parser = null;
735                         this.report.compile_notice("END", "", 0, "");
736                         print("%s\n", valac);
737                         print("ALL OK?\n");
738                         return this.report.line_errors;
739                 }
740         //
741                 // startpoint:
742                 //
743          */
744         }
745 }
746 /*
747 int main (string[] args) {
748
749         var a = new ValaSource(file);
750         a.create_valac_tree();
751         return 0;
752 }
753 */
754
755