Using Roslyn to build a simple C# interactive script engine

http://www.jayway.com/2015/05/09/using-roslyn-to-build-a-simple-c-interactive-script-engine/

The .NET Compiler Platform (a.k.a. Roslyn) version 1.0-rc2 was recently released and got go-live license which means the API’s are to be considered fairly stable. In this post I’ll demonstrate how to build a simple C# interactive scripting* editor using the Scripting API (like the F# interactive window which been around in Visual Studio since…like forever). The idea is to be able to evaluate some code in a REPL but also have the possibility to submit code to it from an editor. Let’s start building the core component of the application and then put on a nice GUI on top of it.

The simple script engine looks like this:

public class CSharpScriptEngine
{
    private static Script _previousInput;
    private static Lazy<object> _nextInputState = new Lazy<object>();
    public static object Execute(string code)
    {
        var script = CSharpScript.Create(code, ScriptOptions.Default).WithPrevious(_previousInput);
        var endState = script.Run(_nextInputState.Value);
        _previousInput = endState.Script;
        _nextInputState = new Lazy<object>(() => endState);
        return endState.ReturnValue;
    }
}

The Execute method uses the CSharpScript.Create method to build a script from the the previously submitted code with the current submitted one.
With this in place we can try out the script engine:

class Program
{
    static void Main(string[] args)
    {
        CSharpScriptEngine.Execute(
            //This could be code submitted from the editor
            @"
            public class ScriptedClass
            {
                public String HelloWorld {get;set;}
                public ScriptedClass()
                {
                    HelloWorld = ""Hello Roslyn!"";
                }
            }");
        //And this from the REPL
        Console.WriteLine(CSharpScriptEngine.Execute("new ScriptedClass().HelloWorld"));
        Console.ReadKey();
    }
}
//Output: "Hello Roslyn!"

Let’s now put a simple editor and a REPL on top of the script engine. The REPL will be a self-hosted Web API console application to which the user can submit code from the editor but also write expressions in the command prompt. The setup of the REPL project is fairly straight-forward and I will only show the interesting parts for brevity (no error handling etc). The Main function sets up the Web API part and then listen for input from the user while the Post method in the controller listens for submitted code from the editor:

static void Main(string[] args)
{
    string baseAddress = "http://localhost:9000/"; 
    // Start OWIN host 
    using (WebApp.Start<Startup>(url: baseAddress))
    {
        while (true)
        {
            var str = Console.ReadLine();
            Console.WriteLine(CSharpScriptEngine.Execute(str));
        }
    }
}

public class CodeController : ApiController
{
    // POST api/code 
    public void Post([FromBody]string code)
    {
        Console.WriteLine(CSharpScriptEngine.Execute(code));
    }
}

The code editor in this case is a simple Windows Form application with a multiline text box as the editor window.
When the user has written a script she selects it and presses Alt + Enter and the code is submitted to the REPL application:

private void CodeEdit_KeyDown(object sender, KeyEventArgs e)
{
    if (CodeEdit.SelectedText.Length > 0 && e.KeyCode == Keys.Enter && e.Alt)
    {
        string baseAddress = "http://localhost:9000/";
        using (var client = new HttpClient())
        {
            var response = client.PostAsJsonAsync(baseAddress + "api/code", CodeEdit.SelectedText).Result;
        }
    }
}

The code editor can now be used to run the scripts as shown above:
ScriptEditor
REPL

Conclusion

Roslyn makes it really easy to build tools around C#/VB.NET. In this post I have shown how you, with just a few lines of code, can build an interactive C# script application.
The complete application code is available here.
Learn more about Roslyn on its Github repo.

* The scripting API’s are not yet available in the v1.0-rc2 “Go-Live” release and aren’t available on NuGet. They can however be fetched from the Rosyln myget feed

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s