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;
80 // FIXME: FIXME: FIXME!
81 // This structure has to be kept small. We need to figure
82 // out ways of moving the CheckState somewhere else
84 // tracks the state of checked/unchecked arithmetic
87 public bool CheckState;
89 public EmitContext (TypeContainer parent, ILGenerator ig)
96 public bool ConvertTo (Type target, Type source, bool verbose)
103 31, "Can not convert to type bool");
108 public bool EmitBoolExpression (Expression e)
110 e = e.Resolve (parent);
115 if (e.Type != TypeManager.bool_type)
116 e = Expression.ConvertImplicit (parent, e, TypeManager.bool_type,
121 31, "Can not convert the expression to a boolean");
130 public void EmitExpression (Expression e)
132 e = e.Resolve (parent);
139 // Emits an If statement. Returns true if the last opcode
140 // emitted was a ret opcode.
142 public bool EmitIf (If s)
144 Label false_target = ig.DefineLabel ();
146 Statement false_stat = s.FalseStatement;
149 if (!EmitBoolExpression (s.Expr))
152 ig.Emit (OpCodes.Brfalse, false_target);
153 is_ret = EmitStatement (s.TrueStatement);
155 if (false_stat != null){
156 end = ig.DefineLabel ();
157 ig.Emit (OpCodes.Br, end);
159 ig.MarkLabel (false_target);
160 is_ret = EmitStatement (s.FalseStatement);
162 if (false_stat != null)
165 ig.MarkLabel (false_target);
170 public void EmitDo (Do s)
172 Label loop = ig.DefineLabel ();
175 EmitStatement (s.EmbeddedStatement);
176 EmitBoolExpression (s.Expr);
177 ig.Emit (OpCodes.Brtrue, loop);
180 public void EmitWhile (While s)
182 Label while_eval = ig.DefineLabel ();
183 Label exit = ig.DefineLabel ();
185 ig.MarkLabel (while_eval);
186 EmitBoolExpression (s.Expr);
187 ig.Emit (OpCodes.Brfalse, exit);
188 EmitStatement (s.Statement);
189 ig.Emit (OpCodes.Br, while_eval);
193 public void EmitFor (For s)
195 Statement init = s.InitStatement;
196 Statement incr = s.Increment;
197 Label loop = ig.DefineLabel ();
198 Label exit = ig.DefineLabel ();
200 if (! (init is EmptyStatement))
201 EmitStatement (init);
204 EmitBoolExpression (s.Test);
205 ig.Emit (OpCodes.Brfalse, exit);
206 EmitStatement (s.Statement);
207 if (!(incr is EmptyStatement))
208 EmitStatement (incr);
209 ig.Emit (OpCodes.Br, loop);
213 void EmitReturn (Return s)
215 Expression ret_expr = s.Expr;
217 if (ret_expr != null)
218 EmitExpression (ret_expr);
219 ig.Emit (OpCodes.Ret);
222 void EmitSwitch (Switch s)
226 void EmitChecked (Checked s)
228 bool previous_state = CheckState;
232 CheckState = previous_state;
236 void EmitUnChecked (Unchecked s)
238 bool previous_state = CheckState;
242 CheckState = previous_state;
245 void EmitStatementExpression (StatementExpression s)
247 ExpressionStatement e = s.Expr;
250 ne = e.Resolve (parent);
252 if (ne is ExpressionStatement)
253 ((ExpressionStatement) ne).EmitStatement (this);
256 ig.Emit (OpCodes.Pop);
262 // Emits the statemets `s'.
264 // Returns true if the statement had a `ret' opcode embedded
266 bool EmitStatement (Statement s)
268 // Console.WriteLine ("Emitting statement of type " + s.GetType ());
275 EmitWhile ((While) s);
278 else if (s is Return){
279 EmitReturn ((Return) s);
281 } else if (s is Switch)
282 EmitSwitch ((Switch) s);
283 else if (s is Checked)
284 EmitChecked ((Checked) s);
285 else if (s is Unchecked)
286 EmitUnChecked ((Unchecked) s);
288 return EmitBlock ((Block) s);
289 else if (s is StatementExpression)
290 EmitStatementExpression ((StatementExpression) s);
292 Console.WriteLine ("Unhandled Statement type: " +
293 s.GetType ().ToString ());
299 bool EmitBlock (Block block)
303 foreach (Statement s in block.Statements){
304 is_ret = EmitStatement (s);
310 public void EmitTopBlock (Block block)
312 bool has_ret = false;
315 int errors = Report.Errors;
317 block.EmitMeta (parent, ig, block, 0);
319 if (Report.Errors == errors){
320 has_ret = EmitBlock (block);
322 if (Report.Errors == errors)
323 block.UsageWarning ();
328 ig.Emit (OpCodes.Ret);