Skip to content

Commit 59421bd

Browse files
committed
Lambda assignable to variable for later call.
1 parent 51f6c97 commit 59421bd

File tree

8 files changed

+106
-15
lines changed

8 files changed

+106
-15
lines changed

CodingSeb.ExpressionEvaluator.Tests/CodingSeb.ExpressionEvaluator.Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@
125125
<ItemGroup>
126126
<None Include="Resources\Script0015.txt" />
127127
</ItemGroup>
128+
<ItemGroup>
129+
<None Include="Resources\Script0016.txt" />
130+
</ItemGroup>
131+
<ItemGroup>
132+
<None Include="Resources\Script0017.txt" />
133+
</ItemGroup>
128134
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
129135
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
130136
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

CodingSeb.ExpressionEvaluator.Tests/ExpressionEvaluatorScriptEvaluateTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,29 @@ public static IEnumerable<TestCaseData> TestCasesForScriptEvaluateTests
935935

936936
#endregion
937937

938+
#region Lambda assignation and call
939+
940+
yield return new TestCaseData(Resources.Script0016, null, null, null)
941+
.SetCategory("Script")
942+
.SetCategory("lambda")
943+
.SetCategory("lambda call")
944+
.SetCategory("lambda assignation")
945+
.SetCategory("return")
946+
.SetCategory("variable assignation")
947+
.Returns(7);
948+
949+
yield return new TestCaseData(Resources.Script0017, null, null, null)
950+
.SetCategory("Script")
951+
.SetCategory("lambda")
952+
.SetCategory("lambda call")
953+
.SetCategory("lambda call imbrication")
954+
.SetCategory("lambda assignation")
955+
.SetCategory("return")
956+
.SetCategory("variable assignation")
957+
.Returns(6);
958+
959+
#endregion
960+
938961
#region More complex script
939962

940963
yield return new TestCaseData(Resources.Script0007, null, null, null)

CodingSeb.ExpressionEvaluator.Tests/Resources.Designer.cs

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CodingSeb.ExpressionEvaluator.Tests/Resources.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,10 @@
163163
<data name="Script0015" type="System.Resources.ResXFileRef, System.Windows.Forms">
164164
<value>resources\script0015.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
165165
</data>
166+
<data name="Script0016" type="System.Resources.ResXFileRef, System.Windows.Forms">
167+
<value>resources\script0016.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
168+
</data>
169+
<data name="Script0017" type="System.Resources.ResXFileRef, System.Windows.Forms">
170+
<value>resources\script0017.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
171+
</data>
166172
</root>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* Script0016 */
2+
Add = (x, y) => x + y;
3+
4+
return Add(3, 4);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* Script0017 */
2+
3+
FirstFunc = x =>
4+
{
5+
y = 3;
6+
return x + y;
7+
};
8+
9+
SecondFunc = (x, y) => FirstFunc(x) - y;
10+
11+
return SecondFunc(5, 2);

CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -752,7 +752,7 @@ object ScriptExpressionEvaluate(ref int index)
752752
return ManageJumpStatementsOrExpressionEval(expression);
753753
}
754754

755-
bool TryParseStringAndParenthis(ref int index)
755+
bool TryParseStringAndParenthisAndCurlyBrackets(ref int index)
756756
{
757757
bool parsed = true;
758758
Match internalStringMatch = stringBeginningRegex.Match(script.Substring(index));
@@ -767,6 +767,11 @@ bool TryParseStringAndParenthis(ref int index)
767767
index++;
768768
GetExpressionsBetweenParenthis(script, ref index, false);
769769
}
770+
else if(script[index] == '{')
771+
{
772+
index++;
773+
GetScriptBetweenCurlyBrackets(script, ref index);
774+
}
770775
else
771776
parsed = false;
772777

@@ -826,7 +831,7 @@ void ExecuteIfList()
826831

827832
while (i < script.Length && continueExpressionParsing)
828833
{
829-
if (TryParseStringAndParenthis(ref i)) { }
834+
if (TryParseStringAndParenthisAndCurlyBrackets(ref i)) { }
830835
else if (script.Length - i > 2 && script.Substring(i, 3).Equals("';'"))
831836
{
832837
i += 2;
@@ -967,7 +972,7 @@ void forAction(int index)
967972
{
968973
ExecuteIfList();
969974

970-
if (TryParseStringAndParenthis(ref i)){}
975+
if (TryParseStringAndParenthisAndCurlyBrackets(ref i)){}
971976
else if (script.Length - i > 2 && script.Substring(i, 3).Equals("';'"))
972977
{
973978
i += 2;
@@ -1302,6 +1307,10 @@ private bool EvaluateVarOrFunc(string expr, string restOfExpression, Stack<objec
13021307
{
13031308
stack.Push(funcResult);
13041309
}
1310+
else if(Variables.TryGetValue(varFuncName, out object o) && o is InternalDelegate lambdaExpression)
1311+
{
1312+
stack.Push(lambdaExpression.Invoke(funcArgs.ConvertAll(e => Evaluate(e)).ToArray()));
1313+
}
13051314
else
13061315
{
13071316
FunctionEvaluationEventArg functionEvaluationEventArg = new FunctionEvaluationEventArg(varFuncName, Evaluate, funcArgs);
@@ -1606,11 +1615,11 @@ private bool EvaluateParenthis(string expr, string s, Stack<object> stack, ref i
16061615
{
16071616
i++;
16081617

1609-
if (stack.Count > 0 && stack.Peek() is lambdaExpressionDelegate)
1618+
if (stack.Count > 0 && stack.Peek() is InternalDelegate)
16101619
{
16111620
List<string> expressionsInParenthis = GetExpressionsBetweenParenthis(expr, ref i, true);
16121621

1613-
lambdaExpressionDelegate lambdaDelegate = stack.Pop() as lambdaExpressionDelegate;
1622+
InternalDelegate lambdaDelegate = stack.Pop() as InternalDelegate;
16141623

16151624
stack.Push(lambdaDelegate(expressionsInParenthis.ConvertAll(arg => Evaluate(arg)).ToArray()));
16161625
}
@@ -1964,7 +1973,7 @@ public string RemoveComments(string scriptWithComments)
19641973

19651974
#region Utils methods for parsing and interpretation
19661975

1967-
private delegate dynamic lambdaExpressionDelegate(params dynamic[] args);
1976+
private delegate dynamic InternalDelegate(params dynamic[] args);
19681977
private bool GetLambdaExpression(string expr, Stack<object> stack)
19691978
{
19701979
Match lambdaExpressionMatch = lambdaExpressionRegex.Match(expr);
@@ -1976,7 +1985,7 @@ private bool GetLambdaExpression(string expr, Stack<object> stack)
19761985
.Cast<Match>().ToList()
19771986
.ConvertAll(argMatch => argMatch.Value);
19781987

1979-
stack.Push(new lambdaExpressionDelegate((object[] args) =>
1988+
stack.Push(new InternalDelegate((object[] args) =>
19801989
{
19811990
Dictionary<string, object> vars = new Dictionary<string, object>(Variables);
19821991

@@ -2062,25 +2071,25 @@ private MethodInfo GetRealMethod(ref Type type, ref object obj, string func, Bin
20622071
string paramTypeName = parameterType.Name;
20632072

20642073
if (paramTypeName.StartsWith("Predicate")
2065-
&& modifiedArgs[a] is lambdaExpressionDelegate)
2074+
&& modifiedArgs[a] is InternalDelegate)
20662075
{
2067-
lambdaExpressionDelegate led = modifiedArgs[a] as lambdaExpressionDelegate;
2076+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
20682077
modifiedArgs[a] = new Predicate<object>(o => (bool)(led(new object[] { o })));
20692078
}
20702079
else if (paramTypeName.StartsWith("Func")
2071-
&& modifiedArgs[a] is lambdaExpressionDelegate)
2080+
&& modifiedArgs[a] is InternalDelegate)
20722081
{
2073-
lambdaExpressionDelegate led = modifiedArgs[a] as lambdaExpressionDelegate;
2082+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
20742083
DelegateEncaps de = new DelegateEncaps(led);
20752084
MethodInfo encapsMethod = de.GetType()
20762085
.GetMethod($"Func{parameterType.GetGenericArguments().Length - 1}")
20772086
.MakeGenericMethod(parameterType.GetGenericArguments());
20782087
modifiedArgs[a] = Delegate.CreateDelegate(parameterType, de, encapsMethod);
20792088
}
20802089
else if (paramTypeName.StartsWith("Converter")
2081-
&& modifiedArgs[a] is lambdaExpressionDelegate)
2090+
&& modifiedArgs[a] is InternalDelegate)
20822091
{
2083-
lambdaExpressionDelegate led = modifiedArgs[a] as lambdaExpressionDelegate;
2092+
InternalDelegate led = modifiedArgs[a] as InternalDelegate;
20842093
modifiedArgs[a] = new Converter<object, object>(o => (led(new object[] { o })));
20852094
}
20862095
else
@@ -2420,12 +2429,12 @@ private class ClassOrTypeName
24202429

24212430
private class DelegateEncaps
24222431
{
2423-
private readonly lambdaExpressionDelegate lambda;
2432+
private readonly InternalDelegate lambda;
24242433

24252434
private MethodInfo methodInfo;
24262435
private readonly object target;
24272436

2428-
public DelegateEncaps(lambdaExpressionDelegate lambda)
2437+
public DelegateEncaps(InternalDelegate lambda)
24292438
{
24302439
this.lambda = lambda;
24312440
}

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ else
265265
}
266266
---------------- Result --------------------
267267
4
268+
269+
--------------------------------------------
270+
Add = (x, y) => x + y;
271+
272+
return Add(3, 4);
273+
---------------- Result --------------------
274+
7
275+
268276
```
269277

270278
To see more scripts examples see scripts uses for tests in sub directories [CodingSeb.ExpressionEvaluator.Tests/Resources](./CodingSeb.ExpressionEvaluator.Tests/Resources)

0 commit comments

Comments
 (0)