/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Preprocessor/ExpressionEvaluator.vb
1 586 строк
73 KB
Jonathon Marolf
update headers
23 янв 2020, 04:01
Не верифицирован
23 янв 2020, 04:01
91571a3
Код
Авторство
О чём код?
' Licensed to the .NET Foundation under one or more agreements. ' The .NET Foundation licenses this file to you under the MIT license. ' See the LICENSE file in the project root for more information. '----------------------------------------------------------------------------- ' Contains expression evaluator for preprocessor expressions. '----------------------------------------------------------------------------- Imports System.Collections.Immutable Imports System.Globalization Imports System.Reflection Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax.TypeHelpers Namespace Microsoft.CodeAnalysis.VisualBasic.Syntax.InternalSyntax Friend Structure ExpressionEvaluator Private ReadOnly _symbols As ImmutableDictionary(Of String, CConst) ' PERF: Using Byte instead of SpecialType because we want the compiler to use array literal initialization. ' The most natural type choice, Enum arrays, are not blittable due to a CLR limitation. Private Shared ReadOnly s_dominantType(,) As Byte Shared Sub New() Const _____Byte = CType(SpecialType.System_Byte, Byte) Const ____SByte = CType(SpecialType.System_SByte, Byte) Const ____Int16 = CType(SpecialType.System_Int16, Byte) Const ___UInt16 = CType(SpecialType.System_UInt16, Byte) Const ____Int32 = CType(SpecialType.System_Int32, Byte) Const ___UInt32 = CType(SpecialType.System_UInt32, Byte) Const ____Int64 = CType(SpecialType.System_Int64, Byte) Const ___UInt64 = CType(SpecialType.System_UInt64, Byte) Const ___Single = CType(SpecialType.System_Single, Byte) Const ___Double = CType(SpecialType.System_Double, Byte) Const __Decimal = CType(SpecialType.System_Decimal, Byte) Const _DateTime = CType(SpecialType.System_DateTime, Byte) Const _____Char = CType(SpecialType.System_Char, Byte) Const __Boolean = CType(SpecialType.System_Boolean, Byte) Const ___String = CType(SpecialType.System_String, Byte) Const ___Object = CType(SpecialType.System_Object, Byte) ' _____Byte, ____SByte, ____Int16, ___UInt16, ____Int32, ___UInt32, ____Int64, ___UInt64, ___Single, ___Double, __Decimal, _DateTime, _____Char, __Boolean, ___String, ___Object s_dominantType = { {_____Byte, ___Object, ____Int16, ___UInt16, ____Int32, ___UInt32, ____Int64, ___UInt64, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Byte {___Object, ____SByte, ____Int16, ___Object, ____Int32, ___Object, ____Int64, ___Object, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' SByte {____Int16, ____Int16, ____Int16, ___Object, ____Int32, ___Object, ____Int64, ___Object, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Int16 {___UInt16, ___Object, ___Object, ___UInt16, ____Int32, ___UInt32, ____Int64, ___UInt64, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' UInt16 {____Int32, ____Int32, ____Int32, ____Int32, ____Int32, ___Object, ____Int64, ___Object, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Int32 {___UInt32, ___Object, ___Object, ___UInt32, ___Object, ___UInt32, ____Int64, ___UInt64, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' UInt32 {____Int64, ____Int64, ____Int64, ____Int64, ____Int64, ____Int64, ____Int64, ___Object, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Int64 {___UInt64, ___Object, ___Object, ___UInt64, ___Object, ___UInt64, ___Object, ___UInt64, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' UInt64 {___Single, ___Single, ___Single, ___Single, ___Single, ___Single, ___Single, ___Single, ___Single, ___Double, ___Single, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Single {___Double, ___Double, ___Double, ___Double, ___Double, ___Double, ___Double, ___Double, ___Double, ___Double, ___Double, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Double {__Decimal, __Decimal, __Decimal, __Decimal, __Decimal, __Decimal, __Decimal, __Decimal, ___Single, ___Double, __Decimal, ___Object, ___Object, ___Object, ___Object, ___Object}, ' Decimal {___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, _DateTime, ___Object, ___Object, ___Object, ___Object}, ' DateTime {___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, _____Char, ___Object, ___String, ___Object}, ' Char {___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, __Boolean, ___Object, ___Object}, ' Boolean {___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___String, ___Object, ___String, ___Object}, ' String {___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object, ___Object} ' Object } #If DEBUG Then Debug.Assert(s_dominantType.GetLength(0) = s_dominantType.GetLength(1)) ' 2d array must be square For i As Integer = 0 To s_dominantType.GetLength(0) - 1 For j As Integer = i + 1 To s_dominantType.GetLength(1) - 1 Debug.Assert(s_dominantType(i, j) = s_dominantType(j, i)) Next Next #End If End Sub Private Shared Function TypeCodeToDominantTypeIndex(specialType As SpecialType) As Integer Select Case specialType Case SpecialType.System_Byte Return 0 Case SpecialType.System_SByte Return 1 Case SpecialType.System_Int16 Return 2 Case SpecialType.System_UInt16 Return 3 Case SpecialType.System_Int32 Return 4 Case SpecialType.System_UInt32 Return 5 Case SpecialType.System_Int64 Return 6 Case SpecialType.System_UInt64 Return 7 Case SpecialType.System_Single Return 8 Case SpecialType.System_Double Return 9 Case SpecialType.System_Decimal Return 10 Case SpecialType.System_DateTime Return 11 Case SpecialType.System_Char Return 12 Case SpecialType.System_Boolean Return 13 Case SpecialType.System_String Return 14 Case SpecialType.System_Object Return 15 Case Else Throw ExceptionUtilities.UnexpectedValue(specialType) End Select End Function Private Sub New(symbols As ImmutableDictionary(Of String, CConst)) _symbols = symbols End Sub Public Shared Function EvaluateCondition(expr As ExpressionSyntax, Optional symbols As ImmutableDictionary(Of String, CConst) = Nothing) As CConst If expr.ContainsDiagnostics Then Return New BadCConst(0) End If Dim value = EvaluateExpression(expr, symbols) If value.IsBad Then Return value End If Return ConvertToBool(value, expr) End Function Public Shared Function EvaluateExpression(expr As ExpressionSyntax, Optional symbols As ImmutableDictionary(Of String, CConst) = Nothing) As CConst If expr.ContainsDiagnostics Then Return New BadCConst(0) End If Dim eval As New ExpressionEvaluator(symbols) Return eval.EvaluateExpressionInternal(expr) End Function Private Function EvaluateExpressionInternal(expr As ExpressionSyntax) As CConst Debug.Assert(expr IsNot Nothing) Select Case expr.Kind Case SyntaxKind.TrueLiteralExpression, SyntaxKind.FalseLiteralExpression, SyntaxKind.CharacterLiteralExpression, SyntaxKind.DateLiteralExpression, SyntaxKind.NumericLiteralExpression, SyntaxKind.NothingLiteralExpression, SyntaxKind.StringLiteralExpression Return EvaluateLiteralExpression(DirectCast(expr, LiteralExpressionSyntax)) Case SyntaxKind.ParenthesizedExpression Return EvaluateParenthesizedExpression(DirectCast(expr, ParenthesizedExpressionSyntax)) Case SyntaxKind.IdentifierName Return EvaluateIdentifierNameExpression(DirectCast(expr, IdentifierNameSyntax)) Case SyntaxKind.PredefinedCastExpression Return EvaluatePredefinedCastExpression(DirectCast(expr, PredefinedCastExpressionSyntax)) Case SyntaxKind.CTypeExpression Return EvaluateCTypeExpression(DirectCast(expr, CastExpressionSyntax)) Case SyntaxKind.DirectCastExpression Return EvaluateDirectCastExpression(DirectCast(expr, CastExpressionSyntax)) Case SyntaxKind.TryCastExpression Return EvaluateTryCastExpression(DirectCast(expr, CastExpressionSyntax)) Case SyntaxKind.UnaryMinusExpression, SyntaxKind.UnaryPlusExpression, SyntaxKind.NotExpression Return EvaluateUnaryExpression(DirectCast(expr, UnaryExpressionSyntax)) Case SyntaxKind.AddExpression, SyntaxKind.SubtractExpression, SyntaxKind.MultiplyExpression, SyntaxKind.DivideExpression, SyntaxKind.IntegerDivideExpression, SyntaxKind.ModuloExpression, SyntaxKind.ExponentiateExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.LessThanExpression, SyntaxKind.GreaterThanExpression, SyntaxKind.LessThanOrEqualExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.ConcatenateExpression, SyntaxKind.AndExpression, SyntaxKind.OrExpression, SyntaxKind.ExclusiveOrExpression, SyntaxKind.AndAlsoExpression, SyntaxKind.OrElseExpression, SyntaxKind.LeftShiftExpression, SyntaxKind.RightShiftExpression Return EvaluateBinaryExpression(DirectCast(expr, BinaryExpressionSyntax)) Case SyntaxKind.BinaryConditionalExpression Return EvaluateBinaryIfExpression(DirectCast(expr, BinaryConditionalExpressionSyntax)) Case SyntaxKind.TernaryConditionalExpression Return EvaluateTernaryIfExpression(DirectCast(expr, TernaryConditionalExpressionSyntax)) End Select Return ReportSemanticError(ERRID.ERR_BadCCExpression, expr) End Function Private Shared Function ReportSemanticError(id As ERRID, node As VisualBasicSyntaxNode) As BadCConst Return ReportSemanticError(id, node, Array.Empty(Of Object)) End Function Private Shared Function ReportSemanticError(id As ERRID, node As VisualBasicSyntaxNode, ParamArray args As Object()) As BadCConst ' TODO: should we use the node? Return New BadCConst(id, args) End Function Private Shared Function EvaluateLiteralExpression(expr As LiteralExpressionSyntax) As CConst Dim token = expr.Token If expr.ContainsDiagnostics Then Return ReportSemanticError(ERRID.ERR_BadCCExpression, expr) End If Select Case token.Kind Case SyntaxKind.TrueKeyword Return CConst.Create(True) Case SyntaxKind.FalseKeyword Return CConst.Create(False) Case SyntaxKind.CharacterLiteralToken Dim typedToken = DirectCast(token, CharacterLiteralTokenSyntax) Return CConst.Create(typedToken.Value) Case SyntaxKind.DateLiteralToken Dim typedToken = DirectCast(token, DateLiteralTokenSyntax) Return CConst.Create(typedToken.Value) Case SyntaxKind.DecimalLiteralToken Dim typedToken = DirectCast(token, DecimalLiteralTokenSyntax) Return CConst.Create(typedToken.Value) Case SyntaxKind.FloatingLiteralToken Dim typedToken = DirectCast(token, FloatingLiteralTokenSyntax) Return CConst.CreateChecked(typedToken.ObjectValue) Case SyntaxKind.IntegerLiteralToken Dim typedToken = DirectCast(token, IntegerLiteralTokenSyntax) Return CConst.CreateChecked(typedToken.ObjectValue) Case SyntaxKind.NothingKeyword Return CConst.CreateNothing() Case SyntaxKind.StringLiteralToken Dim typedToken = DirectCast(token, StringLiteralTokenSyntax) Return CConst.Create(typedToken.Value) Case Else Throw ExceptionUtilities.UnexpectedValue(token.Kind) End Select End Function Private Function EvaluateParenthesizedExpression(expr As ParenthesizedExpressionSyntax) As CConst Return EvaluateExpressionInternal(expr.Expression) End Function Private Function EvaluateIdentifierNameExpression(expr As IdentifierNameSyntax) As CConst If _symbols Is Nothing Then Return CConst.CreateNothing() End If Dim ident = expr.Identifier Dim value As CConst = Nothing If Not _symbols.TryGetValue(ident.IdentifierText, value) Then Return CConst.CreateNothing() End If If value.IsBad Then ' we used to treat the const as bad without giving any error. ' not sure if this correct behavior. Return ReportSemanticError(0, expr) End If Dim typeChar = ident.TypeCharacter If typeChar <> TypeCharacter.None AndAlso typeChar <> AsTypeCharacter(value.SpecialType) Then Return ReportSemanticError(ERRID.ERR_TypecharNoMatch2, expr, GetDisplayString(typeChar), value.SpecialType.GetDisplayName()) End If Return value End Function Private Shared Function GetDisplayString(typeChar As TypeCharacter) As String Select Case typeChar Case TypeCharacter.Integer Return "%" Case TypeCharacter.Long Return "&" Case TypeCharacter.Decimal Return "@" Case TypeCharacter.Single Return "!" Case TypeCharacter.Double Return "#" Case TypeCharacter.String Return "$" Case Else Throw ExceptionUtilities.UnexpectedValue(typeChar) End Select End Function Private Shared Function AsTypeCharacter(specialType As SpecialType) As TypeCharacter Select Case specialType Case SpecialType.System_Int32 Return TypeCharacter.Integer Case SpecialType.System_Int64 Return TypeCharacter.Long Case SpecialType.System_Decimal Return TypeCharacter.Decimal Case SpecialType.System_Single Return TypeCharacter.Single Case SpecialType.System_Double Return TypeCharacter.Double Case SpecialType.System_String Return TypeCharacter.String Case Else Return TypeCharacter.None End Select End Function Private Shared Function GetSpecialType(predefinedType As PredefinedTypeSyntax) As SpecialType Dim kind = predefinedType.Keyword.Kind Select Case (kind) Case SyntaxKind.ShortKeyword Return SpecialType.System_Int16 Case SyntaxKind.UShortKeyword Return SpecialType.System_UInt16 Case SyntaxKind.IntegerKeyword Return SpecialType.System_Int32 Case SyntaxKind.UIntegerKeyword Return SpecialType.System_UInt32 Case SyntaxKind.LongKeyword Return SpecialType.System_Int64 Case SyntaxKind.ULongKeyword Return SpecialType.System_UInt64 Case SyntaxKind.DecimalKeyword Return SpecialType.System_Decimal Case SyntaxKind.SingleKeyword Return SpecialType.System_Single Case SyntaxKind.DoubleKeyword Return SpecialType.System_Double Case SyntaxKind.SByteKeyword Return SpecialType.System_SByte Case SyntaxKind.ByteKeyword Return SpecialType.System_Byte Case SyntaxKind.BooleanKeyword Return SpecialType.System_Boolean Case SyntaxKind.CharKeyword Return SpecialType.System_Char Case SyntaxKind.DateKeyword Return SpecialType.System_DateTime Case SyntaxKind.StringKeyword Return SpecialType.System_String Case SyntaxKind.VariantKeyword, SyntaxKind.ObjectKeyword Return SpecialType.System_Object Case Else Throw ExceptionUtilities.UnexpectedValue(kind) End Select End Function Private Function EvaluateTryCastExpression(expr As CastExpressionSyntax) As CConst Dim value = EvaluateExpressionInternal(expr.Expression) Dim predefinedType = TryCast(expr.Type, PredefinedTypeSyntax) If predefinedType Is Nothing Then Return ReportSemanticError(ERRID.ERR_BadTypeInCCExpression, expr.Type) End If Dim specialType = GetSpecialType(predefinedType) If specialType <> SpecialType.System_Object AndAlso specialType <> SpecialType.System_String Then Return ReportSemanticError(ERRID.ERR_TryCastOfValueType1, expr.Type) End If If value.SpecialType = SpecialType.System_Object OrElse value.SpecialType = SpecialType.System_String Then Return Convert(value, specialType, expr) End If If value.SpecialType = specialType Then If specialType = SpecialType.System_Double OrElse specialType = SpecialType.System_Single Then Return ReportSemanticError(ERRID.ERR_IdentityDirectCastForFloat, expr.Type) Else Return ReportSemanticError(ERRID.WRN_ObsoleteIdentityDirectCastForValueType, expr.Type) End If End If Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr.Type, value.SpecialType.GetDisplayName(), specialType.GetDisplayName()) End Function Private Function EvaluateDirectCastExpression(expr As CastExpressionSyntax) As CConst Dim val = EvaluateExpressionInternal(expr.Expression) Dim predefinedType = TryCast(expr.Type, PredefinedTypeSyntax) If predefinedType Is Nothing Then Return ReportSemanticError(ERRID.ERR_BadTypeInCCExpression, expr.Type) End If Dim specialType = GetSpecialType(predefinedType) If val.SpecialType = SpecialType.System_Object OrElse val.SpecialType = SpecialType.System_String Then Return Convert(val, specialType, expr) End If If val.SpecialType = specialType Then If specialType = SpecialType.System_Double OrElse specialType = SpecialType.System_Single Then Return ReportSemanticError(ERRID.ERR_IdentityDirectCastForFloat, expr.Type) Else Dim result = Convert(val, specialType, expr) result = result.WithError(ERRID.WRN_ObsoleteIdentityDirectCastForValueType) Return result End If End If Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr.Type, val.SpecialType, specialType) End Function Private Function EvaluateCTypeExpression(expr As CastExpressionSyntax) As CConst Dim val = EvaluateExpressionInternal(expr.Expression) Dim predefinedType = TryCast(expr.Type, PredefinedTypeSyntax) If predefinedType Is Nothing Then Return ReportSemanticError(ERRID.ERR_BadTypeInCCExpression, expr.Type) End If Dim specialType = GetSpecialType(predefinedType) Return Convert(val, specialType, expr) End Function Private Function EvaluatePredefinedCastExpression(expr As PredefinedCastExpressionSyntax) As CConst Dim val = EvaluateExpressionInternal(expr.Expression) Dim specialType As SpecialType Select Case expr.Keyword.Kind Case SyntaxKind.CBoolKeyword specialType = SpecialType.System_Boolean Case SyntaxKind.CDateKeyword specialType = SpecialType.System_DateTime Case SyntaxKind.CDblKeyword specialType = SpecialType.System_Double Case SyntaxKind.CSByteKeyword specialType = SpecialType.System_SByte Case SyntaxKind.CByteKeyword specialType = SpecialType.System_Byte Case SyntaxKind.CCharKeyword specialType = SpecialType.System_Char Case SyntaxKind.CShortKeyword specialType = SpecialType.System_Int16 Case SyntaxKind.CUShortKeyword specialType = SpecialType.System_UInt16 Case SyntaxKind.CIntKeyword specialType = SpecialType.System_Int32 Case SyntaxKind.CUIntKeyword specialType = SpecialType.System_UInt32 Case SyntaxKind.CLngKeyword specialType = SpecialType.System_Int64 Case SyntaxKind.CULngKeyword specialType = SpecialType.System_UInt64 Case SyntaxKind.CSngKeyword specialType = SpecialType.System_Single Case SyntaxKind.CStrKeyword specialType = SpecialType.System_String Case SyntaxKind.CDecKeyword specialType = SpecialType.System_Decimal Case SyntaxKind.CObjKeyword Return ConvertToObject(val, expr) Case Else Throw ExceptionUtilities.UnexpectedValue(expr.Keyword.Kind) End Select Return Convert(val, specialType, expr) End Function Private Function EvaluateBinaryIfExpression(expr As BinaryConditionalExpressionSyntax) As CConst Dim op = EvaluateExpressionInternal(expr.FirstExpression) Dim value As Object = op.ValueAsObject If value IsNot Nothing Then If value.GetType().GetTypeInfo().IsValueType Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) Else Return op End If End If Return EvaluateExpressionInternal(expr.SecondExpression) End Function Private Function EvaluateTernaryIfExpression(expr As TernaryConditionalExpressionSyntax) As CConst Dim condition = EvaluateExpressionInternal(expr.Condition) If condition.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Dim cond = ConvertToBool(condition, expr) If cond.IsBad Then Return cond Else Dim whenTrue As CConst = EvaluateExpressionInternal(expr.WhenTrue) Dim whenFalse As CConst = EvaluateExpressionInternal(expr.WhenFalse) If Not whenTrue.IsBad AndAlso Not whenFalse.IsBad Then If IsNothing(whenTrue) Then If Not IsNothing(whenFalse) AndAlso whenFalse.SpecialType <> SpecialType.System_Object Then whenTrue = Convert(whenTrue, whenFalse.SpecialType, expr.WhenTrue) End If ElseIf IsNothing(whenFalse) Then If whenTrue.SpecialType <> SpecialType.System_Object Then whenFalse = Convert(whenFalse, whenTrue.SpecialType, expr.WhenFalse) End If Else Dim dominantType As SpecialType = CType(s_dominantType(TypeCodeToDominantTypeIndex(whenTrue.SpecialType), TypeCodeToDominantTypeIndex(whenFalse.SpecialType)), SpecialType) If dominantType <> whenTrue.SpecialType Then whenTrue = Convert(whenTrue, dominantType, expr.WhenTrue) End If If dominantType <> whenFalse.SpecialType Then whenFalse = Convert(whenFalse, dominantType, expr.WhenFalse) End If End If End If If whenTrue.IsBad Then Return whenTrue End If If whenFalse.IsBad Then Return whenFalse End If Return If(DirectCast(cond, CConst(Of Boolean)).Value, whenTrue, whenFalse) End If End Function Private Shared Function ConvertToBool(value As CConst, expr As ExpressionSyntax) As CConst If value.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Dim specialType = value.SpecialType If specialType = SpecialType.System_Boolean Then Return DirectCast(value, CConst(Of Boolean)) End If If specialType.IsNumericType() Then Return CConst.Create(CBool(value.ValueAsObject)) End If Select Case specialType Case SpecialType.System_Char Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, SpecialType.System_Char.GetDisplayName(), SpecialType.System_Boolean.GetDisplayName()) Case SpecialType.System_DateTime Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, SpecialType.System_DateTime.GetDisplayName(), SpecialType.System_Boolean.GetDisplayName()) Case SpecialType.System_Object If value.ValueAsObject Is Nothing Then Return CConst.Create(CBool(Nothing)) Else Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Case SpecialType.System_String Return ReportSemanticError(ERRID.ERR_RequiredConstConversion2, expr, SpecialType.System_String.GetDisplayName(), SpecialType.System_Boolean.GetDisplayName()) Case Else Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, specialType, SpecialType.System_Boolean.GetDisplayName()) End Select End Function Private Shared Function ConvertToNumeric(value As CConst, toSpecialType As SpecialType, expr As ExpressionSyntax) As CConst Debug.Assert(toSpecialType.IsNumericType()) If value.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If ' nothing for numeric conversions is as good as 0 If IsNothing(value) Then value = CConst.Create(0) End If Dim fromSpecialType = value.SpecialType If fromSpecialType = toSpecialType Then Return value End If If fromSpecialType.IsNumericType() Then Return ConvertNumericToNumeric(value, toSpecialType, expr) End If Select Case fromSpecialType Case SpecialType.System_Boolean Dim tv = DirectCast(value, CConst(Of Boolean)) Dim numericVal As Long = CLng(tv.Value) If toSpecialType.IsUnsignedIntegralType() Then numericVal = NarrowIntegralResult(numericVal, SpecialType.System_Int64, toSpecialType, False) End If Return CConst.CreateChecked(System.Convert.ChangeType(numericVal, toSpecialType.ToRuntimeType(), CultureInfo.InvariantCulture)) Case SpecialType.System_Char Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, SpecialType.System_Char.GetDisplayName(), toSpecialType.GetDisplayName()) Case SpecialType.System_DateTime Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, SpecialType.System_DateTime.GetDisplayName(), toSpecialType.GetDisplayName()) Case SpecialType.System_Object Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) Case SpecialType.System_String Return ReportSemanticError(ERRID.ERR_RequiredConstConversion2, expr, SpecialType.System_String.GetDisplayName(), toSpecialType.GetDisplayName()) Case Else Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType.GetDisplayName(), toSpecialType.GetDisplayName()) End Select End Function Private Shared Function ConvertNumericToNumeric(value As CConst, toSpecialType As SpecialType, expr As ExpressionSyntax) As CConst Debug.Assert(value.SpecialType.IsNumericType()) Debug.Assert(toSpecialType.IsNumericType()) Try Return CConst.CreateChecked(System.Convert.ChangeType(value.ValueAsObject, toSpecialType.ToRuntimeType(), CultureInfo.InvariantCulture)) Catch ex As OverflowException Return ReportSemanticError(ERRID.ERR_ExpressionOverflow1, expr, toSpecialType.GetDisplayName()) End Try End Function Private Shared Function Convert(value As CConst, toSpecialType As SpecialType, expr As ExpressionSyntax) As CConst If value.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Dim fromSpecialType = value.SpecialType If fromSpecialType = toSpecialType Then Return value End If If toSpecialType.IsNumericType() Then Return ConvertToNumeric(value, toSpecialType, expr) End If Select Case toSpecialType Case SpecialType.System_Boolean Return ConvertToBool(value, expr) Case SpecialType.System_Char Return ConvertToChar(value, expr) Case SpecialType.System_DateTime Return ConvertToDate(value, expr) Case SpecialType.System_Object Return ConvertToObject(value, expr) Case SpecialType.System_String Return ConvertToString(value, expr) Case Else Return ReportSemanticError(ERRID.ERR_CannotConvertValue2, expr, fromSpecialType.GetDisplayName(), toSpecialType.GetDisplayName()) End Select End Function Private Shared Function ConvertToChar(value As CConst, expr As ExpressionSyntax) As CConst If value.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Dim fromSpecialType = value.SpecialType If fromSpecialType = SpecialType.System_Char Then Return DirectCast(value, CConst(Of Char)) End If If fromSpecialType.IsIntegralType() Then Return ReportSemanticError(ERRID.ERR_IntegralToCharTypeMismatch1, expr, fromSpecialType.GetDisplayName()) End If Select Case fromSpecialType Case SpecialType.System_Boolean Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_Char.GetDisplayName()) Case SpecialType.System_DateTime Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_Char.GetDisplayName()) Case SpecialType.System_Object If value.ValueAsObject Is Nothing Then Return CConst.Create(CChar(Nothing)) Else Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Case SpecialType.System_String Dim tv = DirectCast(value, CConst(Of String)) Dim ch = If(tv.Value Is Nothing, CChar(Nothing), CChar(tv.Value)) Return CConst.Create(ch) Case Else Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_Char.GetDisplayName()) End Select End Function Private Shared Function ConvertToDate(value As CConst, expr As ExpressionSyntax) As CConst If value.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Dim fromSpecialType = value.SpecialType If fromSpecialType = SpecialType.System_DateTime Then Return DirectCast(value, CConst(Of DateTime)) End If If fromSpecialType.IsIntegralType() Then Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_DateTime.GetDisplayName()) End If Select Case fromSpecialType Case SpecialType.System_Boolean Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_DateTime.GetDisplayName()) Case SpecialType.System_Char Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_DateTime.GetDisplayName()) Case SpecialType.System_String Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) Case SpecialType.System_Object If value.ValueAsObject Is Nothing Then Return CConst.Create(CDate(Nothing)) Else Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Case Else Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, fromSpecialType, SpecialType.System_DateTime.GetDisplayName()) End Select End Function Private Shared Function ConvertToString(value As CConst, expr As ExpressionSyntax) As CConst If value.IsBad Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Dim specialType = value.SpecialType If specialType = SpecialType.System_String Then Return DirectCast(value, CConst(Of String)) End If If specialType.IsIntegralType() Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Select Case specialType Case SpecialType.System_Boolean Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) Case SpecialType.System_Char Dim tv = DirectCast(value, CConst(Of Char)) Return CConst.Create(CStr(tv.Value)) Case SpecialType.System_DateTime Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) Case SpecialType.System_Object If value.ValueAsObject Is Nothing Then Return CConst.Create(CStr(Nothing)) Else Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Case Else Return ReportSemanticError(ERRID.ERR_TypeMismatch2, expr, specialType, SpecialType.System_String.GetDisplayName()) End Select End Function Private Shared Function ConvertToObject(value As CConst, expr As ExpressionSyntax) As CConst If value.IsBad Then Return value End If If IsNothing(value) Then Return ReportSemanticError(ERRID.ERR_RequiredConstExpr, expr) End If Return ReportSemanticError(ERRID.ERR_RequiredConstConversion2, expr, value.SpecialType.GetDisplayName(), SpecialType.System_Object.GetDisplayName()) End Function Private Function EvaluateUnaryExpression(expr As UnaryExpressionSyntax) As CConst Dim val = EvaluateExpressionInternal(expr.Operand) Dim specialType = val.SpecialType If specialType = SpecialType.None Then Return ReportSemanticError(ERRID.ERR_BadCCExpression, expr) End If If specialType = SpecialType.System_String OrElse (specialType = SpecialType.System_Object AndAlso Not IsNothing(val)) OrElse specialType = SpecialType.System_Char OrElse specialType = SpecialType.System_DateTime Then Return ReportSemanticError(ERRID.ERR_UnaryOperand2, expr, expr.OperatorToken.ValueText, specialType.GetDisplayName()) End If Try Select Case expr.Kind Case SyntaxKind.UnaryMinusExpression If IsNothing(val) Then Return CConst.Create(-Nothing) End If Select Case specialType Case SpecialType.System_Boolean Return CConst.Create(-(CShort(DirectCast(val, CConst(Of Boolean)).Value))) Case SpecialType.System_Byte Return CConst.Create(-(DirectCast(val, CConst(Of Byte)).Value)) Case SpecialType.System_Decimal Return CConst.Create(-(DirectCast(val, CConst(Of Decimal)).Value)) Case SpecialType.System_Double Return CConst.Create(-(DirectCast(val, CConst(Of Double)).Value)) Case SpecialType.System_Int16 Return CConst.Create(-(DirectCast(val, CConst(Of Int16)).Value)) Case SpecialType.System_Int32 Return CConst.Create(-(DirectCast(val, CConst(Of Int32)).Value)) Case SpecialType.System_Int64 Return CConst.Create(-(DirectCast(val, CConst(Of Int64)).Value)) Case SpecialType.System_SByte Return CConst.Create(-(DirectCast(val, CConst(Of SByte)).Value)) Case SpecialType.System_Single Return CConst.Create(-(DirectCast(val, CConst(Of Single)).Value)) Case SpecialType.System_UInt16 Return CConst.Create(-(DirectCast(val, CConst(Of UInt16)).Value)) Case SpecialType.System_UInt32 Return CConst.Create(-(DirectCast(val, CConst(Of UInt32)).Value)) Case SpecialType.System_UInt64 Return CConst.Create(-(DirectCast(val, CConst(Of UInt64)).Value)) Case Else Throw ExceptionUtilities.UnexpectedValue(specialType) End Select Case SyntaxKind.UnaryPlusExpression If specialType = SpecialType.System_Boolean Then Return CConst.Create(+(CShort(DirectCast(val, CConst(Of Boolean)).Value))) End If Return val Case SyntaxKind.NotExpression If IsNothing(val) Then Return CConst.Create(Not Nothing) End If Select Case specialType Case SpecialType.System_Boolean Return CConst.Create(Not (DirectCast(val, CConst(Of Boolean)).Value)) Case SpecialType.System_Byte Return CConst.Create(Not (DirectCast(val, CConst(Of Byte)).Value)) Case SpecialType.System_Decimal Return CConst.Create(Not CLng(DirectCast(val, CConst(Of Decimal)).Value)) Case SpecialType.System_Double Return CConst.Create(Not CLng(DirectCast(val, CConst(Of Double)).Value)) Case SpecialType.System_Int16 Return CConst.Create(Not (DirectCast(val, CConst(Of Int16)).Value)) Case SpecialType.System_Int32 Return CConst.Create(Not (DirectCast(val, CConst(Of Int32)).Value)) Case SpecialType.System_Int64 Return CConst.Create(Not (DirectCast(val, CConst(Of Int64)).Value)) Case SpecialType.System_SByte Return CConst.Create(Not (DirectCast(val, CConst(Of SByte)).Value)) Case SpecialType.System_Single Return CConst.Create(Not CLng(DirectCast(val, CConst(Of Single)).Value)) Case SpecialType.System_UInt16 Return CConst.Create(Not (DirectCast(val, CConst(Of UInt16)).Value)) Case SpecialType.System_UInt32 Return CConst.Create(Not (DirectCast(val, CConst(Of UInt32)).Value)) Case SpecialType.System_UInt64 Return CConst.Create(Not (DirectCast(val, CConst(Of UInt64)).Value)) Case Else Throw ExceptionUtilities.UnexpectedValue(specialType) End Select End Select Catch ex As OverflowException Return ReportSemanticError(ERRID.ERR_ExpressionOverflow1, expr) End Try Throw ExceptionUtilities.UnexpectedValue(expr) End Function Private Shared Function IsNothing(val As CConst) As Boolean Return val.SpecialType = SpecialType.System_Object AndAlso val.ValueAsObject Is Nothing End Function Private Function EvaluateBinaryExpression(expr As BinaryExpressionSyntax) As CConst Dim Left = EvaluateExpressionInternal(expr.Left) Dim Right = EvaluateExpressionInternal(expr.Right) Dim BoundOpcode = expr.Kind If Left.IsBad OrElse Right.IsBad Then Return ReportSemanticError(ERRID.ERR_BadCCExpression, expr) End If Dim OperandType As SpecialType = SpecialType.None If IsNothing(Left) OrElse IsNothing(Right) Then If IsNothing(Left) AndAlso IsNothing(Right) Then ' // Comparing Nothing and Nothing succeeds, and operations ' // that provide an explicit type succeed. ' // And and Or succeed with a result type of Integer. ' // Everything else is rejected. ' // ' // The only reason these matter is for conditional compilation ' // expressions that refer to undefined constants. Select Case BoundOpcode Case SyntaxKind.ConcatenateExpression, SyntaxKind.LikeExpression Right = ConvertToString(Right, expr.Right) Case SyntaxKind.OrElseExpression, SyntaxKind.AndAlsoExpression Right = ConvertToBool(Right, expr.Right) Case SyntaxKind.IsExpression, SyntaxKind.IsNotExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.LessThanExpression, SyntaxKind.LessThanOrEqualExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.GreaterThanExpression, SyntaxKind.AddExpression, SyntaxKind.MultiplyExpression, SyntaxKind.DivideExpression, SyntaxKind.SubtractExpression, SyntaxKind.ExponentiateExpression, SyntaxKind.IntegerDivideExpression, SyntaxKind.LeftShiftExpression, SyntaxKind.RightShiftExpression, SyntaxKind.ModuloExpression ' // Treating the operation as if its operands are integers ' // gives correct results. Right = ConvertToNumeric(Right, SpecialType.System_Int32, expr.Right) Case SyntaxKind.OrExpression, SyntaxKind.AndExpression, SyntaxKind.ExclusiveOrExpression Right = ConvertToNumeric(Right, SpecialType.System_Int32, expr.Right) Case Else Throw ExceptionUtilities.UnexpectedValue(expr) End Select End If If IsNothing(Left) Then OperandType = Right.SpecialType Select Case (BoundOpcode) Case SyntaxKind.ConcatenateExpression, SyntaxKind.LikeExpression ' // For & and Like, a Nothing operand is typed String unless the other operand ' // is non-intrinsic OperandType = SpecialType.System_String Case SyntaxKind.LeftShiftExpression, SyntaxKind.RightShiftExpression ' // Nothing should default to Integer for Shift operations. OperandType = SpecialType.System_Int32 End Select Left = Convert(Left, OperandType, expr.Left) ElseIf IsNothing(Right) Then OperandType = Left.SpecialType Select Case (BoundOpcode) Case SyntaxKind.ConcatenateExpression, SyntaxKind.LikeExpression ' // For & and Like, a Nothing operand is typed String unless the other operand ' // is non-intrinsic OperandType = SpecialType.System_String End Select Right = Convert(Right, OperandType, expr.Right) End If End If ' // For comparison operators, the result type computed here is not ' // the result type of the comparison (which is typically boolean), ' // but is the type to which the operands are to be converted. For ' // other operators, the type computed here is both the result type ' // and the common operand type. Dim ResultType = LookupInOperatorTables(BoundOpcode, Left.SpecialType, Right.SpecialType) If ResultType = SpecialType.None Then Return ReportSemanticError(ERRID.ERR_BadTypeInCCExpression, expr) End If OperandType = ResultType Left = Convert(Left, OperandType, expr.Left) If Left.IsBad Then Return Left End If Right = Convert(Right, OperandType, expr.Right) If Right.IsBad Then Return Right End If Select Case BoundOpcode Case SyntaxKind.AddExpression If ResultType = SpecialType.System_String Then ' // Transform the addition into a string concatenation. BoundOpcode = SyntaxKind.ConcatenateExpression End If Case _ SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.LessThanOrEqualExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanExpression, SyntaxKind.GreaterThanExpression ResultType = SpecialType.System_Boolean End Select Dim Result = PerformCompileTimeBinaryOperation( BoundOpcode, ResultType, Left, Right, expr) Return Result End Function Private Shared Function PerformCompileTimeBinaryOperation(opcode As SyntaxKind, resultType As SpecialType, left As CConst, right As CConst, expr As ExpressionSyntax) As CConst Debug.Assert(opcode = SyntaxKind.LeftShiftExpression OrElse opcode = SyntaxKind.RightShiftExpression OrElse left.SpecialType = right.SpecialType, "Binary operation on mismatched types.") If left.SpecialType.IsIntegralType() OrElse left.SpecialType = SpecialType.System_Char OrElse left.SpecialType = SpecialType.System_DateTime Then Dim LeftValue As Int64 = TypeHelpers.UncheckedCLng(left) Dim RightValue As Int64 = TypeHelpers.UncheckedCLng(right) If resultType = SpecialType.System_Boolean Then Dim ComparisonSucceeds As Boolean = False Select Case (opcode) Case SyntaxKind.EqualsExpression ComparisonSucceeds = If(left.SpecialType.IsUnsignedIntegralType(), UncheckedCULng(LeftValue) = UncheckedCULng(RightValue), LeftValue = RightValue) Case SyntaxKind.NotEqualsExpression ComparisonSucceeds = If(left.SpecialType.IsUnsignedIntegralType(), UncheckedCULng(LeftValue) <> UncheckedCULng(RightValue), LeftValue <> RightValue) Case SyntaxKind.LessThanOrEqualExpression ComparisonSucceeds = If(left.SpecialType.IsUnsignedIntegralType(), UncheckedCULng(LeftValue) <= UncheckedCULng(RightValue), LeftValue <= RightValue) Case SyntaxKind.GreaterThanOrEqualExpression ComparisonSucceeds = If(left.SpecialType.IsUnsignedIntegralType(), UncheckedCULng(LeftValue) >= UncheckedCULng(RightValue), LeftValue >= RightValue) Case SyntaxKind.LessThanExpression ComparisonSucceeds = If(left.SpecialType.IsUnsignedIntegralType(), UncheckedCULng(LeftValue) < UncheckedCULng(RightValue), LeftValue < RightValue) Case SyntaxKind.GreaterThanExpression ComparisonSucceeds = If(left.SpecialType.IsUnsignedIntegralType(), UncheckedCULng(LeftValue) > UncheckedCULng(RightValue), LeftValue > RightValue) Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select Return CConst.Create(ComparisonSucceeds) Else ' // Compute the result in 64-bit arithmetic, and determine if the ' // operation overflows the result type. Dim ResultValue As Int64 = 0 Dim Overflow As Boolean = False Select Case (opcode) Case SyntaxKind.AddExpression ResultValue = NarrowIntegralResult( LeftValue + RightValue, left.SpecialType, resultType, Overflow) If Not resultType.IsUnsignedIntegralType() Then If (RightValue > 0 AndAlso ResultValue < LeftValue) OrElse (RightValue < 0 AndAlso ResultValue > LeftValue) Then Overflow = True End If ElseIf ( UncheckedCULng(ResultValue) < UncheckedCULng(LeftValue) ) Then Overflow = True End If Case SyntaxKind.SubtractExpression ResultValue = NarrowIntegralResult( LeftValue - RightValue, left.SpecialType, resultType, Overflow) If Not resultType.IsUnsignedIntegralType() Then If (RightValue > 0 AndAlso ResultValue > LeftValue) OrElse (RightValue < 0 AndAlso ResultValue < LeftValue) Then Overflow = True End If ElseIf UncheckedCULng(ResultValue) > UncheckedCULng(LeftValue) Then Overflow = True End If Case SyntaxKind.MultiplyExpression ResultValue = Multiply(LeftValue, RightValue, left.SpecialType, resultType, Overflow) Case SyntaxKind.IntegerDivideExpression If RightValue = 0 Then Return ReportSemanticError(ERRID.ERR_ZeroDivide, expr) End If ResultValue = NarrowIntegralResult( If(resultType.IsUnsignedIntegralType(), CompileTimeCalculations.UncheckedCLng(UncheckedCULng(LeftValue) \ UncheckedCULng(RightValue)), UncheckedIntegralDiv(LeftValue, RightValue)), left.SpecialType, resultType, Overflow) If Not resultType.IsUnsignedIntegralType() AndAlso LeftValue = Int64.MinValue AndAlso RightValue = -1 Then Overflow = True End If Case SyntaxKind.ModuloExpression If RightValue = 0 Then Return ReportSemanticError(ERRID.ERR_ZeroDivide, expr) End If If resultType.IsUnsignedIntegralType() Then ResultValue = CompileTimeCalculations.UncheckedCLng(UncheckedCULng(LeftValue) Mod UncheckedCULng(RightValue)) ' // 64-bit processors crash on 0, -1 (Bug: dd71694) ElseIf RightValue <> Not CType(0, Int64) Then ResultValue = LeftValue Mod RightValue Else ResultValue = 0 End If Case SyntaxKind.ExclusiveOrExpression ResultValue = LeftValue Xor RightValue Case SyntaxKind.OrExpression ResultValue = LeftValue Or RightValue Case SyntaxKind.AndExpression ResultValue = LeftValue And RightValue Case SyntaxKind.LeftShiftExpression RightValue = RightValue And left.SpecialType.GetShiftSizeMask() ResultValue = LeftValue << CType(RightValue, Integer) ' // Round-trip the result through a cast. We do this for two reasons: ' // a) Bits may have shifted off the end and need to be stripped away. ' // b) The sign bit may have changed which requires the result to be sign-extended. Dim overflowTemp As Boolean = False ResultValue = NarrowIntegralResult(ResultValue, left.SpecialType, resultType, overflowTemp) Case SyntaxKind.RightShiftExpression RightValue = RightValue And left.SpecialType.GetShiftSizeMask() If resultType.IsUnsignedIntegralType() Then ResultValue = CompileTimeCalculations.UncheckedCLng((UncheckedCULng(LeftValue) >> CType(RightValue, Integer))) Else ResultValue = LeftValue >> CType(RightValue, Integer) End If Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select If Overflow Then Return ReportSemanticError(ERRID.ERR_ExpressionOverflow1, expr, resultType.GetDisplayName()) End If Return Convert(CConst.Create(ResultValue), resultType, expr) End If ElseIf left.SpecialType.IsFloatingType() Then Dim LeftValue As Double = CDbl(left.ValueAsObject) Dim RightValue As Double = CDbl(right.ValueAsObject) If resultType = SpecialType.System_Boolean Then Dim ComparisonSucceeds As Boolean = False Select Case (opcode) Case SyntaxKind.EqualsExpression ComparisonSucceeds = LeftValue = RightValue Case SyntaxKind.NotEqualsExpression ComparisonSucceeds = LeftValue <> RightValue Case SyntaxKind.LessThanOrEqualExpression ComparisonSucceeds = LeftValue <= RightValue Case SyntaxKind.GreaterThanOrEqualExpression ComparisonSucceeds = LeftValue >= RightValue Case SyntaxKind.LessThanExpression ComparisonSucceeds = LeftValue < RightValue Case SyntaxKind.GreaterThanExpression ComparisonSucceeds = LeftValue > RightValue Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select Return CConst.Create(If(ComparisonSucceeds, True, False)) Else Dim resultValue As Double = 0 Dim overflow As Boolean = False Select Case (opcode) Case SyntaxKind.AddExpression resultValue = LeftValue + RightValue Case SyntaxKind.SubtractExpression resultValue = LeftValue - RightValue Case SyntaxKind.MultiplyExpression resultValue = LeftValue * RightValue Case SyntaxKind.ExponentiateExpression 'IS_DBL_INFINITY(RightValue) If ( Double.IsInfinity(RightValue) ) Then 'IS_DBL_ONE(LeftValue) If LeftValue = 1.0 Then resultValue = LeftValue Exit Select End If 'IS_DBL_NEGATIVEONE(LeftValue) If LeftValue = -1.0 Then resultValue = Double.NaN Exit Select End If ElseIf ( Double.IsNaN(RightValue) ) Then resultValue = Double.NaN Exit Select End If resultValue = Math.Pow(LeftValue, RightValue) Case SyntaxKind.DivideExpression ' TODO: verify with native code. ' // We have decided not to detect zerodivide in compile-time ' // evaluation of floating expressions. #If 0 Then If ( RightValue = 0 ) ReportSemanticError( ERRID.ERR_ZeroDivide, ExpressionLocation) : return AllocateBadExpression(ExpressionLocation) : End If #End If resultValue = LeftValue / RightValue Case SyntaxKind.ModuloExpression ' // We have decided not to detect zerodivide in compile-time ' // evaluation of floating expressions. #If 0 Then If ( RightValue = 0 ) ReportSemanticError( ERRID.ERR_ZeroDivide, ExpressionLocation) : return AllocateBadExpression(ExpressionLocation) : End If #End If resultValue = Math.IEEERemainder(LeftValue, RightValue) Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select resultValue = NarrowFloatingResult(resultValue, resultType, overflow) ' // We have decided not to detect overflow in compile-time ' // evaluation of floating expressions. #If 0 Then If ( Overflow ) ReportSemanticError( ERRID.ERR_ExpressionOverflow1, ExpressionLocation, ResultType) : return AllocateBadExpression(ExpressionLocation) : End If #End If Return Convert(CConst.Create(resultValue), resultType, expr) End If ElseIf left.SpecialType = SpecialType.System_Decimal Then Dim LeftValue As Decimal = CDec(left.ValueAsObject) Dim RightValue As Decimal = CDec(right.ValueAsObject) If resultType = SpecialType.System_Boolean Then Dim ComparisonSucceeds As Boolean = False Dim ComparisonResult As Integer = LeftValue.CompareTo(RightValue) Select Case (opcode) Case SyntaxKind.EqualsExpression ComparisonSucceeds = (ComparisonResult = 0) Case SyntaxKind.NotEqualsExpression ComparisonSucceeds = Not (ComparisonResult = 0) Case SyntaxKind.LessThanOrEqualExpression ComparisonSucceeds = (ComparisonResult <= 0) Case SyntaxKind.GreaterThanOrEqualExpression ComparisonSucceeds = (ComparisonResult >= 0) Case SyntaxKind.LessThanExpression ComparisonSucceeds = (ComparisonResult < 0) Case SyntaxKind.GreaterThanExpression ComparisonSucceeds = (ComparisonResult > 0) Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select Return CConst.Create(ComparisonSucceeds) Else Dim ResultValue As Decimal Dim Overflow As Boolean = False Select Case (opcode) Case SyntaxKind.AddExpression Overflow = VarDecAdd(LeftValue, RightValue, ResultValue) Case SyntaxKind.SubtractExpression Overflow = VarDecSub(LeftValue, RightValue, ResultValue) Case SyntaxKind.MultiplyExpression Overflow = VarDecMul(LeftValue, RightValue, ResultValue) Case SyntaxKind.DivideExpression If RightValue = Decimal.Zero Then Return ReportSemanticError(ERRID.ERR_ZeroDivide, expr) End If Overflow = VarDecDiv(LeftValue, RightValue, ResultValue) Case SyntaxKind.ModuloExpression If RightValue = Decimal.Zero Then Return ReportSemanticError(ERRID.ERR_ZeroDivide, expr) End If ' // There is no VarDecMod, so we have to do this by hand ' // result = L - (Fix(L / R) * R) ' // CONSIDER (9/12/2003): Doing this by hand generates Overflow ' // for "Decimal.MaxValue Mod 2" when it should ' // generate a result of 1. How to fix? Overflow = VarDecDiv(LeftValue, RightValue, ResultValue) If Not Overflow Then ResultValue = Decimal.Truncate(ResultValue) Overflow = VarDecMul(ResultValue, RightValue, ResultValue) If Not Overflow Then Overflow = VarDecSub(LeftValue, ResultValue, ResultValue) End If End If Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select If Overflow Then Return ReportSemanticError(ERRID.ERR_ExpressionOverflow1, expr, resultType.GetDisplayName()) End If Return CConst.Create(ResultValue) End If ElseIf left.SpecialType = SpecialType.System_String Then ' Nothing strings should be treated the same as "" Dim LeftSpelling = If(CStr(left.ValueAsObject), "") Dim RightSpelling = If(CStr(right.ValueAsObject), "") Select Case (opcode) Case SyntaxKind.ConcatenateExpression Dim ResultString As String = String.Concat(LeftSpelling, RightSpelling) Return CConst.Create(ResultString) Case SyntaxKind.GreaterThanExpression, SyntaxKind.LessThanExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanOrEqualExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression Dim StringComparisonSucceeds As Boolean = False ' // ignore Option Text when conditional compilation(b112186) Dim ComparisonResult = StringComparer.Ordinal.Compare(LeftSpelling, RightSpelling) Select Case (opcode) Case SyntaxKind.EqualsExpression StringComparisonSucceeds = ComparisonResult = 0 Case SyntaxKind.NotEqualsExpression StringComparisonSucceeds = ComparisonResult <> 0 Case SyntaxKind.GreaterThanExpression StringComparisonSucceeds = ComparisonResult > 0 Case SyntaxKind.GreaterThanOrEqualExpression StringComparisonSucceeds = ComparisonResult >= 0 Case SyntaxKind.LessThanExpression StringComparisonSucceeds = ComparisonResult < 0 Case SyntaxKind.LessThanOrEqualExpression StringComparisonSucceeds = ComparisonResult <= 0 End Select Return CConst.Create(StringComparisonSucceeds) Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select ElseIf left.SpecialType = SpecialType.System_Boolean Then Dim LeftValue As Boolean = CBool(left.ValueAsObject) Dim RightValue As Boolean = CBool(right.ValueAsObject) Dim OperationSucceeds As Boolean = False Select Case (opcode) Case SyntaxKind.EqualsExpression OperationSucceeds = LeftValue = RightValue Case SyntaxKind.NotEqualsExpression OperationSucceeds = LeftValue <> RightValue ' // Amazingly, False > True. Case SyntaxKind.GreaterThanExpression OperationSucceeds = LeftValue = False AndAlso RightValue <> False Case SyntaxKind.GreaterThanOrEqualExpression OperationSucceeds = LeftValue = False OrElse RightValue <> False Case SyntaxKind.LessThanExpression OperationSucceeds = LeftValue <> False AndAlso RightValue = False Case SyntaxKind.LessThanOrEqualExpression OperationSucceeds = LeftValue <> False OrElse RightValue = False Case SyntaxKind.ExclusiveOrExpression OperationSucceeds = LeftValue Xor RightValue Case SyntaxKind.OrElseExpression, SyntaxKind.OrExpression OperationSucceeds = LeftValue Or RightValue Case SyntaxKind.AndAlsoExpression, SyntaxKind.AndExpression OperationSucceeds = LeftValue And RightValue Case Else Throw ExceptionUtilities.UnexpectedValue(opcode) End Select Return CConst.Create(OperationSucceeds) End If Throw ExceptionUtilities.Unreachable End Function End Structure End Namespace