diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index 3b04989a30b..b55b0dec344 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -3400,22 +3400,25 @@ public void PropertyFunctionStaticMethodIntrinsicMaths() double expectedResult = 9223372036854775807D + 20D; Assert.Equal(expectedResult.ToString(), result); + } - result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - - Assert.Equal((40 | 2).ToString(), result); - - result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - - Assert.Equal((42 & 2).ToString(), result); - - result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); - - Assert.Equal((213 ^ 255).ToString(), result); + /// + /// Expand intrinsic property functions that call a bit operator + /// + [Fact] + public void PropertyFunctionStaticMethodIntrinsicBitOperations() + { + PropertyDictionary pg = new PropertyDictionary(); - result = expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance); + Expander expander = new Expander(pg, FileSystems.Default); - Assert.Equal((~-43).ToString(), result); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseOr(40, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((40 | 2).ToString()); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseAnd(42, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((42 & 2).ToString()); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseXor(213, 255))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((213 ^ 255).ToString()); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::BitwiseNot(-43))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((~-43).ToString()); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::LeftShift(1, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((1 << 2).ToString()); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::RightShift(-8, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((-8 >> 2).ToString()); + expander.ExpandIntoStringLeaveEscaped(@"$([MSBuild]::RightShiftUnsigned(-8, 2))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance).ShouldBe((-8 >>> 2).ToString()); } /// diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index c76c6a47780..1478cc17550 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -3887,6 +3887,14 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst return true; } } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Unescape), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArg(args, out string arg0)) + { + returnVal = IntrinsicFunctions.Unescape(arg0); + return true; + } + } else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.GetPathOfFileAbove), StringComparison.OrdinalIgnoreCase)) { if (TryGetArgs(args, out string arg0, out string arg1)) @@ -3899,7 +3907,7 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst { if (TryGetArgs(args, out double arg0, out double arg1)) { - returnVal = arg0 + arg1; + returnVal = IntrinsicFunctions.Add(arg0, arg1); return true; } } @@ -3907,7 +3915,7 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst { if (TryGetArgs(args, out double arg0, out double arg1)) { - returnVal = arg0 - arg1; + returnVal = IntrinsicFunctions.Subtract(arg0, arg1); return true; } } @@ -3915,7 +3923,7 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst { if (TryGetArgs(args, out double arg0, out double arg1)) { - returnVal = arg0 * arg1; + returnVal = IntrinsicFunctions.Multiply(arg0, arg1); return true; } } @@ -3923,7 +3931,15 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst { if (TryGetArgs(args, out double arg0, out double arg1)) { - returnVal = arg0 / arg1; + returnVal = IntrinsicFunctions.Divide(arg0, arg1); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.Modulo), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out double arg0, out double arg1)) + { + returnVal = IntrinsicFunctions.Modulo(arg0, arg1); return true; } } @@ -4113,6 +4129,62 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst return true; } } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseOr), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0, out int arg1)) + { + returnVal = IntrinsicFunctions.BitwiseOr(arg0, arg1); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseAnd), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0, out int arg1)) + { + returnVal = IntrinsicFunctions.BitwiseAnd(arg0, arg1); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseXor), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0, out int arg1)) + { + returnVal = IntrinsicFunctions.BitwiseXor(arg0, arg1); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.BitwiseNot), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0)) + { + returnVal = IntrinsicFunctions.BitwiseNot(arg0); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.LeftShift), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0, out int arg1)) + { + returnVal = IntrinsicFunctions.LeftShift(arg0, arg1); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RightShift), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0, out int arg1)) + { + returnVal = IntrinsicFunctions.RightShift(arg0, arg1); + return true; + } + } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.RightShiftUnsigned), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArgs(args, out int arg0, out int arg1)) + { + returnVal = IntrinsicFunctions.RightShiftUnsigned(arg0, arg1); + return true; + } + } } else if (_receiverType == typeof(Path)) { @@ -4489,6 +4561,18 @@ private static bool TryGetArgs(object[] args, out string arg0, out StringCompari return Enum.TryParse(comparisonTypeName, out arg1); } + private static bool TryGetArgs(object[] args, out int arg0) + { + arg0 = 0; + + if (args.Length != 1) + { + return false; + } + + return TryConvertToInt(args[0], out arg0); + } + private static bool TryGetArgs(object[] args, out int arg0, out int arg1) { arg0 = 0; diff --git a/src/Build/Evaluation/IntrinsicFunctions.cs b/src/Build/Evaluation/IntrinsicFunctions.cs index 45ebc5e9a0c..3fff5c28e65 100644 --- a/src/Build/Evaluation/IntrinsicFunctions.cs +++ b/src/Build/Evaluation/IntrinsicFunctions.cs @@ -165,6 +165,21 @@ internal static int BitwiseNot(int first) return ~first; } + internal static int LeftShift(int operand, int count) + { + return operand << count; + } + + internal static int RightShift(int operand, int count) + { + return operand >> count; + } + + internal static int RightShiftUnsigned(int operand, int count) + { + return operand >>> count; + } + /// /// Get the value of the registry key and value, default value is null ///