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