2001-10-31 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / assign.cs
1 //
2 // assign.cs: Assignments.
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.
8 //
9 using System;
10 using System.Reflection;
11 using System.Reflection.Emit;
12
13 namespace CIR {
14
15         // <remarks>
16         //   This interface is implemented by Expressions whose values can not
17         //   store the result on the top of the stack.
18         //
19         //   Expressions implementing this (Properties and Indexers) would
20         //   perform an assignment of the Expression "source" into its final
21         //   location.
22         //
23         //   No values on the top of the stack are expected to be left by
24         //   invoking this method.
25         // </remarks>
26         public interface IAssignMethod {
27                 void EmitAssign (EmitContext ec, Expression source);
28         }
29
30         // <remarks>
31         //   The LocalTemporary class is used to hold temporary values of a given
32         //   type to "simulate" the expression semantics on property and indexer
33         //   access whose return values are void.
34         //
35         //   The local temporary is used to alter the normal flow of code generation
36         //   basically it creates a local variable, and its emit instruction generates
37         //   code to access this value, return its address or save its value.
38         // </remarks>
39         public class LocalTemporary : Expression, IStackStore, IMemoryLocation {
40                 LocalBuilder builder;
41                 
42                 public LocalTemporary (EmitContext ec, Type t)
43                 {
44                         type = t;
45                         eclass = ExprClass.Value;
46                         builder = ec.GetTemporaryStorage (t);
47                 }
48
49                 public override Expression DoResolve (EmitContext ec)
50                 {
51                         return this;
52                 }
53
54                 public override void Emit (EmitContext ec)
55                 {
56                         ec.ig.Emit (OpCodes.Ldloc, builder); 
57                 }
58
59                 public void Store (EmitContext ec)
60                 {
61                         ec.ig.Emit (OpCodes.Stloc, builder);
62                 }
63
64                 public void AddressOf (EmitContext ec)
65                 {
66                         ec.ig.Emit (OpCodes.Ldloca, builder);
67                 }
68         }
69
70         // <remarks>
71         //   The Assign node takes care of assigning the value of source into
72         //   the expression represented by target. 
73         // </remarks>
74         public class Assign : ExpressionStatement {
75                 Expression target, source;
76                 Location l;
77                 
78                 public Assign (Expression target, Expression source, Location l)
79                 {
80                         this.target = target;
81                         this.source = source;
82                         this.l = l;
83                 }
84
85                 public Expression Target {
86                         get {
87                                 return target;
88                         }
89
90                         set {
91                                 target = value;
92                         }
93                 }
94
95                 public Expression Source {
96                         get {
97                                 return source;
98                         }
99
100                         set {
101                                 source = value;
102                         }
103                 }
104
105                 public override Expression DoResolve (EmitContext ec)
106                 {
107                         source = source.Resolve (ec);
108                         if (source == null)
109                                 return null;
110                         
111                         target = target.ResolveLValue (ec, source);
112                         
113                         if (target == null)
114                                 return null;
115
116                         Type target_type = target.Type;
117                         Type source_type = source.Type;
118
119                         type = target_type;
120                         eclass = ExprClass.Value;
121                         
122                         //
123                         // If we are doing a property assignment, then
124                         // set the `value' field on the property, and Resolve
125                         // it.
126                         //
127                         if (target is PropertyExpr){
128                                 PropertyExpr property_assign = (PropertyExpr) target;
129
130                                 //
131                                 // FIXME: Maybe handle this in the LValueResolve
132                                 //
133                                 if (!property_assign.VerifyAssignable ())
134                                         return null;
135                                 
136                                 return this;
137                         }
138
139                         if (target is IndexerAccess){
140                                 IndexerAccess ia = (IndexerAccess) target;
141
142                                 return this;
143                         }
144
145                         if (source is New && target_type.IsSubclassOf (TypeManager.value_type)){
146                                 New n = (New) source;
147
148                                 n.ValueTypeVariable = target;
149
150                                 return n;
151                         }
152
153                         if (target_type != source_type){
154                                 source = ConvertImplicitRequired (ec, source, target_type, l);
155                                 if (source == null)
156                                         return null;
157                         }
158
159                         if (target.ExprClass != ExprClass.Variable){
160                                 Report.Error (131, l,
161                                               "Left hand of an assignment must be a variable, " +
162                                               "a property or an indexer");
163                                 return null;
164                         }
165
166                         return this;
167                 }
168
169                 void Emit (EmitContext ec, bool is_statement)
170                 {
171                         ILGenerator ig = ec.ig;
172                         ExprClass eclass = target.ExprClass;
173                         
174                         if (eclass == ExprClass.Variable){
175
176                                 //
177                                 // If it is an instance field, load the this pointer
178                                 //
179                                 if (target is FieldExpr){
180                                         FieldExpr fe = (FieldExpr) target;
181                                         
182                                         if (!fe.FieldInfo.IsStatic)
183                                                 ig.Emit (OpCodes.Ldarg_0);
184                                 }
185
186                                 source.Emit (ec);
187
188                                 if (!is_statement)
189                                         ig.Emit (OpCodes.Dup);
190
191                                 ((IStackStore) target).Store (ec);
192                         } else if (eclass == ExprClass.PropertyAccess ||
193                                    eclass == ExprClass.IndexerAccess){
194                                 IAssignMethod am = (IAssignMethod) target;
195
196                                 if (is_statement)
197                                         am.EmitAssign (ec, source);
198                                 else {
199                                         LocalTemporary tempo;
200                                         
201                                         tempo = new LocalTemporary (ec, source.Type);
202
203                                         source.Emit (ec);
204                                         tempo.Store (ec);
205                                         am.EmitAssign (ec, source);
206                                         tempo.Emit (ec);
207                                 }
208                         } else {
209                                 Console.WriteLine ("Unhandled class: " + eclass + "\n Type:" + target);
210                         }
211                 }
212                 
213                 public override void Emit (EmitContext ec)
214                 {
215                         Emit (ec, false);
216                 }
217
218                 public override void EmitStatement (EmitContext ec)
219                 {
220                         Emit (ec, true);
221                 }
222         }
223 }
224
225
226
227