|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.TemplateEngine.Utils;
namespace Microsoft.TemplateEngine.Core.Expressions.Cpp
{
internal class Scope
{
public enum NextPlacement
{
Left,
Right,
None
}
public object? Left { get; set; }
public Operator Operator { get; set; }
public object? Right { get; set; }
public object Value
{
set
{
switch (TargetPlacement)
{
case NextPlacement.Left:
Left = value;
TargetPlacement = NextPlacement.Right;
break;
case NextPlacement.Right:
Right = value;
TargetPlacement = NextPlacement.None;
break;
}
}
}
public NextPlacement TargetPlacement { get; set; }
public static TResult EvaluateSides<TLeft, TRight, TResult>(object left, object right, Func<object, TLeft> convertLeft, Func<object, TRight> convertRight, Func<TLeft, TRight, TResult> combine)
{
TLeft l = EvaluateSide(left, convertLeft);
TRight r = EvaluateSide(right, convertRight);
return combine(l, r);
}
public static TResult EvaluateSides<T, TResult>(object left, object right, Func<object, T> convert, Func<T, T, TResult> combine)
{
return EvaluateSides(left, right, convert, convert, combine);
}
public object Evaluate()
{
switch (Operator)
{
case Operator.Not:
return !EvaluateSide(Right!, x => Convert.ToBoolean(x ?? "False"));
case Operator.And:
return EvaluateSides(Left!, Right!, x => (bool)x, (x, y) => x && y);
case Operator.Or:
return EvaluateSides(Left!, Right!, x => (bool)x, (x, y) => x || y);
case Operator.Xor:
return EvaluateSides(Left!, Right!, x => (bool)x, (x, y) => x ^ y);
case Operator.EqualTo:
return EvaluateSides(Left!, Right!, x => x, LenientEquals);
case Operator.NotEqualTo:
return EvaluateSides(Left!, Right!, x => x, (x, y) => !LenientEquals(x, y));
case Operator.GreaterThan:
return EvaluateSides(Left!, Right!, ParserExtensions.ConvertToDoubleCurrentOrInvariant, (x, y) => x > y);
case Operator.GreaterThanOrEqualTo:
return EvaluateSides(Left!, Right!, ParserExtensions.ConvertToDoubleCurrentOrInvariant, (x, y) => x >= y);
case Operator.LessThan:
return EvaluateSides(Left!, Right!, ParserExtensions.ConvertToDoubleCurrentOrInvariant, (x, y) => x < y);
case Operator.LessThanOrEqualTo:
return EvaluateSides(Left!, Right!, ParserExtensions.ConvertToDoubleCurrentOrInvariant, (x, y) => x <= y);
case Operator.LeftShift:
return EvaluateSides(Left!, Right!, Convert.ToInt64, Convert.ToInt32, (x, y) => x << y);
case Operator.RightShift:
return EvaluateSides(Left!, Right!, Convert.ToInt64, Convert.ToInt32, (x, y) => x >> y);
case Operator.BitwiseAnd:
return EvaluateSides(Left!, Right!, Convert.ToInt64, (x, y) => x & y);
case Operator.BitwiseOr:
return EvaluateSides(Left!, Right!, Convert.ToInt64, (x, y) => x | y);
default:
if (Left != null)
{
return EvaluateSide(Left, x => x);
}
return false;
}
}
private static T EvaluateSide<T>(object side, Func<object, T> convert)
{
if (side is Scope scope)
{
return convert(scope.Evaluate());
}
return convert(side);
}
private static bool LenientEquals(object x, object y)
{
if (x is string sx && y is string sy)
{
return string.Equals(sx, sy, StringComparison.OrdinalIgnoreCase);
}
if (MultiValueParameter.TryPerformMultiValueEqual(x, y, out bool result))
{
return result;
}
return Equals(x, y);
}
}
}
|