**** Merged from MCS ****
[mono-project.git] / mcs / class / Cscompmgd / Microsoft.CSharp / Compiler.cs
blobee3a18bc454d218d15dfe28442ae318fb519ccaf
1 // Microsoft.CSharp.Compiler
2 //
3 // Author(s):
4 // Jackson Harper (Jackson@LatitudeGeo.com)
5 //
6 // (C) 2002 Jackson Harper, All rights reserved.
7 //
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System;
31 using System.IO;
32 using System.Text;
33 using System.Collections;
34 using System.Diagnostics;
35 using System.Text.RegularExpressions;
37 namespace Microsoft.CSharp {
39 #if NET_2_0
40 [System.Obsolete]
41 #endif
42 public class Compiler {
44 private Compiler()
48 [MonoTODO("Have not implemented bugreports")]
49 public static CompilerError[] Compile(string[] sourceTexts,
50 string[] sourceTextNames, string target, string[] imports,
51 IDictionary options)
53 VerifyArgs (sourceTexts, sourceTextNames, target);
55 string[] temp_cs_files;
56 CompilerError[] errors;
57 string bugreport_path = null;
58 StreamWriter bug_report = null;
60 temp_cs_files = CreateCsFiles (sourceTexts, sourceTextNames);
62 if (options != null)
63 bugreport_path = (string)options["bugreport"];
65 if (bugreport_path != null) {
66 bug_report = CreateBugReport (sourceTexts, sourceTextNames, bugreport_path);
69 try {
70 errors = CompileFiles (temp_cs_files, target, imports, options, bug_report);
71 } catch {
72 throw;
73 } finally {
74 foreach (string temp_file in temp_cs_files) {
75 FileInfo file = new FileInfo (temp_file);
76 file.Delete ();
78 if (bug_report != null)
79 bug_report.Close ();
82 return errors;
86 // Private Methods
89 private static CompilerError[] CompileFiles (string[] cs_files,
90 string target, string[] imports, IDictionary options, StreamWriter bug_report)
92 ArrayList error_list = new ArrayList ();
93 Process mcs = new Process ();
94 string mcs_output;
95 string[] mcs_output_lines;
97 mcs.StartInfo.FileName = "mcs";
98 mcs.StartInfo.Arguments = BuildArgs (cs_files,
99 target, imports, options);
100 mcs.StartInfo.CreateNoWindow = true;
101 mcs.StartInfo.UseShellExecute = false;
102 mcs.StartInfo.RedirectStandardOutput = true;
104 try {
105 mcs.Start ();
106 mcs_output = mcs.StandardOutput.ReadToEnd();
107 mcs.WaitForExit ();
108 } finally {
109 mcs.Close ();
112 mcs_output_lines = mcs_output.Split (
113 System.Environment.NewLine.ToCharArray ());
114 foreach (string error_line in mcs_output_lines) {
115 CompilerError error = CreateErrorFromString (error_line);
116 if (null != error)
117 error_list.Add (error);
120 if (bug_report != null) {
121 bug_report.WriteLine ("### Compiler Output");
122 bug_report.Write (mcs_output);
125 return (CompilerError[])error_list.ToArray (typeof(CompilerError));
128 /// <summary>
129 /// Converts an error string into a CompilerError object
130 /// Return null if the line was not an error string
131 /// </summary>
132 private static CompilerError CreateErrorFromString(string error_string)
134 CompilerError error = new CompilerError();
135 Regex reg = new Regex (@"^((?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s){0,}(?<level>\w+)\sCS(?<number>\d*):\s(?<message>.*)",
136 RegexOptions.Compiled | RegexOptions.ExplicitCapture);
138 Match match = reg.Match (error_string);
140 if (!match.Success)
141 return null;
143 if (String.Empty != match.Result ("${file}"))
144 error.SourceFile = match.Result ("${file}");
145 if (String.Empty != match.Result ("${line}"))
146 error.SourceLine = Int32.Parse (match.Result ("${line}"));
147 if (String.Empty != match.Result ("${column}"))
148 error.SourceColumn = Int32.Parse (match.Result ("${column}"));
149 error.ErrorLevel = (ErrorLevel)Enum.Parse (typeof(ErrorLevel),
150 match.Result ("${level}"), true);
151 error.ErrorNumber = Int32.Parse (match.Result ("${number}"));
152 error.ErrorMessage = match.Result ("${message}");
154 return error;
157 private static string[] CreateCsFiles (string[] source_text, string[] source_name)
159 ArrayList temp_file_list = new ArrayList ();
161 for (int i=0; i<source_text.Length; i++) {
162 string temp_path = Path.GetTempFileName ();
163 StreamWriter writer = null;
164 try {
165 writer = new StreamWriter (temp_path);
166 writer.WriteLine (String.Format ("#line 1 \"{0}\"",
167 source_name[i]));
168 writer.Write (source_text[i]);
169 } catch {
170 } finally {
171 if (writer != null)
172 writer.Close ();
174 temp_file_list.Add (temp_path);
177 return (string[])temp_file_list.ToArray (typeof(string));
180 private static string BuildArgs(string[] source_files,
181 string target, string[] imports, IDictionary options)
183 StringBuilder args = new StringBuilder ();
185 args.AppendFormat ("/out:{0} ", target);
187 if (null != imports) {
188 foreach (string import in imports)
189 args.AppendFormat ("/r:{0} ", import);
192 if (null != options) {
193 foreach (object option in options.Keys) {
194 object value = options[option];
195 if (!ValidOption ((string)option))
196 continue;
197 args.AppendFormat ("{0} ", OptionString (option,value));
201 foreach (string source in source_files)
202 args.AppendFormat ("{0} ", source);
204 return args.ToString ();
207 private static string OptionString(object option, object value)
209 if (null != value)
210 return String.Format ("/{0}:{1}", option, value);
212 return String.Format("/{0}", option);
215 private static void VerifyArgs (string[] sourceTexts,
216 string[] sourceTextNames, string target)
218 if (null == sourceTexts)
219 throw new ArgumentNullException ("sourceTexts");
220 if (null == sourceTextNames)
221 throw new ArgumentNullException ("sourceTextNames");
222 if (null == target)
223 throw new ArgumentNullException ("target");
225 if (sourceTexts.Length <= 0 || sourceTextNames.Length <= 0)
226 throw new IndexOutOfRangeException ();
229 private static StreamWriter CreateBugReport (string[] source_texts,
230 string[] source_names, string path)
232 StreamWriter bug_report = null;
234 try {
235 bug_report = new StreamWriter (path);
236 bug_report.WriteLine ("### C# Compiler Defect Report," +
237 " created {0}", DateTime.Now);
238 // Compiler Version
239 // Runtime
240 // Operating System
241 // Username
242 for (int i=0; i<source_texts.Length; i++) {
243 bug_report.WriteLine ("### Source file: '{0}'",
244 source_names[i]);
245 bug_report.Write (source_texts[i]);
247 } catch {
248 if (bug_report != null)
249 bug_report.Close ();
250 throw;
253 return bug_report;
257 private static bool ValidOption (string option)
259 switch (option) {
260 case "addmodule":
261 case "baseaddress":
262 case "checked":
263 case "d":
264 case "debug":
265 case "doc":
266 case "filealign":
267 case "incr":
268 case "lib":
269 case "linkres":
270 case "m":
271 case "nostdlib":
272 case "nowarn":
273 case "o":
274 case "r":
275 case "res":
276 case "target":
277 case "unsafe":
278 case "w":
279 case "warnaserror":
280 case "win32icon":
281 case "win32res":
282 return true;
284 return false;