1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 4 using System.Collections; 5 using System.Globalization; 6 using System.IO; 7 using System; 8 9 using Microsoft.Build.Shared; 10 11 namespace Microsoft.Build.Evaluation 12 { 13 /// <summary> 14 /// Evaluates a numeric comparison, such as less-than, or greater-or-equal-than 15 /// Does not update conditioned properties table. 16 /// </summary> 17 internal abstract class NumericComparisonExpressionNode : OperatorExpressionNode 18 { 19 /// <summary> 20 /// Compare numbers 21 /// </summary> Compare(double left, double right)22 protected abstract bool Compare(double left, double right); 23 24 /// <summary> 25 /// Compare Versions. This is only intended to compare version formats like "A.B.C.D" which can otherwise not be compared numerically 26 /// </summary> Compare(Version left, Version right)27 protected abstract bool Compare(Version left, Version right); 28 29 /// <summary> 30 /// Compare mixed numbers and Versions 31 /// </summary> Compare(Version left, double right)32 protected abstract bool Compare(Version left, double right); 33 34 /// <summary> 35 /// Compare mixed numbers and Versions 36 /// </summary> Compare(double left, Version right)37 protected abstract bool Compare(double left, Version right); 38 39 /// <summary> 40 /// Evaluate as boolean 41 /// </summary> BoolEvaluate(ConditionEvaluator.IConditionEvaluationState state)42 internal override bool BoolEvaluate(ConditionEvaluator.IConditionEvaluationState state) 43 { 44 bool isLeftNum = LeftChild.CanNumericEvaluate(state); 45 bool isLeftVersion = LeftChild.CanVersionEvaluate(state); 46 bool isRightNum = RightChild.CanNumericEvaluate(state); 47 bool isRightVersion = RightChild.CanVersionEvaluate(state); 48 bool isNumeric = isLeftNum && isRightNum; 49 bool isVersion = isLeftVersion && isRightVersion; 50 bool isValidComparison = isNumeric || isVersion || (isLeftNum && isRightVersion) || (isLeftVersion && isRightNum); 51 52 ProjectErrorUtilities.VerifyThrowInvalidProject 53 (isValidComparison, 54 state.ElementLocation, 55 "ComparisonOnNonNumericExpression", 56 state.Condition, 57 /* helpfully display unexpanded token and expanded result in error message */ 58 (LeftChild.CanNumericEvaluate(state) ? RightChild.GetUnexpandedValue(state) : LeftChild.GetUnexpandedValue(state)), 59 (LeftChild.CanNumericEvaluate(state) ? RightChild.GetExpandedValue(state) : LeftChild.GetExpandedValue(state))); 60 61 // If the values identify as numeric, make that comparison instead of the Version comparison since numeric has a stricter definition 62 if (isNumeric) 63 { 64 return Compare(LeftChild.NumericEvaluate(state), RightChild.NumericEvaluate(state)); 65 } 66 else if (isVersion) 67 { 68 return Compare(LeftChild.VersionEvaluate(state), RightChild.VersionEvaluate(state)); 69 } 70 71 // If the numbers are of a mixed type, call that specific Compare method 72 if (isLeftNum && isRightVersion) 73 { 74 return Compare(LeftChild.NumericEvaluate(state), RightChild.VersionEvaluate(state)); 75 } 76 else if (isLeftVersion && isRightNum) 77 { 78 return Compare(LeftChild.VersionEvaluate(state), RightChild.NumericEvaluate(state)); 79 } 80 81 // Throw error here as this code should be unreachable 82 ErrorUtilities.ThrowInternalErrorUnreachable(); 83 return false; 84 } 85 } 86 } 87