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:
10 // The above copyright notice and this permission notice shall be
11 // included in all copies or substantial portions of the Software.
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.
21 // Copyright (C) Lluis Sanchez Gual, 2004
27 using System.Collections;
28 using System.Reflection.Emit;
29 using System.Reflection;
31 namespace Mono.CodeGeneration
33 public class CodeBuilder
36 CodeBlock currentBlock;
37 Stack blockStack = new Stack ();
40 ArrayList nestedIfs = new ArrayList();
41 int currentIfSerie = -1;
44 public CodeBuilder (CodeClass codeClass)
46 this.codeClass = codeClass;
47 mainBlock = new CodeBlock ();
48 currentBlock = mainBlock;
51 CodeBuilder (CodeBlock block)
56 public CodeBlock CurrentBlock
63 public CodeClass OwnerClass
65 get { return codeClass; }
68 public void Generate (ILGenerator gen)
71 mainBlock.Generate (gen);
74 catch (Exception ex) {
75 string m = ex.Message + "\nCode block:\n";
76 m += "-----------------------\n";
78 m += "-----------------------\n";
79 throw new Exception (m, ex);
84 public string PrintCode ()
86 StringWriter sw = new StringWriter ();
87 CodeWriter cw = new CodeWriter (sw);
89 return sw.ToString ();
92 public void PrintCode (CodeWriter cp)
94 mainBlock.PrintCode (cp);
97 public CodeVariableReference DeclareVariable (Type type)
99 return DeclareVariable (type, null);
102 public CodeVariableReference DeclareVariable (Type type, object ob)
104 return DeclareVariable (type, Exp.Literal(ob));
107 public CodeVariableReference DeclareVariable (CodeExpression initValue)
109 return DeclareVariable (initValue.GetResultType(), initValue);
112 public CodeVariableReference DeclareVariable (Type type, CodeExpression initValue)
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);
122 public void Assign (CodeValueReference var, CodeExpression val)
124 currentBlock.Add (new CodeAssignment (var, val));
127 public void If (CodeExpression condition)
129 currentBlock.Add (new CodeIf (condition));
134 public void ElseIf (CodeExpression condition)
136 if (nestedIfs.Count == 0)
137 throw new InvalidOperationException ("'Else' not allowed here");
140 currentBlock.Add (new CodeIf (condition));
142 nestedIfs [nestedIfs.Count-1] = 1 + (int)nestedIfs [nestedIfs.Count-1];
147 CodeBlock block = PopBlock ();
148 CodeIf cif = currentBlock.GetLastItem () as CodeIf;
150 if (cif == null || cif.TrueBlock != null)
151 throw new InvalidOperationException ("'Else' not allowed here");
153 cif.TrueBlock = block;
159 CodeBlock block = PopBlock ();
160 CodeIf cif = currentBlock.GetLastItem () as CodeIf;
162 if (cif == null || cif.FalseBlock != null || nestedIfs.Count == 0)
163 throw new InvalidOperationException ("'EndIf' not allowed here");
165 if (cif.TrueBlock == null)
166 cif.TrueBlock = block;
168 cif.FalseBlock = block;
170 int num = (int) nestedIfs [nestedIfs.Count-1];
172 nestedIfs [nestedIfs.Count-1] = --num;
176 nestedIfs.RemoveAt (nestedIfs.Count - 1);
180 public void Select ()
182 currentBlock.Add (new CodeSelect ());
186 public void Case (CodeExpression condition)
189 CodeSelect select = currentBlock.GetLastItem () as CodeSelect;
191 throw new InvalidOperationException ("'Case' not allowed here");
194 select.AddCase (condition, currentBlock);
197 public void EndSelect ()
200 CodeSelect select = currentBlock.GetLastItem () as CodeSelect;
202 throw new InvalidOperationException ("'EndSelect' not allowed here");
206 public void While (CodeExpression condition)
208 currentBlock.Add (new CodeWhile (condition));
212 public void EndWhile ()
214 CodeBlock block = PopBlock ();
215 CodeWhile cif = currentBlock.GetLastItem () as CodeWhile;
217 if (cif == null || cif.WhileBlock != null)
218 throw new InvalidOperationException ("'EndWhile' not allowed here");
220 cif.WhileBlock = block;
223 public void Foreach (Type type, out CodeExpression item, CodeExpression array)
225 CodeForeach cfe = new CodeForeach (array, type);
226 item = cfe.ItemExpression;
227 currentBlock.Add (cfe);
231 public void EndForeach ()
233 CodeBlock block = PopBlock ();
234 CodeForeach cif = currentBlock.GetLastItem () as CodeForeach;
236 if (cif == null || cif.ForBlock != null)
237 throw new InvalidOperationException ("'EndForeach' not allowed here");
239 cif.ForBlock = block;
242 public void For (CodeExpression initExp, CodeExpression conditionExp, CodeExpression nextExp)
244 currentBlock.Add (new CodeFor (initExp, conditionExp, nextExp));
248 public void EndFor ()
250 CodeBlock block = PopBlock ();
251 CodeFor cif = currentBlock.GetLastItem () as CodeFor;
253 if (cif == null || cif.ForBlock != null)
254 throw new InvalidOperationException ("'EndFor' not allowed here");
256 cif.ForBlock = block;
260 public void Call (CodeExpression target, string name, params CodeExpression[] parameters)
262 if ((object) target == null)
263 throw new ArgumentNullException ("target");
265 throw new ArgumentNullException ("name");
266 currentBlock.Add (new CodeMethodCall (target, name, parameters));
269 public void Call (CodeExpression target, MethodBase method, params CodeExpression[] parameters)
271 if ((object) target == null)
272 throw new ArgumentNullException ("target");
274 throw new ArgumentNullException ("method");
275 currentBlock.Add (new CodeMethodCall (target, method, parameters));
278 public void Call (CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
280 if ((object) target == null)
281 throw new ArgumentNullException ("target");
283 throw new ArgumentNullException ("method");
284 currentBlock.Add (new CodeMethodCall (target, method, parameters));
287 public void Call (Type type, string name, params CodeExpression[] parameters)
290 throw new ArgumentNullException ("type");
292 throw new ArgumentNullException ("name");
293 currentBlock.Add (new CodeMethodCall (type, name, parameters));
296 public void Call (MethodInfo method, params CodeExpression[] parameters)
299 throw new ArgumentNullException ("method");
300 currentBlock.Add (new CodeMethodCall (method, parameters));
303 public void Call (CodeMethod method, params CodeExpression[] parameters)
305 if ((object) method == null)
306 throw new ArgumentNullException ("method");
307 currentBlock.Add (new CodeMethodCall (method, parameters));
310 public CodeExpression CallFunc (CodeExpression target, string name, params CodeExpression[] parameters)
312 if ((object) target == null)
313 throw new ArgumentNullException ("target");
315 throw new ArgumentNullException ("name");
316 return new CodeMethodCall (target, name, parameters);
319 public CodeExpression CallFunc (CodeExpression target, MethodInfo method, params CodeExpression[] parameters)
321 if ((object) target == null)
322 throw new ArgumentNullException ("target");
324 throw new ArgumentNullException ("method");
325 return new CodeMethodCall (target, method, parameters);
328 public CodeExpression CallFunc (CodeExpression target, CodeMethod method, params CodeExpression[] parameters)
330 if ((object) target == null)
331 throw new ArgumentNullException ("target");
333 throw new ArgumentNullException ("method");
334 return new CodeMethodCall (target, method, parameters);
337 public CodeExpression CallFunc (Type type, string name, params CodeExpression[] parameters)
340 throw new ArgumentNullException ("type");
342 throw new ArgumentNullException ("name");
343 return new CodeMethodCall (type, name, parameters);
346 public CodeExpression CallFunc (MethodInfo method, params CodeExpression[] parameters)
349 throw new ArgumentNullException ("method");
350 return new CodeMethodCall (method, parameters);
353 public CodeExpression CallFunc (CodeMethod method, params CodeExpression[] parameters)
355 if ((object) method == null)
356 throw new ArgumentNullException ("method");
357 return new CodeMethodCall (method, parameters);
360 public void Inc (CodeValueReference val)
362 Assign (val, new CodeIncrement (val));
365 public void Dec (CodeValueReference val)
367 Assign (val, new CodeDecrement (val));
370 public CodeExpression When (CodeExpression condition, CodeExpression trueResult, CodeExpression falseResult)
372 return new CodeWhen (condition, trueResult, falseResult);
375 public void ConsoleWriteLine (params CodeExpression[] parameters)
377 Call (typeof(Console), "WriteLine", parameters);
380 public void ConsoleWriteLine (params object[] parameters)
382 CodeExpression[] exps = new CodeExpression [parameters.Length];
383 for (int n=0; n<exps.Length; n++)
384 exps[n] = Exp.Literal (parameters[n]);
386 ConsoleWriteLine (exps);
389 public void Return (CodeExpression exp)
391 currentBlock.Add (new CodeReturn (this, exp));
394 public void Return ()
396 currentBlock.Add (new CodeReturn (this));
399 public static CodeBuilder operator+(CodeBuilder cb, CodeItem e)
401 cb.currentBlock.Add (e);
405 internal Label ReturnLabel
407 get { return returnLabel; }
408 set { returnLabel = value; }
413 blockStack.Push (currentBlock);
414 currentBlock = new CodeBlock ();
417 CodeBlock PopBlock ()
419 CodeBlock block = currentBlock;
420 currentBlock = (CodeBlock) blockStack.Pop ();