Eval-Expression.NET icon indicating copy to clipboard operation
Eval-Expression.NET copied to clipboard

Left hand side of subtraction misinterpreted as cast

Open void80 opened this issue 1 year ago • 6 comments

Have a look at the following test cases

    [TestMethod]
    [DataRow("#1", "a1", 1)]
    [DataRow("#2", "(a1)", 1)]
    [DataRow("#3", "(a1)+(a1)", 2)]
    [DataRow("#4", "(a1)+a1", 2)]
    [DataRow("#5", "(a1)-(a1)", 0)]
    [DataRow("#6", "(a1)-a1", 0)]
    public void TestSimpleFalseCastExpressions(string id, string expression, int expected)
    {
        var context = new EvalContext();

        var types = new Dictionary<string, Type>
        {
            { "a1", typeof(double) },
        };

        var values = new Dictionary<object, double>
        {
            { "a1", 1.0 },
        };

        var compiled = context.Compile(expression, types);
        var result = compiled.Invoke(values);

        result.Should().Be(expected);
    }

The cases #5 and #6 fail with the following exception:

Test method EvalExpressionsTests.TestSimpleFalseCastExpressions threw exception: 
Z.Expressions.Compiler.Shared.EvalException: Oops! The type was not found.. The error occurred for expression "(" at position 0 near "(a1)-(a1)".
    at .(ExpressionScope , SyntaxNode , Expression , Boolean )
   at .(ExpressionScope , SyntaxNode , Expression , Boolean )
   at .(ExpressionScope , SyntaxNode , Expression , Boolean )
   at Z.Expressions.CodeCompiler.CSharp.ExpressionParser.ParseSyntax(ExpressionScope scope, SyntaxNode node, Type resultType)
   at .[](EvalContext , String , IDictionary`2 , Type , EvalCompilerParameterKind , ExpressionScope , String , Boolean , Boolean )
   at .[](EvalContext , String , IDictionary`2 , Type , EvalCompilerParameterKind , Boolean , Boolean , Boolean )
   at Z.Expressions.EvalContext.Compile(String code, IDictionary`2 parameterTypes)
   at EvalExpressionsTests.TestSimpleFalseCastExpressions(String id, String expression, Int32 expected) in EvalExpressionsTests.cs:line 141
   at InvokeStub_EvalExpressionsTests.TestSimpleFalseCastExpressions(Object, Span`1)
   at System.Reflection.MethodBaseInvoker.InvokeWithFewArgs(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)

My suspicion is that (a1) is (wrongly) interpreted as cast when followed by a - sign, because the - is interpreted as unary negation operator.

I would expect the parser to be able to distinguish between a real cast and an expression in parens.

For example "(double) -1" should be identified as a cast, "(a1)-1" should be identified as a subtraction.

void80 avatar Feb 06 '24 07:02 void80

Hello @void80 ,

Thank you for reporting.

Your suspicion is probably 100% right. I remember we fixed a similar issue recently but slightly different #154 (he wanted to cast it on his side).

We will look at it.

Best Regards,

Jon

JonathanMagnan avatar Feb 06 '24 15:02 JonathanMagnan

We've figured out that a downgrade to 6.0.1 works around the problem, in case this helps you. Best regards, Sebastian

strohhaecker avatar Mar 04 '24 09:03 strohhaecker

Hello @strohhaecker , @void80

A new version, v6.1.7, has been released today.

All known cases we found have been fixed in this issue.

Could you test the latest version and let us know if everything is working? Or report any missing expression that still have an error.

Best Regards,

Jon

JonathanMagnan avatar Jun 18 '24 21:06 JonathanMagnan

Hi Jon, I'll try to verify this fixes some problems we had, though we have changed a lot around the expression evaluation since that time. Thanks for keeping this up! Sebastian

strohhaecker avatar Jun 20 '24 14:06 strohhaecker

Hi Jon,

we verified that all of our use cases work with the version 6.1.7.

However, I just wanted to check some cases we are not using. There seems to be one problem remaining (which we are not using).

    [TestMethod]
    [DataRow("#1", "a1", 1)]
    [DataRow("#2", "(a1)", 1)]
    [DataRow("#3", "(a1)+(a1)", 2)]
    [DataRow("#4", "(a1)+a1", 2)]
    [DataRow("#5", "(a1)-(a1)", 0)]
    [DataRow("#6", "(a1)-a1", 0)]
    [DataRow("#7", "(int)-1", -1)]
    [DataRow("#8", "(int)+1", +1)]
    [DataRow("#9", "+1", +1)]
    public void TestSimpleFalseCastExpressions(string id, string expression, int expected)
    {
        var context = new EvalContext();

        var types = new Dictionary<string, Type>
        {
            { "a1", typeof(double) },
        };

        var values = new Dictionary<object, double>
        {
            { "a1", 1.0 },
        };

        var compiled = context.Compile(expression, types);
        var result = compiled.Invoke(values);

        result.Should().Be(expected);
    }

Use case #8 is not working. That is, a cast followed by a unary + operator. Strangely enough, the unary operator itself seems to work (case #9).

Regards Sven

void80 avatar Jun 21 '24 07:06 void80

Thank you @void80 for reporting.

Indeed, we only added the logic for the minus sign, never for the plus sign. We will see if it is worth doing a similar logic (we are more afraid of the side impact here).

Best Regards,

Jon

JonathanMagnan avatar Jun 21 '24 13:06 JonathanMagnan

Hello @void80 ,

The v6.1.8 has been released.

We added an identical logic to the plus sign that we did with the minus sign.

Let me know if this time everything is working as expected.

Best Regards,

Jon

JonathanMagnan avatar Jul 22 '24 21:07 JonathanMagnan