Moved ProviderCollectionTest.cs from System assembly to System.Configuration.
[mono.git] / mcs / class / System.ServiceModel / Mono.CodeGeneration / CodeBuilder.cs
1 //
2 // Permission is hereby granted, free of charge, to any person obtaining
3 // a copy of this software and associated documentation files (the
4 // "Software"), to deal in the Software without restriction, including
5 // without limitation the rights to use, copy, modify, merge, publish,
6 // distribute, sublicense, and/or sell copies of the Software, and to
7 // permit persons to whom the Software is furnished to do so, subject to
8 // the following conditions:
9 // 
10 // The above copyright notice and this permission notice shall be
11 // included in all copies or substantial portions of the Software.
12 // 
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
17 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 //
21 // Copyright (C) Lluis Sanchez Gual, 2004
22 //
23
24 using System;
25 using System.IO;
26 using System.Collections;
27 using System.Reflection.Emit;
28 using System.Reflection;
29
30 namespace Mono.CodeGeneration
31 {
32         public class CodeBuilder
33         {
34                 CodeBlock mainBlock;
35                 CodeBlock currentBlock;
36                 Stack blockStack = new Stack ();
37                 int varId;
38                 Label returnLabel;
39                 ArrayList nestedIfs = new ArrayList();
40                 int currentIfSerie = -1;
41                 CodeClass codeClass;
42
43                 public CodeBuilder (CodeClass codeClass)
44                 {
45                         this.codeClass = codeClass;
46                         mainBlock = new CodeBlock ();
47                         currentBlock = mainBlock;
48                 }
49                 
50                 CodeBuilder (CodeBlock block)
51                 {
52                         currentBlock = block;
53                 }
54                 
55                 public CodeBlock CurrentBlock
56                 {
57                         get {
58                                 return currentBlock;
59                         }
60                 }
61                 
62                 public CodeClass OwnerClass
63                 {
64                         get { return codeClass; }
65                 }
66                 
67                 public void Generate (ILGenerator gen)
68                 {
69 //                      try {
70                                 mainBlock.Generate (gen);
71 /*
72                         }
73                         catch (Exception ex) {
74                                 string m = ex.Message + "\nCode block:\n";
75                                 m += "-----------------------\n";
76                                 m += PrintCode ();
77                                 m += "-----------------------\n";
78                                 throw new Exception (m, ex);
79                         }
80 */
81                 }
82                 
83                 public string PrintCode ()
84                 {
85                         StringWriter sw = new StringWriter ();
86                         CodeWriter cw = new CodeWriter (sw);
87                         PrintCode (cw);
88                         return sw.ToString ();
89                 }
90                 
91                 public void PrintCode (CodeWriter cp)
92                 {
93                         mainBlock.PrintCode (cp);
94                 }
95                 
96                 public CodeVariableReference DeclareVariable (Type type)
97                 {
98                         return DeclareVariable (type, null);
99                 }
100                 
101                 public CodeVariableReference DeclareVariable (Type type, object ob)
102                 {
103                         return DeclareVariable (type, Exp.Literal(ob));
104                 }
105                 
106                 public CodeVariableReference DeclareVariable (CodeExpression initValue)
107                 {
108                         return DeclareVariable (initValue.GetResultType(), initValue);
109                 }
110                 
111                 public CodeVariableReference DeclareVariable (Type type, CodeExpression initValue)
112                 {
113                         string name = "v" + (varId++);
114                         CodeVariableDeclaration var = new CodeVariableDeclaration (type, name);
115                         currentBlock.Add (var);
116                         if (!object.ReferenceEquals (initValue, null)) 
117                                 Assign (var.Variable, initValue);
118                         return var.Variable;
119                 }
120                 
121                 public void Assign (CodeValueReference var, CodeExpression val)
122                 {
123                         currentBlock.Add (new CodeAssignment (var, val)); 
124                 }
125                 
126                 public void If (CodeExpression condition)
127                 {
128                         currentBlock.Add (new CodeIf (condition));
129                         PushNewBlock ();
130                         nestedIfs.Add (0);
131                 }
132                 
133                 public void ElseIf (CodeExpression condition)
134                 {
135                         if (nestedIfs.Count == 0)
136                                 throw new InvalidOperationException ("'Else' not allowed here");
137
138                         Else ();
139                         currentBlock.Add (new CodeIf (condition));
140                         PushNewBlock ();
141                         nestedIfs [nestedIfs.Count-1] = 1 + (int)nestedIfs [nestedIfs.Count-1];
142                 }
143                 
144                 public void Else ()
145                 {
146                         CodeBlock block = PopBlock ();
147                         CodeIf cif = currentBlock.GetLastItem () as CodeIf;
148                         
149                         if (cif == null || cif.TrueBlock != null)
150                                 throw new InvalidOperationException ("'Else' not allowed here");
151                                 
152                         cif.TrueBlock = block;
153                         PushNewBlock ();
154                 }
155                 
156                 public void EndIf ()
157                 {
158                         CodeBlock block = PopBlock ();
159                         CodeIf cif = currentBlock.GetLastItem () as CodeIf;
160                         
161                         if (cif == null || cif.FalseBlock != null || nestedIfs.Count == 0)
162                                 throw new InvalidOperationException ("'EndIf' not allowed here");
163                         
164                         if (cif.TrueBlock == null)
165                                 cif.TrueBlock = block;
166                         else
167                                 cif.FalseBlock = block;
168                                 
169                         int num = (int) nestedIfs [nestedIfs.Count-1];
170                         if (num > 0) {
171                                 nestedIfs [nestedIfs.Count-1] = --num;
172                                 EndIf ();
173                         }
174                         else {
175                                 nestedIfs.RemoveAt (nestedIfs.Count - 1);
176                         }
177                 }
178                 
179                 public void Select ()
180                 {
181                         currentBlock.Add (new CodeSelect ());
182                         PushNewBlock ();
183                 }
184                 
185                 public void Case (CodeExpression condition)
186                 {
187                         PopBlock ();
188                         CodeSelect select = currentBlock.GetLastItem () as CodeSelect;
189                         if (select == null)
190                                 throw new InvalidOperationException ("'Case' not allowed here");
191
192                         PushNewBlock ();
193                         select.AddCase (condition, currentBlock);
194                 }
195                 
196                 public void EndSelect ()
197                 {
198                         PopBlock ();
199                         CodeSelect select = currentBlock.GetLastItem () as CodeSelect;
200                         if (select == null)
201                                 throw new InvalidOperationException ("'EndSelect' not allowed here");
202                 }
203                 
204                 
205                 public void While (CodeExpression condition)
206                 {
207                         currentBlock.Add (new CodeWhile (condition));
208                         PushNewBlock ();
209                 }
210                 
211                 public void EndWhile ()
212                 {
213                         CodeBlock block = PopBlock ();
214                         CodeWhile cif = currentBlock.GetLastItem () as CodeWhile;
215                         
216                         if (cif == null || cif.WhileBlock != null)
217                                 throw new InvalidOperationException ("'EndWhile' not allowed here");
218                         
219                         cif.WhileBlock = block;
220                 }
221                 
222                 public void Foreach (Type type, out CodeExpression item, CodeExpression array)
223                 {
224                         CodeForeach cfe = new CodeForeach (array, type);
225                         item = cfe.ItemExpression;
226                         currentBlock.Add (cfe);
227                         PushNewBlock ();
228                 }
229                 
230                 public void EndForeach ()
231                 {
232                         CodeBlock block = PopBlock ();
233                         CodeForeach cif = currentBlock.GetLastItem () as CodeForeach;
234                         
235                         if (cif == null || cif.ForBlock != null)
236                                 throw new InvalidOperationException ("'EndForeach' not allowed here");
237                         
238                         cif.ForBlock = block;
239                 }
240                 
241                 public void For (CodeExpression initExp, CodeExpression conditionExp, CodeExpression nextExp)
242                 {
243                         currentBlock.Add (new CodeFor (initExp, conditionExp, nextExp));
244                         PushNewBlock ();
245                 }
246                 
247                 public void EndFor ()
248                 {
249                         CodeBlock block = PopBlock ();
250                         CodeFor cif = currentBlock.GetLastItem () as CodeFor;
251                         
252                         if (cif == null || cif.ForBlock != null)
253                                 throw new InvalidOperationException ("'EndFor' not allowed here");
254                         
255                         cif.ForBlock = block;
256                 }
257                 
258                 
259                 public void Call (CodeExpression target, string name, params CodeExpression[] parameters)
260                 {
261                         if ((object) target == null)
262                                 throw new ArgumentNullException ("target");
263                         if (name == null)
264                                 throw new ArgumentNullException ("name");
265                         currentBlock.Add (new CodeMethodCall (target, name, parameters));
266                 }
267                 
268                 public void Call (CodeExpression target, MethodBase method, params CodeExpression[] parameters)
269                 {
270                         if ((object) target == null)
271                                 throw new ArgumentNullException ("target");
272                         if (method == null)
273                                 throw new ArgumentNullException ("method");
274                         currentBlock.Add (new CodeMethodCall (target, method, parameters));
275                 }
276                 
277                 public void Call (CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
278                 {
279                         if ((object) target == null)
280                                 throw new ArgumentNullException ("target");
281                         if (method == null)
282                                 throw new ArgumentNullException ("method");
283                         currentBlock.Add (new CodeMethodCall (target, method, parameters));
284                 }
285                 
286                 public void Call (Type type, string name, params CodeExpression[] parameters)
287                 {
288                         if (type == null)
289                                 throw new ArgumentNullException ("type");
290                         if (name == null)
291                                 throw new ArgumentNullException ("name");
292                         currentBlock.Add (new CodeMethodCall (type, name, parameters));
293                 }
294                 
295                 public void Call (MethodInfo method, params CodeExpression[] parameters)
296                 {
297                         if (method == null)
298                                 throw new ArgumentNullException ("method");
299                         currentBlock.Add (new CodeMethodCall (method, parameters));
300                 }
301                 
302                 public void Call (CodeMethod method, params CodeExpression[] parameters)
303                 {
304                         if ((object) method == null)
305                                 throw new ArgumentNullException ("method");
306                         currentBlock.Add (new CodeMethodCall (method, parameters));
307                 }
308                 
309                 public CodeExpression CallFunc (CodeExpression target, string name, params CodeExpression[] parameters)
310                 {
311                         if ((object) target == null)
312                                 throw new ArgumentNullException ("target");
313                         if (name == null)
314                                 throw new ArgumentNullException ("name");
315                         return new CodeMethodCall (target, name, parameters);
316                 }
317                 
318                 public CodeExpression CallFunc (CodeExpression target, MethodInfo method, params CodeExpression[] parameters)
319                 {
320                         if ((object) target == null)
321                                 throw new ArgumentNullException ("target");
322                         if (method == null)
323                                 throw new ArgumentNullException ("method");
324                         return new CodeMethodCall (target, method, parameters);
325                 }
326                 
327                 public CodeExpression CallFunc (CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
328                 {
329                         if ((object) target == null)
330                                 throw new ArgumentNullException ("target");
331                         if (method == null)
332                                 throw new ArgumentNullException ("method");
333                         return new CodeMethodCall (target, method, parameters);
334                 }
335                 
336                 public CodeExpression CallFunc (Type type, string name, params CodeExpression[] parameters)
337                 {
338                         if (type == null)
339                                 throw new ArgumentNullException ("type");
340                         if (name == null)
341                                 throw new ArgumentNullException ("name");
342                         return new CodeMethodCall (type, name, parameters);
343                 }
344                 
345                 public CodeExpression CallFunc (MethodInfo method, params CodeExpression[] parameters)
346                 {
347                         if (method == null)
348                                 throw new ArgumentNullException ("method");
349                         return new CodeMethodCall (method, parameters);
350                 }
351                 
352                 public CodeExpression CallFunc (CodeMethod method, params CodeExpression[] parameters)
353                 {
354                         if ((object) method == null)
355                                 throw new ArgumentNullException ("method");
356                         return new CodeMethodCall (method, parameters);
357                 }
358                 
359                 public void Inc (CodeValueReference val)
360                 {
361                         Assign (val, new CodeIncrement (val));
362                 }
363                 
364                 public void Dec (CodeValueReference val)
365                 {
366                         Assign (val, new CodeDecrement (val));
367                 }
368                 
369                 public CodeExpression When (CodeExpression condition, CodeExpression trueResult, CodeExpression falseResult)
370                 {
371                         return new CodeWhen (condition, trueResult, falseResult);
372                 }
373                 
374                 public void ConsoleWriteLine (params CodeExpression[] parameters)
375                 {
376                         Call (typeof(Console), "WriteLine", parameters);
377                 }
378                 
379                 public void ConsoleWriteLine (params object[] parameters)
380                 {
381                         CodeExpression[] exps = new CodeExpression [parameters.Length];
382                         for (int n=0; n<exps.Length; n++)
383                                 exps[n] = Exp.Literal (parameters[n]);
384                                 
385                         ConsoleWriteLine (exps);
386                 }
387                 
388                 public void Return (CodeExpression exp)
389                 {
390                         currentBlock.Add (new CodeReturn (this, exp));
391                 }
392                 
393                 public void Return ()
394                 {
395                         currentBlock.Add (new CodeReturn (this));
396                 }
397                 
398                 public static CodeBuilder operator+(CodeBuilder cb, CodeItem e)
399                 {
400                         cb.currentBlock.Add (e);
401                         return cb;
402                 }
403                 
404                 internal Label ReturnLabel
405                 {
406                         get { return returnLabel; }
407                         set { returnLabel = value; }
408                 }
409                 
410                 void PushNewBlock ()
411                 {
412                         blockStack.Push (currentBlock);
413                         currentBlock = new CodeBlock ();
414                 }
415                 
416                 CodeBlock PopBlock ()
417                 {
418                         CodeBlock block = currentBlock;
419                         currentBlock = (CodeBlock) blockStack.Pop ();
420                         return block;
421                 }
422         }
423 }