|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Microsoft.CSharp.RuntimeBinder.Semantics
{
internal static class EXPRExtensions
{
public static Expr Map(this Expr expr, Func<Expr, Expr> f)
{
Debug.Assert(f != null);
if (expr == null)
{
return f(null);
}
Expr result = null;
Expr tail = null;
foreach (Expr item in expr.ToEnumerable())
{
Expr mappedItem = f(item);
ExprFactory.AppendItemToList(mappedItem, ref result, ref tail);
}
return result;
}
public static IEnumerable<Expr> ToEnumerable(this Expr expr)
{
Expr exprCur = expr;
while (exprCur != null)
{
if (exprCur is ExprList list)
{
yield return list.OptionalElement;
exprCur = list.OptionalNextListNode;
}
else
{
yield return exprCur;
yield break;
}
}
}
[Conditional("DEBUG")]
public static void AssertIsBin(this Expr expr)
{
Debug.Assert(expr?.Kind >= ExpressionKind.TypeLimit && 0 != (expr.Flags & EXPRFLAG.EXF_BINOP));
}
public static bool isLvalue(this Expr expr)
{
return (expr == null) ? false : 0 != (expr.Flags & EXPRFLAG.EXF_LVALUE);
}
public static bool isChecked(this Expr expr)
{
return (expr == null) ? false : 0 != (expr.Flags & EXPRFLAG.EXF_CHECKOVERFLOW);
}
public static bool isNull(this Expr expr)
=> expr is ExprConstant constant && expr.Type.FundamentalType == FUNDTYPE.FT_REF && constant.Val.IsNullRef;
public static bool IsZero(this Expr expr) => expr is ExprConstant constant && constant.IsZero;
private static Expr GetSeqVal(this Expr expr)
{
// Scan through EK_SEQUENCE and EK_SEQREV exprs to get the real value.
if (expr == null)
{
return null;
}
Expr exprVal = expr;
while (exprVal.Kind == ExpressionKind.Sequence)
{
exprVal = ((ExprBinOp)exprVal).OptionalRightChild;
}
return exprVal;
}
/***************************************************************************************************
Determine whether this expr has a constant value (EK_CONSTANT or EK_ZEROINIT), possibly with
side effects (via EK_SEQUENCE or EK_SEQREV). Returns NULL if not, or the constant expr if so.
The returned Expr will always be an EK_CONSTANT or EK_ZEROINIT.
***************************************************************************************************/
public static Expr GetConst(this Expr expr)
{
Expr exprVal = expr.GetSeqVal();
switch (exprVal?.Kind)
{
case ExpressionKind.Constant:
case ExpressionKind.ZeroInit:
return exprVal;
}
return null;
}
}
}
|