Skip to content

Commit 8ab18b3

Browse files
Parse expressions from activity implementations
1 parent 7d795e5 commit 8ab18b3

File tree

7 files changed

+1766
-18
lines changed

7 files changed

+1766
-18
lines changed

src/Test/TestCases.Workflows/ExpressionCompilerResults/CS_ExpressionCompilerResult

Lines changed: 755 additions & 0 deletions
Large diffs are not rendered by default.

src/Test/TestCases.Workflows/ExpressionCompilerResults/VB_ExpressionCompilerResult

Lines changed: 778 additions & 0 deletions
Large diffs are not rendered by default.

src/Test/TestCases.Workflows/ExpressionTests.cs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Activities.Expressions;
77
using System.Activities.Statements;
88
using System.Activities.Validation;
9+
using System.Activities.XamlIntegration;
910
using System.Collections.Generic;
1011
using System.Linq;
1112
using System.Threading.Tasks;
@@ -566,4 +567,98 @@ public void VB_IsCaseInsensitive()
566567
var valid = ActivityValidationServices.Validate(seq, _useValidator);
567568
valid.Errors.ShouldBeEmpty();
568569
}
570+
571+
[Fact]
572+
public void VB_CompileAndInvokeActivityWithValueInImplementation()
573+
{
574+
foreach (var activity in GetActivitiesWithVBValues())
575+
{
576+
var root = new DynamicActivity { Implementation = () => activity };
577+
ActivityXamlServices.Compile(root, new() { CompileExpressions = true });
578+
WorkflowInvoker.Invoke(root);
579+
}
580+
}
581+
582+
[Fact]
583+
public void CS_CompileAndInvokeActivityWithValueInImplementation()
584+
{
585+
foreach (var activity in GetActivitiesWithCSValues())
586+
{
587+
var root = new DynamicActivity { Implementation = () => activity };
588+
ActivityXamlServices.Compile(root, new() { CompileExpressions = true });
589+
WorkflowInvoker.Invoke(root);
590+
}
591+
}
592+
593+
private static IEnumerable<Activity> GetActivitiesWithVBValues()
594+
{
595+
yield return new ActivityWithVBValue("(1 + 2).ToString");
596+
yield return new ActivityWithMultipleNestedVBValues();
597+
}
598+
599+
private static IEnumerable<Activity> GetActivitiesWithCSValues()
600+
{
601+
yield return new ActivityWithCSValue("(1 + 2).ToString()");
602+
yield return new ActivityWithMultipleNestedCSValues();
603+
}
604+
605+
private class ActivityWithVBValue : Activity
606+
{
607+
public ActivityWithVBValue(string expressionText)
608+
{
609+
Implementation = () => new WriteLine() { Text = new InArgument<string>(new VisualBasicValue<string>(expressionText)) };
610+
}
611+
}
612+
613+
private class ActivityWithCSValue : Activity
614+
{
615+
public ActivityWithCSValue(string expressionText)
616+
{
617+
Implementation = () => new WriteLine() { Text = new InArgument<string>(new CSharpValue<string>(expressionText)) };
618+
}
619+
}
620+
621+
private class ActivityWithMultipleNestedVBValues : Activity
622+
{
623+
public ActivityWithMultipleNestedVBValues()
624+
{
625+
Implementation = () => new Sequence()
626+
{
627+
Activities =
628+
{
629+
new ActivityWithVBValue("99.ToString"),
630+
new Sequence()
631+
{
632+
Activities =
633+
{
634+
new ActivityWithVBValue("(1 + 2).ToString"),
635+
}
636+
},
637+
new ActivityWithVBValue("{1, 2, 3}.ToString")
638+
}
639+
};
640+
}
641+
}
642+
643+
private class ActivityWithMultipleNestedCSValues : Activity
644+
{
645+
public ActivityWithMultipleNestedCSValues()
646+
{
647+
Implementation = () => new Sequence()
648+
{
649+
Activities =
650+
{
651+
new ActivityWithCSValue("99.ToString()"),
652+
new Sequence()
653+
{
654+
Activities =
655+
{
656+
new ActivityWithCSValue("(1 + 2).ToString()"),
657+
}
658+
},
659+
new ActivityWithCSValue("(new int[] {1, 2, 3}).ToString()")
660+
}
661+
};
662+
}
663+
}
569664
}

src/Test/TestCases.Workflows/TestCases.Workflows.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
<ItemGroup>
77
<Page Remove="**\*.xaml" />
88
<EmbeddedResource Include="TestXamls\*.xaml" />
9+
<Page Remove="ExpressionCompilerResults\CS_ExpressionCompilerResult" />
10+
<Page Remove="ExpressionCompilerResults\VB_ExpressionCompilerResult" />
11+
<EmbeddedResource Include="ExpressionCompilerResults\CS_ExpressionCompilerResult" />
12+
<EmbeddedResource Include="ExpressionCompilerResults\VB_ExpressionCompilerResult" />
913
</ItemGroup>
1014
<ItemGroup>
1115
<PackageReference Include="AgileObjects.ReadableExpressions" Version="3.1.0" />
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
using Xunit;
2+
using System;
3+
using System.IO;
4+
using System.Activities;
5+
using Microsoft.CSharp.Activities;
6+
using System.Activities.Statements;
7+
using Microsoft.VisualBasic.Activities;
8+
using System.Activities.XamlIntegration;
9+
10+
namespace TestCases.Workflows
11+
{
12+
public class TextExpressionCompilerTests
13+
{
14+
[Theory]
15+
[InlineData("VB")]
16+
[InlineData("C#")]
17+
public void EnsureCompilationParity(string expressionLanguage)
18+
{
19+
var actualSourceWriter = new StringWriter();
20+
var currentAsm = typeof(TextExpressionCompilerTests).Assembly;
21+
22+
TextExpressionCompilerSettings settings = new()
23+
{
24+
RootNamespace = null,
25+
ForImplementation = true,
26+
ActivityName = "TestClass",
27+
AlwaysGenerateSource = true,
28+
Language = expressionLanguage,
29+
GenerateAsPartialClass = false,
30+
ActivityNamespace = "TestNamespace",
31+
Activity = new DynamicActivity { Implementation = () => GetActivity(expressionLanguage) },
32+
};
33+
34+
new TextExpressionCompiler(settings).GenerateSource(actualSourceWriter);
35+
var expectedStream = currentAsm.GetManifestResourceStream($"{currentAsm.GetName().Name}.ExpressionCompilerResults.{GetExpectedResourceName(expressionLanguage)}");
36+
37+
var actualSource = actualSourceWriter.ToString();
38+
var expectedSource = new StreamReader(expectedStream).ReadToEnd();
39+
Assert.Equal(expectedSource, actualSource);
40+
}
41+
42+
private static string GetExpectedResourceName(string expressionLanguage)
43+
=> expressionLanguage switch
44+
{
45+
"C#" => "CS_ExpressionCompilerResult",
46+
"VB" => "VB_ExpressionCompilerResult",
47+
_ => throw new NotImplementedException()
48+
};
49+
50+
private static Activity GetActivity(string expressionLanguage)
51+
=> expressionLanguage switch
52+
{
53+
"C#" => GetActivity(v1 => new CSharpValue<bool>(v1), v2 => new CSharpValue<string>(v2), v3 => new CSharpReference<string>(v3)),
54+
"VB" => GetActivity(v1 => new VisualBasicValue<bool>(v1), v2 => new VisualBasicValue<string>(v2), v3 => new VisualBasicReference<string>(v3)),
55+
_ => throw new NotImplementedException()
56+
};
57+
58+
private static Activity GetActivity<T1, T2, T3>(Func<string, T1> boolValueFactory, Func<string, T2> strValueFactory, Func<string, T3> referenceFactory)
59+
where T1 : TextExpressionBase<bool>
60+
where T2 : TextExpressionBase<string>
61+
where T3 : TextExpressionBase<Location<string>>
62+
=> new Sequence()
63+
{
64+
Variables =
65+
{
66+
new Variable<string>("var1")
67+
},
68+
Activities =
69+
{
70+
new WriteLine() { Text = new InArgument<string>(strValueFactory("var1")) },
71+
new Assign() { To = new OutArgument<string>(referenceFactory("var1")), Value = new InArgument<string>("test1") },
72+
new If() {
73+
Condition = new InArgument<bool>(boolValueFactory("var1 != \"test\"")),
74+
Then = new Sequence()
75+
{
76+
Variables =
77+
{
78+
new Variable<string>("var2")
79+
},
80+
Activities =
81+
{
82+
new Assign() { To = new OutArgument<string>(referenceFactory("var2")), Value = new InArgument<string>("test2") },
83+
new WriteLine() { Text = new InArgument<string>(strValueFactory("var2")) },
84+
}
85+
},
86+
Else = new Sequence()
87+
{
88+
Activities =
89+
{
90+
new Sequence()
91+
{
92+
Activities =
93+
{
94+
new WriteLine() { Text = new InArgument<string>(strValueFactory("test3")) },
95+
}
96+
}
97+
}
98+
}
99+
}
100+
}
101+
};
102+
}
103+
}

src/UiPath.Workflow.Runtime/Expressions/CompiledExpressionInvoker.cs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,16 +169,14 @@ private bool TryGetCurrentCompiledExpressionRoot(ActivityContext activityContext
169169
{
170170
ActivityInstance current = activityContext.CurrentInstance;
171171

172-
while (current != null && current.Activity != _metadataRoot)
172+
while (current != null)
173173
{
174-
175-
if (TryGetCompiledExpressionRoot(current.Activity, true, out ICompiledExpressionRoot currentCompiledExpressionRoot))
174+
if (current.Activity != _metadataRoot
175+
&& TryGetCompiledExpressionRoot(current.Activity, true, out ICompiledExpressionRoot currentCompiledExpressionRoot)
176+
&& CanExecuteExpression(currentCompiledExpressionRoot, out expressionId))
176177
{
177-
if (CanExecuteExpression(currentCompiledExpressionRoot, out expressionId))
178-
{
179-
compiledExpressionRoot = currentCompiledExpressionRoot;
180-
return true;
181-
}
178+
compiledExpressionRoot = currentCompiledExpressionRoot;
179+
return true;
182180
}
183181
current = current.Parent;
184182
}

src/UiPath.Workflow.Runtime/XamlIntegration/CompiledExpressionActivityVisitor.cs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ protected virtual void Visit(Activity activity, out bool exit)
5656
{
5757
return;
5858
}
59+
60+
VisitImplementationChildren(activity, out exit);
61+
if (exit)
62+
{
63+
return;
64+
}
5965
}
6066

6167
protected virtual void VisitRoot(Activity activity, out bool exit)
@@ -205,6 +211,22 @@ protected virtual void VisitImportedChildren(Activity activity, out bool exit)
205211
exit = false;
206212
}
207213

214+
protected virtual void VisitImplementationChildren(Activity activity, out bool exit)
215+
{
216+
if (activity.ImplementationChildren is not null)
217+
{
218+
for (int i = 0; i < activity.ImplementationChildren.Count; i++)
219+
{
220+
VisitCore(activity.ImplementationChildren[i], out exit);
221+
if (exit)
222+
{
223+
return;
224+
}
225+
}
226+
}
227+
exit = false;
228+
}
229+
208230
protected virtual void VisitDelegates(Activity activity, out bool exit)
209231
{
210232
if (activity.Delegates != null)
@@ -370,18 +392,11 @@ private void VisitRootImplementation(Activity activity, out bool exit)
370392
return;
371393
}
372394

373-
if (activity.ImplementationChildren != null)
395+
VisitImplementationChildren(activity, out exit);
396+
if (exit)
374397
{
375-
for (int i = 0; i < activity.ImplementationChildren.Count; i++)
376-
{
377-
VisitCore(activity.ImplementationChildren[i], out exit);
378-
if (exit)
379-
{
380-
return;
381-
}
382-
}
398+
return;
383399
}
384-
exit = false;
385400
}
386401

387402
private void VisitPublicActivities(Activity activity, out bool exit)

0 commit comments

Comments
 (0)