* Compiler.cs: marked ctor private to match MS.NET
[mono.git] / mcs / class / Cscompmgd / Microsoft.CSharp / Compiler.cs
1 // Microsoft.CSharp.Compiler
2 //
3 // Author(s):
4 //  Jackson Harper (Jackson@LatitudeGeo.com)
5 //
6 // (C) 2002 Jackson Harper, All rights reserved.
7 //
8
9 using System;
10 using System.IO;
11 using System.Text;
12 using System.Collections;
13 using System.Diagnostics;
14 using System.Text.RegularExpressions;
15
16 namespace Microsoft.CSharp {
17
18         public class Compiler {
19                 
20                 private Compiler()
21                 {
22                 }
23
24                 [MonoTODO("Have not implemented bugreports")]
25                 public static CompilerError[] Compile(string[] sourceTexts,
26                         string[] sourceTextNames, string target, string[] imports,
27                         IDictionary options)
28                 {
29                         VerifyArgs (sourceTexts, sourceTextNames, target);
30                         
31                         string[] temp_cs_files;
32                         CompilerError[] errors;
33                         string bugreport_path = null;   
34                         StreamWriter bug_report = null;
35                         
36                         temp_cs_files = CreateCsFiles (sourceTexts, sourceTextNames);
37                         
38                         if (options != null)
39                                 bugreport_path = (string)options["bugreport"];  
40                         
41                         if (bugreport_path != null) {
42                                 bug_report = CreateBugReport (sourceTexts, sourceTextNames, bugreport_path);
43                         }                       
44
45                         try {
46                                 errors = CompileFiles (temp_cs_files, target, imports, options, bug_report);
47                         } catch {
48                                 throw;
49                         } finally {
50                                 foreach (string temp_file in temp_cs_files) {
51                                         FileInfo file = new FileInfo (temp_file);
52                                         file.Delete ();
53                                 }
54                                 if (bug_report != null)
55                                         bug_report.Close ();
56                         }
57                         
58                         return errors;
59                 }
60                 
61                 //
62                 // Private Methods
63                 //
64
65                 private static CompilerError[] CompileFiles (string[] cs_files,
66                         string target, string[] imports, IDictionary options, StreamWriter bug_report) 
67                 {
68                         ArrayList error_list = new ArrayList ();
69                         Process mcs = new Process ();
70                         string mcs_output;
71                         string[] mcs_output_lines;
72
73                         mcs.StartInfo.FileName = "mcs";
74                         mcs.StartInfo.Arguments = BuildArgs (cs_files, 
75                                 target, imports, options);
76                         mcs.StartInfo.CreateNoWindow = true;
77                         mcs.StartInfo.UseShellExecute = false;
78                         mcs.StartInfo.RedirectStandardOutput = true;
79
80                         try {
81                                 mcs.Start ();
82                                 mcs_output = mcs.StandardOutput.ReadToEnd();
83                                 mcs.WaitForExit ();
84                         } finally {
85                                 mcs.Close ();
86                         }
87                         
88                         mcs_output_lines = mcs_output.Split (
89                                 System.Environment.NewLine.ToCharArray ());
90                         foreach (string error_line in mcs_output_lines) {
91                                 CompilerError error = CreateErrorFromString (error_line);
92                                 if (null != error)
93                                         error_list.Add (error); 
94                         }
95                         
96                         if (bug_report != null) {
97                                 bug_report.WriteLine ("### Compiler Output");
98                                 bug_report.Write (mcs_output);
99                         }
100
101                         return (CompilerError[])error_list.ToArray (typeof(CompilerError));
102                 }
103
104                 /// <summary>
105                 ///   Converts an error string into a CompilerError object
106                 ///   Return null if the line was not an error string
107                 /// </summary>
108                 private static CompilerError CreateErrorFromString(string error_string) 
109                 {
110                         CompilerError error = new CompilerError();
111                         Regex reg = new Regex (@"^((?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s){0,}(?<level>\w+)\sCS(?<number>\d*):\s(?<message>.*)", 
112                         RegexOptions.Compiled | RegexOptions.ExplicitCapture);
113
114                         Match match = reg.Match (error_string);
115                         
116                         if (!match.Success)
117                                 return null;
118                         
119                         if (String.Empty != match.Result ("${file}"))
120                                 error.SourceFile = match.Result ("${file}");
121                         if (String.Empty != match.Result ("${line}"))
122                                 error.SourceLine = Int32.Parse (match.Result ("${line}"));
123                         if (String.Empty != match.Result ("${column}"))
124                                 error.SourceColumn = Int32.Parse (match.Result ("${column}"));
125                         error.ErrorLevel = (ErrorLevel)Enum.Parse (typeof(ErrorLevel),
126                                 match.Result ("${level}"), true);
127                         error.ErrorNumber = Int32.Parse (match.Result ("${number}"));
128                         error.ErrorMessage = match.Result ("${message}");
129                         
130                         return error;
131                 }
132
133                 private static string[] CreateCsFiles (string[] source_text, string[] source_name) 
134                 {
135                         ArrayList temp_file_list = new ArrayList ();
136
137                         for (int i=0; i<source_text.Length; i++) {
138                                 string temp_path = Path.GetTempFileName ();
139                                 StreamWriter writer = null;
140                                 try {
141                                         writer = new StreamWriter (temp_path);
142                                         writer.WriteLine (String.Format ("#line 1 \"{0}\"", 
143                                                 source_name[i]));
144                                         writer.Write (source_text[i]);
145                                 } catch {
146                                 } finally {
147                                         if (writer != null)
148                                                 writer.Close ();
149                                 }
150                                 temp_file_list.Add (temp_path);
151                         }
152                 
153                         return (string[])temp_file_list.ToArray (typeof(string));       
154                 }
155
156                 private static string BuildArgs(string[] source_files,
157                         string target, string[] imports, IDictionary options)
158                 {
159                         StringBuilder args = new StringBuilder ();
160
161                         args.AppendFormat ("/out:{0} ", target);
162                         
163                         if (null != imports) {
164                                 foreach (string import in imports)
165                                         args.AppendFormat ("/r:{0} ", import);
166                         }
167                         
168                         if (null != options) {
169                                 foreach (object option in options.Keys) {
170                                         object value = options[option];
171                                         if (!ValidOption ((string)option))
172                                                 continue;
173                                         args.AppendFormat ("{0} ", OptionString (option,value));
174                                 }
175                         }
176                         
177                         foreach (string source in source_files)
178                                 args.AppendFormat ("{0} ", source);
179
180                         return args.ToString ();
181                 }
182
183                 private static string OptionString(object option, object value)
184                 {
185                         if (null != value)
186                                 return String.Format ("/{0}:{1}", option, value);
187                         
188                         return String.Format("/{0}", option);
189                 }
190
191                 private static void VerifyArgs (string[] sourceTexts,
192                         string[] sourceTextNames, string target)
193                 {
194                         if (null == sourceTexts)
195                                 throw new ArgumentNullException ("sourceTexts");
196                         if (null == sourceTextNames)
197                                 throw new ArgumentNullException ("sourceTextNames");
198                         if (null == target)
199                                 throw new ArgumentNullException ("target");
200
201                         if (sourceTexts.Length <= 0 || sourceTextNames.Length <= 0)
202                                 throw new IndexOutOfRangeException ();
203                 }
204
205                 private static StreamWriter CreateBugReport (string[] source_texts, 
206                         string[] source_names, string path)
207                 {
208                         StreamWriter bug_report = null;
209
210                         try {
211                                 bug_report = new StreamWriter (path);
212                                 bug_report.WriteLine ("### C# Compiler Defect Report," + 
213                                         " created {0}", DateTime.Now);
214                                 // Compiler Version
215                                 // Runtime
216                                 // Operating System
217                                 // Username
218                                 for (int i=0; i<source_texts.Length; i++) {
219                                         bug_report.WriteLine ("### Source file: '{0}'",
220                                                 source_names[i]);
221                                         bug_report.Write (source_texts[i]);
222                                 }
223                         } catch {
224                                 if (bug_report != null)
225                                         bug_report.Close ();
226                                 throw;
227                         }
228                         
229                         return bug_report;
230                 }
231
232
233                 private static bool ValidOption (string option)
234                 {
235                         switch (option) {
236                                 case "addmodule":
237                                 case "baseaddress":
238                                 case "checked":
239                                 case "d":
240                                 case "debug":
241                                 case "doc":
242                                 case "filealign":
243                                 case "incr":
244                                 case "lib":
245                                 case "linkres":
246                                 case "m":
247                                 case "nostdlib":
248                                 case "nowarn":
249                                 case "o":
250                                 case "r":
251                                 case "res":
252                                 case "target":
253                                 case "unsafe":
254                                 case "w":
255                                 case "warnaserror":
256                                 case "win32icon":
257                                 case "win32res":
258                                         return true;
259                         }
260                         return false;
261                 }
262
263         }
264
265 }
266