2001-11-08 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                 
63                 public AssemblyBuilder AssemblyBuilder {
64                         get {
65                                 return assembly_builder;
66                         }
67                 }
68                 
69                 public ModuleBuilder ModuleBuilder {
70                         get {
71                                 return module_builder;
72                         }
73                 }
74                 
75                 public void Save (string name)
76                 {
77                         try {
78                                 assembly_builder.Save (Basename (name));
79                         } catch (System.IO.IOException io){
80                                 Report.Error (16, "Coult not write to file `"+name+"', cause: " + io.Message);
81                         } 
82                 }
83         }
84
85         // <summary>
86         //   An Emit Context is created for each body of code (from methods,
87         //   properties bodies, indexer bodies or constructor bodies)
88         // </summary>
89         public class EmitContext {
90                 public TypeContainer TypeContainer;
91                 public ILGenerator   ig;
92                 public bool CheckState;
93
94                 // <summary>
95                 //   Whether we are emitting code inside a static or instance method
96                 // </summary>
97                 public bool IsStatic;
98
99                 // <summary>
100                 //   The value that is allowed to be returned or NULL if there is no
101                 //   return type.
102                 // </summary>
103                 public Type ReturnType;
104
105                 // <summary>
106                 //   Whether this is generating code for a constructor
107                 // </summary>
108                 public bool IsConstructor;
109                 
110                 // <summary>
111                 //   Keeps track of the Type to LocalBuilder temporary storage created
112                 //   to store structures (used to compute the address of the structure
113                 //   value on structure method invocations)
114                 // </summary>
115                 public Hashtable temporary_storage;
116
117                 public Block CurrentBlock;
118                 
119                 public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type,
120                                     int code_flags, bool is_constructor)
121                 {
122                         this.ig = ig;
123
124                         TypeContainer = parent;
125                         CheckState = parent.RootContext.Checked;
126                         IsStatic = (code_flags & Modifiers.STATIC) != 0;
127                         ReturnType = return_type;
128                         IsConstructor = is_constructor;
129                         CurrentBlock = null;
130                         
131                         if (ReturnType == TypeManager.void_type)
132                                 ReturnType = null;
133                 }
134
135                 public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type, int code_flags)
136                         : this (parent, ig, return_type, code_flags, false)
137                 {
138                 }
139
140                 public void EmitTopBlock (Block block)
141                 {
142                         bool has_ret = false;
143                         
144                         if (block != null){
145                                 int errors = Report.Errors;
146                                 
147                                 block.EmitMeta (TypeContainer, ig, block, 0);
148                                 
149                                 if (Report.Errors == errors){
150                                         has_ret = block.Emit (this);
151                                         
152                                         if (Report.Errors == errors)
153                                                 block.UsageWarning ();
154                                 }
155                         }
156
157                         if (!has_ret)
158                                 ig.Emit (OpCodes.Ret);
159                 }
160
161                 // <summary>
162                 //   Returns a temporary storage for a variable of type t as 
163                 //   a local variable in the current body.
164                 // </summary>
165                 public LocalBuilder GetTemporaryStorage (Type t)
166                 {
167                         LocalBuilder location;
168                         
169                         if (temporary_storage == null)
170                                 temporary_storage = new Hashtable ();
171
172                         location = (LocalBuilder) temporary_storage [t];
173                         if (location != null)
174                                 return location;
175
176                         location = ig.DeclareLocal (t);
177                         temporary_storage.Add (t, location);
178
179                         return location;
180                 }
181
182                 //
183                 // Current loop begin and end labels.
184                 //
185                 public Label LoopBegin, LoopEnd;
186
187                 //
188                 // Whether we are inside a loop and break/continue are possible.
189                 // 
190                 public bool  InLoop;
191
192         }
193 }