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 ();
40 an.Name = "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 (Report report, 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 {
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)
102 parent.RootContext.Report.Error (
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);
118 if (e == null || e.Type != TypeManager.bool_type){
119 parent.RootContext.Report.Error (
120 31, "Can not convert the expression to a boolean");
129 public void EmitExpression (Expression e)
131 e = e.Resolve (parent);
138 // Emits an If statement. Returns true if the last opcode
139 // emitted was a ret opcode.
141 public bool EmitIf (If s)
143 Label false_target = ig.DefineLabel ();
145 Statement false_stat = s.FalseStatement;
148 if (!EmitBoolExpression (s.Expr))
151 ig.Emit (OpCodes.Brfalse, false_target);
152 is_ret = EmitStatement (s.TrueStatement);
154 if (false_stat != null){
155 end = ig.DefineLabel ();
156 ig.Emit (OpCodes.Br, end);
158 ig.MarkLabel (false_target);
159 is_ret = EmitStatement (s.FalseStatement);
161 if (false_stat != null)
164 ig.MarkLabel (false_target);
169 public void EmitDo (Do s)
171 Label loop = ig.DefineLabel ();
174 EmitStatement (s.EmbeddedStatement);
175 EmitBoolExpression (s.Expr);
176 ig.Emit (OpCodes.Brtrue, loop);
179 public void EmitWhile (While s)
181 Label while_eval = ig.DefineLabel ();
182 Label exit = ig.DefineLabel ();
184 ig.MarkLabel (while_eval);
185 EmitBoolExpression (s.Expr);
186 ig.Emit (OpCodes.Brfalse, exit);
187 EmitStatement (s.Statement);
188 ig.Emit (OpCodes.Br, while_eval);
192 public void EmitFor (For s)
194 Statement init = s.InitStatement;
195 Statement incr = s.Increment;
196 Label loop = ig.DefineLabel ();
197 Label exit = ig.DefineLabel ();
199 if (! (init is EmptyStatement))
200 EmitStatement (init);
203 EmitBoolExpression (s.Test);
204 ig.Emit (OpCodes.Brfalse, exit);
205 EmitStatement (s.Statement);
206 if (!(incr is EmptyStatement))
207 EmitStatement (incr);
208 ig.Emit (OpCodes.Br, loop);
212 void EmitReturn (Return s)
214 Expression ret_expr = s.Expr;
216 if (ret_expr != null)
217 EmitExpression (ret_expr);
218 ig.Emit (OpCodes.Ret);
221 void EmitSwitch (Switch s)
225 void EmitChecked (Checked s)
227 bool previous_state = CheckState;
231 CheckState = previous_state;
235 void EmitUnChecked (Unchecked s)
237 bool previous_state = CheckState;
241 CheckState = previous_state;
244 void EmitStatementExpression (StatementExpression s)
246 ExpressionStatement e = s.Expr;
249 ne = e.Resolve (parent);
251 if (ne is ExpressionStatement)
252 ((ExpressionStatement) ne).EmitStatement (this);
255 ig.Emit (OpCodes.Pop);
261 // Emits the statemets `s'.
263 // Returns true if the statement had a `ret' opcode embedded
265 bool EmitStatement (Statement s)
267 // Console.WriteLine ("Emitting statement of type " + s.GetType ());
274 EmitWhile ((While) s);
277 else if (s is Return){
278 EmitReturn ((Return) s);
280 } else if (s is Switch)
281 EmitSwitch ((Switch) s);
282 else if (s is Checked)
283 EmitChecked ((Checked) s);
284 else if (s is Unchecked)
285 EmitUnChecked ((Unchecked) s);
287 return EmitBlock ((Block) s);
288 else if (s is StatementExpression)
289 EmitStatementExpression ((StatementExpression) s);
291 Console.WriteLine ("Unhandled Statement type: " +
292 s.GetType ().ToString ());
298 bool EmitBlock (Block block)
302 foreach (Statement s in block.Statements){
303 is_ret = EmitStatement (s);
309 public void EmitTopBlock (Block block)
311 bool has_ret = false;
314 block.EmitMeta (parent, ig, block, 0);
315 has_ret = EmitBlock (block);
319 ig.Emit (OpCodes.Ret);