@@ -6397,6 +6397,16 @@ public static class Interpreter
63976397 /// <summary>Always returns false</summary>
63986398 public static readonly Func<bool> FalseFunc = static () => false;
63996399
6400+ /// <summary>Single instance of true object</summary>
6401+ public static readonly object TrueObject = true;
6402+ /// <summary>Single instance of false object</summary>
6403+ public static readonly object FalseObject = false;
6404+
6405+ private static T UnreachableCase<T>()
6406+ {
6407+ throw new InvalidCastException("Unreachable switch case reached");
6408+ }
6409+
64006410 /// <summary>Operation accepting bool inputs and producing bool output</summary>
64016411 [MethodImpl(MethodImplOptions.AggressiveInlining)]
64026412 public static bool IsLogical(ExpressionType nodeType) =>
@@ -6553,7 +6563,7 @@ public static bool TryEvalPureArithmeticAndLogic(out object result, Expression e
65536563 public static bool TryEvalPrimitive(out object result, Expression expr)
65546564 {
65556565 Debug.Assert(expr.Type.IsPrimitive);
6556- result = false ;
6566+ result = null ;
65576567
65586568 var nodeType = expr.NodeType;
65596569 if (nodeType == ExpressionType.Constant)
@@ -6566,6 +6576,8 @@ public static bool TryEvalPrimitive(out object result, Expression expr)
65666576 return true;
65676577 }
65686578
6579+ // todo: @wip handle the DefaultExpression
6580+
65696581 if (nodeType == ExpressionType.Convert)
65706582 {
65716583 var unaryExpr = (UnaryExpression)expr;
@@ -6584,7 +6596,7 @@ public static bool TryEvalPrimitive(out object result, Expression expr)
65846596 var unaryExpr = (UnaryExpression)expr;
65856597 if (!TryEvalPrimitive(out var boolVal, unaryExpr.Operand))
65866598 return false;
6587- result = !(bool) boolVal;
6599+ result = boolVal == TrueObject ? FalseObject : TrueObject ;
65886600 return true;
65896601 }
65906602
@@ -6595,42 +6607,45 @@ public static bool TryEvalPrimitive(out object result, Expression expr)
65956607 return false;
65966608
65976609 // Short circuit the evalution, because this is an actual logic of these logical operations
6598- if ((bool)leftVal)
6599- return nodeType == ExpressionType.OrElse
6600- || TryEvalPrimitive(out result, binaryExpr.Right);
6601- // left is false
6602- if (nodeType == ExpressionType.AndAlso)
6603- result = leftVal; // return the false result
6604- // otherwise for || evaluate the right result
6610+ if (leftVal == TrueObject & nodeType == ExpressionType.OrElse ||
6611+ leftVal == FalseObject & nodeType == ExpressionType.AndAlso)
6612+ {
6613+ result = leftVal;
6614+ return true;
6615+ }
66056616 return TryEvalPrimitive(out result, binaryExpr.Right);
66066617 }
66076618
66086619 if (IsComparison(nodeType))
66096620 {
66106621 var binaryExpr = (BinaryExpression)expr;
6611- if (!TryEvalPrimitive(out var left , binaryExpr.Left) ||
6612- !TryEvalPrimitive(out var right , binaryExpr.Right))
6622+ if (!TryEvalPrimitive(out var leftVal , binaryExpr.Left) ||
6623+ !TryEvalPrimitive(out var rightVal , binaryExpr.Right))
66136624 return false;
66146625
6615- if (nodeType == ExpressionType.Equal)
6616- result = left.Equals(right);
6617- else if (nodeType == ExpressionType.NotEqual)
6618- result = !left.Equals(right);
6626+ if (nodeType == ExpressionType.Equal | nodeType == ExpressionType.NotEqual)
6627+ {
6628+ var boolVal = leftVal.Equals(rightVal);
6629+ result = nodeType == ExpressionType.Equal
6630+ ? (boolVal ? TrueObject : FalseObject)
6631+ : (boolVal ? FalseObject : TrueObject);
6632+ }
66196633 else
66206634 {
66216635 // Assuming that the both sides are of the same type, we can use only the left one for comparison
6622- var cmp = left as IComparable;
6636+ var cmp = leftVal as IComparable;
66236637 if (cmp == null)
66246638 return false;
6625- var res = cmp.CompareTo(right );
6626- result = nodeType switch
6639+ var res = cmp.CompareTo(rightVal );
6640+ var boolVal = nodeType switch
66276641 {
66286642 ExpressionType.GreaterThan => res > 0,
66296643 ExpressionType.GreaterThanOrEqual => res >= 0,
66306644 ExpressionType.LessThan => res < 0,
66316645 ExpressionType.LessThanOrEqual => res <= 0,
6632- _ => null ,
6646+ _ => UnreachableCase<bool>() ,
66336647 };
6648+ result = boolVal ? TrueObject : FalseObject;
66346649 }
66356650 return true;
66366651 }
@@ -6655,14 +6670,16 @@ public static bool TryEvalPrimitive(out object result, Expression expr)
66556670 return result != null;
66566671 }
66576672
6658- result = false ;
6673+ result = null ;
66596674 return false;
66606675 }
66616676 }
66626677 }
66636678
6664- // Helpers targeting the performance. Extensions method names may be a bit funny (non standard),
6665- // in order to prevent conflicts with YOUR helpers with standard names
6679+ /// <summary>
6680+ /// Helpers targeting the performance. Extensions method names may be a bit funny (non standard),
6681+ /// in order to prevent conflicts with YOUR helpers with standard names
6682+ /// </summary>
66666683 public static class Tools
66676684 {
66686685 public static Expression AsExpr(this object obj) => obj as Expression ?? Constant(obj);
0 commit comments