nreco / lambdaparser

Runtime parser for string expressions (formulas, method calls). Builds dynamic LINQ expression tree and compiles it to lambda delegate.
http://www.nrecosite.com/
MIT License
307 stars 55 forks source link

The problem of checking expression statements #50

Open DNetORM opened 5 months ago

DNetORM commented 5 months ago

When I wrote some code expressions, I wanted to check the syntax, such as whether the properties and methods were correct. I think using type reflection can check, but I wrote an incorrect property and did not prompt me for any errors. Why do I need this feature? Because I have defined some types of variables that may not have been assigned values, even though I have written code expressions, using Eval() function to check in real time will definitely result in errors. So, I wonder if you can implement pre checking for some code expressions, just to check if the syntax is correct. I think it should be possible in theory, but I don't know how to do it

var varContext = new Dictionary<string, object>(); varContext["dt"] = datatable;

Expression expr = lambdaParser.Parse("dt.Rows1[0]"); var exprParams = LambdaParser.GetExpressionParameters(expr);

dt is a System.DataTable type variable,Rows1 is an incorrect property,But it didn't give me any exceptions,i need some checks,how to do?

VitaliyMF commented 5 months ago

LambdaParser.Parse parses an expression into .NET Expression, and you don't get any errors if it is syntactically correct.

dt is a System.DataTable type variable,Rows1 is an incorrect property,But it didn't give me any exceptions,i need some checks,how to do?

It is possible to determine that "Rows1" is incorrect property only when your expression is evaluated (for the concrete evaluation context with contains concrete "dt" instance), and you'll get an error when you'll call "Eval" for this expression and the evaluation context.

DNetORM commented 5 months ago

Is it possible to do this? Provide a dictionary that stores types with the same key values, and then perform syntax checks based on this dictionary, such as varTypeContext

var varContext = new Dictionary<string, object>(); varContext["dt"] = datatable;

var varTypeContext = new Dictionary<string, object>(); varTypeContext ["dt"] = "System.DataTable";

bool res = lambdaParser.CheckExpression("dt.Rows1[0]");

DNetORM commented 5 months ago

I am developing a simple workflow engine and need to define some variables in advance. These variables may have mutual usage relationships, but when defining variables, I do not know the specific values of the variables. I just want to check the syntax of the expression because some variables will only be instantiated at runtime, so I cannot use eval() at this stage

VitaliyMF commented 5 months ago

Is it possible to do this? Provide a dictionary that stores types with the same key values, and then perform syntax checks based on this dictionary, such as varTypeContext bool res = lambdaParser.CheckExpression("dt.Rows1[0]");

Internal behavior of "CheckExpression" is equivalent to

var res = true;
try {
  lambdaParser.Eval("dt.Rows1[0]", varContext);
} catch (Exception ex) {
  res = false;
}

(note that it is not possible to check an expression for run-time errors without the evaluation context and performing actual evaluation).

Also, if an expression has conditions, this kind of check can verify only correctness for the concrete evaluation context. It is not possible to verify an expression for runtime errors in another way (in the same way as you cannot check for JS runtime errors just by parsing JS code).

I don't see a real need in this API inside LambdaParser because handling of errors may be rather application-specific.

VitaliyMF commented 5 months ago

but when defining variables, I do not know the specific values of the variables. I just want to check the syntax of the expression because some variables will only be instantiated at runtime, so I cannot use eval() at this stage

This means that you can validate expression's syntax with Parse method, but you'll not able to detect runtime errors that depend on the concrete evaluation context. An expression "dt.Rows1[0]" can be valid in one case (if "dt" variable is set and it has "Rows1" property) and can cause an error in anther case. Without evaluation with concrete "dt" value, you cannot validate that (this is a conceptual limitation, not technical).

DNetORM commented 5 months ago

I have changed my approach and used Rosslyn CSharpCompilation to check for syntax issues in compilation. Since Rosslyn can do it, technically your project should also be able to implement it. I think it's just whether you're willing to think about improving it or not

VitaliyMF commented 5 months ago

Since Rosslyn can do it, technically your project should also be able to implement it.

You're wrong with this assumption. NReco.LambdaParser was specially designed for dynamic typing, it implements special mechanism to support this capability: you are not obligated explicitly define variables and their (.net) types, and this means that all methods/properties are resolved in the run-time (via reflection). A side effect of dynamic typing is that you cannot validate types just by parsing the expression, this is conceptual difference from Roslyn (or any other parsing of strictly-typed expressions).

You may check LambdaParser code to realize that it is not possible to handle type-related errors (like calling wrong method or property) simply because when you have "dt" variable (ParameterExpression) it has System.Object type and parser simply don't have information about its real type - it is known only in the run-time, when an expression is evaluated for the concrete variables context.