Merge pull request #681 from tritao/dll-api
[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 #if !FULL_AOT_RUNTIME
25 using System;
26 using System.IO;
27 using System.Collections;
28 using System.Reflection.Emit;
29 using System.Reflection;
30
31 namespace Mono.CodeGeneration
32 {
33         public class CodeBuilder
34         {
35                 CodeBlock mainBlock;
36                 CodeBlock currentBlock;
37                 Stack blockStack = new Stack ();
38                 int varId;
39                 Label returnLabel;
40                 ArrayList nestedIfs = new ArrayList();
41                 int currentIfSerie = -1;
42                 CodeClass codeClass;
43
44                 public CodeBuilder (CodeClass codeClass)
45                 {
46                         this.codeClass = codeClass;
47                         mainBlock = new CodeBlock ();
48                         currentBlock = mainBlock;
49                 }
50                 
51                 CodeBuilder (CodeBlock block)
52                 {
53                         currentBlock = block;
54                 }
55                 
56                 public CodeBlock CurrentBlock
57                 {
58                         get {
59                                 return currentBlock;
60                         }
61                 }
62                 
63                 public CodeClass OwnerClass
64                 {
65                         get { return codeClass; }
66                 }
67                 
68                 public void Generate (ILGenerator gen)
69                 {
70 //                      try {
71                                 mainBlock.Generate (gen);
72 /*
73                         }
74                         catch (Exception ex) {
75                                 string m = ex.Message + "\nCode block:\n";
76                                 m += "-----------------------\n";
77                                 m += PrintCode ();
78                                 m += "-----------------------\n";
79                                 throw new Exception (m, ex);
80                         }
81 */
82                 }
83                 
84                 public string PrintCode ()
85                 {
86                         StringWriter sw = new StringWriter ();
87                         CodeWriter cw = new CodeWriter (sw);
88                         PrintCode (cw);
89                         return sw.ToString ();
90                 }
91                 
92                 public void PrintCode (CodeWriter cp)
93                 {
94                         mainBlock.PrintCode (cp);
95                 }
96                 
97                 public CodeVariableReference DeclareVariable (Type type)
98                 {
99                         return DeclareVariable (type, null);
100                 }
101                 
102                 public CodeVariableReference DeclareVariable (Type type, object ob)
103                 {
104                         return DeclareVariable (type, Exp.Literal(ob));
105                 }
106                 
107                 public CodeVariableReference DeclareVariable (CodeExpression initValue)
108                 {
109                         return DeclareVariable (initValue.GetResultType(), initValue);
110                 }
111                 
112                 public CodeVariableReference DeclareVariable (Type type, CodeExpression initValue)
113                 {
114                         string name = "v" + (varId++);
115                         CodeVariableDeclaration var = new CodeVariableDeclaration (type, name);
116                         currentBlock.Add (var);
117                         if (!object.ReferenceEquals (initValue, null)) 
118                                 Assign (var.Variable, initValue);
119                         return var.Variable;
120                 }
121                 
122                 public void Assign (CodeValueReference var, CodeExpression val)
123                 {
124                         currentBlock.Add (new CodeAssignment (var, val)); 
125                 }
126                 
127                 public void If (CodeExpression condition)
128                 {
129                         currentBlock.Add (new CodeIf (condition));
130                         PushNewBlock ();
131                         nestedIfs.Add (0);
132                 }
133                 
134                 public void ElseIf (CodeExpression condition)
135                 {
136                         if (nestedIfs.Count == 0)
137                                 throw new InvalidOperationException ("'Else' not allowed here");
138
139                         Else ();
140                         currentBlock.Add (new CodeIf (condition));
141                         PushNewBlock ();
142                         nestedIfs [nestedIfs.Count-1] = 1 + (int)nestedIfs [nestedIfs.Count-1];
143                 }
144                 
145                 public void Else ()
146                 {
147                         CodeBlock block = PopBlock ();
148                         CodeIf cif = currentBlock.GetLastItem () as CodeIf;
149                         
150                         if (cif == null || cif.TrueBlock != null)
151                                 throw new InvalidOperationException ("'Else' not allowed here");
152                                 
153                         cif.TrueBlock = block;
154                         PushNewBlock ();
155                 }
156                 
157                 public void EndIf ()
158                 {
159                         CodeBlock block = PopBlock ();
160                         CodeIf cif = currentBlock.GetLastItem () as CodeIf;
161                         
162                         if (cif == null || cif.FalseBlock != null || nestedIfs.Count == 0)
163                                 throw new InvalidOperationException ("'EndIf' not allowed here");
164                         
165                         if (cif.TrueBlock == null)
166                                 cif.TrueBlock = block;
167                         else
168                                 cif.FalseBlock = block;
169                                 
170                         int num = (int) nestedIfs [nestedIfs.Count-1];
171                         if (num > 0) {
172                                 nestedIfs [nestedIfs.Count-1] = --num;
173                                 EndIf ();
174                         }
175                         else {
176                                 nestedIfs.RemoveAt (nestedIfs.Count - 1);
177                         }
178                 }
179                 
180                 public void Select ()
181                 {
182                         currentBlock.Add (new CodeSelect ());
183                         PushNewBlock ();
184                 }
185                 
186                 public void Case (CodeExpression condition)
187                 {
188                         PopBlock ();
189                         CodeSelect select = currentBlock.GetLastItem () as CodeSelect;
190                         if (select == null)
191                                 throw new InvalidOperationException ("'Case' not allowed here");
192
193                         PushNewBlock ();
194                         select.AddCase (condition, currentBlock);
195                 }
196                 
197                 public void EndSelect ()
198                 {
199                         PopBlock ();
200                         CodeSelect select = currentBlock.GetLastItem () as CodeSelect;
201                         if (select == null)
202                                 throw new InvalidOperationException ("'EndSelect' not allowed here");
203                 }
204                 
205                 
206                 public void While (CodeExpression condition)
207                 {
208                         currentBlock.Add (new CodeWhile (condition));
209                         PushNewBlock ();
210                 }
211                 
212                 public void EndWhile ()
213                 {
214                         CodeBlock block = PopBlock ();
215                         CodeWhile cif = currentBlock.GetLastItem () as CodeWhile;
216                         
217                         if (cif == null || cif.WhileBlock != null)
218                                 throw new InvalidOperationException ("'EndWhile' not allowed here");
219                         
220                         cif.WhileBlock = block;
221                 }
222                 
223                 public void Foreach (Type type, out CodeExpression item, CodeExpression array)
224                 {
225                         CodeForeach cfe = new CodeForeach (array, type);
226                         item = cfe.ItemExpression;
227                         currentBlock.Add (cfe);
228                         PushNewBlock ();
229                 }
230                 
231                 public void EndForeach ()
232                 {
233                         CodeBlock block = PopBlock ();
234                         CodeForeach cif = currentBlock.GetLastItem () as CodeForeach;
235                         
236                         if (cif == null || cif.ForBlock != null)
237                                 throw new InvalidOperationException ("'EndForeach' not allowed here");
238                         
239                         cif.ForBlock = block;
240                 }
241                 
242                 public void For (CodeExpression initExp, CodeExpression conditionExp, CodeExpression nextExp)
243                 {
244                         currentBlock.Add (new CodeFor (initExp, conditionExp, nextExp));
245                         PushNewBlock ();
246                 }
247                 
248                 public void EndFor ()
249                 {
250                         CodeBlock block = PopBlock ();
251                         CodeFor cif = currentBlock.GetLastItem () as CodeFor;
252                         
253                         if (cif == null || cif.ForBlock != null)
254                                 throw new InvalidOperationException ("'EndFor' not allowed here");
255                         
256                         cif.ForBlock = block;
257                 }
258                 
259                 
260                 public void Call (CodeExpression target, string name, params CodeExpression[] parameters)
261                 {
262                         if ((object) target == null)
263                                 throw new ArgumentNullException ("target");
264                         if (name == null)
265                                 throw new ArgumentNullException ("name");
266                         currentBlock.Add (new CodeMethodCall (target, name, parameters));
267                 }
268                 
269                 public void Call (CodeExpression target, MethodBase method, params CodeExpression[] parameters)
270                 {
271                         if ((object) target == null)
272                                 throw new ArgumentNullException ("target");
273                         if (method == null)
274                                 throw new ArgumentNullException ("method");
275                         currentBlock.Add (new CodeMethodCall (target, method, parameters));
276                 }
277                 
278                 public void Call (CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
279                 {
280                         if ((object) target == null)
281                                 throw new ArgumentNullException ("target");
282                         if (method == null)
283                                 throw new ArgumentNullException ("method");
284                         currentBlock.Add (new CodeMethodCall (target, method, parameters));
285                 }
286                 
287                 public void Call (Type type, string name, params CodeExpression[] parameters)
288                 {
289                         if (type == null)
290                                 throw new ArgumentNullException ("type");
291                         if (name == null)
292                                 throw new ArgumentNullException ("name");
293                         currentBlock.Add (new CodeMethodCall (type, name, parameters));
294                 }
295                 
296                 public void Call (MethodInfo method, params CodeExpression[] parameters)
297                 {
298                         if (method == null)
299                                 throw new ArgumentNullException ("method");
300                         currentBlock.Add (new CodeMethodCall (method, parameters));
301                 }
302                 
303                 public void Call (CodeMethod method, params CodeExpression[] parameters)
304                 {
305                         if ((object) method == null)
306                                 throw new ArgumentNullException ("method");
307                         currentBlock.Add (new CodeMethodCall (method, parameters));
308                 }
309                 
310                 public CodeExpression CallFunc (CodeExpression target, string name, params CodeExpression[] parameters)
311                 {
312                         if ((object) target == null)
313                                 throw new ArgumentNullException ("target");
314                         if (name == null)
315                                 throw new ArgumentNullException ("name");
316                         return new CodeMethodCall (target, name, parameters);
317                 }
318                 
319                 public CodeExpression CallFunc (CodeExpression target, MethodInfo method, params CodeExpression[] parameters)
320                 {
321                         if ((object) target == null)
322                                 throw new ArgumentNullException ("target");
323                         if (method == null)
324                                 throw new ArgumentNullException ("method");
325                         return new CodeMethodCall (target, method, parameters);
326                 }
327                 
328                 public CodeExpression CallFunc (CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
329                 {
330                         if ((object) target == null)
331                                 throw new ArgumentNullException ("target");
332                         if (method == null)
333                                 throw new ArgumentNullException ("method");
334                         return new CodeMethodCall (target, method, parameters);
335                 }
336                 
337                 public CodeExpression CallFunc (Type type, string name, params CodeExpression[] parameters)
338                 {
339                         if (type == null)
340                                 throw new ArgumentNullException ("type");
341                         if (name == null)
342                                 throw new ArgumentNullException ("name");
343                         return new CodeMethodCall (type, name, parameters);
344                 }
345                 
346                 public CodeExpression CallFunc (MethodInfo method, params CodeExpression[] parameters)
347                 {
348                         if (method == null)
349                                 throw new ArgumentNullException ("method");
350                         return new CodeMethodCall (method, parameters);
351                 }
352                 
353                 public CodeExpression CallFunc (CodeMethod method, params CodeExpression[] parameters)
354                 {
355                         if ((object) method == null)
356                                 throw new ArgumentNullException ("method");
357                         return new CodeMethodCall (method, parameters);
358                 }
359                 
360                 public void Inc (CodeValueReference val)
361                 {
362                         Assign (val, new CodeIncrement (val));
363                 }
364                 
365                 public void Dec (CodeValueReference val)
366                 {
367                         Assign (val, new CodeDecrement (val));
368                 }
369                 
370                 public CodeExpression When (CodeExpression condition, CodeExpression trueResult, CodeExpression falseResult)
371                 {
372                         return new CodeWhen (condition, trueResult, falseResult);
373                 }
374                 
375                 public void ConsoleWriteLine (params CodeExpression[] parameters)
376                 {
377                         Call (typeof(Console), "WriteLine", parameters);
378                 }
379                 
380                 public void ConsoleWriteLine (params object[] parameters)
381                 {
382                         CodeExpression[] exps = new CodeExpression [parameters.Length];
383                         for (int n=0; n<exps.Length; n++)
384                                 exps[n] = Exp.Literal (parameters[n]);
385                                 
386                         ConsoleWriteLine (exps);
387                 }
388                 
389                 public void Return (CodeExpression exp)
390                 {
391                         currentBlock.Add (new CodeReturn (this, exp));
392                 }
393                 
394                 public void Return ()
395                 {
396                         currentBlock.Add (new CodeReturn (this));
397                 }
398                 
399                 public static CodeBuilder operator+(CodeBuilder cb, CodeItem e)
400                 {
401                         cb.currentBlock.Add (e);
402                         return cb;
403                 }
404                 
405                 internal Label ReturnLabel
406                 {
407                         get { return returnLabel; }
408                         set { returnLabel = value; }
409                 }
410                 
411                 void PushNewBlock ()
412                 {
413                         blockStack.Push (currentBlock);
414                         currentBlock = new CodeBlock ();
415                 }
416                 
417                 CodeBlock PopBlock ()
418                 {
419                         CodeBlock block = currentBlock;
420                         currentBlock = (CodeBlock) blockStack.Pop ();
421                         return block;
422                 }
423         }
424 }
425 #endif