// // codegen.cs: The code generator // // Author: // Miguel de Icaza (miguel@ximian.com) // // (C) 2001 Ximian, Inc. // using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; namespace Mono.CSharp { /// /// Code generator class. /// public class CodeGen { AppDomain current_domain; AssemblyBuilder assembly_builder; ModuleBuilder module_builder; string Basename (string name) { int pos = name.LastIndexOf ("/"); if (pos != -1) return name.Substring (pos + 1); pos = name.LastIndexOf ("\\"); if (pos != -1) return name.Substring (pos + 1); return name; } string TrimExt (string name) { int pos = name.LastIndexOf ("."); return name.Substring (0, pos); } public CodeGen (string name, string output) { AssemblyName an; an = new AssemblyName (); an.Name = TrimExt (Basename (name)); current_domain = AppDomain.CurrentDomain; assembly_builder = current_domain.DefineDynamicAssembly ( an, AssemblyBuilderAccess.RunAndSave); // // Pass a path-less name to DefineDynamicModule. Wonder how // this copes with output in different directories then. // FIXME: figure out how this copes with --output /tmp/blah // module_builder = assembly_builder.DefineDynamicModule ( Basename (name), Basename (output)); } public AssemblyBuilder AssemblyBuilder { get { return assembly_builder; } } public ModuleBuilder ModuleBuilder { get { return module_builder; } } public void Save (string name) { try { assembly_builder.Save (Basename (name)); } catch (System.IO.IOException io){ Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message); } } } /// /// An Emit Context is created for each body of code (from methods, /// properties bodies, indexer bodies or constructor bodies) /// public class EmitContext { public TypeContainer TypeContainer; public ILGenerator ig; public bool CheckState; /// /// Whether we are emitting code inside a static or instance method /// public bool IsStatic; /// /// The value that is allowed to be returned or NULL if there is no /// return type. /// public Type ReturnType; /// /// Whether this is generating code for a constructor /// public bool IsConstructor; /// /// Keeps track of the Type to LocalBuilder temporary storage created /// to store structures (used to compute the address of the structure /// value on structure method invocations) /// public Hashtable temporary_storage; public Block CurrentBlock; public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type, int code_flags, bool is_constructor) { this.ig = ig; TypeContainer = parent; CheckState = parent.RootContext.Checked; IsStatic = (code_flags & Modifiers.STATIC) != 0; ReturnType = return_type; IsConstructor = is_constructor; CurrentBlock = null; if (ReturnType == TypeManager.void_type) ReturnType = null; } public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type, int code_flags) : this (parent, ig, return_type, code_flags, false) { } public void EmitTopBlock (Block block) { bool has_ret = false; if (block != null){ int errors = Report.Errors; block.EmitMeta (TypeContainer, ig, block, 0); if (Report.Errors == errors){ has_ret = block.Emit (this); if (Report.Errors == errors) block.UsageWarning (); } } if (!has_ret){ Statement s = new Return (null, Location.Null); s.Emit (this); } } /// /// Returns a temporary storage for a variable of type t as /// a local variable in the current body. /// public LocalBuilder GetTemporaryStorage (Type t) { LocalBuilder location; if (temporary_storage == null) temporary_storage = new Hashtable (); location = (LocalBuilder) temporary_storage [t]; if (location != null) return location; location = ig.DeclareLocal (t); temporary_storage.Add (t, location); return location; } /// /// Current loop begin and end labels. /// public Label LoopBegin, LoopEnd; /// /// Whether we are inside a loop and break/continue are possible. /// public bool InLoop; } }