2 // Copyright (c) 2004, Rodrigo B. de Oliveira (rbo@acm.org)
3 // All rights reserved.
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright notice,
11 // this list of conditions and the following disclaimer in the documentation
12 // and/or other materials provided with the distribution.
13 // * Neither the name of Rodrigo B. de Oliveira nor the names of its
14 // contributors may be used to endorse or promote products derived from this
15 // software without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 using System
.Collections
;
32 using System
.Diagnostics
;
34 using System
.Globalization
;
35 using System
.Threading
;
36 using Boo
.Lang
.Compiler
.Ast
.Visitors
;
37 using Assembly
= System
.Reflection
.Assembly
;
38 using Boo
.Lang
.Compiler
;
39 using Boo
.Lang
.Compiler
.IO
;
40 using Boo
.Lang
.Compiler
.Pipelines
;
41 using Boo
.Lang
.Compiler
.Resources
;
51 ArrayList _responseFileList
= new ArrayList();
52 CompilerParameters _options
= null;
54 ArrayList _references
= new ArrayList();
55 ArrayList _packages
= new ArrayList();
56 bool _noConfig
= false;
57 string _pipelineName
= null;
58 bool _debugSteps
= false;
59 bool _whiteSpaceAgnostic
= false;
62 /// The main entry point for the application.
65 static int Main(string[] args
)
67 if (((IList
)args
).Contains("-utf8"))
69 using (StreamWriter writer
= new StreamWriter(Console
.OpenStandardError(), Encoding
.UTF8
))
71 // leave the byte order mark in its own line and out
74 Console
.SetError(writer
);
75 return new App().Run(args
);
80 return new App().Run(args
);
84 public int Run(string[] args
)
88 AppDomain
.CurrentDomain
.AssemblyResolve
+= new ResolveEventHandler(AssemblyResolve
);
94 DateTime start
= DateTime
.Now
;
96 _options
= new CompilerParameters(false); //false means no stdlib loading yet
97 _options
.GenerateInMemory
= false;
99 BooCompiler compiler
= new BooCompiler(_options
);
103 if (0 == _options
.Input
.Count
)
105 throw new ApplicationException(Boo
.Lang
.ResourceManager
.GetString("BooC.NoInputSpecified"));
108 //move standard libpaths below any new ones:
109 _options
.LibPaths
.Add(_options
.LibPaths
[0]);
110 _options
.LibPaths
.Add(_options
.LibPaths
[1]);
111 _options
.LibPaths
.RemoveAt(0);
112 _options
.LibPaths
.RemoveAt(0);
116 _options
.LoadDefaultReferences();
120 _references
.Insert(0, "mscorlib");
126 if (_options
.TraceSwitch
.TraceInfo
)
128 compiler
.Parameters
.Pipeline
.BeforeStep
+= new CompilerStepEventHandler(OnBeforeStep
);
129 compiler
.Parameters
.Pipeline
.AfterStep
+= new CompilerStepEventHandler(OnAfterStep
);
132 TimeSpan setupTime
= DateTime
.Now
- start
;
134 start
= DateTime
.Now
;
135 CompilerContext context
= compiler
.Run();
136 TimeSpan processingTime
= DateTime
.Now
- start
;
138 if (context
.Warnings
.Count
> 0)
140 Console
.Error
.WriteLine(context
.Warnings
);
141 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.Warnings", context
.Warnings
.Count
));
144 if (context
.Errors
.Count
> 0)
146 foreach (CompilerError error
in context
.Errors
)
148 Console
.Error
.WriteLine(error
.ToString(_options
.TraceSwitch
.TraceInfo
));
150 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.Errors", context
.Errors
.Count
));
157 if (_options
.TraceSwitch
.TraceWarning
)
159 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.ProcessingTime", _options
.Input
.Count
, processingTime
.TotalMilliseconds
, setupTime
.TotalMilliseconds
));
164 object message
= _options
.TraceSwitch
.TraceWarning
? (object)x
: (object)x
.Message
;
165 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.FatalError", message
));
170 void LoadReferences()
172 foreach (string r
in _references
)
174 _options
.References
.Add(_options
.LoadAssembly(r
, true));
176 foreach (string p
in _packages
)
178 _options
.LoadReferencesFromPackage(p
);
182 void CheckBooCompiler()
184 string path
= Path
.Combine(Path
.GetDirectoryName(
185 Assembly
.GetExecutingAssembly().Location
),
186 "Boo.Lang.Compiler.dll");
187 if (File
.Exists(path
))
189 foreach (Assembly a
in AppDomain
.CurrentDomain
.GetAssemblies())
191 if (a
.FullName
.StartsWith("Boo.Lang.Compiler"))
193 if (string.Compare(a
.Location
, path
, true) != 0)
195 //can't use ResourceManager, boo.lang.dll may be out of date
196 string msg
=string.Format("WARNING: booc is not using the Boo.Lang.Compiler.dll next to booc.exe. Using '{0}' instead of '{1}'. You may need to remove boo dlls from the GAC using gacutil or Mscorcfg.",
198 //has to be all 1 line for things like msbuild that parse booc output.
199 Console
.Error
.WriteLine(msg
);
207 string Consume(TextReader reader
)
209 StringWriter writer
= new StringWriter();
210 string line
= reader
.ReadLine();
213 writer
.WriteLine(line
);
214 line
= reader
.ReadLine();
216 return writer
.ToString();
221 Console
.Write("Boo Compiler version "+Builtins
.BooVersion
.ToString());
222 Console
.WriteLine(" (CLR v"+Environment
.Version
.ToString()+")");
228 "Usage is: booc [options] file1 ...\n" +
230 " -c:CULTURE Sets the UI culture to be CULTURE\n" +
231 " -debug[+|-] Generate debugging information (default: +)\n" +
232 " -delaysign Delay assembly signing\n" +
233 " -ducky Turns on duck typing by default\n" +
234 " -checked[+|-] Turns on or off checked operations (default: +)\n" +
235 " -embedres:FILE[,ID] Embeds FILE with the optional ID\n"+
236 " -lib:DIRS Adds the comma-separated DIRS to the assembly search path\n" +
237 " -noconfig Do not load the standard configuration\n" +
238 " -nostdlib Do not reference any of the default libraries\n" +
239 " -nologo Do not display the compiler logo\n" +
240 " -p:PIPELINE Sets the pipeline to PIPELINE\n" +
241 " -o:FILE Set the output file name to FILE\n" +
242 " -keyfile:FILE The strongname key file used to strongname the assembly\n" +
243 " -keycontainer:NAME The key pair container used to strongname the assembly\n" +
244 " -reference:ASS References the specified assembly (-r:ASS)\n" +
245 " -srcdir:DIR Adds DIR as a directory where sources can be found\n" +
246 " -target:TYPE Set the target type (exe, library or winexe)\n" +
247 " -resource:FILE[,ID] Embed FILE as a resource\n" +
248 " -utf8 Source file is in utf8 format\n" +
249 " -v, -vv, -vvv Set verbosity level from warnings to very detailed\n" +
250 " -wsa Enable white-space-agnostic builds\n"
255 void ParseOptions(string[] args
)
259 ArrayList arglist
= new ArrayList(args
);
260 ExpandResponseFiles(ref arglist
);
261 AddDefaultResponseFile(ref arglist
);
262 foreach (string arg
in arglist
)
266 _options
.Input
.Add(new StringInput("<stdin>", Consume(Console
.In
)));
271 _options
.Input
.Add(new FileInput(StripQuotes(arg
)));
274 if ("-utf8" == arg
) continue;
280 if (arg
== "-help" || arg
== "-h")
291 _options
.WhiteSpaceAgnostic
= _whiteSpaceAgnostic
= true;
302 _options
.TraceSwitch
.Level
= TraceLevel
.Warning
;
303 Trace
.Listeners
.Add(new TextWriterTraceListener(Console
.Error
));
306 switch (arg
.Substring(1))
310 _options
.TraceSwitch
.Level
= TraceLevel
.Info
;
317 _options
.TraceSwitch
.Level
= TraceLevel
.Verbose
;
324 _options
.TraceSwitch
.Level
= TraceLevel
.Warning
;
331 if (arg
.IndexOf(":") > 2 && arg
.Substring(1, 9) != "reference")
333 switch (arg
.Substring(1, 8))
337 int start
= arg
.IndexOf(":") + 1;
338 AddResource(StripQuotes(arg
.Substring(start
)));
351 string assemblyName
= StripQuotes(arg
.Substring(arg
.IndexOf(":")+1));
352 _references
.Add(assemblyName
);
359 switch (arg
.Substring(1, 3))
363 string paths
= arg
.Substring(arg
.IndexOf(":")+1);
366 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.BadLibPath", arg
));
370 foreach(string dir
in paths
.Split(new Char
[] {','}
))
372 if (Directory
.Exists(dir
))
374 _options
.LibPaths
.Add(dir
);
378 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.BadLibPath", dir
));
395 if (arg
== "-nologo")
399 else if (arg
== "-noconfig")
403 else if (arg
== "-nostdlib")
405 _options
.StdLib
= false;
416 _options
.OutputAssembly
= StripQuotes(arg
.Substring(arg
.IndexOf(":")+1));
422 string targetType
= arg
.Substring(arg
.IndexOf(":")+1);
427 _options
.OutputType
= CompilerOutputType
.Library
;
433 _options
.OutputType
= CompilerOutputType
.ConsoleApplication
;
439 _options
.OutputType
= CompilerOutputType
.WindowsApplication
;
454 if (arg
.StartsWith("-pkg:"))
456 string packages
= StripQuotes(arg
.Substring(arg
.IndexOf(":")+1));
457 _packages
.Add(packages
);
460 _pipelineName
= StripQuotes(arg
.Substring(3));
467 switch (arg
.Substring(1))
472 _options
.Checked
= true;
478 _options
.Checked
= false;
484 string culture
= arg
.Substring(3);
485 Thread
.CurrentThread
.CurrentUICulture
= CultureInfo
.CreateSpecificCulture(culture
);
494 switch (arg
.Substring(1, 6))
498 string path
= StripQuotes(arg
.Substring(8));
499 AddFilesForPath(path
, _options
);
514 if (arg
.Substring(1, 7) == "keyfile")
516 _options
.KeyFile
= StripQuotes(arg
.Substring(9));
518 else if (arg
.Substring(1, 12) == "keycontainer")
520 _options
.KeyContainer
= StripQuotes(arg
.Substring(14));
531 switch (arg
.Substring(1))
536 _options
.Debug
= true;
542 _options
.Debug
= false;
548 _options
.Ducky
= true;
560 _options
.DelaySign
= true;
575 switch (arg
.Substring(1,8))
581 throw new ApplicationException("-embedres is only supported on mono. Try -resource.");
583 int start
= arg
.IndexOf(":") + 1;
584 EmbedResource(StripQuotes(arg
.Substring(start
)));
613 get { return Type.GetType("System.MonoType", false) != null; }
616 private void EmbedResource(string resourceFile
)
619 int comma
= resourceFile
.LastIndexOf(',');
622 string resourceName
= resourceFile
.Substring(comma
+1);
623 resourceFile
= resourceFile
.Substring(0, comma
);
624 _options
.Resources
.Add(new NamedEmbeddedFileResource(resourceFile
, resourceName
));
628 _options
.Resources
.Add(new EmbeddedFileResource(resourceFile
));
632 private void AddResource(string resourceFile
)
634 int comma
= resourceFile
.LastIndexOf(',');
637 string resourceName
= resourceFile
.Substring(comma
+1);
638 resourceFile
= resourceFile
.Substring(0, comma
);
639 _options
.Resources
.Add(new NamedFileResource(resourceFile
, resourceName
));
643 _options
.Resources
.Add(new FileResource(resourceFile
));
647 private void ConfigurePipeline()
649 if (null != _pipelineName
)
651 _options
.Pipeline
= CompilerPipeline
.GetPipeline(_pipelineName
);
655 _options
.Pipeline
= new CompileToFile();
657 if (_whiteSpaceAgnostic
)
659 _options
.Pipeline
[0] = new Boo
.Lang
.Parser
.WSABooParsingStep();
663 _options
.Pipeline
.AfterStep
+= new CompilerStepEventHandler(new StepDebugger().AfterStep
);
667 private string StripQuotes(string s
)
669 if (s
.Length
> 1 && s
.StartsWith("\"") && s
.EndsWith("\""))
671 return s
.Substring(1,s
.Length
-2);
676 private class StepDebugger
680 public void AfterStep(object sender
, CompilerStepEventArgs args
)
682 Console
.WriteLine("********* {0} *********", args
.Step
);
684 StringWriter writer
= new StringWriter();
685 args
.Context
.CompileUnit
.Accept(new BooPrinterVisitor(writer
, BooPrinterVisitor
.PrintOptions
.PrintLocals
));
686 string code
= writer
.ToString();
689 Console
.WriteLine(code
);
693 Console
.WriteLine("no changes");
699 ArrayList
LoadResponseFile(string file
)
701 file
= Path
.GetFullPath(file
);
702 if (_responseFileList
.Contains(file
))
704 throw new ApplicationException(
705 Boo
.Lang
.ResourceManager
.Format("BCE0500", file
));
707 _responseFileList
.Add(file
);
708 if (!File
.Exists(file
))
710 throw new ApplicationException(Boo
.Lang
.ResourceManager
.Format("BCE0501", file
));
712 ArrayList arglist
= new ArrayList();
715 using (StreamReader sr
= new StreamReader(file
))
718 while ((line
= sr
.ReadLine()) != null)
721 if (line
.Length
> 0 && line
[0] != '#')
723 if (line
.StartsWith("@") && line
.Length
> 2)
725 arglist
.AddRange(LoadResponseFile(line
.Substring(1)));
735 catch (ApplicationException
)
741 throw new ApplicationException(
742 Boo
.Lang
.ResourceManager
.Format("BCE0502", file
),
748 void ExpandResponseFiles(ref ArrayList arglist
)
750 ArrayList result
= new ArrayList();
751 foreach (string arg
in arglist
)
753 if (arg
.StartsWith("@") && arg
.Length
> 2)
755 result
.AddRange(LoadResponseFile(arg
.Substring(1)));
765 void AddDefaultResponseFile(ref ArrayList arglist
)
767 ArrayList result
= new ArrayList();
768 foreach (string arg
in arglist
)
770 if (arg
== "-noconfig")
781 string file
= Path
.Combine(Path
.GetDirectoryName(Assembly
.GetExecutingAssembly().Location
), "booc.rsp");
782 if (File
.Exists(file
))
784 result
.InsertRange(0, LoadResponseFile(file
));
790 void OnBeforeStep(object sender
, CompilerStepEventArgs args
)
792 args
.Context
.TraceEnter("Entering {0}", args
.Step
);
795 void OnAfterStep(object sender
, CompilerStepEventArgs args
)
797 args
.Context
.TraceLeave("Leaving {0}", args
.Step
);
800 void InvalidOption(string arg
)
802 Console
.Error
.WriteLine(Boo
.Lang
.ResourceManager
.Format("BooC.InvalidOption", arg
));
805 bool IsFlag(string arg
)
807 return arg
[0] == '-';
810 void AddFilesForPath(string path
, CompilerParameters _options
)
812 foreach (string fname
in Directory
.GetFiles(path
, "*.boo"))
814 if (!fname
.EndsWith(".boo")) continue;
815 _options
.Input
.Add(new FileInput(Path
.GetFullPath(fname
)));
818 foreach (string dirName
in Directory
.GetDirectories(path
))
820 AddFilesForPath(dirName
, _options
);
824 void MonitorAppDomain()
826 if (_options
.TraceSwitch
.TraceInfo
)
828 AppDomain
.CurrentDomain
.AssemblyLoad
+= new AssemblyLoadEventHandler(OnAssemblyLoad
);
829 foreach(Assembly a
in AppDomain
.CurrentDomain
.GetAssemblies())
831 Trace
.WriteLine("ASSEMBLY AT STARTUP: "+GetAssemblyLocation(a
));
836 static void OnAssemblyLoad(object sender
, AssemblyLoadEventArgs args
)
838 Trace
.WriteLine("ASSEMBLY LOADED: " + GetAssemblyLocation(args
.LoadedAssembly
));
841 static string GetAssemblyLocation(Assembly a
)
850 loc
= "<dynamic>"+a
.FullName
;
855 static Assembly
AssemblyResolve(object sender
, ResolveEventArgs args
)
857 string simpleName
= args
.Name
.Split(',')[0];
858 string fileName
= Path
.Combine(Environment
.CurrentDirectory
,
859 simpleName
+ ".dll");
860 if (File
.Exists(fileName
))
862 return Assembly
.LoadFile(fileName
);