2004-06-24 Anirban Bhattacharjee <banirban@novell.com>
[mono.git] / mcs / class / Microsoft.VisualBasic / Microsoft.VisualBasic / VisualBasicCodeCompiler.cs
1 //\r
2 // Microsoft VisualBasic VBCodeCompiler Class implementation\r
3 //\r
4 // Author:\r
5 //   Jochen Wezel (jwezel@compumaster.de)\r
6 //\r
7 \r
8 namespace Microsoft.VisualBasic\r
9 {\r
10         using System;\r
11         using System.CodeDom;\r
12         using System.CodeDom.Compiler;\r
13         using System.IO;\r
14         using System.Text;\r
15         using System.Reflection;\r
16         using System.Collections;\r
17         using System.Collections.Specialized;\r
18         using System.Diagnostics;\r
19         using System.Text.RegularExpressions;\r
20 \r
21         internal class VisualBasicCodeCompiler: VisualBasicCodeGenerator, ICodeCompiler\r
22         {\r
23                 //\r
24                 // Constructors\r
25                 //\r
26                 public VisualBasicCodeCompiler()\r
27                 {\r
28                 }\r
29 \r
30                 //\r
31                 // Methods\r
32                 //\r
33                 [MonoTODO]\r
34                 public CompilerResults CompileAssemblyFromDom (\r
35                         CompilerParameters options,CodeCompileUnit e)\r
36                 {\r
37                         return CompileAssemblyFromDomBatch(options,new CodeCompileUnit[]{e});\r
38                 }\r
39                 public CompilerResults CompileAssemblyFromDomBatch (\r
40                         CompilerParameters options,CodeCompileUnit[] ea)\r
41                 {\r
42                         string[] fileNames=new string[ea.Length];\r
43                         int i=0;\r
44                         if (options == null)\r
45                                 options = new CompilerParameters ();\r
46                         \r
47                         StringCollection assemblies = options.ReferencedAssemblies;\r
48 \r
49                         foreach (CodeCompileUnit e in ea)\r
50                         {\r
51                                 fileNames[i]=Path.ChangeExtension(Path.GetTempFileName(),"vb");\r
52                                 FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);\r
53                                 StreamWriter s=new StreamWriter(f);\r
54                                 if (e.ReferencedAssemblies != null) {\r
55                                         foreach (string str in e.ReferencedAssemblies) {\r
56                                                 if (!assemblies.Contains (str))\r
57                                                         assemblies.Add (str);\r
58                                         }\r
59                                 }\r
60 \r
61                                 ((ICodeGenerator)this).GenerateCodeFromCompileUnit (e, s, new CodeGeneratorOptions());\r
62                                 s.Close();\r
63                                 f.Close();\r
64                                 i++;\r
65                         }\r
66                         return CompileAssemblyFromFileBatch(options,fileNames);\r
67                 }\r
68                 public CompilerResults CompileAssemblyFromFile (\r
69                         CompilerParameters options,string fileName)\r
70                 {\r
71                         return CompileAssemblyFromFileBatch(options,new string[]{fileName});\r
72                 }\r
73                 public CompilerResults CompileAssemblyFromFileBatch (\r
74                         CompilerParameters options,string[] fileNames)\r
75                 {\r
76                         if (null == options)\r
77                                 throw new ArgumentNullException("options");\r
78                         if (null == fileNames)\r
79                                 throw new ArgumentNullException("fileNames");\r
80 \r
81                         CompilerResults results=new CompilerResults(options.TempFiles);\r
82                         Process mcs=new Process();\r
83 \r
84                         string mcs_output;\r
85                         string[] mcs_output_lines;\r
86                         mcs.StartInfo.FileName="mbas";\r
87                         mcs.StartInfo.Arguments=BuildArgs(options,fileNames);\r
88                         mcs.StartInfo.CreateNoWindow=true;\r
89                         mcs.StartInfo.UseShellExecute=false;\r
90                         mcs.StartInfo.RedirectStandardOutput=true;\r
91                         try {\r
92                                 mcs.Start();\r
93                                 mcs_output=mcs.StandardOutput.ReadToEnd();\r
94                                 mcs.WaitForExit();\r
95                         } finally {\r
96                                 results.NativeCompilerReturnValue = mcs.ExitCode;\r
97                                 mcs.Close();\r
98                         }\r
99                         mcs_output_lines=mcs_output.Split(\r
100                                 System.Environment.NewLine.ToCharArray());\r
101                         bool loadIt=true;\r
102                         foreach (string error_line in mcs_output_lines)\r
103                         {\r
104                                 CompilerError error=CreateErrorFromString(error_line);\r
105                                 if (null!=error)\r
106                                 {\r
107                                         results.Errors.Add(error);\r
108                                         if (!error.IsWarning) loadIt=false;\r
109                                 }\r
110                         }\r
111                         if (loadIt)\r
112                                 results.CompiledAssembly=Assembly.LoadFrom(options.OutputAssembly);\r
113                         else\r
114                                 results.CompiledAssembly=null;\r
115                         return results;\r
116                 }\r
117                 public CompilerResults CompileAssemblyFromSource (\r
118                         CompilerParameters options,string source)\r
119                 {\r
120                         return CompileAssemblyFromSourceBatch(options,new string[]{source});\r
121                 }\r
122                 public CompilerResults CompileAssemblyFromSourceBatch (\r
123                         CompilerParameters options,string[] sources)\r
124                 {\r
125                         string[] fileNames=new string[sources.Length];\r
126                         int i=0;\r
127                         foreach (string source in sources)\r
128                         {\r
129                                 fileNames[i]=Path.ChangeExtension(Path.GetTempFileName(),"vb");\r
130                                 FileStream f=new FileStream(fileNames[i],FileMode.OpenOrCreate);\r
131                                 StreamWriter s=new StreamWriter(f);\r
132                                 s.Write(source);\r
133                                 s.Close();\r
134                                 f.Close();\r
135                                 i++;\r
136                         }\r
137                         return CompileAssemblyFromFileBatch(options,fileNames);\r
138                 }\r
139                 private static string BuildArgs(\r
140                         CompilerParameters options,string[] fileNames)\r
141                 {\r
142                         StringBuilder args=new StringBuilder();\r
143                         if (options.GenerateExecutable)\r
144                                 args.AppendFormat("/target:exe ");\r
145                         else\r
146                                 args.AppendFormat("/target:library ");\r
147                         if (options.IncludeDebugInformation)\r
148                                 args.AppendFormat("/debug ");\r
149                         if (options.TreatWarningsAsErrors)\r
150                                 args.AppendFormat("/warnaserror ");\r
151 \r
152                         if (options.WarningLevel != -1)\r
153                                 args.AppendFormat ("/warn:{0} ", options.WarningLevel);\r
154 \r
155                         if (options.OutputAssembly==null)\r
156                                 options.OutputAssembly=Path.ChangeExtension(Path.GetTempFileName(),"dll");\r
157                         args.AppendFormat("/out:\"{0}\" ",options.OutputAssembly);\r
158                         if (null != options.ReferencedAssemblies)\r
159                         {\r
160                                 foreach (string import in options.ReferencedAssemblies)\r
161                                         args.AppendFormat("/r:\"{0}\" ",import);\r
162                         }\r
163                         foreach (string source in fileNames)\r
164                                 args.AppendFormat("\"{0}\" ",source);\r
165                         return args.ToString();\r
166                 }\r
167                 private static CompilerError CreateErrorFromString(string error_string)\r
168                 {\r
169                         // When IncludeDebugInformation is true, prevents the debug symbols stats from braeking this.\r
170                         if (error_string.StartsWith ("WROTE SYMFILE") || error_string.StartsWith ("OffsetTable"))\r
171                                 return null;\r
172 \r
173                         CompilerError error=new CompilerError();\r
174                         Regex reg = new Regex (@"^(\s*(?<file>.*)\((?<line>\d*)(,(?<column>\d*))?\)\s+)*(?<level>\w+)\s*(?<number>.*):\s(?<message>.*)",\r
175                                 RegexOptions.Compiled | RegexOptions.ExplicitCapture);\r
176                         Match match=reg.Match(error_string);\r
177                         if (!match.Success) return null;\r
178                         if (String.Empty != match.Result("${file}"))\r
179                                 error.FileName=match.Result("${file}");\r
180                         if (String.Empty != match.Result("${line}"))\r
181                                 error.Line=Int32.Parse(match.Result("${line}"));\r
182                         if (String.Empty != match.Result("${column}"))\r
183                                 error.Column=Int32.Parse(match.Result("${column}"));\r
184                         if (match.Result("${level}")=="warning")\r
185                                 error.IsWarning=true;\r
186                         error.ErrorNumber=match.Result("${number}");\r
187                         error.ErrorText=match.Result("${message}");\r
188                         return error;\r
189                 }\r
190         }\r
191 }\r