2 // driver.cs: Guides the compilation process through the different phases.
5 // Cesar Lopez Nataren (cesar@ciencias.unam.mx)
7 // (C) 2003, Cesar Lopez Nataren
8 // (C) Copyright 2005, Novell Inc. (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using Microsoft.JScript;
37 using System.Reflection;
38 using System.Collections;
39 using Microsoft.JScript.Vsa;
40 using System.Reflection.Emit;
43 namespace Mono.JScript {
47 // Assemblies references to be linked. Initialized with
50 private static ArrayList references;
53 private static ArrayList link_paths;
56 private static ArrayList files;
58 private static string first_source;
60 private static bool want_debugging_support = false;
62 private static string output_file;
64 private static Assembly [] assemblies = new Assembly [0];
66 private static bool StdLib;
68 private static void Usage ()
70 Console.WriteLine ("Mono JScript compiler\n" +
71 "(C) 2003 - 2004 Cesar Lopez Nataren\n" +
72 "(C) 2004 - 2005 Novell Inc (http://novell.com)\n\n" +
73 "mjs [options] source-file\n" +
74 " /about About the Mono JScript compiler\n" +
75 " /lib:PATH1,PATH2 Adds the paths to the assembly link path\n" +
76 " /r[eference]:ASS Reference the specified assembly\n");
79 private static void About ()
82 "The Mono JScript compiler is:\n" +
83 "(C) 2003 - 2004 Cesar Lopez Nataren\n" +
84 "(C) 2004 - 2005 Novell Inc.\n\n" +
85 "The compiler source code is released under the terms of both the MIT X11 and MPL\n" +
86 "The compiler was written by Cesar Lopez Nataren");
91 /// Loads all assemblies referenced on the command line
93 private static void LoadReferences ()
95 foreach (string r in references)
96 LoadAssembly (r, false);
100 private static void LoadAssembly (string assembly, bool soft)
103 string total_log = "";
106 char [] path_chars = { '/', '\\' };
108 if (assembly.IndexOfAny (path_chars) != -1) {
109 a = Assembly.LoadFrom (assembly);
111 string ass = assembly;
112 if (ass.EndsWith (".dll") || ass.EndsWith (".exe"))
113 ass = assembly.Substring (0, assembly.Length - 4);
114 a = Assembly.Load (ass);
118 } catch (FileNotFoundException){
119 foreach (string dir in link_paths){
120 string full_path = Path.Combine (dir, assembly);
121 if (!assembly.EndsWith (".dll") && !assembly.EndsWith (".exe"))
125 a = Assembly.LoadFrom (full_path);
128 } catch (FileNotFoundException ff) {
129 total_log += ff.FusionLog;
134 Console.WriteLine ("Cannot find assembly `" + assembly + "'" );
135 } catch (BadImageFormatException f) {
136 Console.WriteLine ("Cannot load assembly (bad file format)" + f.FusionLog);
137 } catch (FileLoadException f){
138 Console.WriteLine ("Cannot load assembly " + f.FusionLog);
139 } catch (ArgumentNullException){
140 Console.WriteLine ("Cannot load assembly (null argument)");
145 /// Registers an assembly to load types from.
147 private static void AddAssembly (Assembly a)
149 foreach (Assembly assembly in assemblies) {
154 int top = assemblies.Length;
155 Assembly [] n = new Assembly [top + 1];
157 assemblies.CopyTo (n, 0);
163 static string [] LoadArgs (string file)
166 ArrayList args = new ArrayList ();
169 f = new StreamReader (file);
174 StringBuilder sb = new StringBuilder ();
176 while ((line = f.ReadLine ()) != null){
179 for (int i = 0; i < t; i++){
182 if (c == '"' || c == '\''){
185 for (i++; i < t; i++){
192 } else if (c == ' '){
194 args.Add (sb.ToString ());
201 args.Add (sb.ToString ());
206 string [] ret_value = new string [args.Count];
207 args.CopyTo (ret_value, 0);
213 // Returns the directory where the system assemblies are installed
215 static string GetSystemDir ()
217 return Path.GetDirectoryName (typeof (object).Assembly.Location);
221 static void SetOutputFile (string name)
226 static void Version ()
228 string version = Assembly.GetExecutingAssembly ().GetName ().Version.ToString ();
229 Console.WriteLine ("Mono JScript compiler version {0}", version);
230 Environment.Exit (0);
233 static bool UnixParseOption (string arg, ref string [] args, ref int i)
240 case "/?": case "/h": case "/help":
243 Environment.Exit (0);
247 if ((i + 1) >= args.Length){
249 Environment.Exit (1);
251 SetOutputFile (args [++i]);
254 if ((i + 1) >= args.Length){
256 Environment.Exit (1);
259 references.Add (args [++i]);
263 if ((i + 1) >= args.Length){
265 Environment.Exit (1);
267 link_paths.Add (args [++i]);
278 // This parses the -arg and /arg options to the compiler, even if the strings
279 // in the following text use "/arg" on the strings.
281 static bool CSCParseOption (string option, ref string [] args, ref int i)
283 int idx = option.IndexOf (':');
289 arg = option.Substring (0, idx);
291 value = option.Substring (idx + 1);
301 Environment.Exit (1);
303 SetOutputFile (value);
309 Console.WriteLine ("/reference requires an argument");
310 Environment.Exit (1);
313 string [] refs = value.Split (new char [] { ';', ',' });
314 foreach (string r in refs){
324 Console.WriteLine ("/lib requires an argument");
325 Environment.Exit (1);
328 libdirs = value.Split (new Char [] { ',' });
329 foreach (string dir in libdirs)
330 link_paths.Add (dir);
337 static string [] AddArgs (string [] args, string [] extra_args)
340 new_args = new string [extra_args.Length + args.Length];
342 // if args contains '--' we have to take that into account
343 // split args into first half and second half based on '--'
344 // and add the extra_args before --
345 int split_position = Array.IndexOf (args, "--");
346 if (split_position != -1)
348 Array.Copy (args, new_args, split_position);
349 extra_args.CopyTo (new_args, split_position);
350 Array.Copy (args, split_position, new_args, split_position + extra_args.Length, args.Length - split_position);
354 args.CopyTo (new_args, 0);
355 extra_args.CopyTo (new_args, args.Length);
362 // Given a path specification, splits the path from the file/pattern
364 static void SplitPathAndPattern (string spec, out string path, out string pattern)
366 int p = spec.LastIndexOf ('/');
369 // Windows does not like /file.cs, switch that to:
374 pattern = spec.Substring (1);
376 path = spec.Substring (0, p);
377 pattern = spec.Substring (p + 1);
382 p = spec.LastIndexOf ('\\');
384 path = spec.Substring (0, p);
385 pattern = spec.Substring (p + 1);
393 static void ProcessFile (string f)
395 if (first_source == null)
401 static void CompileFiles (string spec, bool recurse)
403 string path, pattern;
405 SplitPathAndPattern (spec, out path, out pattern);
406 if (pattern.IndexOf ('*') == -1){
411 string [] files = null;
413 files = Directory.GetFiles (path, pattern);
414 } catch (System.IO.DirectoryNotFoundException) {
415 Console.WriteLine ("Source file `" + spec + "' could not be found");
417 } catch (System.IO.IOException){
418 Console.WriteLine ("Source file `" + spec + "' could not be found");
421 foreach (string f in files)
427 string [] dirs = null;
430 dirs = Directory.GetDirectories (path);
434 foreach (string d in dirs) {
436 // Don't include path in this string, as each
437 // directory entry already does
438 CompileFiles (d + "/" + pattern, true);
442 internal static bool MainDriver (string [] args)
445 bool parsing_options = true;
447 references = new ArrayList ();
448 link_paths = new ArrayList ();
449 files = new ArrayList ();
451 Hashtable response_file_list = null;
453 for (i = 0; i < args.Length; i++){
454 string arg = args [i];
458 if (arg.StartsWith ("@")){
459 string [] extra_args;
460 string response_file = arg.Substring (1);
462 if (response_file_list == null)
463 response_file_list = new Hashtable ();
465 if (response_file_list.Contains (response_file)){
466 Console.WriteLine ("Response file `" + response_file + "' specified multiple times");
467 Environment.Exit (1);
470 response_file_list.Add (response_file, response_file);
472 extra_args = LoadArgs (response_file);
473 if (extra_args == null){
474 Console.WriteLine ("Unable to open response file: " + response_file);
478 args = AddArgs (args, extra_args);
482 if (parsing_options){
484 parsing_options = false;
488 if (arg.StartsWith ("-")){
489 if (UnixParseOption (arg, ref args, ref i))
493 string csc_opt = "/" + arg.Substring (1);
494 if (CSCParseOption (csc_opt, ref args, ref i))
497 if (arg.StartsWith ("/")){
498 if (CSCParseOption (arg, ref args, ref i))
503 CompileFiles (arg, false);
507 // If there is nothing to put in the assembly, and we are not a library
509 if (first_source == null) /* && embedded_resources == null && resources == null) */ {
510 Console.WriteLine ("fatal error JS2026: No input sources specified");
515 // Load Core Library for default compilation
518 references.Insert (0, "mscorlib");
522 // Load assemblies required
524 link_paths.Add (GetSystemDir ());
525 link_paths.Add (Directory.GetCurrentDirectory ());
533 private static void Main (string [] args) {
535 if (args.Length < 1) {
537 Environment.Exit (0);
540 VsaEngine engine = new VsaEngine ();
541 engine.InitVsaEngine ("mjs:com.mono-project", new MonoEngineSite ());
543 foreach (string asm in references) {
544 IVsaReferenceItem item = (IVsaReferenceItem) engine.Items.CreateItem (asm, VsaItemType.Reference, VsaItemFlag.None);
545 item.AssemblyName = asm;
548 string asm_name = String.Empty;
550 foreach (Assembly assembly in assemblies) {
551 asm_name = assembly.GetName ().FullName;
552 IVsaReferenceItem item = (IVsaReferenceItem) engine.Items.CreateItem (asm_name, VsaItemType.Reference, VsaItemFlag.None);
553 item.AssemblyName = asm_name;
556 foreach (string file in files) {
557 IVsaCodeItem item = (IVsaCodeItem) engine.Items.CreateItem (file, VsaItemType.Code, VsaItemFlag.None);
558 item.SourceText = GetCodeFromFile (file);
560 engine.SetOption ("debug", want_debugging_support);
561 engine.SetOption ("link_path", link_paths);
562 engine.SetOption ("first_source", first_source);
563 engine.SetOption ("assemblies", assemblies);
567 static string GetCodeFromFile (string fn)
570 StreamReader reader = new StreamReader (fn);
571 return reader.ReadToEnd ();
572 } catch (FileNotFoundException) {
573 throw new JScriptException (JSError.FileNotFound);
574 } catch (ArgumentNullException) {
575 throw new JScriptException (JSError.FileNotFound);
576 } catch (ArgumentException) {
577 throw new JScriptException (JSError.FileNotFound);
578 } catch (IOException) {
579 throw new JScriptException (JSError.NoError);
580 } catch (OutOfMemoryException) {
581 throw new JScriptException (JSError.OutOfMemory);
586 class MonoEngineSite : IVsaSite {
587 public void GetCompiledState (out byte [] pe, out byte [] debugInfo)
589 throw new NotImplementedException ();
592 public object GetEventSourceInstance (string itemName, string eventSourceName)
594 throw new NotImplementedException ();
597 public object GetGlobalInstance (string name)
599 throw new NotImplementedException ();
602 public void Notify (string notify, object info)
604 throw new NotImplementedException ();
607 public bool OnCompilerError (IVsaError error)
609 throw new NotImplementedException ();