Skip to content

Commit 1113636

Browse files
committed
Improve the doc on scripts and propose some alternative libs
1 parent 6aa6431 commit 1113636

File tree

1 file changed

+236
-9
lines changed

1 file changed

+236
-9
lines changed

README.md

Lines changed: 236 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
A Simple Math and Pseudo C# Expression Evaluator in One C# File.
44

5+
And now can execute small C# like scripts
6+
57
It is largely based on and inspired by the following resources [this post on stackoverflow](http://stackoverflow.com/questions/333737/evaluating-string-342-yield-int-18/333749), [NCalc](https://ncalc.codeplex.com/) and [C# Operators](https://msdn.microsoft.com/en-us/library/6a71f45d.aspx)
68

79
## Status
@@ -23,10 +25,17 @@ It is largely based on and inspired by the following resources [this post on st
2325
* You can call Methods and/or Properties on your own classes (just pass a object as custom variables)
2426
* [C# primary types](#primary-types)
2527
* Use strings as in C# (@"", $"", $@"" available)
26-
* Linq, generics and lambda expressions
28+
* Lambda expressions
2729
* Classes like File, Directory, Regex, List ... available ([You can extend the list of Namespaces](#namespaces))
2830
* Create instance with [new(MyClassName, constructorArgs)](#standard-functions) or [new MyClassName(constructorArgs)](#operators)
2931
* [Call void methods with fluid prefix convention to chain operations](#go-fluid-with-a-simple-methods-prefixing-convention)
32+
* Manage now assignation operators like =, +=, -=, *= ... (On variables and sub properties)
33+
* Manage now postfix operators ++ and -- (On variables and sub properties)
34+
35+
## And with [ScriptEvaluate](#scripts)
36+
* Small C# like script evaluation (Multi expressions separated by ;)
37+
* Some conditional and loop blocks [keywords](#script-keywords) (if, while, for ...)
38+
* Multi-line (multi expression) Lambda expressions.
3039

3140
## Getting started
3241

@@ -39,16 +48,18 @@ Install-Package CodingSeb.ExpressionEvaluator
3948

4049
or copy the [CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs](./CodingSeb.ExpressionEvaluator/ExpressionEvaluator.cs) in your project :
4150

42-
4351
## Basic C# usage
52+
53+
### Simple expressions
54+
4455
```c#
4556
using CodingSeb.ExpressionEvaluator;
4657
//...
4758
string expression;
4859
//...
4960
ExpressionEvaluator evaluator = new ExpressionEvaluator();
50-
Console.Write(expression);
51-
Console.Write(evaluator.Evaluate(expression));
61+
Console.WriteLine(expression);
62+
Console.WriteLine(evaluator.Evaluate(expression));
5263
```
5364
Results with some expressions :
5465

@@ -141,6 +152,123 @@ Enumerable.Repeat(3,6).Cast().ToList()[4]
141152
true
142153
```
143154

155+
### Small scripts
156+
157+
```c#
158+
using CodingSeb.ExpressionEvaluator;
159+
//...
160+
string script;
161+
//...
162+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
163+
Console.WriteLine("--------------------------------------------");
164+
Console.WriteLine(script);
165+
Console.WriteLine("---------------- Result --------------------");
166+
Console.WriteLine(evaluator.Evaluate(script));
167+
```
168+
Results with some scripts :
169+
170+
```
171+
--------------------------------------------
172+
x = 0;
173+
result = "";
174+
175+
while(x < 5)
176+
{
177+
result += $"{x},";
178+
x++;
179+
}
180+
181+
result.Remove(result.Length - 1);
182+
---------------- Result --------------------
183+
0,1,2,3,4
184+
185+
--------------------------------------------
186+
result = "";
187+
188+
for(x = 0; x < 5;x++)
189+
{
190+
result += $"{x},";
191+
}
192+
193+
result.Remove(result.Length - 1);
194+
---------------- Result --------------------
195+
0,1,2,3,4
196+
197+
--------------------------------------------
198+
x = 0;
199+
y = 1;
200+
result = 0;
201+
202+
if(y != 0)
203+
{
204+
return 1;
205+
}
206+
else if(x == 0)
207+
{
208+
return 2;
209+
}
210+
else if(x < 0)
211+
{
212+
return 3;
213+
}
214+
else
215+
{
216+
return 4;
217+
}
218+
---------------- Result --------------------
219+
1
220+
221+
--------------------------------------------
222+
x = 0;
223+
y = 0;
224+
result = 0;
225+
226+
if(y != 0)
227+
{
228+
return 1;
229+
}
230+
else if(x == 0)
231+
{
232+
return 2;
233+
}
234+
else if(x < 0)
235+
{
236+
return 3;
237+
}
238+
else
239+
{
240+
return 4;
241+
}
242+
---------------- Result --------------------
243+
2
244+
245+
--------------------------------------------
246+
x = 5;
247+
y = 0;
248+
result = 0;
249+
250+
if(y != 0)
251+
{
252+
return 1;
253+
}
254+
else if(x == 0)
255+
{
256+
return 2;
257+
}
258+
else if(x < 0)
259+
{
260+
return 3;
261+
}
262+
else
263+
{
264+
return 4;
265+
}
266+
---------------- Result --------------------
267+
4
268+
```
269+
270+
To see more scripts examples see scripts uses for tests in sub directories [CodingSeb.ExpressionEvaluator.Tests/Resources](./CodingSeb.ExpressionEvaluator.Tests/Resources)
271+
144272
## Standard constants (variables)
145273

146274
The evaluation of variables name is case insensitive so you can write it as you want.
@@ -206,7 +334,6 @@ The following functions are internally defined. (Most of these are [System.Math
206334
|**[Exp](https://msdn.microsoft.com/en-us/library/system.math.exp(v=vs.110).aspx)**(double d)|Return a double value that is e raised to the specified d power|`Exp(3d)`|`20.0855369231877d`|
207335
|**[Floor](https://msdn.microsoft.com/en-us/library/e0b5f0xb(v=vs.110).aspx)**(double d)|Return a double value that is the largest integer less than or equal to the specified d argument|`Floor(4.23d)`|`4d`|
208336
|**[IEEERemainder](https://msdn.microsoft.com/en-us/library/system.math.ieeeremainder(v=vs.110).aspx)**(double x, double y)|Return a double value that is the remainder resulting from the division of x by y|`IEEERemainder(9, 8)`|`1d`|
209-
|**if**(bool condition, object yes, object no)|Return the yes object value if condition is true.<br/>Return the no object if condition is false|`if(1>2, "It is true", "It is false")`|`"It is false"`|
210337
|**in**(object valueToFind, object obj1, object obj2...)|Return a boolean value that indicate if the first argument is found in the other arguments|`in(8, 4, 2, 8)`|`true`|
211338
|**List**(object obj1, object obj2 ,...)|Return a List (System.Collections.Generic.List<object>) of all given arguments|`List(1, "Hello", true)`|`new List<object>(){1, "Hello", true}`|
212339
|**[Log](https://msdn.microsoft.com/en-us/library/system.math.log(v=vs.110).aspx)**(double a, double base)|Return a double value that is the logarithm of a in the specified base|`Log(64d, 2d)`|`6d`|
@@ -224,6 +351,9 @@ The following functions are internally defined. (Most of these are [System.Math
224351
|**[Tanh](https://msdn.microsoft.com/en-us/library/system.math.tanh(v=vs.110).aspx)**(double angle)|Return a double value that is the hyperbolic tangent of the specified angle in radian|`Tanh(2d)`|`0.964027580075817d`|
225352
|**[Truncate](https://msdn.microsoft.com/en-us/library/c2eabd70(v=vs.110).aspx)**(double d)|Return a double value that is the integer part of the specified d value|`Truncate(2.45d)`|`2d`|
226353
354+
355+
*Remark : The old if function (NCalc style) has been removed. This to avoid conflicts with the new if, else if, else keywords in script mode. To do something similar on a expression level use the conditional operator [( ? : )](#Operators) instead.*
356+
227357
## On the fly variables and functions evaluation
228358
In addition to custom variables, you can add variables and/or functions with on the fly evaluation.
229359
2 C# events are provided that are fired when variables or functions are not fund as standard ones in evaluation time.
@@ -277,7 +407,7 @@ Hello Bob
277407
Since ExpressionEvaluator evaluate one expression at a time.
278408
There are cases where we need to use void methods in a fluid syntax manner.
279409

280-
To do so, you only need to prefix the method name with "Fluid" or "Fluent"
410+
You only need to prefix the method name with "Fluid" or "Fluent"
281411

282412
```C#
283413
// Example Add on List
@@ -336,8 +466,8 @@ Here is a list of which operators are supported in ExpressionEvaluator or not
336466
|Primary|[x?[y]](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators)|Supported|
337467
|Primary|[f(x)](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/invocation-operator)|Supported|
338468
|Primary|[a[x]](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/index-operator)|Supported|
339-
|Primary|[x++](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/increment-operator)|Supported|
340-
|Primary|[x--](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/decrement-operator)|Supported|
469+
|Primary|[x++](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/increment-operator)|Supported **Warning change the state of the postfixed element**|
470+
|Primary|[x--](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/decrement-operator)|Supported **Warning change the state of the postfixed element**|
341471
|Primary|[new](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/new-operator)|Supported you can also use [new() function](#standard-functions)|
342472
|Primary|[typeof](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/typeof)|Supported|
343473
|Primary|[checked](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked)|Not Supported|
@@ -380,7 +510,88 @@ Here is a list of which operators are supported in ExpressionEvaluator or not
380510
|Conditional|[t ? x : y](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator)|Supported equivalent to the [if() function](#standard-functions)|
381511
|Lambda|[=>](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-operator)|Supported|
382512
383-
Assignment Operators are not supported in ExpressionEvaluator
513+
### Assignation operators
514+
515+
** Warning all of the following operators change the value of their left element.**
516+
517+
Assignation operators (and also postfix operators (++ and --)) are usable on :
518+
519+
|Elements|What is changing|Options|
520+
|---|---|---|
521+
|Custom variables|The variable in the Variables dictionary is changed and if the variable doesn't exists, it automatically created with the = operator|Can be disabled with ```evaluator.OptionVariableAssignationActive = false;```|
522+
|Properties or fields on objects|If the property/field is not readonly it is changed|Can be disabled with ```evaluator.OptionPropertyOrFieldSetActive = false;```|
523+
|Indexed object like arrays, list or dictionaries|The value at the specified index is changed|Can be disabled with ```evaluator.OptionIndexingAssignationActive = false;```|
524+
525+
Here is the list of available assignation operator
526+
527+
|Operator|Support|
528+
|---|---|
529+
|[=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator)|Supported (Can be use to declare a new variable that will be injected in the Variables dictionary)|
530+
|[+=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/addition-assignment-operator)|Supported|
531+
|[-=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/subtraction-assignment-operator)|Supported|
532+
|[*=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/multiplication-assignment-operator)|Supported|
533+
|[/=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/division-assignment-operator)|Supported|
534+
|[%=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/remainder-assignment-operator)|Supported|
535+
|[&=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/and-assignment-operator)|Supported|
536+
|[|=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/or-assignment-operator)|Supported|
537+
|[^=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/xor-assignment-operator)|Supported|
538+
|[<<=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/left-shift-assignment-operator)|Supported|
539+
|[>>=](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/right-shift-assignment-operator)|Supported|
540+
541+
## Scripts
542+
In addition to simple expression evaluation you can also evaluate small script with the method ```ScriptEvaluate(string script)```.
543+
Scripts are just a serie of expressions to evaluate separated with a ; character and leaded by severals additionals keywords.
544+
545+
To declare a variable types are not yet supported and are for now dynamically deduced.
546+
547+
```C#
548+
// Not supported
549+
int x = 2;
550+
string text = "hello";
551+
552+
for(int i = 0; i < 10; i++)
553+
...
554+
555+
// Write this instead :
556+
x = 2;
557+
text = "hello";
558+
559+
for(i = 0; i < 10; i++)
560+
...
561+
```
562+
563+
### Script keywords
564+
565+
Currently the following script keywords are supported
566+
567+
|Type|Operator|Support|
568+
|---|---|---|
569+
|Selection|[if](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else)|Supported|
570+
|Selection|[else if](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else)|Supported|
571+
|Selection|[else](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else)|Supported|
572+
|Selection|[switch case](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch)|Not yet supported|
573+
|Iteration|[do ... while](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/do)|Supported|
574+
|Iteration|[for](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for)|Supported|
575+
|Iteration|[foreach, in](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in)|Not yet supported|
576+
|Iteration|[while](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/while)|Supported|
577+
|Jump|[break](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break)|Supported in do, for and while blocks|
578+
|Jump|[continue](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/continue)|Supported in do, for and while blocks|
579+
|Jump|[goto](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/goto)|Not supported (But if you looked after it -> Booo !!! Bad code)|
580+
|Jump|[return](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return)|Supported|
581+
582+
*Remark : The way ScriptEvaluate works is to evaluate expressions one by one. There is no syntax check before the evaluation. So be aware that syntax or naming bugs only appears at execution and some code can already be evaluated at this time. Futhermore a syntaxic/naming bug in an if-else block for example can simply be ignored until the corresponding condition is met to evaluate the specific line of code.*
583+
584+
## Code comments
585+
By default comments are not managed in expressions and scripts evaluations.
586+
But they can be manually removed with the specific method ```string RemoveComments(string scriptWithComments)```
587+
588+
To be sure that your commented script is evaluated correctly you can do :
589+
590+
```C#
591+
ExpressionEvaluator evaluator = new ExpressionEvaluator();
592+
evaluator.ScriptEvaluate(evaluator.RemoveComments(scriptWithComments));
593+
```
594+
It remove line comments // and blocks comments /* ... */
384595
385596
## Namespaces and types
386597
By default the following list of namespaces are available :
@@ -411,3 +622,19 @@ You can also add a specific type :
411622
```C#
412623
evaluator.Types.Add(typeof(MyClass));
413624
```
625+
626+
## Similar projects
627+
### Free
628+
* [NCalc](https://archive.codeplex.com/?p=ncalc) or [NCalc new home](https://github.com/sheetsync/NCalc)
629+
* [Jint](https://github.com/sebastienros/jint) Support scripting but with Javascript
630+
* [DynamicExpresso](https://github.com/davideicardi/DynamicExpresso/)
631+
* [Flee](https://github.com/mparlak/Flee)
632+
* [CS-Script](https://github.com/oleg-shilo/cs-script) Best alternative (I use it some times) -> Real C# scripts better than ExpressionEvaluator (But everything is compiled. Read the doc. Execution is faster but compilation can make it very slow. And if not done the right way, it can lead to memory leaks)
633+
634+
### Commercial
635+
* [Eval Expression.NET](http://eval-expression.net/)
636+
637+
I would say every C# evaluation libraries have drawbacks and benefits, ExpressionEvaluator is not an exception so choose wisely.
638+
639+
The biggest difference of ExpressionEvaluator is that everything is evaluated on the fly, nothing is compiled or transpile nor in CLR/JIT nor in lambda expressions nor in javascript or other languages stuffs.
640+
So it can be slower in some cases (sometimes not) but it also avoid a lot of memory leaks and already allow to evaluate some small scripts.

0 commit comments

Comments
 (0)