Skip to content

Commit

Permalink
Merge pull request #39 from codingseb/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
codingseb authored Sep 24, 2019
2 parents 56ae71c + 7ef014e commit 0514161
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 43 deletions.
11 changes: 6 additions & 5 deletions CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,10 @@ public void TypeTesting(string expression, Type type)
[TestCase("new List<string>().GetType()", ExpectedResult = typeof(List<string>), Category = "new Keyword, Generics")]
[TestCase("new Dictionary<string,List<int>>().GetType()", ExpectedResult = typeof(Dictionary<string, List<int>>), Category = "new Keyword, Generics")]

// Linq and Types inference
[TestCase("new List<int>() { 1, 2, 3, 4 }.Where<int>(x => x > 2).Json", ExpectedResult = "[3,4]", Category = "Linq, Lambda, new Keyword, Generics")]
[TestCase("new List<int>() { 1, 2, 3, 4 }.Where(x => x > 2).Json", ExpectedResult = "[3,4]", Category = "Linq, Type inference, Lambda, new Keyword, Generics")]

#endregion

#region Complex expressions
Expand Down Expand Up @@ -1967,12 +1971,9 @@ public object EvaluateWithSpecificEvaluator(ExpressionEvaluator evaluator, strin
{
return evaluator.Evaluate(expression);
}
catch (Exception exception)
catch (Exception exception) when (inCaseOfException != null)
{
if (inCaseOfException == null)
throw;
else
return inCaseOfException(exception);
return inCaseOfException(exception);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<Product>CodingSeb.ExpressionEvaluator</Product>
<Description>A Simple Math and Pseudo C# Expression Evaluator in One C# File. Can also execute small C# like scripts</Description>
<Copyright>Copyright © Coding Seb 2017</Copyright>
<Version>1.4.1.0</Version>
<AssemblyVersion>1.4.1.0</AssemblyVersion>
<FileVersion>1.4.1.0</FileVersion>
<Version>1.4.2.0</Version>
<AssemblyVersion>1.4.2.0</AssemblyVersion>
<FileVersion>1.4.2.0</FileVersion>
<OutputPath>bin\$(Configuration)\</OutputPath>
<Authors>Coding Seb</Authors>
<PackageId>CodingSeb.ExpressionEvaluator</PackageId>
Expand All @@ -19,7 +19,11 @@
<PackageIconUrl>https://github.com/codingseb/ExpressionEvaluator/blob/master/Icon.png?raw=true</PackageIconUrl>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageReleaseNotes>Correction of bug :
* Added a righthandOperator 'Not' does not work</PackageReleaseNotes>
* In Lambda blocks did not keep options, namespaces and assemblies.

Improvement
* Easy and optimistic generic types inference
* Default assemblies (all loaded assemblies) Loaded statically (for better perfs)</PackageReleaseNotes>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
Expand Down
87 changes: 53 additions & 34 deletions CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/******************************************************************************************************
Title : ExpressionEvaluator (https://github.com/codingseb/ExpressionEvaluator)
Version : 1.4.1.0
Version : 1.4.2.0
(if last digit (the forth) is not a zero, the version is an intermediate version and can be unstable)
Author : Coding Seb
Expand Down Expand Up @@ -452,11 +452,18 @@ public static void ClearAllCaches()

#region Assemblies, Namespaces and types lists

private static IList<Assembly> staticAssemblies;
private IList<Assembly> assemblies;

/// <summary>
/// All assemblies needed to resolves Types
/// by default all Assemblies loaded in the current AppDomain
/// </summary>
public virtual IList<Assembly> Assemblies { get; set; } = new List<Assembly>();
public virtual IList<Assembly> Assemblies
{
get { return assemblies ?? (assemblies = staticAssemblies) ?? (assemblies = staticAssemblies = AppDomain.CurrentDomain.GetAssemblies().ToList()); }
set { assemblies = value; }
}

/// <summary>
/// All Namespaces Where to find types
Expand Down Expand Up @@ -848,8 +855,6 @@ public IDictionary<string, object> Variables
/// </summary>
public ExpressionEvaluator()
{
AssembliesInit();

DefaultDecimalSeparatorInit();

Init();
Expand All @@ -864,11 +869,6 @@ public ExpressionEvaluator(IDictionary<string, object> variables) : this()
Variables = variables;
}

protected virtual void AssembliesInit()
{
Assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
}

protected virtual void DefaultDecimalSeparatorInit()
{
numberRegexPattern = string.Format(numberRegexOrigPattern, @"\.", string.Empty);
Expand Down Expand Up @@ -1362,8 +1362,6 @@ void forAction(int index)
breakCalled = isBreak;
continueCalled = isContinue;

inScript = false;

if (isReturn || OptionOnNoReturnKeywordFoundInScriptAction == OptionOnNoReturnKeywordFoundInScriptAction.ReturnAutomaticallyLastEvaluatedExpression)
return lastResult;
else if (OptionOnNoReturnKeywordFoundInScriptAction == OptionOnNoReturnKeywordFoundInScriptAction.ReturnNull)
Expand Down Expand Up @@ -1419,7 +1417,7 @@ public object Evaluate(string expression)

for (int i = 0; i < expression.Length; i++)
{
if (!ParsingMethods.Any(m => m(expression, stack, ref i)))
if (!ParsingMethods.Any(parsingMethod => parsingMethod(expression, stack, ref i)))
{
string s = expression.Substring(i, 1);

Expand Down Expand Up @@ -1735,6 +1733,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
object obj = stack.Pop();
object keepObj = obj;
Type objType = null;
Type[] inferedGenericsTypes = obj.GetType().GenericTypeArguments;
ValueTypeNestingTrace valueTypeNestingTrace = null;

if (obj != null && TypesToBlock.Contains(obj.GetType()))
Expand Down Expand Up @@ -1775,7 +1774,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
throw new ExpressionEvaluatorSyntaxErrorException($"[{objType}] object has no Method named \"{varFuncName}\".");

// Standard Instance or public method find
MethodInfo methodInfo = GetRealMethod(ref objType, ref obj, varFuncName, flag, oArgs, genericsTypes);
MethodInfo methodInfo = GetRealMethod(ref objType, ref obj, varFuncName, flag, oArgs, genericsTypes, inferedGenericsTypes);

// if not found check if obj is an expandoObject or similar
if (obj is IDynamicMetaObjectProvider
Expand Down Expand Up @@ -1807,7 +1806,7 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
for (int e = 0; e < StaticTypesForExtensionsMethods.Count && methodInfo == null; e++)
{
Type type = StaticTypesForExtensionsMethods[e];
methodInfo = GetRealMethod(ref type, ref extentionObj, varFuncName, StaticBindingFlag, oArgs, genericsTypes);
methodInfo = GetRealMethod(ref type, ref extentionObj, varFuncName, StaticBindingFlag, oArgs, genericsTypes, inferedGenericsTypes);
isExtention = methodInfo != null;
}
}
Expand Down Expand Up @@ -2042,17 +2041,14 @@ protected virtual bool EvaluateVarOrFunc(string expression, Stack<object> stack,
{
dictionaryObject[varFuncName] = varValue;
}
else if (valueTypeNestingTrace != null)
{
valueTypeNestingTrace.Value = varValue;
valueTypeNestingTrace.AssignValue();
}
else
{
if (valueTypeNestingTrace != null)
{
valueTypeNestingTrace.Value = varValue;
valueTypeNestingTrace.AssignValue();
}
else
{
((dynamic)member).SetValue(obj, varValue);
}
((dynamic)member).SetValue(obj, varValue);
}
}
}
Expand Down Expand Up @@ -2756,21 +2752,33 @@ protected virtual bool GetLambdaExpression(string expression, Stack<object> stac

stack.Push(new InternalDelegate((object[] args) =>
{
Dictionary<string, object> vars = new Dictionary<string, object>(Variables);
var vars = new Dictionary<string, object>(variables);

for (int a = 0; a < argsNames.Count || a < args.Length; a++)
{
vars[argsNames[a]] = args[a];
}

ExpressionEvaluator expressionEvaluator = new ExpressionEvaluator(vars);
var savedVars = variables;
Variables = vars;

string lambdaBody = lambdaExpressionMatch.Groups["expression"].Value.Trim();

object result = null;

if (inScript && lambdaBody.StartsWith("{") && lambdaBody.EndsWith("}"))
return expressionEvaluator.ScriptEvaluate(lambdaBody.Substring(1, lambdaBody.Length - 2));
{
result = ScriptEvaluate(lambdaBody.Substring(1, lambdaBody.Length - 2));
inScript = true;
}
else
return expressionEvaluator.Evaluate(lambdaExpressionMatch.Groups["expression"].Value);
{
result = Evaluate(lambdaExpressionMatch.Groups["expression"].Value);
}

variables = savedVars;

return result;
}));

return true;
Expand All @@ -2781,7 +2789,7 @@ protected virtual bool GetLambdaExpression(string expression, Stack<object> stac
}
}

protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string func, BindingFlags flag, List<object> args, string genericsTypes = "")
protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string func, BindingFlags flag, List<object> args, string genericsTypes, Type[] inferedGenericsTypes)
{
MethodInfo methodInfo = null;
List<object> modifiedArgs = new List<object>(args);
Expand All @@ -2790,7 +2798,7 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
&& (func.StartsWith("Fluid", StringComparisonForCasing)
|| func.StartsWith("Fluent", StringComparisonForCasing)))
{
methodInfo = GetRealMethod(ref type, ref obj, func.Substring(func.StartsWith("Fluid", StringComparisonForCasing) ? 5 : 6), flag, modifiedArgs, genericsTypes);
methodInfo = GetRealMethod(ref type, ref obj, func.Substring(func.StartsWith("Fluid", StringComparisonForCasing) ? 5 : 6), flag, modifiedArgs, genericsTypes, inferedGenericsTypes);
if (methodInfo != null)
{
if (methodInfo.ReturnType == typeof(void))
Expand Down Expand Up @@ -2818,7 +2826,7 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string

if (methodInfo != null)
{
methodInfo = MakeConcreteMethodIfGeneric(methodInfo, genericsTypes);
methodInfo = MakeConcreteMethodIfGeneric(methodInfo, genericsTypes, inferedGenericsTypes);
}
else
{
Expand All @@ -2828,7 +2836,7 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string

for (int m = 0; m < methodInfos.Count && methodInfo == null; m++)
{
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m], genericsTypes);
methodInfos[m] = MakeConcreteMethodIfGeneric(methodInfos[m], genericsTypes, inferedGenericsTypes);

bool parametersCastOK = true;

Expand Down Expand Up @@ -2891,14 +2899,25 @@ protected virtual MethodInfo GetRealMethod(ref Type type, ref object obj, string
return methodInfo;
}

protected virtual MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo, string genericsTypes = "")
protected virtual MethodInfo MakeConcreteMethodIfGeneric(MethodInfo methodInfo, string genericsTypes, Type[] inferedGenericsTypes)
{
if (methodInfo.IsGenericMethod)
{
if (genericsTypes.Equals(string.Empty))
return methodInfo.MakeGenericMethod(Enumerable.Repeat(typeof(object), methodInfo.GetGenericArguments().Length).ToArray());
{
if(inferedGenericsTypes != null && inferedGenericsTypes.Length == methodInfo.GetGenericArguments().Length)
{
return methodInfo.MakeGenericMethod(inferedGenericsTypes);
}
else
{
return methodInfo.MakeGenericMethod(Enumerable.Repeat(typeof(object), methodInfo.GetGenericArguments().Length).ToArray());
}
}
else
{
return methodInfo.MakeGenericMethod(GetConcreteTypes(genericsTypes));
}
}

return methodInfo;
Expand Down Expand Up @@ -3135,7 +3154,7 @@ protected virtual Type GetTypeByFriendlyName(string typeName, string genericType

if (result == null)
{
result = Types.ToList().Find(type => type.Name.Equals(typeName, StringComparisonForCasing));
result = Types.ToList().Find(type => type.Name.Equals(typeName, StringComparisonForCasing) || type.FullName.StartsWith(typeName + ","));
}

for (int a = 0; a < Assemblies.Count && result == null; a++)
Expand Down

0 comments on commit 0514161

Please sign in to comment.