using System;
using System.Collections;
using System.Text.RegularExpressions;
using IwbZero.ExprFunctions;
using IwbZero.IwbBase;
using IwbZero.ToolCommon.StringModel;
namespace IwbZero.Expr
{
public class EvalExpr
{
// Fields
private static IdCollection _functions;
private static IdCollection _operators;
private static Regex _RegexDate = new Regex("[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}( [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}[ ]*(AM|PM)?)?", RegexOptions.IgnoreCase);
private static Regex _RegexDateAdd = new Regex("[0-9]+(d|m|y)", RegexOptions.IgnoreCase);
private static Regex _RegexDecimal = new Regex(@"-?[0-9]*\.[0-9]*", RegexOptions.IgnoreCase);
private static Regex _RegexInt = new Regex("-?[0-9]+", RegexOptions.IgnoreCase);
private static Regex _RegexVariable = new Regex("[_@a-zA-Z][_@a-zA-Z0-9.$]*", RegexOptions.IgnoreCase);
// Methods
public static string Evaluate(ExprObject exprObj)
{
string str = "";
if (exprObj.ChildCount == 0)
{
return exprObj.Expr;
}
EvaluateAllChildren(exprObj);
ExprObject expr = null;
for (int i = 0; i < exprObj.ChildCount; i++)
{
ExprObject child = exprObj.GetChild(i);
if (child.IsOperator)
{
var @operator = child.GetOperator();
ExprObject expr3 = exprObj.GetChild(i + 1);
if (expr3 != null)
{
expr = @operator.Calculate(expr, expr3);
i++;
}
}
else if (expr == null)
{
expr = child;
}
}
if (expr != null) str = expr.Expr;
return str;
}
public static string Evaluate(string exprStr)
{
string str = exprStr;
try
{
ExprObject exprObj = new ExprObject(exprStr, ExprElements.Expression);
if (Parse(exprObj, true))
{
str = Evaluate(exprObj);
}
}
catch (Exception)
{
// ignored
}
return str;
}
public static string Evaluate(string exprStr, Hashtable variableValueDic)
{
var exprStr2 = TransVariable(exprStr, variableValueDic);
var str = Evaluate(exprStr2);
return str;
}
#region Methods
public static ExprElements GetElementType(string expression)
{
ExprElements variable = ExprElements.Value;
expression = expression.Trim();
Match match = _RegexVariable.Match(expression);
if (((match.Index == 0)) && (match.Length == expression.Length))
{
variable = ExprElements.Variable;
}
return variable;
}
public static ExprTypes GetExprTypes(string expression)
{
ExprTypes date = ExprTypes.String;
expression = expression.Trim();
if ((expression.UAndT() == "TRUE") || (expression.UAndT() == "FALSE"))
{
return ExprTypes.Bool;
}
Match match = _RegexVariable.Match(expression);
if (((match.Index == 0)) && (match.Length == expression.Length))
{
return ExprTypes.Variable;
}
match = _RegexDecimal.Match(expression);
if (((match.Index == 0)) && (match.Length == expression.Length))
{
return ExprTypes.Decimal;
}
match = _RegexInt.Match(expression);
if (((match.Index == 0)) && (match.Length == expression.Length))
{
return ExprTypes.Integer;
}
match = _RegexDateAdd.Match(expression);
if (((match.Index == 0)) && (match.Length == expression.Length))
{
return ExprTypes.DateAdd;
}
match = _RegexDate.Match(expression);
if (((match.Index == 0)) && (match.Length == expression.Length))
{
date = ExprTypes.Date;
}
return date;
}
public static ExprTypes GetExprTypes(ExprObject exprObj)
{
ExprTypes @bool = ExprTypes.String;
if (exprObj.ElementType != ExprElements.String)
{
string str = exprObj.Expr.Trim();
if ((str.UAndT() == "TRUE") || (str.UAndT() == "FALSE"))
{
@bool = ExprTypes.Bool;
str = "";
}
if (str == "")
{
return @bool;
}
Match match = _RegexDecimal.Match(str);
if (((match.Index == 0)) && (match.Length == str.Length))
{
return ExprTypes.Decimal;
}
match = _RegexInt.Match(str);
if (((match.Index == 0)) && (match.Length == str.Length))
{
return ExprTypes.Integer;
}
match = _RegexDateAdd.Match(str);
if (((match.Index == 0)) && (match.Length == str.Length))
{
return ExprTypes.DateAdd;
}
match = _RegexDate.Match(str);
if (((match.Index == 0)) && (match.Length == str.Length))
{
@bool = ExprTypes.Date;
}
}
return @bool;
}
public static DateTime GetLastDayOfMonth(DateTime datetime)
{
int year = datetime.Year;
int month = datetime.Month + 1;
if (month > 12)
{
year++;
month = 1;
}
int day = 1;
return (new DateTime(year, month, day) - new TimeSpan(1, 0, 0, 0));
}
public static DateTime AddDays(DateTime datetime, string toAdd)
{
DateTime time = datetime;
toAdd = toAdd.UAndT();
int days = toAdd.ValI();
if (toAdd.IndexOf("D", StringComparison.Ordinal) >= 0)
{
return (time + new TimeSpan(days, 0, 0, 0));
}
int year;
int month = datetime.Month;
int day = datetime.Day;
if (toAdd.IndexOf("M", StringComparison.Ordinal) >= 0)
{
int num5 = ((datetime.Year * 12) + datetime.Month) + days;
year = num5 / 12;
month = num5 - (year * 12);
}
else
{
year = datetime.Year + days;
}
DateTime lastDayOfMonth = GetLastDayOfMonth(new DateTime(year, month, 1));
if (lastDayOfMonth.Day < day)
{
day = lastDayOfMonth.Day;
}
return new DateTime(year, month, day, datetime.Hour, datetime.Minute, datetime.Second, datetime.Millisecond);
}
public static string TransVariable(string exprStr, Hashtable variableValueDic)
{
string str = exprStr;
var variables = GetVariablesInString(exprStr);
if (variables != null)
{
foreach (string v in variables)
{
var value = GetVariableValue(v, variableValueDic);
if (value != null)
{
str = str.Replace(v, value);
}
}
}
return str;
}
public static string TransGlobalVariable(string exprStr, Hashtable variableValueDic)
{
string str = exprStr;
var variables = GetVariablesInString(exprStr);
if (variables != null)
{
foreach (string v in variables)
{
var value = GetVariableValue(v, variableValueDic);
str = str.Replace(v, value);
}
}
return str;
}
private static void EvaluateAllChildren(ExprObject exprObj)
{
if (exprObj != null)
{
for (int i = 0; i < exprObj.ChildCount; i++)
{
ExprObject child = exprObj.GetChild(i);
EvaluateAllChildren(child);
if (child != null)
{
string str = null;
switch (child.ElementType)
{
case ExprElements.Function:
str = EvaluateFunction(child);
break;
case ExprElements.Variable:
//str = TransSessionVariables(child.Expr);
break;
case ExprElements.Expression:
str = Evaluate(child);
break;
}
if (str != null)
{
child.Expr = str;
child.ElementType = ExprElements.Value;
}
}
}
}
}
public static string EvaluateFunction(ExprObject exprObj)
{
string str = "";
string functionId = exprObj.Expr.UAndT();
if (_functions == null)
{
_functions = new IdCollection();
}
IwbFunction function = (IwbFunction)_functions[functionId];
if (function == null)
{
function = IwbFunction.LoadById(functionId);
if (function != null)
{
_functions.Add(function);
}
}
if (function != null)
{
str = function.InvokeFunction(exprObj);
}
return str;
}
private static bool IsStartingParent(char pcChar)
{
return (pcChar == '(');
}
private static bool IsStartingQuote(char pcChar)
{
if (pcChar != '"')
{
return (pcChar == '\'');
}
return true;
}
private static int GetStaticString(string pcString, char pcQuote)
{
int length = pcString.Length;
for (int i = 0; i < length; i++)
{
char ch = pcString[i];
if (ch == pcQuote)
{
return i;
}
if ((ch == '\\') && (i < (length - 1)))
{
switch (pcString[i + 1])
{
case '"':
case '\'':
i++;
break;
}
}
}
return -1;
}
private static int GetClosingParenthesis(string pcString)
{
int num = -1;
int length = pcString.Length;
int num3 = 0;
for (int i = 0; i < length; i++)
{
char pcQuote = pcString[i];
if (((pcQuote == '"') || (pcQuote == '\'')) && (i < (length - 1)))
{
int staticString = GetStaticString(pcString.Substring(i + 1), pcQuote);
if (staticString >= 0)
{
i += staticString + 1;
}
}
if (pcQuote == '(')
{
num3++;
}
else if (pcQuote == ')')
{
if (num3 == 0)
{
num = i;
}
else
{
num3--;
}
}
}
return num;
}
#endregion
#region 变量赋值
public static ArrayList GetVariablesInString(string pcString)
{
var arr1 = GetStringVariables(pcString) ?? new ArrayList();
var arr2 = GetStringVariables(pcString, IwbVariableType.Global) ?? new ArrayList();
arr1.AddRange(arr2);
return arr1;
}
public static ArrayList GetStringVariables(string pcString, string variableHeader = IwbVariableType.Local)
{
int index;
ArrayList poArrayList = new ArrayList();
for (int i = pcString.IndexOf(variableHeader, StringComparison.Ordinal); i >= 0; i = pcString.IndexOf(variableHeader, index, StringComparison.Ordinal))
{
string pcName = variableHeader;
for (index = i + variableHeader.Length; index < pcString.Length; index++)
{
char ch = pcString[index];
if ((((ch < 'a') || (ch > 'z')) && ((ch < 'A') || (ch > 'Z'))) && (((ch < '0') || (ch > '9')) && (ch != '_')))
{
break;
}
pcName = pcName + ch;
}
poArrayList.InsertIdentifier(pcName);
}
return poArrayList;
}
public static string GetVariableValue(string pcVariable, Hashtable variableValueDic)
{
var key = pcVariable.UAndT();
foreach (DictionaryEntry dic in variableValueDic)
{
if (dic.Key.UAndT() == key)
{
return ((IwbRtVariable)dic.Value).GetStringValue();
}
}
return null;
}
#endregion 变量赋值
#region 表达式转换为ExprObject
public static bool Parse(ExprObject exprObj, bool plThrowException)
{
bool flag = true;
try
{
Parse(exprObj);
}
catch (Exception)
{
if (plThrowException)
{
throw;
}
flag = false;
}
return flag;
}
private static void Parse(ExprObject exprObj, string pcExpression = null)
{
pcExpression = (pcExpression ?? exprObj.Expr)?.Trim() ?? "";
switch (GetExprTypes(pcExpression))
{
case ExprTypes.Integer:
case ExprTypes.Decimal:
case ExprTypes.Date:
case ExprTypes.Bool:
exprObj.AddChild(new ExprObject(pcExpression, ExprElements.Value));
return;
case ExprTypes.Variable:
exprObj.AddChild(new ExprObject(pcExpression, ExprElements.Variable));
return;
}
ExprObject exprObject = null;
string str = "";
while (pcExpression != "")
{
var poNode = GetNextElement(ref pcExpression);
if (poNode != null)
{
if (((poNode.ElementType != ExprElements.String) && (poNode.Expr == "-")) && ((exprObject == null) || exprObject.IsOperator))
{
str = "-";
}
else
{
poNode.Expr = str + poNode.Expr;
exprObj.AddChild(poNode);
str = "";
}
exprObject = poNode;
}
}
CollapseSyntaxTree(exprObj);
}
private static ExprObject GetNextElement(ref string pcString)
{
ExprObject exprObj = null;
string pcExpr = "";
bool flag = false;
int length = pcString.Length;
for (int i = 0; i < length; i++)
{
char pcChar = pcString[i];
string str2 = "";
if (i < (length - 1))
{
str2 = pcString.Substring(i + 1);
}
int closingParenthesis;
if (IsStartingParent(pcChar))
{
closingParenthesis = GetClosingParenthesis(str2);
if (closingParenthesis < 0)
{
throw new Exception("No ending parenthesis.");
}
if (pcExpr != "")
{
string pcExpression = pcString.Substring(i + 1, closingParenthesis);
exprObj = new ExprObject(pcExpr, ExprElements.Function);
if (pcExpression != "")
{
Parse(exprObj, pcExpression);
CollapseFunctionCall(exprObj);
}
}
else
{
exprObj = new ExprObject(pcString.Substring(i + 1, closingParenthesis), ExprElements.Expression);
Parse(exprObj, exprObj.Expr);
}
i = (i + closingParenthesis) + 2;
flag = true;
}
else if (IsStartingQuote(pcChar))
{
if (pcExpr != "")
{
throw new Exception("Operand required.");
}
closingParenthesis = GetStaticString(str2, pcChar);
if (closingParenthesis < 0)
{
throw new Exception("No ending quote.");
}
exprObj = new ExprObject(pcString.Substring(i + 1, closingParenthesis), ExprElements.String);
i = (i + closingParenthesis) + 2;
flag = true;
}
else
{
ExprOperator @operator = GetOperator(pcString.Substring(i));
bool flag2 = true;
if (i == (length - 1))
{
pcString = "";
}
if (((@operator != null) && (pcExpr != "")) && (GetExprTypes(pcExpr) == ExprTypes.String))
{
@operator = null;
}
if (@operator != null)
{
if (pcExpr == "")
{
exprObj = new ExprObject(@operator.Id, ExprElements.Operator);
i += @operator.Symbol.Length;
}
flag = true;
flag2 = false;
}
else if ((pcExpr == "") && (pcChar == ' '))
{
flag2 = false;
}
if (flag2)
{
pcExpr = pcExpr + pcChar.ToString();
}
if ((pcExpr != "") && ((@operator != null) || (i == (length - 1))))
{
ExprElements elementType = GetElementType(pcExpr);
exprObj = new ExprObject(pcExpr, elementType);
flag = true;
}
}
if (flag)
{
if (i < pcString.Length)
{
pcString = pcString.Substring(i);
return exprObj;
}
pcString = "";
return exprObj;
}
}
return null;
}
private static ExprOperator GetOperator(string pcString)
{
foreach (ExprOperator operator2 in Operators)
{
if (operator2.IsSymbolMatched(pcString))
{
return operator2;
}
}
return null;
}
///
/// 构建表达式树
///
///
private static void CollapseSyntaxTree(ExprObject poExprObject)
{
int level = -1;
int piStart = -1;
int piLevel = 100;
for (int i = 0; i < poExprObject.ChildCount; i++)
{
ExprOperator @operator = poExprObject.GetChild(i).GetOperator();
if (i == (poExprObject.ChildCount - 1))
{
@operator = new ExprOperator("", "", piLevel, 0);
i++;
}
if (@operator != null)
{
if (piLevel > @operator.Level)
{
piLevel = @operator.Level;
}
if (@operator.Level > level)
{
piStart = i - @operator.LeftOperands;
}
else if (@operator.Level < level)
{
CollapseSyntaxTree(poExprObject, piStart, i - 1);
CollapseSyntaxTree(poExprObject);
}
level = @operator.Level;
}
}
}
///
/// 构建表达式树
///
///
///
///
private static void CollapseSyntaxTree(ExprObject poExprObject, int piStart, int piEnd)
{
if (piEnd > piStart)
{
ExprObject poNode = new ExprObject("", ExprElements.Expression);
for (int i = piStart; i <= piEnd; i++)
{
ExprObject child = poExprObject.GetChild(piStart);
poExprObject.RemoveChildAt(piStart);
poNode.AddChild(child);
poNode.Expr = poNode.Expr + " " + child.Expr;
}
poExprObject.InsertChildAt(poNode, piStart);
}
}
private static void CollapseFunctionCall(ExprObject poExprObject)
{
if (poExprObject.ChildCount > 1)
{
bool flag = false;
foreach (ExprObject expr in poExprObject.ChildNodes)
{
if (expr.IsOperator && (expr.Expr.Trim() == ","))
{
flag = true;
break;
}
}
if (!flag)
{
ExprObject poNode = new ExprObject(poExprObject.Expr, ExprElements.Expression);
foreach (ExprObject expr3 in poExprObject.ChildNodes)
{
poNode.AddChild(expr3);
}
poExprObject.ChildNodes.Clear();
poExprObject.AddChild(poNode);
}
}
}
public static IdCollection Operators =>
_operators ?? (_operators = new IdCollection
{
new ExprOperator("+", "+", 4, 1),
new ExprOperator("-", "-", 4, 1),
new ExprOperator(",", ",", 0, 0),
new ExprOperator("and", " and ", 1, 1),
new ExprOperator("&&", " && ", 1, 1),
new ExprOperator("or", " or ", 1, 1),
new ExprOperator("||", " || ", 1, 1),
new ExprOperator("not", "not ", 2, 0),
new ExprOperator("!", "! ", 2, 0),
new ExprOperator("!=", "!=", 3, 1),
new ExprOperator("=", "=", 3, 1),
new ExprOperator(">=", ">=", 3, 1),
new ExprOperator(">", ">", 3, 1),
new ExprOperator("<=", "<=", 3, 1),
new ExprOperator("<", "<", 3, 1),
new ExprOperator("like", " like ", 3, 1),
new ExprOperator("*", "*", 5, 1),
new ExprOperator("/", "/", 5, 1),
new ExprOperator("%", "%", 5, 1)
});
#endregion 表达式转换为ExprObject
}
}