Merge pull request #1345 from mattleibow/websocket-continuation-frame-fix
[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 //
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.
28 //
29
30 using System;
31 using System.IO;
32 using System.Text;
33 using System.Collections;
34 using System.Diagnostics;
35 using System.Text.RegularExpressions;
36
37 namespace Microsoft.CSharp {
38
39         [System.Obsolete]
40         public class Compiler {
41                 
42                 private Compiler()
43                 {
44                 }
45
46                 [MonoTODO("Have not implemented bugreports")]
47                 public static CompilerError[] Compile(string[] sourceTexts,
48                         string[] sourceTextNames, string target, string[] imports,
49                         IDictionary options)
50                 {
51                         VerifyArgs (sourceTexts, sourceTextNames, target);
52                         
53                         string[] temp_cs_files;
54                         CompilerError[] errors;
55                         string bugreport_path = null;   
56                         StreamWriter bug_report = null;
57                         
58                         temp_cs_files = CreateCsFiles (sourceTexts, sourceTextNames);
59                         
60                         if (options != null)
61                                 bugreport_path = (string)options["bugreport"];  
62                         
63                         if (bugreport_path != null) {
64                                 bug_report = CreateBugReport (sourceTexts, sourceTextNames, bugreport_path);
65                         }                       
66
67                         try {
68                                 errors = CompileFiles (temp_cs_files, target, imports, options, bug_report);
69                         } catch {
70                                 throw;
71                         } finally {
72                                 foreach (string temp_file in temp_cs_files) {
73                                         FileInfo file = new FileInfo (temp_file);
74                                         file.Delete ();
75                                 }
76                                 if (bug_report != null)
77                                         bug_report.Close ();
78                         }
79                         
80                         return errors;
81                 }
82                 
83                 //
84                 // Private Methods
85                 //
86
87                 private static CompilerError[] CompileFiles (string[] cs_files,
88                         string target, string[] imports, IDictionary options, StreamWriter bug_report) 
89                 {
90                         ArrayList error_list = new ArrayList ();
91                         Process mcs = new Process ();
92                         string mcs_output;
93                         string[] mcs_output_lines;
94
95                         mcs.StartInfo.FileName = "mcs";
96                         mcs.StartInfo.Arguments = BuildArgs (cs_files, 
97                                 target, imports, options);
98                         mcs.StartInfo.CreateNoWindow = true;
99                         mcs.StartInfo.UseShellExecute = false;
100                         mcs.StartInfo.RedirectStandardOutput = true;
101                         mcs.StartInfo.RedirectStandardError = true;
102
103                         try {
104                                 mcs.Start ();
105                                 mcs_output = mcs.StandardError.ReadToEnd ();
106                                 mcs.StandardOutput.ReadToEnd ();
107                                 mcs.WaitForExit ();
108                         } finally {
109                                 mcs.Close ();
110                         }
111                         
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); 
118                         }
119                         
120                         if (bug_report != null) {
121                                 bug_report.WriteLine ("### Compiler Output");
122                                 bug_report.Write (mcs_output);
123                         }
124
125                         return (CompilerError[])error_list.ToArray (typeof(CompilerError));
126                 }
127
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) 
133                 {
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);
137
138                         Match match = reg.Match (error_string);
139                         
140                         if (!match.Success)
141                                 return null;
142                         
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}");
153                         
154                         return error;
155                 }
156
157                 private static string[] CreateCsFiles (string[] source_text, string[] source_name) 
158                 {
159                         ArrayList temp_file_list = new ArrayList ();
160
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 ();
173                                 }
174                                 temp_file_list.Add (temp_path);
175                         }
176                 
177                         return (string[])temp_file_list.ToArray (typeof(string));       
178                 }
179
180                 private static string BuildArgs(string[] source_files,
181                         string target, string[] imports, IDictionary options)
182                 {
183                         StringBuilder args = new StringBuilder ();
184
185                         args.AppendFormat ("/out:{0} ", target);
186                         
187                         if (null != imports) {
188                                 foreach (string import in imports)
189                                         args.AppendFormat ("/r:{0} ", import);
190                         }
191                         
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));
198                                 }
199                         }
200                         
201                         foreach (string source in source_files)
202                                 args.AppendFormat ("{0} ", source);
203
204                         return args.ToString ();
205                 }
206
207                 private static string OptionString(object option, object value)
208                 {
209                         if (null != value)
210                                 return String.Format ("/{0}:{1}", option, value);
211                         
212                         return String.Format("/{0}", option);
213                 }
214
215                 private static void VerifyArgs (string[] sourceTexts,
216                         string[] sourceTextNames, string target)
217                 {
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");
224
225                         if (sourceTexts.Length <= 0 || sourceTextNames.Length <= 0)
226                                 throw new IndexOutOfRangeException ();
227                 }
228
229                 private static StreamWriter CreateBugReport (string[] source_texts, 
230                         string[] source_names, string path)
231                 {
232                         StreamWriter bug_report = null;
233
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]);
246                                 }
247                         } catch {
248                                 if (bug_report != null)
249                                         bug_report.Close ();
250                                 throw;
251                         }
252                         
253                         return bug_report;
254                 }
255
256
257                 private static bool ValidOption (string option)
258                 {
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;
283                         }
284                         return false;
285                 }
286
287         }
288
289 }
290