2 // codegen.cs: The code generator
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
11 using System.Reflection;
12 using System.Reflection.Emit;
16 public class CodeGen {
17 AppDomain current_domain;
18 AssemblyBuilder assembly_builder;
19 ModuleBuilder module_builder;
21 string Basename (string name)
23 int pos = name.LastIndexOf ("/");
26 return name.Substring (pos + 1);
28 pos = name.LastIndexOf ("\\");
30 return name.Substring (pos + 1);
35 public CodeGen (string name, string output)
39 an = new AssemblyName ();
41 current_domain = AppDomain.CurrentDomain;
42 assembly_builder = current_domain.DefineDynamicAssembly (
43 an, AssemblyBuilderAccess.RunAndSave);
46 // Pass a path-less name to DefineDynamicModule. Wonder how
47 // this copes with output in different directories then.
48 // FIXME: figure out how this copes with --output /tmp/blah
50 module_builder = assembly_builder.DefineDynamicModule (
51 Basename (name), Basename (output));
54 public AssemblyBuilder AssemblyBuilder {
56 return assembly_builder;
60 public ModuleBuilder ModuleBuilder {
62 return module_builder;
66 public void Save (string name)
69 assembly_builder.Save (Basename (name));
70 } catch (System.IO.IOException io){
71 Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
76 public struct EmitContext {
77 public TypeContainer parent;
78 public ILGenerator ig;
81 // FIXME: FIXME: FIXME!
82 // This structure has to be kept small. We need to figure
83 // out ways of moving the CheckState somewhere else
85 // tracks the state of checked/unchecked arithmetic
88 public bool CheckState;
90 public EmitContext (TypeContainer parent, ILGenerator ig)
98 public bool ConvertTo (Type target, Type source, bool verbose)
100 if (target == source)
105 31, "Can not convert to type bool");
110 public bool EmitBoolExpression (Expression e)
112 e = e.Resolve (parent);
117 if (e.Type != TypeManager.bool_type)
118 e = Expression.ConvertImplicit (parent, e, TypeManager.bool_type,
123 31, "Can not convert the expression to a boolean");
132 public void EmitExpression (Expression e)
134 e = e.Resolve (parent);
141 // Emits an If statement. Returns true if the last opcode
142 // emitted was a ret opcode.
144 public bool EmitIf (If s)
146 Label false_target = ig.DefineLabel ();
148 Statement false_stat = s.FalseStatement;
151 if (!EmitBoolExpression (s.Expr))
154 ig.Emit (OpCodes.Brfalse, false_target);
155 is_ret = EmitStatement (s.TrueStatement);
157 if (false_stat != null){
158 end = ig.DefineLabel ();
159 ig.Emit (OpCodes.Br, end);
161 ig.MarkLabel (false_target);
162 is_ret = EmitStatement (s.FalseStatement);
164 if (false_stat != null)
167 ig.MarkLabel (false_target);
172 public void EmitDo (Do s)
174 Label loop = ig.DefineLabel ();
177 EmitStatement (s.EmbeddedStatement);
178 EmitBoolExpression (s.Expr);
179 ig.Emit (OpCodes.Brtrue, loop);
182 public void EmitWhile (While s)
184 Label while_eval = ig.DefineLabel ();
185 Label exit = ig.DefineLabel ();
187 ig.MarkLabel (while_eval);
188 EmitBoolExpression (s.Expr);
189 ig.Emit (OpCodes.Brfalse, exit);
190 EmitStatement (s.Statement);
191 ig.Emit (OpCodes.Br, while_eval);
195 public void EmitFor (For s)
197 Statement init = s.InitStatement;
198 Statement incr = s.Increment;
199 Label loop = ig.DefineLabel ();
200 Label exit = ig.DefineLabel ();
202 if (! (init is EmptyStatement))
203 EmitStatement (init);
206 EmitBoolExpression (s.Test);
207 ig.Emit (OpCodes.Brfalse, exit);
208 EmitStatement (s.Statement);
209 if (!(incr is EmptyStatement))
210 EmitStatement (incr);
211 ig.Emit (OpCodes.Br, loop);
215 bool ProbeCollectionType (Type t)
220 void EmitForeach (Foreach f)
222 Expression e = f.Expr;
224 e = e.Resolve (parent);
228 if (!ProbeCollectionType (e.Type))
232 void EmitReturn (Return s)
234 Expression ret_expr = s.Expr;
236 if (ret_expr != null)
237 EmitExpression (ret_expr);
238 ig.Emit (OpCodes.Ret);
241 void EmitSwitch (Switch s)
245 void EmitChecked (Checked s)
247 bool previous_state = CheckState;
251 CheckState = previous_state;
255 void EmitUnChecked (Unchecked s)
257 bool previous_state = CheckState;
261 CheckState = previous_state;
264 void EmitStatementExpression (StatementExpression s)
266 ExpressionStatement e = s.Expr;
269 ne = e.Resolve (parent);
271 if (ne is ExpressionStatement)
272 ((ExpressionStatement) ne).EmitStatement (this);
275 ig.Emit (OpCodes.Pop);
281 // Emits the statemets `s'.
283 // Returns true if the statement had a `ret' opcode embedded
285 bool EmitStatement (Statement s)
287 // Console.WriteLine ("Emitting statement of type " + s.GetType ());
294 EmitWhile ((While) s);
297 else if (s is Return){
298 EmitReturn ((Return) s);
300 } else if (s is Switch)
301 EmitSwitch ((Switch) s);
302 else if (s is Checked)
303 EmitChecked ((Checked) s);
304 else if (s is Unchecked)
305 EmitUnChecked ((Unchecked) s);
307 return EmitBlock ((Block) s);
308 else if (s is StatementExpression)
309 EmitStatementExpression ((StatementExpression) s);
310 else if (s is Foreach)
311 EmitForeach ((Foreach) s);
313 Console.WriteLine ("Unhandled Statement type: " +
314 s.GetType ().ToString ());
320 bool EmitBlock (Block block)
323 Block last_block = current_block;
325 current_block = block;
326 foreach (Statement s in block.Statements){
327 is_ret = EmitStatement (s);
329 current_block = last_block;
334 public void EmitTopBlock (Block block)
336 bool has_ret = false;
339 int errors = Report.Errors;
341 block.EmitMeta (parent, ig, block, 0);
343 if (Report.Errors == errors){
344 has_ret = EmitBlock (block);
346 if (Report.Errors == errors)
347 block.UsageWarning ();
352 ig.Emit (OpCodes.Ret);