Skip to content

Commit 6b212bb

Browse files
Merge pull request #26 from delegateas/dev
Release
2 parents d900c15 + c774d68 commit 6b212bb

13 files changed

Lines changed: 258 additions & 47 deletions

File tree

.github/workflows/build.yml

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,43 @@ jobs:
1111
test:
1212
runs-on: windows-latest
1313
name: Testing
14+
strategy:
15+
matrix:
16+
dotnet: [ 'netcoreapp3.1', 'net5.0' ]
1417
steps:
1518
- name: Checkout code base
1619
uses: actions/checkout@v2
1720

1821
- name: Run tests
19-
run: dotnet test --verbosity normal
22+
run: dotnet test --verbosity normal -f ${{ matrix.dotnet }}
2023

2124
build:
2225
runs-on: windows-latest
2326
name: Building
27+
strategy:
28+
matrix:
29+
dotnet: ['netcoreapp3.1', 'net5.0']
2430
steps:
2531
- name: Checkout code base
2632
uses: actions/checkout@v2
2733

28-
- name: Setup MSBuild
29-
uses: microsoft/setup-msbuild@v1
34+
- uses: actions/setup-dotnet@v1
35+
with:
36+
dotnet-version: '5.0.x'
37+
38+
- name: Cleaning
39+
run: dotnet clean
3040

3141
- name: Restore NuGet packages
32-
run: nuget restore ExpressionEngine.sln
42+
run: dotnet restore ExpressionEngine.sln
3343

3444
- name: Build solution
35-
run: msbuild /p:OutputPath=../build /p:Configuration=Release /p:RestorePackages=false
45+
run: dotnet build -o ../build/${{ matrix.dotnet }} -c Release --no-restore -m:1 -f ${{ matrix.dotnet }}
3646

3747
- name: Archive build to artifacts
3848
uses: actions/upload-artifact@v2
3949
with:
4050
name: build
4151
path: |
42-
build/ExpressionEngine.dll
43-
retention-days: 5
52+
build/${{ matrix.dotnet }}/*
53+
retention-days: 5

.github/workflows/release.yml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@ on:
88

99
jobs:
1010
test:
11-
name: Testing
1211
runs-on: windows-latest
12+
name: Testing
13+
strategy:
14+
matrix:
15+
dotnet: [ 'netcoreapp3.1', 'net5.0' ]
1316
steps:
14-
- name: Checkout repo
17+
- name: Checkout code base
1518
uses: actions/checkout@v2
1619

1720
- name: Run tests
18-
run: dotnet test --verbosity normal
21+
run: dotnet test --verbosity normal -f ${{ matrix.dotnet }}
22+
1923

2024
release:
2125
name: Releasing
@@ -26,6 +30,10 @@ jobs:
2630
- name: Checkout repo
2731
uses: actions/checkout@v2
2832

33+
- uses: actions/setup-dotnet@v1
34+
with:
35+
dotnet-version: '5.0.x'
36+
2937
- name: Setup Node.js
3038
uses: actions/setup-node@v1
3139
with:
@@ -51,17 +59,17 @@ jobs:
5159
- name: Print release verison
5260
run: echo ${env:RELEASE_VERSION}
5361

54-
- name: Setup MSBuild
55-
uses: microsoft/setup-msbuild@v1
62+
- name: Cleaning
63+
run: dotnet clean
5664

5765
- name: Restore NuGet packages
58-
run: nuget restore ExpressionEngine.sln
66+
run: dotnet restore ExpressionEngine.sln
5967

6068
- name: Package Parser
61-
run: msbuild /t:pack /p:PackageVersion=${env:RELEASE_VERSION} /p:OutputPath=..\\artifacts
69+
run: dotnet pack -c Release -p:PackageVersion=${env:RELEASE_VERSION} -o ./artifacts
6270
if: ${{ env.RELEASE_VERSION }}
6371

64-
- name: Release to GitHub
72+
- name: Release to GitHub and NuGet
6573
working-directory: .\\.github\\workflows
6674
env:
6775
CI_NUGET_API_KEY: ${{ secrets.NUGETAPIKEY }}

ExpressionEngine/ExpressionEngine.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFramework>netcoreapp3.1</TargetFramework>
4+
<TargetFrameworks>netcoreapp3.1;net5.0</TargetFrameworks>
55

66
<PackageId>Delegate.ExpressionEngine</PackageId>
77
<Authors>Delegate A/S,thygesteffensen</Authors>

ExpressionEngine/ExpressionGrammar.cs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public ExpressionGrammar(IEnumerable<IFunction> functions)
1717

1818
#region BasicAuxParsers
1919

20+
Parser<IRule> boolean = Parse.String("true").Select(b => new ConstantRule(new ValueContainer(true)))
21+
.Or(Parse.String("false").Select(b => new ConstantRule(new ValueContainer(false))));
22+
2023
Parser<IRule> integer =
2124
Parse.Digit.AtLeastOnce().Text()
2225
.Select(
@@ -26,10 +29,6 @@ public ExpressionGrammar(IEnumerable<IFunction> functions)
2629
Parser<string> simpleString =
2730
Parse.AnyChar.Except(Parse.Char('@')).AtLeastOnce().Text();
2831

29-
Parser<ConstantRule> simpleStringRule =
30-
Parse.AnyChar.Except(Parse.Char('@')).Except(Parse.Char('(').Except(Parse.Char(')'))).AtLeastOnce()
31-
.Text().Select(x => new ConstantRule(new ValueContainer(x)));
32-
3332
Parser<char> escapedCharacters =
3433
from c in
3534
Parse.String("''").Select(n => '\'')
@@ -49,27 +48,34 @@ from content in Parse.CharExcept('\'').Or(escapedCharacters).Many().Text()
4948

5049
#endregion
5150

52-
5351
var lBracket = Parse.Char('[');
5452
var rBracket = Parse.Char(']');
5553
var lParenthesis = Parse.Char('(');
5654
var rParenthesis = Parse.Char(')');
5755

5856
Parser<bool> nullConditional = Parse.Char('?').Optional().Select(nC => !nC.IsEmpty);
5957

60-
Parser<IRule> indices =
58+
Parser<IRule> bracketIndices =
6159
from nll in nullConditional
6260
from index in _method.Or(stringLiteral).Or(integer).Contained(lBracket, rBracket)
6361
select new IndexRule(index, nll);
62+
63+
Parser<IRule> dotIndices =
64+
from nll in nullConditional
65+
from dot in Parse.Char('.')
66+
from index in Parse.AnyChar.Except(
67+
lBracket
68+
.Or(rBracket)
69+
.Or(lParenthesis)
70+
.Or(rParenthesis)
71+
.Or(Parse.Char('@'))
72+
).Many().Text()
73+
select new IndexRule(new StringLiteralRule(new ValueContainer(index)), nll);
6474

6575
Parser<IRule> argument =
66-
from arg in Parse.Ref(() => _method.Or(stringLiteral).Or(integer))
76+
from arg in Parse.Ref(() => _method.Or(stringLiteral).Or(integer).Or(boolean))
6777
select arg;
6878

69-
Parser<IRule[]> emptyArgument =
70-
from empty in Parse.String("()")
71-
select new IRule[0];
72-
7379
Parser<IOption<IEnumerable<IRule>>> arguments =
7480
from args in argument.Token().DelimitedBy(Parse.Char(',')).Optional()
7581
select args;
@@ -86,9 +92,8 @@ from args in arguments.Contained(lParenthesis, rParenthesis)
8692
_method =
8793
Parse.Ref(() =>
8894
from func in function
89-
from indexes in indices.Many()
95+
from indexes in bracketIndices.Or(dotIndices).Many()
9096
select (IRule) new AccessValueRule(func, indexes));
91-
// .Or(simpleStringRule);
9297

9398
Parser<ValueContainer> enclosedExpression =
9499
_method.Contained(
@@ -100,8 +105,7 @@ from indexes in indices.Many()
100105
from at in Parse.Char('@')
101106
from method in _method
102107
select method.Evaluate();
103-
104-
108+
105109
Parser<string> allowedString =
106110
from t in simpleString.Or(allowedCharacters).Many()
107111
select string.Concat(t);

ExpressionEngine/FlowRunnerDependencyExtension.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
using ExpressionEngine;
2-
using ExpressionEngine.Functions.Base;
1+
using ExpressionEngine.Functions.Base;
32
using ExpressionEngine.Functions.Implementations.CollectionFunctions;
43
using ExpressionEngine.Functions.Implementations.ConversionFunctions;
54
using ExpressionEngine.Functions.Implementations.LogicalComparisonFunctions;
65
using ExpressionEngine.Functions.Implementations.StringFunctions;
76
using Microsoft.Extensions.DependencyInjection;
8-
using Parser.ExpressionParser.Functions.Implementations.StringFunctions;
97

10-
namespace Parser
8+
namespace ExpressionEngine
119
{
1210
public static class FlowRunnerDependencyExtension
1311
{
1412
public static void AddExpressionEngine(this IServiceCollection services)
1513
{
16-
services.AddScoped<IExpressionEngine, ExpressionEngine.ExpressionEngine>();
17-
services.AddScoped<ExpressionGrammar>();
14+
services.AddScoped<IExpressionEngine, ExpressionEngine>();
15+
services.AddSingleton<ExpressionGrammar>();
1816

1917
AddStringFunctions(services);
2018
AddCollectionFunction(services);

ExpressionEngine/Functions/Implementations/StringFunctions/GuidFunction.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
using System;
22
using System.Linq;
3-
using ExpressionEngine;
43
using ExpressionEngine.Functions.Base;
54
using ExpressionEngine.Functions.CustomException;
6-
using ExpressionEngine.Functions.Implementations.StringFunctions;
75

8-
namespace Parser.ExpressionParser.Functions.Implementations.StringFunctions
6+
namespace ExpressionEngine.Functions.Implementations.StringFunctions
97
{
108
public class GuidFunction : Function
119
{

ExpressionEngine/Functions/Implementations/StringFunctions/LastIndexOfFunction.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@ public override ValueContainer ExecuteFunction(params ValueContainer[] parameter
1717
throw new ArgumentError("Too few arguments");
1818
}
1919

20+
if (string.IsNullOrEmpty(AuxiliaryMethods.VcIsString(parameters[1])))
21+
{
22+
/* LastIndexOf does not return the correct value!
23+
* "".LastIndexOf("") should return -1, since "" is empty
24+
* and "abc".LastIndexOf("") returns `2` and `3` for dotnetcore3.1 and net5.0 respectively,
25+
* which does not make sense.
26+
* Therefore, if the search string is empty, we return the length of the string being searched,
27+
* because it corresponds to the behavior of PowerAutomate.
28+
*
29+
* -1 because the returned index is zero-based
30+
*/
31+
if (string.IsNullOrEmpty(AuxiliaryMethods.VcIsString(parameters[0])))
32+
{
33+
return new ValueContainer(0);
34+
}
35+
return new ValueContainer(AuxiliaryMethods.VcIsString(parameters[0]).Length-1);
36+
}
37+
2038
return new ValueContainer(AuxiliaryMethods.VcIsString(parameters[0])
2139
.LastIndexOf(AuxiliaryMethods.VcIsString(parameters[1]), StringComparison.OrdinalIgnoreCase));
2240
}

ExpressionEngine/ReadMe.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Parser
2+
3+
This is the readme for the parser project which is a part of the FlowRunner.
4+
5+
6+
## BNF
7+
8+
This is the BNF, [Backus-Nuar form](https://da.wikipedia.org/wiki/Backus-Naur_form), of the language used in Power Automate / Logic Apps expressions.
9+
Their JSON definition can be found [here](https://docs.microsoft.com/en-us/azure/logic-apps/workflow-definition-language-functions-reference) and [here](https://docs.microsoft.com/en-us/azure/logic-apps/logic-apps-workflow-definition-language#functions) and the [json](https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json).
10+
11+
### Examples
12+
`@triggerOutputs()`
13+
14+
`@toLower('TEXT')`
15+
16+
`@toLower(toUpper('text'))`
17+
18+
`@variables('var')`
19+
20+
`@variables('array')[0]`
21+
22+
`@variables('object')['user']`
23+
24+
`@variables('object')[toLower('USER')]`
25+
26+
`@{toLower('USER')}@{toUpper('user')}`
27+
28+
`Name: @{variables('object')[toLower('USER')]}`
29+
30+
31+
```xml
32+
<input> ::= <expression> | <joinedString> | <atPrefixedString>
33+
<atPrefixedString> ::= <string> <!-- NO ( ) -->
34+
35+
<joinedString> ::= *(*<allowedString> *<enclosedExpression>)
36+
<allowedString> ::= *([A-Za-z] | [0-9] | [\_]) <!-- Add the correct characters -->
37+
38+
<expression> ::= "@" <method>
39+
<enclosedExpression> ::= "@{" <method> "}"
40+
41+
<method> ::= <function> *<operators>
42+
43+
<function> ::= <string> "(" [ <arguments> ] ")"
44+
<arguments> ::= <argument> *("," <argument>)
45+
<argument> ::= <method> | <string>
46+
47+
<operators> ::= *( [ <nullconditional> ] "[" <index> "]") | <dot>
48+
<nullconditional> ::= "?"
49+
<index> ::= <int> | <string> | <method>
50+
<dot> ::= "." <string>
51+
```
52+
53+
`string` contains a valid string including characters according to Azure Workflow definition language.
54+
55+
56+
## Special expressions
57+
Some expressions the user can define itself, since it is idempotent and does not use the engine state.
58+
59+
Some expression should not be user dependent, such as
60+
61+
* compose
62+
* outputs
63+
* triggerOutputs
64+
* variables
65+
66+
These are all expression which interact with data stored in the state.
67+
68+
69+
70+
Eventuelt skriv om hvordan det var sværet bare at gå igang, men efter du læste en artikel og lavede en BNF var det nemt. Dette var måske også fordi du vidste hvordan Sprache virkede og hvad der skete under moteren og aritklen gav dig en dybere forståelse af hvad man kan! :D
71+
72+
73+
## Extra observations
74+
### Null conditional
75+
We'll handle this, of course, and I've created a flow to figure out how to handle this :D
76+
77+
As seen in the currect version of owner grammer, we'll accept null conditional after a function or after a indexer. If the part before the null conditional is null, we'll stop executing and return??
78+
79+
The flow used to test is called: `null condtional` and is located in DG Lab 6; [link to flow](https://emea.flow.microsoft.com/manage/environments/934e6690-2c92-4a37-ab81-31be17f7724a/solutions/86491904-39dd-ea11-a813-000d3ab11761/flows/d40eaddf-55a2-4b98-87e3-c21c4fcfc57a).
80+
81+
Error (with out null condition):
82+
> InvalidTemplate. Unable to process template language expressions in action 'Respond_to_a_PowerApp_or_flow_-_Without_null_conditional' inputs at line '1' and column '2357': 'The template language expression 'variables('NullVariable')['first']' cannot be evaluated because property 'first' cannot be selected. Please see https://aka.ms/logicexpressions for usage details.'.
83+
84+
With null condtion, the answer is null and read as an empty string in some cases?

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,4 @@ The `main` branch is the release branch which will release a production NuGet pa
5353
The `dev` branch is the development branch and will release a development NuGet package with the determined version number.
5454

5555
Therefore, start by making a pull-request against `dev` which will trigger a pre-release and later on we can make a production release.
56+

Test/Expression/StringFunctionTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using ExpressionEngine;
22
using ExpressionEngine.Functions.Implementations.StringFunctions;
33
using NUnit.Framework;
4-
using Parser.ExpressionParser.Functions.Implementations.StringFunctions;
54

65
namespace Test.Expression
76
{

0 commit comments

Comments
 (0)