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