1'
2' Visual Basic.Net Compiler
3' Copyright (C) 2004 - 2010 Rolf Bjarne Kvinge, RKvinge@novell.com
4'
5' This library is free software; you can redistribute it and/or
6' modify it under the terms of the GNU Lesser General Public
7' License as published by the Free Software Foundation; either
8' version 2.1 of the License, or (at your option) any later version.
9'
10' This library is distributed in the hope that it will be useful,
11' but WITHOUT ANY WARRANTY; without even the implied warranty of
12' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13' Lesser General Public License for more details.
14'
15' You should have received a copy of the GNU Lesser General Public
16' License along with this library; if not, write to the Free Software
17' Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18'
19
20''' <summary>
21''' Every variable has an associated type, namely the declared type of the variable.
22''' </summary>
23''' <remarks></remarks>
24Public Class VariableClassification
25    Inherits ExpressionClassification
26
27    Private m_ParameterInfo As Mono.Cecil.ParameterDefinition
28    Private m_FieldInfo As Mono.Cecil.FieldReference
29    Private m_LocalBuilder As Mono.Cecil.Cil.VariableDefinition
30
31    Private m_InstanceExpression As Expression
32    Private m_Parameter As Parameter
33    Private m_Variable As VariableDeclaration
34    Private m_LocalVariable As LocalVariableDeclaration
35    Private m_TypeVariable As TypeVariableDeclaration
36    Private m_Method As IMethod
37    Private m_Expression As Expression
38
39    Private m_ExpressionType As Mono.Cecil.TypeReference
40
41    Private m_ArrayVariable As Expression
42    Private m_Arguments As ArgumentList
43
44    ReadOnly Property LocalVariable As LocalVariableDeclaration
45        Get
46            Return m_LocalVariable
47        End Get
48    End Property
49
50    ReadOnly Property Method() As IMethod
51        Get
52            Return m_Method
53        End Get
54    End Property
55
56    ReadOnly Property Expression() As Expression
57        Get
58            Return m_Expression
59        End Get
60    End Property
61
62    ReadOnly Property ArrayVariable() As Expression
63        Get
64            Return m_ArrayVariable
65        End Get
66    End Property
67
68    ReadOnly Property Arguments() As ArgumentList
69        Get
70            Return m_Arguments
71        End Get
72    End Property
73
74    Public Overrides Function GetConstant(ByRef value As Object, ByVal ShowError As Boolean) As Boolean
75        If Me.FieldInfo IsNot Nothing Then
76            Dim attrib As Object
77            Dim dec As Decimal, dt As Date
78            Dim constant As ConstantDeclaration
79            Dim enumc As EnumMemberDeclaration
80
81            attrib = FieldDefinition.Annotations(Compiler)
82
83            If attrib IsNot Nothing Then
84                enumc = TryCast(attrib, EnumMemberDeclaration)
85                If enumc IsNot Nothing Then Return enumc.GetConstantValue(value)
86
87                constant = TryCast(attrib, ConstantDeclaration)
88                If constant IsNot Nothing Then Return constant.GetConstant(value, ShowError)
89            End If
90
91            If Me.FieldDefinition.IsLiteral Then
92                value = Me.FieldDefinition.Constant
93                Return True
94            ElseIf Me.FieldDefinition.IsInitOnly Then
95                If ConstantDeclaration.GetDecimalConstant(Compiler, FieldDefinition, dec) Then
96                    value = dec
97                    Return True
98                ElseIf ConstantDeclaration.GetDateConstant(Compiler, FieldDefinition, dt) Then
99                    value = dt
100                    Return True
101                Else
102                    If ShowError Then Parent.Show30059()
103                    Return False
104                End If
105            Else
106                If ShowError Then Parent.Show30059()
107                Return False
108            End If
109        ElseIf m_LocalVariable IsNot Nothing Then
110            If m_LocalVariable.IsConst Then
111                If m_LocalVariable.VariableInitializer.IsRegularInitializer Then
112                    Return m_LocalVariable.VariableInitializer.AsRegularInitializer.GetConstant(value, ShowError)
113                End If
114                If ShowError Then Parent.Show30059()
115                Return False
116            End If
117        Else
118            If ShowError Then Parent.Show30059()
119            Return False
120        End If
121    End Function
122
123    ReadOnly Property ParameterInfo() As Mono.Cecil.ParameterDefinition
124        Get
125            Return m_ParameterInfo
126        End Get
127    End Property
128
129    ReadOnly Property LocalBuilder() As Mono.Cecil.Cil.VariableDefinition
130        Get
131            If m_LocalVariable IsNot Nothing Then
132                Return m_LocalVariable.LocalBuilder
133            Else
134                Return Nothing
135            End If
136        End Get
137    End Property
138
139    ReadOnly Property FieldDefinition() As Mono.Cecil.FieldDefinition
140        Get
141            If m_TypeVariable IsNot Nothing AndAlso m_TypeVariable.FieldBuilder IsNot Nothing Then
142                Return m_TypeVariable.FieldBuilder
143            ElseIf m_LocalVariable IsNot Nothing AndAlso m_LocalVariable.FieldBuilder IsNot Nothing Then
144                Return m_LocalVariable.FieldBuilder
145            Else
146                Return CecilHelper.FindDefinition(m_FieldInfo)
147            End If
148        End Get
149    End Property
150
151    ReadOnly Property FieldInfo() As Mono.Cecil.FieldReference
152        Get
153            If m_TypeVariable IsNot Nothing AndAlso m_TypeVariable.FieldBuilder IsNot Nothing Then
154                Return m_TypeVariable.FieldBuilder
155            ElseIf m_LocalVariable IsNot Nothing AndAlso m_LocalVariable.FieldBuilder IsNot Nothing Then
156                Return m_LocalVariable.FieldBuilder
157            Else
158                Return m_FieldInfo
159            End If
160        End Get
161    End Property
162
163
164    ''' <summary>
165    ''' Loads the value of the variable.
166    ''' </summary>
167    ''' <param name="Info"></param>
168    ''' <returns></returns>
169    ''' <remarks></remarks>
170    Friend Function GenerateCodeAsValue(ByVal Info As EmitInfo) As Boolean
171        Dim result As Boolean = True
172
173        Helper.Assert(Info.DesiredType IsNot Nothing)
174
175        If m_InstanceExpression IsNot Nothing Then
176            result = m_InstanceExpression.GenerateCode(Info) AndAlso result
177        End If
178
179        If FieldInfo IsNot Nothing Then
180            If Info.IsRHS Then
181                Emitter.EmitLoadVariable(Info, FieldInfo)
182            Else
183                Return Compiler.Report.ShowMessage(Messages.VBNC99997, Parent.Location)
184            End If
185        ElseIf LocalBuilder IsNot Nothing Then
186            If Info.IsRHS Then
187                Emitter.EmitLoadVariable(Info, LocalBuilder)
188            Else
189                Return Compiler.Report.ShowMessage(Messages.VBNC99997, Parent.Location)
190            End If
191        ElseIf ParameterInfo IsNot Nothing Then
192            Helper.Assert(m_InstanceExpression Is Nothing)
193            If Info.IsRHS Then
194                Emitter.EmitLoadVariable(Info, ParameterInfo)
195            Else
196                Return Compiler.Report.ShowMessage(Messages.VBNC99997, Parent.Location)
197            End If
198        ElseIf m_ArrayVariable IsNot Nothing Then
199            result = Helper.EmitLoadArrayElement(Info, m_ArrayVariable, m_Arguments) AndAlso result
200        ElseIf m_Expression IsNot Nothing Then
201            result = m_Expression.GenerateCode(Info) AndAlso result
202        Else
203            Throw New InternalException(Me)
204        End If
205
206        If CecilHelper.IsByRef(Info.DesiredType) Then
207            Dim elementType As Mono.Cecil.TypeReference = CecilHelper.GetElementType(Info.DesiredType)
208            Dim local As Mono.Cecil.Cil.VariableDefinition
209            local = Emitter.DeclareLocal(Info, elementType)
210
211            Emitter.EmitStoreVariable(Info, local)
212            Emitter.EmitLoadVariableLocation(Info, local)
213        End If
214
215        Return result
216    End Function
217
218    ''' <summary>
219    ''' Stores at the address of the variable.
220    ''' </summary>
221    ''' <param name="Info"></param>
222    ''' <returns></returns>
223    ''' <remarks></remarks>
224    Friend Overrides Function GenerateCode(ByVal Info As EmitInfo) As Boolean
225        Dim result As Boolean = True
226
227        If m_Expression IsNot Nothing Then
228            Return m_Expression.GenerateCode(Info)
229        End If
230
231        Helper.Assert(Info.IsRHS AndAlso Info.RHSExpression Is Nothing OrElse Info.IsLHS AndAlso Info.RHSExpression IsNot Nothing)
232
233        If m_InstanceExpression IsNot Nothing Then
234            Dim exp As Mono.Cecil.TypeReference = m_InstanceExpression.ExpressionType
235            If CecilHelper.IsValueType(exp) AndAlso CecilHelper.IsByRef(exp) = False Then
236                exp = Compiler.TypeManager.MakeByRefType(Me.Parent, exp)
237            End If
238            result = m_InstanceExpression.GenerateCode(Info.Clone(Parent, True, False, exp)) AndAlso result
239        End If
240
241        If FieldInfo IsNot Nothing Then
242            If Info.IsRHS Then
243                If CecilHelper.IsByRef(Info.DesiredType) Then
244                    Emitter.EmitLoadVariableLocation(Info, FieldInfo)
245                Else
246                    Emitter.EmitLoadVariable(Info, FieldInfo)
247                End If
248            Else
249                Dim rInfo As EmitInfo = Info.Clone(Parent, True, False, FieldInfo.FieldType)
250
251                Helper.Assert(Info.RHSExpression IsNot Nothing)
252                Helper.Assert(Info.RHSExpression.Classification.IsValueClassification)
253                result = Info.RHSExpression.Classification.GenerateCode(rInfo) AndAlso result
254
255                Emitter.EmitConversion(Info.RHSExpression.ExpressionType, FieldInfo.FieldType, Info.Clone(Parent, Info.RHSExpression.ExpressionType))
256                Emitter.EmitStoreField(Info, FieldInfo)
257            End If
258        ElseIf LocalBuilder IsNot Nothing Then
259            result = VariableExpression.Emit(Info, LocalBuilder) AndAlso result
260        ElseIf ParameterInfo IsNot Nothing Then
261            Dim isByRef As Boolean
262            Dim isByRefStructure As Boolean
263            Dim paramType As Mono.Cecil.TypeReference
264            Dim paramElementType As Mono.Cecil.TypeReference = Nothing
265
266            paramType = ParameterInfo.ParameterType
267            isByRef = CecilHelper.IsByRef(paramType)
268            If isByRef Then
269                paramElementType = CecilHelper.GetElementType(paramType)
270                isByRefStructure = CecilHelper.IsValueType(paramElementType)
271            End If
272
273            Helper.Assert(m_InstanceExpression Is Nothing)
274
275            If Info.IsRHS Then
276                If isByRef Then
277                    Return Compiler.Report.ShowMessage(Messages.VBNC99997, Parent.Location)
278                Else
279                    Emitter.EmitLoadVariable(Info, ParameterInfo)
280                End If
281            Else
282                Dim rInfo As EmitInfo
283                Dim rhs As Expression = Info.RHSExpression
284                Dim paramConsumed As Boolean
285
286                If isByRefStructure Then
287                    Emitter.EmitLoadVariable(Info.Clone(Parent, paramType), ParameterInfo)
288                    If TypeOf rhs Is GetRefExpression Then rhs = DirectCast(rhs, GetRefExpression).Expression
289                    'paramConsumed = TypeOf rhs Is NewExpression
290                    If paramConsumed Then
291                        rInfo = Info.Clone(Parent, True, False, paramType)
292                    Else
293                        rInfo = Info.Clone(Parent, True, False, paramElementType)
294                    End If
295                ElseIf isByRef Then
296                    Emitter.EmitLoadVariableLocation(Info, ParameterInfo)
297                    rInfo = Info.Clone(Parent, True, False, paramElementType)
298                Else
299                    rInfo = Info.Clone(Parent, True, False, paramType)
300                End If
301
302                Helper.Assert(rhs IsNot Nothing, "RHSExpression Is Nothing!")
303                Helper.Assert(rhs.Classification.IsValueClassification)
304                result = rhs.Classification.GenerateCode(rInfo) AndAlso result
305
306                If Not paramConsumed Then
307                    If isByRef = False Then
308                        Emitter.EmitConversion(rhs.ExpressionType, paramType, Info)
309                    End If
310                    If isByRefStructure Then
311                        Emitter.EmitStoreIndirect(Info, paramType)
312                    Else
313                        Emitter.EmitStoreVariable(Info, ParameterInfo)
314                    End If
315                End If
316            End If
317        ElseIf Me.m_Variable IsNot Nothing Then
318            If Info.IsRHS Then
319                Return Compiler.Report.ShowMessage(Messages.VBNC99997, Parent.Location)
320            Else
321                Dim rInfo As EmitInfo = Info.Clone(Parent, True, False, m_Variable.VariableType)
322
323                Helper.Assert(Info.RHSExpression IsNot Nothing)
324                Helper.Assert(Info.RHSExpression.Classification.IsValueClassification)
325                result = Info.RHSExpression.Classification.GenerateCode(rInfo) AndAlso result
326
327                Emitter.EmitConversion(Info.RHSExpression.ExpressionType, m_Variable.VariableType, Info)
328
329                If Helper.CompareType(m_Variable.VariableType, Compiler.TypeCache.System_Object) AndAlso Helper.CompareType(Info.RHSExpression.ExpressionType, Compiler.TypeCache.System_Object) Then
330                    Emitter.EmitCall(Info, Compiler.TypeCache.System_Runtime_CompilerServices_RuntimeHelpers__GetObjectValue_Object)
331                End If
332
333                Emitter.EmitStoreVariable(Info, LocalBuilder)
334                Return Compiler.Report.ShowMessage(Messages.VBNC99997, Parent.Location)
335            End If
336        ElseIf m_ArrayVariable IsNot Nothing Then
337            If Info.IsRHS Then
338                result = Me.GenerateCodeAsValue(Info) AndAlso result
339            Else
340                result = Helper.EmitStoreArrayElement(Info, m_ArrayVariable, m_Arguments) AndAlso result
341
342            End If
343        ElseIf m_Method IsNot Nothing Then
344            If Info.IsRHS Then
345                Emitter.EmitLoadVariable(Info, m_Method.DefaultReturnVariable)
346            Else
347                Helper.Assert(Info.RHSExpression IsNot Nothing, "RHSExpression Is Nothing!")
348                Helper.Assert(Info.RHSExpression.Classification.IsValueClassification)
349                result = Info.RHSExpression.Classification.GenerateCode(Info.Clone(Parent, True, False, m_Method.DefaultReturnVariable.VariableType)) AndAlso result
350                Emitter.EmitStoreVariable(Info, m_Method.DefaultReturnVariable)
351            End If
352        Else
353            Throw New InternalException(Me)
354        End If
355
356        Return result
357    End Function
358
359    ReadOnly Property InstanceExpression() As Expression
360        Get
361            Return m_InstanceExpression
362        End Get
363    End Property
364
365    <Obsolete()> Overloads Function ReclassifyToValue() As ValueClassification
366        Return New ValueClassification(Me)
367    End Function
368
369    ''' <summary>
370    ''' A variable declaration which refers to the implicitly declared local variable
371    ''' for methods with return values (functions and get properties)
372    ''' </summary>
373    ''' <param name="Parent"></param>
374    ''' <param name="method"></param>
375    ''' <remarks></remarks>
376    Sub New(ByVal Parent As ParsedObject, ByVal method As IMethod)
377        MyBase.New(Classifications.Variable, Parent)
378        Helper.Assert(TypeOf method Is FunctionDeclaration OrElse TypeOf method Is PropertyGetDeclaration)
379        m_Method = method
380    End Sub
381
382    Sub New(ByVal Parent As ParsedObject, ByVal parameter As Parameter)
383        MyBase.New(Classifications.Variable, Parent)
384        m_Parameter = parameter
385        m_ParameterInfo = parameter.CecilBuilder
386    End Sub
387
388    Sub New(ByVal Parent As ParsedObject, ByVal variable As VariableDeclaration, Optional ByVal InstanceExpression As Expression = Nothing)
389        MyBase.New(Classifications.Variable, Parent)
390        m_Variable = variable
391        m_LocalVariable = TryCast(m_Variable, LocalVariableDeclaration)
392        m_TypeVariable = TryCast(m_Variable, TypeVariableDeclaration)
393        m_InstanceExpression = InstanceExpression
394    End Sub
395
396    Sub New(ByVal Parent As ParsedObject, ByVal Expression As Expression, ByVal ExpressionType As Mono.Cecil.TypeReference)
397        MyBase.new(Classifications.Variable, Parent)
398        m_Expression = Expression
399        m_ExpressionType = ExpressionType
400    End Sub
401
402    Sub New(ByVal Parent As ParsedObject, ByVal variable As Mono.Cecil.FieldReference, ByVal InstanceExpression As Expression)
403        MyBase.New(Classifications.Variable, Parent)
404        m_FieldInfo = variable
405        m_InstanceExpression = InstanceExpression
406        Helper.Assert(m_InstanceExpression Is Nothing OrElse m_InstanceExpression.IsResolved)
407        Helper.Assert((Helper.IsShared(variable) AndAlso m_InstanceExpression Is Nothing) OrElse (Helper.IsShared(variable) = False AndAlso m_InstanceExpression IsNot Nothing))
408    End Sub
409
410    ''' <summary>
411    ''' Creates a variable classification for an array access.
412    ''' </summary>
413    ''' <param name="Parent"></param>
414    ''' <param name="Arguments"></param>
415    ''' <remarks></remarks>
416    Sub New(ByVal Parent As ParsedObject, ByVal ArrayVariableExpression As Expression, ByVal Arguments As ArgumentList)
417        MyBase.New(Classifications.Variable, Parent)
418        m_ArrayVariable = ArrayVariableExpression
419        m_Arguments = Arguments
420        Helper.Assert(ArrayVariable IsNot Nothing)
421        Helper.Assert(Arguments IsNot Nothing)
422    End Sub
423
424    ReadOnly Property Type() As Mono.Cecil.TypeReference
425        Get
426            Dim result As Mono.Cecil.TypeReference
427            If m_ExpressionType IsNot Nothing Then
428                result = m_ExpressionType
429            ElseIf m_Method IsNot Nothing Then
430                result = m_Method.Signature.ReturnType
431            ElseIf m_Variable IsNot Nothing Then
432                result = m_Variable.VariableType
433            ElseIf m_FieldInfo IsNot Nothing Then
434                If Helper.IsEnum(Compiler, m_FieldInfo.DeclaringType) Then
435                    result = m_FieldInfo.DeclaringType
436                Else
437                    result = m_FieldInfo.FieldType
438                End If
439            ElseIf m_Parameter IsNot Nothing Then
440                result = m_Parameter.ParameterType
441            ElseIf m_ArrayVariable IsNot Nothing Then
442                result = CecilHelper.GetElementType(m_ArrayVariable.ExpressionType)
443            Else
444                Throw New InternalException(Me)
445            End If
446            Helper.Assert(result IsNot Nothing)
447            Return result
448        End Get
449    End Property
450End Class
451
452