codingseb / expressionevaluator Goto Github PK
View Code? Open in Web Editor NEWA Simple Math and Pseudo C# Expression Evaluator in One C# File. Can also execute small C# like scripts
License: MIT License
A Simple Math and Pseudo C# Expression Evaluator in One C# File. Can also execute small C# like scripts
License: MIT License
If your regional settings has decimal separator other than .
you will end up with an exception. numberRegex
should be changed to take care of culture settings.
Hello,
Couldn't find anything about this - but is there a support for named optional arguments in function calls?
Here is something I'm trying to do:
public class Program
{
public class Ctx
{
public double Subtract(double x = 0, double y = 1)
{
return x - y;
}
}
public static void Main()
{
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.Context = new Ctx();
string expression = "Subtract(y:2)";
Console.WriteLine(expression);
Console.WriteLine(evaluator.Evaluate(expression));
Console.WriteLine(string.Empty);
}
}
So I'd expect to be able to use named argument just like in C#, is there a support for that? If no, do you have any plans for implementing it?
Thank you.
Hi everybody,
I noticed that when OptionForceIntegerNumbersEvaluationsAsDoubleByDefault is turned on, the Round function would throw an Invalid cast exception.
The problem in around line 471, where:
return Math.Round(Convert.ToDouble(self.Evaluate(args[0])), (int)self.Evaluate(args[1]), (MidpointRounding)self.Evaluate(args[2]));
tries to cast to int a (now forced) Double value.
I suggest to substitute the cast with a Convert.ToInt32()
Same thing a few rows down, always with Math.Round() call.
Try this:
P1 = 5;
P2 = 6;
P1 < 1 && P2 > 3;
Hi
I was trying to make an evaluation, a Sum on a List, but I'm getting an error: CodingSeb.ExpressionEvaluator.ExpressionEvaluatorSyntaxErrorException: 'Function [Sum] unknown in expression : [Sum(x => x.Nombre == "uno" ? (x.Valor ?? 0m) : 0m)]'
What am I doing wrong? or it is not supported?
var Lista = new List<Test>() { new Test { Nombre = "uno", Valor = 1.11m }, new Test { Nombre = "uno", Valor = 2.22m }, new Test { Nombre = "uno", Valor = null }, new Test { Nombre = "dos", Valor = 3.33m } };
string script = "Sum(x => x.Nombre == \"uno\" ? (x.Valor ?? 0m) : 0m)";
ExpressionEvaluator Eval = new ExpressionEvaluator()
{
StaticTypesForExtensionsMethods = new List<Type> { typeof(Enumerable) },
Namespaces = new List<string>() { "System", "System.Linq"},
OptionVariableAssignationActive = false,
OptionPropertyOrFieldSetActive = false,
CacheTypesResolutions = true
};
Eval.Context = Lista;
var result = Eval.Evaluate(script);
// ***********************************************************************
public class Test
{
public string Nombre { get; set; }
public decimal? Valor { get; set; }
}
Hey there,
If I try to evaluate (130-120)/(2*250)
I get 0
instead of 0.02
.
I´ll deep dive into this, but maybe someone already stumble across this.
Update:
After looking at the code, I´ll guess the problem is that after the first cycle of evaluating my expression, the values are int
and in the next cycle the division will happen with two int
´s. And that´s why I get no double
Value.
Is there a Way to ensure all calculated Values are double
Values?
Thanks for your response.
Hi, when trying to evaluate boolean expressions, it throws a RuntimeBinderException.
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.Variables = new Dictionary<string, object>()
{
{ "A", true },
{ "B", false },
{ "C", false },
{ "E", true },
};
var result = evaluator.Evaluate("(A&&B&&C)||(A&&B)||(A&&E&&C)");
Stacktrace
Message:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : Operator '&&' cannot be applied to operands of type 'bool' and 'double'
Stack Trace:
CallSite.Target(Closure , CallSite , Object , Object )
UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
CallSite.Target(Closure , CallSite , Object , Object )
<.cctor>b__270_29(Object left, Object right)
CallSite.Target(Closure , CallSite , Func`3 , Object , Object )
UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
CallSite.Target(Closure , CallSite , Func`3 , Object , Object )
<>c__DisplayClass250_0.<ProcessStack>b__3(IDictionary`2 operatorEvalutationsDict)
List`1.ForEach(Action`1 action)
ExpressionEvaluator.ProcessStack(Stack`1 stack)
ExpressionEvaluator.Evaluate(String expression)
ExpressionEvaluator.EvaluateParenthis(String expression, Stack`1 stack, Int32& i)
<>c__DisplayClass238_1.<Evaluate>b__0(ParsingMethodDelegate parsingMethod)
Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
ExpressionEvaluator.Evaluate(String expression)
ExpressionTest.TestEvaluator() line 176
I used the following code.
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.Variables = new Dictionary<string, object>();
evaluator.Variables["a"] = 1;
evaluator.Variables["b"] = 2;
evaluator.Variables["c"] = "a+b";
evaluator.Variables["d"] = "c+3";
Console.WriteLine(evaluator.Evaluate("a"));
Console.WriteLine(evaluator.Evaluate("b"));
Console.WriteLine(evaluator.Evaluate("c"));
Console.WriteLine(evaluator.Evaluate("d"));
The output was
1
2
a+b
c+3
Shouldn't the output be the following?
1
2
3
6
Something is broken handling nulls and inexistent variables
if Name has a valid string, everything is ok, but if Name is null an exception should be triggered but it doesn't
and if instead of Name you call some other property (inexistent) an exception should be triggered too but it doesn't
the problem happens when the expression is compossed with some elements
Eval.Context = new { Person = new Person { Name = null, Value = 1.11m } };
try
{
var result2 = Eval.Evaluate("\"test one \" + Person.Name.Trim()");
var result3 = Eval.Evaluate("\"test two\" + Person.AnotherName.Trim()");
}
catch(Exception e)
{
// no exception is triggered
Console.WriteLine(e.Message);
}
//****************************************************
public class Person
{
public string Name { get; set; }
public decimal? Value { get; set; }
}
Hi, this is a snippet from latest version of EE, starting from line 2942.
If stack count is eq to 0 you are calling stack.Peek()
, which results in an unthrown error. The comment on this line else if (evaluationStackCount == 1)
is your original code, commented by me.
stack.Clear();
for (int i = 0; i < list.Count; i++)
{
stack.Push(list[i]);
}
if (stack.Count > 1)
{
foreach (var item in stack)
{
if (item is BubbleExceptionContainer bubbleExceptionContainer)
{
throw bubbleExceptionContainer.Exception; //Throw the first occuring error
}
}
throw new ExpressionEvaluatorSyntaxErrorException("Syntax error. Check that no operator is missing");
}
else if (evaluationStackCount == 1) // && stack.Peek() is BubbleExceptionContainer bubbleExceptionContainer <-- peek on empty stack
{
//We reached the top level of the evaluation. So we want to throw the resulting exception.
throw new Exception(); // <-- here you throw bubbleExceptionContainer in original code
}
return stack.Pop();
Best possible resolution here would be to properly throw why the error occured.
Occurs on zero tokens eval:
new EE().Evaluate("")
Hello, I need to call IDictionary.TryGetValue method in my expression, as I understand out parameters are not supported now.
I've tried to execute following code in TryWindow application:
var dictionary = new Dictionary<string, object>();
dictionary.Add("x", 5);
object number = null;
if (dictionary.TryGetValue("x", out number))
return number;
return 0;
and have got following message:
Variable [out] unknown in expression : [out number]
Mb I did something wrong?
Are there any plans to support out parameters feature?
Consider these examples:
int a = 0;
a = -~a;
return a; // returns 1 in c#, EE crashes
int a = 0;
a = +-+-+-+-+a;
return a; // returns 0 in c#, EE crashes
int a = 0;
a = a >> +-+-+-+2 << +-+-+-+-2 >> +-+-+-+-+2 << +-+-+-+-+2;
return a; // returns 0 in c#, EE crashes
For now : things like : stuffToIndex[1,4]
do not work only one dimensional indexing works.
Hi,
I am trying to execute following kind of expression
evaluator.Evaluate("Enumerable.Range(0, 10).Select(x => x * x)");
but I get following error for it:
CodingSeb.ExpressionEvaluator.ExpressionEvaluatorSyntaxErrorException: '[System.Linq.Enumerable+d__113] object has no Method named "Select".'
Interesting part is that this works in LINQPad (.NET Core 3.1.8) but not within Visual Studio (.NET Framework 4.7.2).
If I run following code in VS:
var result_a = Enumerable.Range(0, 10);
var result_b = evaluator.Evaluate("Enumerable.Range(0, 10)");
I can see that both variables have value
System.Linq.Enumerable.<RangeIterator>d__113}
but different types:
result_a: System.Collections.Generic.IEnumerable<int> {System.Linq.Enumerable.<RangeIterator>d__113}
result_b: object {System.Linq.Enumerable.<RangeIterator>d__113}
I don't get what is going on here and why it works in LINQPad but not in VS. Any hints?
The code
var evaluator = new ExpressionEvaluator()
{
OptionForceIntegerNumbersEvaluationsAsDoubleByDefault = true
};
string expression = "Math.Round(1,0,MidpointRounding.AwayFromZero)";
Console.WriteLine(expression);
Console.WriteLine(evaluator.Evaluate(expression));
gives the error
[System.Math] object has no Method named "Round".
instead of the expected result "1".
This came about in 1.4.31.0 and worked in 1.4.30.0 (but 1.4.31.0 is a good fix for #110, so thanks for that!)
Expression: 1==1?true:false
run will show exception.
Code in function "EvaluateTernaryConditionalOperator" under s2.Equals(":")
:
stack.Push(condition ? Evaluate(restOfExpression.Substring(1, j-1)) : Evaluate(restOfExpression.Substring(j + 1)));
replace with
stack.Push(condition ? Evaluate(restOfExpression.Substring(0, j)) : Evaluate(restOfExpression.Substring(j + 1)));
It will be work.
For example to use WebUtility.UrlEncode method from inside System.Net namespace without adding the namespace to the namespace list I would like to execute something like:
"System.Net.WebUtility.UrlEncode(...)"
Is it possible somehow? because it returns an error that "System" variable is not recognized. This would allow to execute a lot of methods without needing to add the namespace each time.
First, I want to say it's a fascinating and high-quality module, congratulations and thank you for putting it up here!
I have a problem evaluating expressions with variables when using ConditionalAnd and null values:
Dictionary<string, object> dictValues = new Dictionary<string, object>();
string nullString = null;
dictValues[ "TestNullString" ] = nullString;
//pass dictValues as expEval.Variables into expression evaluation instance and then...
string expression = "!string.IsNullOrEmpty(TestNullString) && TestNullString.StartsWith(\"ABC\")";
var result = expEval.Evaluate(expression);
This throws a NullReferenceException with the second half, where "plain C#" would skip evaluating this part. The issue seems related to some that were discussed here recently, especially #51 and #53, but the fixes don't address it. The exception details are:
at ExpressionEvaluator.DetermineInstanceOrStatic(Type& objType, Object& obj, ValueTypeNestingTrace& valueTypeNestingTrace) in EvaluatorTest\ExpressionEvaluator.cs
Pow(2,((2+2/3)*2)) + (123-7) = 156.31747359...
Expression Evaluator evaluates Pow(2,((2+2/3)*2)) + (123-7) = 132
Currently this is not included in todo / roadmap document here - https://github.com/codingseb/ExpressionEvaluator/wiki/ExpressionEvaluator-Todo-List
Implementing async
/ await
(with priority on await
) would greatly increase flexibility of EE. C# is becoming more and more asynchronous with each new version and by using async patterns we can free current thread while external work is being processed (querying a database, creating/saving a stream, waiting for an external library to do some work...). This is critical for web applications where threadpool is very limited and we need to free our threads as often as possible.
This suggestion hence proposes that async
/ await
keywords would be recognized when parsing scripts.
Backend:
public class Main {
public staic void Main() {
ExpressionEvaluator eval = new();
eval .StaticTypesForExtensionsMethods.Add(typeof(MyClassExt));
eval.Variables = new Dictionary<string, object> {
{ "SomeAsyncMethod", new Func<int>(async () => await someAwaitableJobReturningInt())} }
}
eval.ScriptEvaluate(script);
}
}
Script:
myResult = await SomeAsyncMethod();
Note that we would also need to support this on extension methods.
For the sake of supporting various syntaxes keywords should be remappable.
myResult = waitfor SomeAsyncMethod(); /* waitfor = await */
Hi, I'm not quite sure if I missed this in the docs, but is something like this possible?
[void] myMethod([int] a) {
}
myMethod(1);
running the above from new EE().ScriptEvaluate()
, myMethod
is defined inside of script, not on input / context, []
means optional.
Hi! I didn't do an excessive research about that bug, but I received an exception when I tried to change the value of a field of a struct.
Message:
Operator '==' cannot be applied to operands of type '<my_struct_type>' and 'NULL'
StackTrace:
at CallSite.Target(Closure , CallSite , Object , Object ) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at CallSite.Target(Closure , CallSite , Object , Object ) at CodingSeb.ExpressionEvaluator.ExpressionEvaluator.EvaluateVarOrFunc(String expr, String restOfExpression, Stack'1 stack, Int32& i) in [...]\ExpressionEvaluator.cs:line 1833 at CodingSeb.ExpressionEvaluator.ExpressionEvaluator.Evaluate(String expression) in [...]\ExpressionEvaluator.cs:line 1385
The expression was simply:
struct.field = anotherVariable
It was somehow related to the dictionary read in line 1833, where you tried to read the variable value into a dynamic variable. I was able to fix the issue by changing the type of 'cusVarValueToPush' to 'object' and only casting it to 'dynamic' in line 1872 and 1876.
I created a pull request with the fix. #31
Instead of mandatory ()
around an expression in listed keywords an option would exist to parse them without brackets.
Now:
if (expr) {
}
With suggestion option toggled on:
if expr {
}
Since EE already supports lightweighted syntactic constructs (myVar = 0;
instead of [type] myVar = 0;
), this would a nice addition for Python like scripting.
In 1.4.20 I started having an issue with member methods not being found, specifically on DateTime and DateTimeOffset. Some digging and it looks like the parameter filter are causing some of the basic methods like AddDays(double d)
to be excluded when the given parameter is in fact an int.
var evaluator = new ExpressionEvaluator();
evaluator.Evaluate("DateTime.Now.AddDays(1)");
This will yield an exception, CodingSeb.ExpressionEvaluator.ExpressionEvaluatorSyntaxErrorException: [System.DateTime] object has no Method named "AddDays".]
Specifying the variable as a double fixes the issue, evaluator.Evaluate("DateTime.Now.AddDays(1d)");
but this isn't always ideal or obvious as int is implicitly convertable to double and passing an int to AddDays
is valid C#.
I see in the commits that this section of code is being worked on - is this something I should try to fix and send in a pull request? Or hold off till next release, or let the maintainers handle?
Now when invalid token / expression is encountered during evaluation throw
statement is used to notify user something went wrong. In scenarios where EE is "proxied" behind some interface (for example a simple web application where I can create and evaluate my scripts) this is suboptimal behavior.
throw
is expensive and shouldn't be used in scenarios where can be triggered oftentry-catch
)This suggestion hence proposes that EE.ScriptEvaluate
would return ExpressionEvaluatorResult
insted of object
. ExpressionEvaluatorResult
is technically a tuple (could be reduced to a tuple) but for the sake of supporting pre-tuple versions of c# it would be nice to keep this as a class.
public class ExpressionEvaluatorResult {
public object Result {get; set;} // <-- this is what ScriptEvaluate returns now
public EvaluationResults State {get; set;} // <-- enum indicating result of evaluation
public EvaluationResultErrorInfo ErrorInfo {get; set;} // <-- when "ok" this is null
}
Inner members definitions:
public enum EvaluationResults {
Ok, // <-- first entry indicates the evaluation was successful
MissingLParen, // <-- following entries all indicate an error
MissingRParen
...
}
public class EvaluationResultErrorInfo {
public int Line {get; set;} // <-- line in script where error occured
public int Character {get; set;} // <-- character index in that line
public string Message {get; set;} // <-- text we now pass to throw
}
Usage would then be:
ExpressionEvaluatorResult result = new ExpressionEvaluator("return 1 + 1;");
if (result.State == EvaluationResults.Ok) {
// script evaluated successfully
int ret = (int)result.Result;
}
Please note that all naming used is open for consideration and improvement, it should be as intuitive as possible and this is just from the top of my head.
When a method implement default value for a parameter like :
public void MyMethod(int x, int y = 100)
{
// ...
}
For now, calling this method with EE force us to define the parameter (here y
). In C# we can omit it.
EE should allow to omit parameters with default values when we call this kind of method.
I create here an issue to follow and document (first for myself but for who is interested) the evolution of the work to version 2.0
The goal is to deeply refactor ExpressionEvaluator to internally build a syntaxic tree with different kinds of tokens.
The evaluation will be executed in 2 phases.
This will allow a lot of stuffs that are not possible with the current "on the fly" way of evaluating things.
It should allow to :
Risks and drawdowns
I will also decide how to split things between version 1 and 2.
The code
var evaluator = new ExpressionEvaluator()
{
OptionForceIntegerNumbersEvaluationsAsDoubleByDefault = true
};
string expression = "3/Math.Round(Avg(1,2),MidpointRounding.AwayFromZero)";
Console.WriteLine(expression);
Console.WriteLine(evaluator.Evaluate(expression));
gives the error
Unhandled exception. Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Operator '/' cannot be applied to operands of type 'double' and 'decimal'
It worked in 1.4.20
and first stopped working in 1.4.21
. Math.Round
is picking the decimal overload when I'd expect it to pick the double overload. It works without OptionForceIntegerNumbersEvaluationsAsDoubleByDefault
.
Hello, thanks for this great lib, is the support for NetStandard / dotnet core something we can wait for ?
Stuff like (double[])myDoubleArray
or typeof(string[])
generate an exception "Empty expression or no token found"
In instance creation like new new double[] {1.2, 4d, 2.3, 5.6}
it works.
Method name "EvaluateTwoCharsOperators" implies it.
If one were to add "And" and "Or" operators as aliases for && and ||, the current implementation wouldn't work because "And" has three characters.
Making this change seems to work, but not sure it's the best way:
BEFORE
private bool EvaluateTwoCharsOperators(string expr, Stack<object> stack, ref int i)
{
if (i < expr.Length - 1)
{
string op = expr.Substring(i, 2);
if (operatorsDictionary.ContainsKey(op))
{
stack.Push(operatorsDictionary[op]);
i++;
return true;
}
}
return false;
}
AFTER
private bool EvaluateTwoCharsOperators(string expr, Stack<object> stack, ref int i)
{
if (i < expr.Length - 1)
{
string op = expr.Substring(i, 2);
var containsKey = operatorsDictionary.ContainsKey(op);
if (!containsKey && expr.Length >= i + 3)
{
op = expr.Substring(i, 3);
containsKey = operatorsDictionary.ContainsKey(op);
}
if (containsKey)
{
stack.Push(operatorsDictionary[op]);
i += op.Length - 1;
return true;
}
}
return false;
}
For now types that are defined in a parent class are not supported in EE.
So something like below do not work :
string path = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
This because the enum SpecialFolder
is defined in the class Environment
.
Small request.
The "ExpressionEvaluator()" method that takes a Dictionary of variables, I'd like to suggest that it instead take IDictionary or, better yet, IReadOnlyDictionary. The reason is because the host code may already have a set of "variables" in a dictionary but the "value" item of each entry is not the variable value, but a different object that contains the value, in addition to other things. Passing that directly to your code wouldn't work because your code expects the Value of the dictionary entry to be an actual intrinsic value such as an int or a double. So today, I have to create a separate dictionary just for the evaluator which is wasteful. If the ExpressionEvaluator code took on an interface instead, I could implement that interface in my object that used the existing dictionary internal to our code.
In general, parameters to methods should be the least simplest form that the code requires. So if your code isn't going to add items to the dictionary, than IReadOnlyDictionary<string, object> is all you need to require.
I tried to create a new righthand operator named "Not" which does exactly the same as ExpressionOperator.LogicalNegation
But it will fail because the function 'EvaluateVarOrFunc' throws an error like
"Variable [Not] unknown in expression : []");
I think the problem is that 'Not' is a string and because of that it will be tried to parse it to a function in steat of an operator.
Maybe a solution could be to add on line 1716:
&& !operatorsDictionary.ContainsKey(varFuncMatch.Groups["name"].Value)
Evaluating a simple expression like
null?.Trim()
should return null
but instead is returning an exception "reference not set to an instance of an object"
this a complete library... one of the best I've seen. the only feature that is missing is support for extended methods.
for example. I declare this class
public static class MyAuxiliarMethods
{
public static string MyExtendedMethod(this string str)
{
return str + " extended";
}
}
then I should add this type somewhere so all the exteded methods became registered.
or maybe just adding the corresponding namespace...
then I could evaluate an expression like this:
AnStringVariable.MyExtendedMethod()
Say I have an object, OBJ, which has a property Property.
I also setup an EvaluateVariable() delegate.
In my variable dictionary, I have the entry ("OBJ", OBJ)
I ask the engine to evaluate:
OBJ.Property
In regards to OBJ, the EvaluateVariable() delegate is only called if the OBJ entry is not included in the dictionary.
However, in regards to Property, EvaluateVariable() is called every time.
Is this the intended behavior? It seems inconsistent. I expected EvaluateVariable() would only get called for Property, if the Property was not part of OBJ proper.
VS2019, NuGet version 1.3.7
Hi!
I'm trying to see if your libraries fits my needs.
When i import the .cs file to my project, i get an error in the file on lines 282 and 283 that "classOrTypeName" does not exist in the current context.
Am i missing something?
Hi Seb!
First of all I'd like to say this library is quite a marvel compared to the alternatives we have in the dotnet world!.
Keep up the good work!!
This is not an issue per say, but i'm wondering if there is a way to escape the variables names in expressions.
The goal here would be to allow hyphen-case variables to be properly identified by the parser
for example i'd like to be able to evaluate expressions like this :
var exp = "net-pv / Total::net-pv"
where net-pv and Total::net-pv are both variables.
If the functionality does not exist , a quick win might be to use string literals to help distinguish variable names in the expression
var exp = $"{net-pv}/{Total::net-pv}"
There seems to be no way to support this project financially, do you think it would be possible to either mark this project as open for github sponsors or add PayPal / whatever payment gate link? I (and possibly others) would like to chip in to support this.
Having a Dynamic Object with a null value for a Property results in the following error:
LogParsing.ExpressionEvaluatorSyntaxErrorException: '[System.Dynamic.ExpandoObject] object has no public Property or Member named "NullValue".'
dynamic MyDynamic = new System.Dynamic.ExpandoObject();
MyDynamic.NullValue = null;
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.Variables = new Dictionary<string, object>()
{
{ "md", MyDynamic },
};
string expression = "md.NullValue ?? \"A\"";
var exp = evaluator.Evaluate(expression);
Verified on the latest version of the code. Any ideas?
the library is resolving sum like an integer... not diferenciating if a property is a decimal... probably it's failing for another datatypes like float, double, etc.
var Persons = new List<Person>() { new Person() { Code = "QT00010", Name = "Pedrito", Number = 11.11m },
new Person() { Code = "QT00011", Name = "Pablito", Number = 12.11m }};
ExpressionEvaluator evaluator = new ExpressionEvaluator();
evaluator.Context = new { Persons };
object val1 = evaluator.Evaluate("Persons.Sum(x=>x.Number)");
Console.WriteLine(val1);
public class Person{
public string Code { get; set; }
public string Name { get; set; }
public decimal Number { get; set; }
}
this should print a decimal 23.22, but it's printing an int 23
"".Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
throws error in EvaluateInstanceCreationWithNewKeyword method "No '(' found after..."
same for
"".Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
any quick workaround?
Hi,
I found the bug, that if I assign the function result to a variable an exception thrown by that function will be assigned to that variable.
In the following example I would expect the Evaluate function to throw the exception and the result variable does not exist, but in the current version the exception is thrown and additionally assigned to the variable.
[Test]
public void Evaluate_WithException_ThrowsExceptionAndDoesNotAssignIt()
{
TestConnectExpressionEvaluator evaluator = new TestConnectExpressionEvaluator();
evaluator.Variables.Add("dummy", new DummyForException());
Assert.Throws<ExpressionEvaluatorSyntaxErrorException>(() => evaluator.Evaluate("result = dummy.bang()"));
Assert.That(evaluator.Variables.ContainsKey("result"), Is.False);
}
public class DummyForException
{
public void bang()
{
throw new Exception();
}
}
This is a followup suggestion for #73. Now to instantiate, only standard c# syntax can be used (on right hand of expression):
myList = new List<int>();
Keyword new
should be remappable (either as regex or string array) to keep consistency with recently added options to modify syntax of other constructs.
// my exotic syntax
myList = -> List<int>();
Great piece of code! Would love to use it in a project I'm working on, but would need a free license like MIT included. Could you add that license file?
Thanks! :)
Receiving a list of variables is helpfull, but it would be great if instead of this
var eval = new ExpressionEvaluator(variables);
the library could receive an object which would be the context. (similar to what roslyn does)
var eval = new ExpressionEvaluator(Person1);
then all the properties, variables and methods would be directly accessible
eval.Evaluate(" Name + \" \" + LastName ");
eval.Evaluate(" aPersonMethod() + 10");
where Person1 is an instance of the class
public class Person{
public string Name {get;set;}
public string LastName {get;set;}
public int aPersonMethod(){
return 10;
}
}
When I try the following code:
var evaluator = new ExpressionEvaluator
{
Variables = new Dictionary<string, object>()
{
{"values", "1,2,3,4,5,6,-1"}
}
};
var script = "var numbers = Array.ConvertAll(values.Split(','), Int32.Parse); return numbers.Min();";
return evaluator.ScriptEvaluate(script);
...it fails with the error:
[System.Array] object has no Method named "ConvertAll".
Should this work?
Currently EE can evaluate anonymous object declarations:
x = new {a = 10, b = 20, c = 30}
property = value
is enforced in method InitSimpleObjet
(we should rename that to InitSimpleObject
). First part of this suggestion is to relax this syntax and allow customization (preferably in the way customization of new
works now) such as:
x = new {a: 10, b: 20, c: 30}
second part of this suggestion proposes support of JS-like anonymous array declaration (respecting c# new
initialization pattern), which would internally map to List<object>
:
x = new [10, 20, 30] // x[2] = 30
@codingseb do you think this would be possible to implement and of use?
Hi
I'd like to say your work is quite a nice and useful to me. Thank you.
I want to use "Unicode variable name" like standard c#. (for example Korean, Chinese ...),
so I modified your code as below, and then it works fine for Korean.
// changed line
const string diactiticsKeywordsRegexPattern = @"\p{L}_";
Example
// english
one = 1;
two = 2;
three = one + two;
// korean
하나 = 1;
둘 = 2;
셋 = 하나 + 둘;
I hope, you can make a option, like "OptionsUnicodeVariableNameActive".
Thank you!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.