2001-10-22 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / codegen.cs
1 //
2 // codegen.cs: The code generator
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9
10 using System;
11 using System.Collections;
12 using System.Reflection;
13 using System.Reflection.Emit;
14
15 namespace CIR {
16         
17         public class CodeGen {
18                 AppDomain current_domain;
19                 AssemblyBuilder assembly_builder;
20                 ModuleBuilder   module_builder;
21
22                 string Basename (string name)
23                 {
24                         int pos = name.LastIndexOf ("/");
25
26                         if (pos != -1)
27                                 return name.Substring (pos + 1);
28
29                         pos = name.LastIndexOf ("\\");
30                         if (pos != -1)
31                                 return name.Substring (pos + 1);
32
33                         return name;
34                 }
35
36                 string TrimExt (string name)
37                 {
38                         int pos = name.LastIndexOf (".");
39
40                         return name.Substring (0, pos);
41                 }
42                 
43                 public CodeGen (string name, string output)
44                 {
45                         AssemblyName an;
46                         
47                         an = new AssemblyName ();
48                         an.Name = TrimExt (name);
49                         current_domain = AppDomain.CurrentDomain;
50                         assembly_builder = current_domain.DefineDynamicAssembly (
51                                 an, AssemblyBuilderAccess.RunAndSave);
52
53                         //
54                         // Pass a path-less name to DefineDynamicModule.  Wonder how
55                         // this copes with output in different directories then.
56                         // FIXME: figure out how this copes with --output /tmp/blah
57                         //
58                         module_builder = assembly_builder.DefineDynamicModule (
59                                 Basename (name), Basename (output));
60                 }
61                 
62                 public AssemblyBuilder AssemblyBuilder {
63                         get {
64                                 return assembly_builder;
65                         }
66                 }
67                 
68                 public ModuleBuilder ModuleBuilder {
69                         get {
70                                 return module_builder;
71                         }
72                 }
73                 
74                 public void Save (string name)
75                 {
76                         try {
77                                 assembly_builder.Save (Basename (name));
78                         } catch (System.IO.IOException io){
79                                 Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
80                         }
81                 }
82         }
83
84         public class EmitContext {
85                 public TypeContainer TypeContainer;
86                 public ILGenerator   ig;
87                 public bool CheckState;
88
89                 // <summary>
90                 //   Whether we are emitting code inside a static or instance method
91                 // </summary>
92                 public bool IsStatic;
93
94                 // <summary>
95                 //   The value that is allowed to be returned or NULL if there is no
96                 //   return type.
97                 // </summary>
98                 public Type ReturnType;
99
100                 // <summary>
101                 //   Whether this is generating code for a constructor
102                 // </summary>
103                 public bool IsConstructor;
104                 
105                 // <summary>
106                 //   Keeps track of the Type to LocalBuilder temporary storage created
107                 //   to store structures (used to compute the address of the structure
108                 //   value on structure method invocations)
109                 // </summary>
110                 public Hashtable temporary_storage;
111
112                 public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type,
113                                     int code_flags, bool is_constructor)
114                 {
115                         this.ig = ig;
116
117                         TypeContainer = parent;
118                         CheckState = false;
119                         IsStatic = (code_flags & Modifiers.STATIC) != 0;
120                         ReturnType = return_type;
121                         IsConstructor = is_constructor;
122                         
123                         if (ReturnType == TypeManager.void_type)
124                                 ReturnType = null;
125                 }
126
127                 public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type, int code_flags)
128                         : this (parent, ig, return_type, code_flags, false)
129                 {
130                 }
131
132                 public void EmitTopBlock (Block block)
133                 {
134                         bool has_ret = false;
135                         
136                         if (block != null){
137                                 int errors = Report.Errors;
138                                 
139                                 block.EmitMeta (TypeContainer, ig, block, 0);
140                                 
141                                 if (Report.Errors == errors){
142                                         has_ret = block.Emit (this);
143                                         
144                                         if (Report.Errors == errors)
145                                                 block.UsageWarning ();
146                                 }
147                         }
148
149                         if (!has_ret)
150                                 ig.Emit (OpCodes.Ret);
151                 }
152
153                 // <summary>
154                 //   Returns a temporary storage for a variable of type t as 
155                 //   a local variable in the current body.
156                 // </summary>
157                 public LocalBuilder GetTemporaryStorage (Type t)
158                 {
159                         LocalBuilder location;
160                         
161                         if (temporary_storage == null)
162                                 temporary_storage = new Hashtable ();
163
164                         location = (LocalBuilder) temporary_storage [t];
165                         if (location != null)
166                                 return location;
167
168                         location = ig.DeclareLocal (t);
169                         temporary_storage.Add (t, location);
170
171                         return location;
172                 }
173
174                 //
175                 // Current loop begin and end labels.
176                 //
177                 public Label LoopBegin, LoopEnd;
178
179                 //
180                 // Whether we are inside a loop and break/continue are possible.
181                 // 
182                 public bool  InLoop;
183         }
184 }