none
Is it possible to convert a Roslyn AST expression tree to a LINQ expression Tree? Is there a Roslyn ScriptEngine.Evaluate?

    Question

  • I'd like to use Roslyn to get the Expression that is assigned to an argument in an custom attribute and evaluate it to get the runtime value. I'd replace all enumerations with their integer equivalent first so that all operands are primitives. I figured Roslyn would expose some API to evaluate an expression or convert it to an LINQ expression tree but I cannot locate it. So does Roslyn expose an API to convert a Roslyn AST to a Linq.Expression or straight to a delegate? I see ScriptEngine.Execute which takes in a string and executes the code. But what if I have a Roslyn AST (say LiteralExpressionSyntax) and I want to evaluate that?

    Thanks!
    Chris 

    Monday, November 14, 2011 2:19 AM

Answers

  • As far as I am aware, there are no APIs that can take a Roslyn AST and return the corresponding LINQ expression tree.

    You could use the scripting APIs to evaluate simple expressions as shown in the below example - but this wouldn't work for more complicated cases. You can also use semanticInfo.ConstantValue to evaluate expressiosn that only contain compile time constants as shown in the below example.

    var engine = new ScriptEngine();
    var tree = SyntaxTree.ParseCompilationUnit(@"
    class c1
    {
        void m1()
        {
            const int x = 1 + 2;
            var y = x + x;
        }
    }");

    Console.WriteLine("Using ScriptEngine: ");
    foreach (var e in tree.Root.DescendentNodes().OfType<ExpressionSyntax>())
    {
        try
        {
            var result = engine.Execute(@"var eval = " + e.GetText() + ";" + "eval");
            Console.WriteLine("Expression = '" + e.GetText() + "' Value = " + result);
        }
        catch
        {
            // Above code only handles simple cases
        }
    }

    Console.WriteLine();
    Console.WriteLine("Using SemanticInfo:");
    var mscorlib = new AssemblyFileReference(
        typeof(object).Assembly.Location);

    var comp = Compilation.Create(
        "MyCompilation",
        syntaxTrees: new[] { tree },
        references: new[] { mscorlib });
    var semanticModel = comp.GetSemanticModel(tree);

    foreach(var e in tree.Root.DescendentNodes().OfType<ExpressionSyntax>())
    {
        var semanticInfo = semanticModel.GetSemanticInfo(e);
        if (semanticInfo.IsCompileTimeConstant)
        {
            Console.WriteLine("Expression = '" + e.GetText() + "' Value = " + semanticInfo.ConstantValue);
        }
    }

    Update: Unfortunately, GetSemanticInfo() does not seem to work when you pass it the AttributeSyntax.Expression. This looks like a bug to me - however, since full support for Attributes is not done yet, this is probably expected at the moment.

    This thread also has some related discussion - http://social.msdn.microsoft.com/Forums/en-US/roslyn/thread/5ce1b129-92fa-4867-9df2-509154ef4c9c


    Shyam Namboodiripad | Software Development Engineer in Test | Roslyn Compilers Team
    Monday, November 14, 2011 8:19 PM

All replies

  • As far as I am aware, there are no APIs that can take a Roslyn AST and return the corresponding LINQ expression tree.

    You could use the scripting APIs to evaluate simple expressions as shown in the below example - but this wouldn't work for more complicated cases. You can also use semanticInfo.ConstantValue to evaluate expressiosn that only contain compile time constants as shown in the below example.

    var engine = new ScriptEngine();
    var tree = SyntaxTree.ParseCompilationUnit(@"
    class c1
    {
        void m1()
        {
            const int x = 1 + 2;
            var y = x + x;
        }
    }");

    Console.WriteLine("Using ScriptEngine: ");
    foreach (var e in tree.Root.DescendentNodes().OfType<ExpressionSyntax>())
    {
        try
        {
            var result = engine.Execute(@"var eval = " + e.GetText() + ";" + "eval");
            Console.WriteLine("Expression = '" + e.GetText() + "' Value = " + result);
        }
        catch
        {
            // Above code only handles simple cases
        }
    }

    Console.WriteLine();
    Console.WriteLine("Using SemanticInfo:");
    var mscorlib = new AssemblyFileReference(
        typeof(object).Assembly.Location);

    var comp = Compilation.Create(
        "MyCompilation",
        syntaxTrees: new[] { tree },
        references: new[] { mscorlib });
    var semanticModel = comp.GetSemanticModel(tree);

    foreach(var e in tree.Root.DescendentNodes().OfType<ExpressionSyntax>())
    {
        var semanticInfo = semanticModel.GetSemanticInfo(e);
        if (semanticInfo.IsCompileTimeConstant)
        {
            Console.WriteLine("Expression = '" + e.GetText() + "' Value = " + semanticInfo.ConstantValue);
        }
    }

    Update: Unfortunately, GetSemanticInfo() does not seem to work when you pass it the AttributeSyntax.Expression. This looks like a bug to me - however, since full support for Attributes is not done yet, this is probably expected at the moment.

    This thread also has some related discussion - http://social.msdn.microsoft.com/Forums/en-US/roslyn/thread/5ce1b129-92fa-4867-9df2-509154ef4c9c


    Shyam Namboodiripad | Software Development Engineer in Test | Roslyn Compilers Team
    Monday, November 14, 2011 8:19 PM
  • See this post for more explanation of LINQ and Expr Trees v2: http://social.msdn.microsoft.com/Forums/en-US/roslyn/thread/6313ffe8-db52-4e93-9578-f1af06b03823

    The short answer is that we may provide, or someone may write a Roslyn tree to ET v2, but Roslyn trees can represent the full languages of VB and C# while ETs v2 cannot (for example, type definitions or some ref-involved exprs).

    Shyam pointed you to a couple of examples of the Roslyn Scripting API, and there are two walkthroughs in the CTP that demonstrate them.  You can also see the doc for where our current thinking is, but these APIs are more likely than not to change: http://tinyurl.com/3ezykda .

    If you're curious, the full ET spec is at http://tinyurl.com/ylkf2ke .  There are several pages of design intro that discusses some trade-offs and limitations.  You'll note that any converter needs to map Roslyn Syntax API plus info from the Roslyn Semantic API to ETs since ETS are a semantic model, not syntactic.

    Cheers,

    Bill


    Tuesday, November 15, 2011 7:36 PM