Skip to content

Commit 7e78bd1

Browse files
author
Sébastien Geiser
committed
PreEvaluate events OK
1 parent 0c64d4d commit 7e78bd1

File tree

1 file changed

+141
-39
lines changed

1 file changed

+141
-39
lines changed

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 141 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -838,14 +838,28 @@ public IDictionary<string, object> Variables
838838
}
839839

840840
/// <summary>
841-
/// Is Fired when no internal variable is found for a variable name.
841+
/// Is Fired before a variable, field or property resolution.
842+
/// Allow to define a variable and the corresponding value on the fly.
843+
/// Allow also to cancel the evaluation of this variable (consider it does'nt exists)
844+
/// </summary>
845+
public event EventHandler<VariablePreEvaluationEventArg> PreEvaluateVariable;
846+
847+
/// <summary>
848+
/// Is Fired before a function or method resolution.
849+
/// Allow to define a function or method and the corresponding value on the fly.
850+
/// Allow also to cancel the evaluation of this function (consider it does'nt exists)
851+
/// </summary>
852+
public event EventHandler<FunctionPreEvaluationEventArg> PreEvaluateFunction;
853+
854+
/// <summary>
855+
/// Is Fired if no variable, field or property were found
842856
/// Allow to define a variable and the corresponding value on the fly.
843857
/// </summary>
844858
public event EventHandler<VariableEvaluationEventArg> EvaluateVariable;
845859

846860
/// <summary>
847-
/// Is Fired when no internal function is found for a variable name.
848-
/// Allow to define a function and the corresponding value on the fly.
861+
/// Is Fired if no function or method when were found.
862+
/// Allow to define a function or method and the corresponding value on the fly.
849863
/// </summary>
850864
public event EventHandler<FunctionEvaluationEventArg> EvaluateFunction;
851865

@@ -1766,13 +1780,17 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
17661780
}
17671781
else
17681782
{
1769-
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, Evaluate, funcArgs, this, obj, genericsTypes, GetConcreteTypes);
1783+
FunctionPreEvaluationEventArg functionPreEvaluationEventArg = new FunctionPreEvaluationEventArg(varFuncName, Evaluate, funcArgs, this, obj, genericsTypes, GetConcreteTypes);
17701784

1771-
EvaluateFunction?.Invoke(this, functionEvaluationEventArg);
1785+
PreEvaluateFunction?.Invoke(this, functionPreEvaluationEventArg);
17721786

1773-
if (functionEvaluationEventArg.FunctionReturnedValue)
1787+
if (functionPreEvaluationEventArg.CancelEvaluation)
17741788
{
1775-
stack.Push(functionEvaluationEventArg.Value);
1789+
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType}] object has no Method named \"{varFuncName}\".");
1790+
}
1791+
else if (functionPreEvaluationEventArg.FunctionReturnedValue)
1792+
{
1793+
stack.Push(functionPreEvaluationEventArg.Value);
17761794
}
17771795
else
17781796
{
@@ -1802,22 +1820,26 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
18021820
}
18031821
else
18041822
{
1823+
bool isExtention = false;
1824+
18051825
// if not found try to Find extension methods.
18061826
if (methodInfo == null && obj != null)
18071827
{
18081828
oArgs.Insert(0, obj);
18091829
objType = obj.GetType();
1810-
obj = null;
1830+
//obj = null;
1831+
object extentionObj = null;
18111832
for (int e = 0; e < StaticTypesForExtensionsMethods.Count && methodInfo == null; e++)
18121833
{
18131834
Type type = StaticTypesForExtensionsMethods[e];
1814-
methodInfo = GetRealMethod(ref type, ref obj, varFuncName, StaticBindingFlag, oArgs, genericsTypes);
1835+
methodInfo = GetRealMethod(ref type, ref extentionObj, varFuncName, StaticBindingFlag, oArgs, genericsTypes);
1836+
isExtention = methodInfo != null;
18151837
}
18161838
}
18171839

18181840
if (methodInfo != null)
18191841
{
1820-
stack.Push(methodInfo.Invoke(obj, oArgs.ToArray()));
1842+
stack.Push(methodInfo.Invoke(isExtention ? null : obj, oArgs.ToArray()));
18211843
}
18221844
else if (objType.GetProperty(varFuncName, StaticBindingFlag) is PropertyInfo staticPropertyInfo
18231845
&& (staticPropertyInfo.PropertyType.IsSubclassOf(typeof(Delegate)) || staticPropertyInfo.PropertyType == typeof(Delegate)))
@@ -1826,7 +1848,16 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
18261848
}
18271849
else
18281850
{
1829-
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType}] object has no Method named \"{varFuncName}\".");
1851+
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, Evaluate, funcArgs, this, obj, genericsTypes, GetConcreteTypes);
1852+
1853+
EvaluateFunction?.Invoke(this, functionEvaluationEventArg);
1854+
1855+
if (functionEvaluationEventArg.FunctionReturnedValue)
1856+
{
1857+
stack.Push(functionEvaluationEventArg.Value);
1858+
}
1859+
else
1860+
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType}] object has no Method named \"{varFuncName}\".");
18301861
}
18311862
}
18321863
}
@@ -1846,31 +1877,46 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
18461877
}
18471878
}
18481879
}
1849-
else if (DefaultFunctions(varFuncName, funcArgs, out object funcResult))
1850-
{
1851-
stack.Push(funcResult);
1852-
}
1853-
else if (Variables.TryGetValue(varFuncName, out object o) && o is InternalDelegate lambdaExpression)
1854-
{
1855-
stack.Push(lambdaExpression.Invoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
1856-
}
1857-
else if (Variables.TryGetValue(varFuncName, out o) && o is Delegate delegateVar)
1858-
{
1859-
stack.Push(delegateVar.DynamicInvoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
1860-
}
18611880
else
18621881
{
1863-
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, Evaluate, funcArgs, this, genericTypes: genericsTypes, evaluateGenericTypes: GetConcreteTypes);
1882+
FunctionPreEvaluationEventArg functionPreEvaluationEventArg = new FunctionPreEvaluationEventArg(varFuncName, Evaluate, funcArgs, this, null, genericsTypes, GetConcreteTypes);
18641883

1865-
EvaluateFunction?.Invoke(this, functionEvaluationEventArg);
1884+
PreEvaluateFunction?.Invoke(this, functionPreEvaluationEventArg);
18661885

1867-
if (functionEvaluationEventArg.FunctionReturnedValue)
1886+
if (functionPreEvaluationEventArg.CancelEvaluation)
1887+
{
1888+
throw new ExpressionEvaluatorSyntaxErrorException($"Function [{varFuncName}] unknown in expression : [{expr.Replace("\r", "").Replace("\n", "")}]");
1889+
}
1890+
else if (functionPreEvaluationEventArg.FunctionReturnedValue)
1891+
{
1892+
stack.Push(functionPreEvaluationEventArg.Value);
1893+
}
1894+
else if (DefaultFunctions(varFuncName, funcArgs, out object funcResult))
1895+
{
1896+
stack.Push(funcResult);
1897+
}
1898+
else if (Variables.TryGetValue(varFuncName, out object o) && o is InternalDelegate lambdaExpression)
1899+
{
1900+
stack.Push(lambdaExpression.Invoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
1901+
}
1902+
else if (Variables.TryGetValue(varFuncName, out o) && o is Delegate delegateVar)
18681903
{
1869-
stack.Push(functionEvaluationEventArg.Value);
1904+
stack.Push(delegateVar.DynamicInvoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
18701905
}
18711906
else
18721907
{
1873-
throw new ExpressionEvaluatorSyntaxErrorException($"Function [{varFuncName}] unknown in expression : [{expr.Replace("\r", "").Replace("\n", "")}]");
1908+
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, Evaluate, funcArgs, this, genericTypes: genericsTypes, evaluateGenericTypes: GetConcreteTypes);
1909+
1910+
EvaluateFunction?.Invoke(this, functionEvaluationEventArg);
1911+
1912+
if (functionEvaluationEventArg.FunctionReturnedValue)
1913+
{
1914+
stack.Push(functionEvaluationEventArg.Value);
1915+
}
1916+
else
1917+
{
1918+
throw new ExpressionEvaluatorSyntaxErrorException($"Function [{varFuncName}] unknown in expression : [{expr.Replace("\r", "").Replace("\n", "")}]");
1919+
}
18741920
}
18751921
}
18761922
}
@@ -1971,13 +2017,17 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
19712017
}
19722018
else
19732019
{
1974-
VariableEvaluationEventArg variableEvaluationEventArg = new VariableEvaluationEventArg(varFuncName, this, obj, genericsTypes, GetConcreteTypes);
2020+
VariablePreEvaluationEventArg variablePreEvaluationEventArg = new VariablePreEvaluationEventArg(varFuncName, this, obj, genericsTypes, GetConcreteTypes);
19752021

1976-
EvaluateVariable?.Invoke(this, variableEvaluationEventArg);
2022+
PreEvaluateVariable?.Invoke(this, variablePreEvaluationEventArg);
19772023

1978-
if (variableEvaluationEventArg.HasValue)
2024+
if(variablePreEvaluationEventArg.CancelEvaluation)
19792025
{
1980-
stack.Push(variableEvaluationEventArg.Value);
2026+
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType}] object has no public Property or Member named \"{varFuncName}\".", new Exception("Variable evaluation canceled"));
2027+
}
2028+
else if (variablePreEvaluationEventArg.HasValue)
2029+
{
2030+
stack.Push(variablePreEvaluationEventArg.Value);
19812031
}
19822032
else
19832033
{
@@ -2003,11 +2053,24 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
20032053
if (isDynamic)
20042054
{
20052055
if (!varFuncMatch.Groups["assignationOperator"].Success || varFuncMatch.Groups["assignmentPrefix"].Success)
2006-
varValue = dictionaryObject[varFuncName];
2056+
varValue = dictionaryObject.ContainsKey(varFuncName) ? dictionaryObject[varFuncName] : null;
20072057
else
20082058
pushVarValue = false;
20092059
}
2010-
else
2060+
2061+
if (member == null && pushVarValue)
2062+
{
2063+
VariableEvaluationEventArg variableEvaluationEventArg = new VariableEvaluationEventArg(varFuncName, this, obj, genericsTypes, GetConcreteTypes);
2064+
2065+
EvaluateVariable?.Invoke(this, variableEvaluationEventArg);
2066+
2067+
if (variableEvaluationEventArg.HasValue)
2068+
{
2069+
varValue = variableEvaluationEventArg.Value;
2070+
}
2071+
}
2072+
2073+
if (varValue == null && pushVarValue)
20112074
{
20122075
varValue = ((dynamic)member).GetValue(obj);
20132076

@@ -2111,13 +2174,17 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
21112174
}
21122175
else
21132176
{
2114-
VariableEvaluationEventArg variableEvaluationEventArg = new VariableEvaluationEventArg(varFuncName, this, genericTypes: genericsTypes, evaluateGenericTypes: GetConcreteTypes);
2177+
VariablePreEvaluationEventArg variablePreEvaluationEventArg = new VariablePreEvaluationEventArg(varFuncName, this, genericTypes: genericsTypes, evaluateGenericTypes: GetConcreteTypes);
21152178

2116-
EvaluateVariable?.Invoke(this, variableEvaluationEventArg);
2179+
PreEvaluateVariable?.Invoke(this, variablePreEvaluationEventArg);
21172180

2118-
if (variableEvaluationEventArg.HasValue)
2181+
if (variablePreEvaluationEventArg.CancelEvaluation)
2182+
{
2183+
throw new ExpressionEvaluatorSyntaxErrorException($"Variable [{varFuncName}] unknown in expression : [{expr}]");
2184+
}
2185+
else if (variablePreEvaluationEventArg.HasValue)
21192186
{
2120-
stack.Push(variableEvaluationEventArg.Value);
2187+
stack.Push(variablePreEvaluationEventArg.Value);
21212188
}
21222189
else
21232190
{
@@ -2162,7 +2229,18 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
21622229
}
21632230
else
21642231
{
2165-
throw new ExpressionEvaluatorSyntaxErrorException($"Variable [{varFuncName}] unknown in expression : [{expr}]");
2232+
VariableEvaluationEventArg variableEvaluationEventArg = new VariableEvaluationEventArg(varFuncName, this, genericTypes: genericsTypes, evaluateGenericTypes: GetConcreteTypes);
2233+
2234+
EvaluateVariable?.Invoke(this, variableEvaluationEventArg);
2235+
2236+
if (variableEvaluationEventArg.HasValue)
2237+
{
2238+
stack.Push(variableEvaluationEventArg.Value);
2239+
}
2240+
else
2241+
{
2242+
throw new ExpressionEvaluatorSyntaxErrorException($"Variable [{varFuncName}] unknown in expression : [{expr}]");
2243+
}
21662244
}
21672245
}
21682246
}
@@ -3393,6 +3471,18 @@ public Type[] EvaluateGenericTypes()
33933471
}
33943472
}
33953473

3474+
public class VariablePreEvaluationEventArg : VariableEvaluationEventArg
3475+
{
3476+
public VariablePreEvaluationEventArg(string name, ExpressionEvaluator evaluator = null, object onInstance = null, string genericTypes = null, Func<string, Type[]> evaluateGenericTypes = null)
3477+
: base(name, evaluator, onInstance, genericTypes, evaluateGenericTypes)
3478+
{ }
3479+
3480+
/// <summary>
3481+
/// If set to true cancel the evaluation of the current variable, field or property and throw an exception it does not exists
3482+
/// </summary>
3483+
public bool CancelEvaluation { get; set; } = false;
3484+
}
3485+
33963486
public partial class FunctionEvaluationEventArg : EventArgs
33973487
{
33983488
private readonly Func<string, object> evaluateFunc = null;
@@ -3503,5 +3593,17 @@ public Type[] EvaluateGenericTypes()
35033593
}
35043594
}
35053595

3596+
public class FunctionPreEvaluationEventArg : FunctionEvaluationEventArg
3597+
{
3598+
public FunctionPreEvaluationEventArg(string name, Func<string, object> evaluateFunc, List<string> args = null, ExpressionEvaluator evaluator = null, object onInstance = null, string genericTypes = null, Func<string, Type[]> evaluateGenericTypes = null)
3599+
: base(name, evaluateFunc, args, evaluator, onInstance, genericTypes, evaluateGenericTypes)
3600+
{ }
3601+
3602+
/// <summary>
3603+
/// If set to true cancel the evaluation of the current function or method and throw an exception that the function does not exists
3604+
/// </summary>
3605+
public bool CancelEvaluation { get; set; } = false;
3606+
}
3607+
35063608
#endregion
35073609
}

0 commit comments

Comments
 (0)