Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to interpret a C# expression tree to emit JavaScript?

For example, if you have an expression like this:

Expression<Func<int, int>> fn = x => x * x; 

Is there anything that will traverse the expression tree and generate this?

"function(x) { return x * x; }" 
like image 750
Chris Fulstow Avatar asked May 14 '11 01:05

Chris Fulstow


People also ask

What is C stats?

The concordance (c) statistic is the most commonly used statistic which measures discrimination. For binary outcomes, the c-statistic represents the area under the receiver operating characteristic curve (which is constructed by plotting the false positive rate against the true positive rate of the test data set).

How do you interpret logistic regression coefficients?

E.g., if we were using GPA to predict test scores, a coefficient of 10 for GPA would mean that for every one-point increase in GPA we expect a 10-point increase on the test. Technically, the logistic regression coefficient means the same thing: as GPA goes up by 1, the log odds of being accepted go up by 1.051109.


1 Answers

It's probably not easy, but yes, it's absolutely feasible. ORMs like Entity Framework or Linq to SQL do it to translate Linq queries into SQL, but you can actually generate anything you want from the expression tree...

You should implement an ExpressionVisitor to analyse and transform the expression.


EDIT: here's a very basic implementation that works for your example:

Expression<Func<int, int>> fn = x => x * x; var visitor = new JsExpressionVisitor(); visitor.Visit(fn); Console.WriteLine(visitor.JavaScriptCode);  ...  class JsExpressionVisitor : ExpressionVisitor {     private readonly StringBuilder _builder;      public JsExpressionVisitor()     {         _builder = new StringBuilder();     }      public string JavaScriptCode     {         get { return _builder.ToString(); }     }      public override Expression Visit(Expression node)     {         _builder.Clear();         return base.Visit(node);     }      protected override Expression VisitParameter(ParameterExpression node)     {         _builder.Append(node.Name);         base.VisitParameter(node);         return node;     }      protected override Expression VisitBinary(BinaryExpression node)     {         base.Visit(node.Left);         _builder.Append(GetOperator(node.NodeType));         base.Visit(node.Right);         return node;     }      protected override Expression VisitLambda<T>(Expression<T> node)     {         _builder.Append("function(");         for (int i = 0; i < node.Parameters.Count; i++)         {             if (i > 0)                 _builder.Append(", ");             _builder.Append(node.Parameters[i].Name);         }         _builder.Append(") {");         if (node.Body.Type != typeof(void))         {             _builder.Append("return ");         }         base.Visit(node.Body);         _builder.Append("; }");         return node;     }      private static string GetOperator(ExpressionType nodeType)     {         switch (nodeType)         {             case ExpressionType.Add:                 return " + ";             case ExpressionType.Multiply:                 return " * ";             case ExpressionType.Subtract:                 return " - ";             case ExpressionType.Divide:                 return " / ";             case ExpressionType.Assign:                 return " = ";             case ExpressionType.Equal:                 return " == ";             case ExpressionType.NotEqual:                 return " != ";              // TODO: Add other operators...         }         throw new NotImplementedException("Operator not implemented");     } } 

It only handles lambdas with a single instruction, but anyway the C# compiler can't generate an expression tree for a block lambda.

There's still a lot of work to do of course, this is a very minimal implementation... you probably need to add method calls (VisitMethodCall), property and field access (VisitMember), etc.

like image 101
Thomas Levesque Avatar answered Sep 22 '22 19:09

Thomas Levesque