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