Skip to content

Commit fe7e60e

Browse files
committed
Enables the expression language to have only single chars operations
1 parent f3756a8 commit fe7e60e

File tree

6 files changed

+95
-37
lines changed

6 files changed

+95
-37
lines changed

Diff for: Jace.Tests/Jace.Tests.csproj

+20-30
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.props')" />
34
<PropertyGroup>
45
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
56
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
@@ -17,6 +18,8 @@
1718
<IsCodedUITest>False</IsCodedUITest>
1819
<TestProjectType>UnitTest</TestProjectType>
1920
<TargetFrameworkProfile />
21+
<NuGetPackageImportStamp>
22+
</NuGetPackageImportStamp>
2023
</PropertyGroup>
2124
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
2225
<DebugSymbols>true</DebugSymbols>
@@ -38,23 +41,17 @@
3841
<Prefer32Bit>false</Prefer32Bit>
3942
</PropertyGroup>
4043
<ItemGroup>
44+
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
45+
<HintPath>..\packages\MSTest.TestFramework.2.0.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
46+
</Reference>
47+
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
48+
<HintPath>..\packages\MSTest.TestFramework.2.0.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
49+
</Reference>
4150
<Reference Include="System" />
4251
<Reference Include="System.Core">
4352
<RequiredTargetFramework>3.5</RequiredTargetFramework>
4453
</Reference>
4554
</ItemGroup>
46-
<Choose>
47-
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
48-
<ItemGroup>
49-
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
50-
</ItemGroup>
51-
</When>
52-
<Otherwise>
53-
<ItemGroup>
54-
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
55-
</ItemGroup>
56-
</Otherwise>
57-
</Choose>
5855
<ItemGroup>
5956
<Compile Include="AssertExtensions.cs" />
6057
<Compile Include="AstBuilderTests.cs" />
@@ -75,26 +72,19 @@
7572
<Name>Jace</Name>
7673
</ProjectReference>
7774
</ItemGroup>
78-
<Choose>
79-
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
80-
<ItemGroup>
81-
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
82-
<Private>False</Private>
83-
</Reference>
84-
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
85-
<Private>False</Private>
86-
</Reference>
87-
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
88-
<Private>False</Private>
89-
</Reference>
90-
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
91-
<Private>False</Private>
92-
</Reference>
93-
</ItemGroup>
94-
</When>
95-
</Choose>
75+
<ItemGroup>
76+
<None Include="packages.config" />
77+
</ItemGroup>
9678
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
9779
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
80+
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
81+
<PropertyGroup>
82+
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
83+
</PropertyGroup>
84+
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.props'))" />
85+
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.targets'))" />
86+
</Target>
87+
<Import Project="..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.0.0\build\net45\MSTest.TestAdapter.targets')" />
9888
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
9989
Other similar extension points exist, see Microsoft.Common.targets.
10090
<Target Name="BeforeBuild">

Diff for: Jace.Tests/TokenReaderTests.cs

+23
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,29 @@ public void TestTokenReader1()
3939
Assert.AreEqual(2, tokens[2].Length);
4040
}
4141

42+
[TestMethod]
43+
[DataRow("42==31", '=', false)]
44+
[DataRow("42=31", '=', true)]
45+
[DataRow("42!=31", '≠', false)]
46+
[DataRow("42!31", '≠', true)]
47+
[DataRow("42||31", '|', false)]
48+
[DataRow("42|31", '|', true)]
49+
[DataRow("42&&31", '&', false)]
50+
[DataRow("42&31", '&', true)]
51+
public void TestTokenReader_Equals(string expression, object token, bool enableSingleCharacterOperations)
52+
{
53+
TokenReader reader = new TokenReader(new JaceOptions() { EnableSingleCharacterOperations = enableSingleCharacterOperations });
54+
List<Token> tokens = reader.Read(expression);
55+
56+
Assert.AreEqual(3, tokens.Count);
57+
58+
Assert.AreEqual(42, tokens[0].Value);
59+
60+
Assert.AreEqual(token, tokens[1].Value);
61+
62+
Assert.AreEqual(31, tokens[2].Value);
63+
}
64+
4265
[TestMethod]
4366
public void TestTokenReader2()
4467
{

Diff for: Jace.Tests/packages.config

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Microsoft.VisualStudio.TestPlatform" version="14.0.0.0" targetFramework="net461" />
4+
<package id="MSTest.TestAdapter" version="2.0.0" targetFramework="net461" />
5+
<package id="MSTest.TestFramework" version="2.0.0" targetFramework="net461" />
6+
</packages>

Diff for: Jace/CalculationEngine.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ namespace Jace
1919
/// </summary>
2020
public class CalculationEngine
2121
{
22+
private readonly JaceOptions options;
2223
private readonly IExecutor executor;
2324
private readonly Optimizer optimizer;
2425
private readonly CultureInfo cultureInfo;
2526
private readonly MemoryCache<string, Func<IDictionary<string, double>, double>> executionFormulaCache;
2627
private readonly bool cacheEnabled;
2728
private readonly bool optimizerEnabled;
2829
private readonly bool caseSensitive;
30+
private readonly bool enableSingleCharacterOperations;
2931

3032
/// <summary>
3133
/// Creates a new instance of the <see cref="CalculationEngine"/> class with
@@ -106,13 +108,15 @@ public CalculationEngine(CultureInfo cultureInfo, ExecutionMode executionMode, b
106108
/// <param name="options">The <see cref="JaceOptions"/> to configure the behaviour of the engine.</param>
107109
public CalculationEngine(JaceOptions options)
108110
{
111+
this.options = options;
109112
this.executionFormulaCache = new MemoryCache<string, Func<IDictionary<string, double>, double>>(options.CacheMaximumSize, options.CacheReductionSize);
110113
this.FunctionRegistry = new FunctionRegistry(false);
111114
this.ConstantRegistry = new ConstantRegistry(false);
112115
this.cultureInfo = options.CultureInfo;
113116
this.cacheEnabled = options.CacheEnabled;
114117
this.optimizerEnabled = options.OptimizerEnabled;
115118
this.caseSensitive = options.CaseSensitive;
119+
this.enableSingleCharacterOperations = options.EnableSingleCharacterOperations;
116120

117121
if (options.ExecutionMode == ExecutionMode.Interpreted)
118122
executor = new Interpreter(caseSensitive);
@@ -420,7 +424,8 @@ private void RegisterDefaultConstants()
420424
/// <returns>The abstract syntax tree of the formula.</returns>
421425
private Operation BuildAbstractSyntaxTree(string formulaText, ConstantRegistry compiledConstants)
422426
{
423-
TokenReader tokenReader = new TokenReader(cultureInfo);
427+
TokenReader tokenReader = new TokenReader(cultureInfo, options);
428+
424429
List<Token> tokens = tokenReader.Read(formulaText);
425430

426431
AstBuilder astBuilder = new AstBuilder(FunctionRegistry, caseSensitive, compiledConstants);

Diff for: Jace/JaceOptions.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
using Jace.Execution;
2-
using System;
3-
using System.Collections.Generic;
1+
using System;
2+
using Jace.Execution;
43
using System.Globalization;
5-
using System.Text;
64

75
namespace Jace
86
{
@@ -22,6 +20,7 @@ public JaceOptions()
2220
DefaultConstants = true;
2321
CacheMaximumSize = DefaultCacheMaximumSize;
2422
CacheReductionSize = DefaultCacheReductionSize;
23+
EnableSingleCharacterOperations = false;
2524
}
2625

2726
/// <summary>
@@ -83,5 +82,6 @@ public bool AdjustVariableCase {
8382
/// Enable or disable the default constants.
8483
/// </summary>
8584
public bool DefaultConstants { get; set; }
85+
public bool EnableSingleCharacterOperations { get; set; }
8686
}
8787
}

Diff for: Jace/Tokenizer/TokenReader.cs

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Globalization;
4-
using System.Linq;
54
using System.Text;
65

76
namespace Jace.Tokenizer
@@ -14,19 +13,34 @@ public class TokenReader
1413
private readonly CultureInfo cultureInfo;
1514
private readonly char decimalSeparator;
1615
private readonly char argumentSeparator;
16+
private readonly bool enableSingleCharacterOperations;
17+
18+
public TokenReader(JaceOptions options)
19+
: this()
20+
{
21+
if (options == null) throw new ArgumentNullException(nameof(options));
22+
enableSingleCharacterOperations = options.EnableSingleCharacterOperations;
23+
}
1724

1825
public TokenReader()
1926
: this(CultureInfo.CurrentCulture)
2027
{
2128
}
2229

30+
public TokenReader(CultureInfo cultureInfo, JaceOptions options)
31+
: this(cultureInfo)
32+
{
33+
if (options == null) throw new ArgumentNullException(nameof(options));
34+
enableSingleCharacterOperations = options.EnableSingleCharacterOperations;
35+
}
36+
2337
public TokenReader(CultureInfo cultureInfo)
2438
{
2539
this.cultureInfo = cultureInfo;
2640
this.decimalSeparator = cultureInfo.NumberFormat.NumberDecimalSeparator[0];
2741
this.argumentSeparator = cultureInfo.TextInfo.ListSeparator[0];
2842
}
29-
43+
3044
/// <summary>
3145
/// Read in the provided formula and convert it into a list of takens that can be processed by the
3246
/// Abstract Syntax Tree Builder.
@@ -182,6 +196,11 @@ public List<Token> Read(string formula)
182196
{
183197
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '≠', StartPosition = i++, Length = 2 });
184198
isFormulaSubPart = false;
199+
}
200+
else if (enableSingleCharacterOperations)
201+
{
202+
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '≠', StartPosition = i, Length = 1 });
203+
isFormulaSubPart = false;
185204
}
186205
else
187206
throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i));
@@ -192,6 +211,11 @@ public List<Token> Read(string formula)
192211
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '&', StartPosition = i++, Length = 2 });
193212
isFormulaSubPart = false;
194213
}
214+
else if (enableSingleCharacterOperations)
215+
{
216+
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '&', StartPosition = i, Length = 1 });
217+
isFormulaSubPart = false;
218+
}
195219
else
196220
throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i));
197221
break;
@@ -201,6 +225,11 @@ public List<Token> Read(string formula)
201225
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '|', StartPosition = i++, Length = 2 });
202226
isFormulaSubPart = false;
203227
}
228+
else if (enableSingleCharacterOperations)
229+
{
230+
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '|', StartPosition = i, Length = 1 });
231+
isFormulaSubPart = false;
232+
}
204233
else
205234
throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i));
206235
break;
@@ -210,6 +239,11 @@ public List<Token> Read(string formula)
210239
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '=', StartPosition = i++, Length = 2 });
211240
isFormulaSubPart = false;
212241
}
242+
else if (enableSingleCharacterOperations)
243+
{
244+
tokens.Add(new Token() { TokenType = TokenType.Operation, Value = '=', StartPosition = i, Length = 1 });
245+
isFormulaSubPart = false;
246+
}
213247
else
214248
throw new ParseException(string.Format("Invalid token \"{0}\" detected at position {1}.", characters[i], i));
215249
break;

0 commit comments

Comments
 (0)