mparlak / Flee

Fast Lightweight Expression Evaluator
624 stars 119 forks source link

Evaluate throws exception if culture is not US #72

Open Jerac102 opened 5 years ago

Jerac102 commented 5 years ago

Hi,

I am using German OS (I am in Germany) and Flee throws exception if I implement function with signature MyFunction(int a, int b) telling that: ParserLogException: unexpected character ',', on line: 1 column: 15 I manage to change current thread culture to 'us' and then it works, but culture should stay on 'DE-de' because of other parts of program.

hunkydoryrepair commented 3 years ago

I suspect you set decimal separator and function separator manually. By default it will treat comma as a decimal separator for DE-de, and consequently the argument separator becomes a semi-colon.

Olivenberg commented 3 years ago

I have a very similar problem. I too use the "de-DE" parse culture. The decimal separator by itself works fine as a comma in simple expressions. However, if I try to compile expressions like these If(2,57 > 2,7; 2,57; 1000) Round(2,7654; 2)

an Exception like this is thrown:

SyntaxError: unexpected character ';', on line: 1 column: 14

I tried explicitly setting context.ParserOptions.FunctionArgumentSeparator = ';', which did not help.

Like with Jerac102, using the "en-US" parse culture, expressions like If(2.57 > 2.7, 2.57, 1000) work fine.

It's very unfortuante that this does not seem to work as expected, because the parse culture is the reason I chose Flee. I would appreciate any insight on this.

hunkydoryrepair commented 3 years ago

How are you setting the culture? The documented way doesn't appear to work anymore. It appears that the culture is now fixed to InvariantCulture and you must explicitly set both the NumberDecimalSeparator and FunctionArgumentSeparator

hunkydoryrepair commented 3 years ago

Here's a quick sample of how to make it work. The part you were missing is probably the call to "RecreateParser"

    var context = new ExpressionContext();
        context.ParserOptions.DecimalSeparator = ',';
        context.ParserOptions.FunctionArgumentSeparator = ':';
        var script = @"If(2,57 < 2,7: 3,57: 1000)";
        context.ParserOptions.RecreateParser();
        var expr = context.CompileDynamic(script);
        var result = expr.Evaluate();
Olivenberg commented 3 years ago

It appears that the culture is now fixed to InvariantCulture

I don't think that is the case, since with the "de-DE" culture, expressions like 2,56 + 5,44 do work (it does seem change the decimal separator, but not the function argument separator).

You were right, what I was missing was to call .RecreateParser(). My solution looks like this:

context.Options.ParseCulture = new CultureInfo("de-DE"); context.ParserOptions.FunctionArgumentSeparator = ';'; context.ParserOptions.RecreateParser();

Thank you!

hunkydoryrepair commented 3 years ago

Glad to hear it! Turns out the example on this page is wrong as it shows a ParseCulture property on the context: Culture-Sensitive-Expressions

There is a private CultureInfo member in ParseOptions which cannot be changed, but setting the culture on Options sets the decimal and list separators in ParseOptions.

Explicitly setting argument separator should not be necessary (and was not in my tests).