C# Eval: An Embeddable Compiler

Hello Internets and C# Lovers!

After the C# Interactive Shell started working, it became obvious that we now had C#'s eval and that it would be incredibly interesting to enable people to embed a C# Eval in their application.

I did a little bit of refactoring on the codebase last night, and now we expose a few methods that allow developers to evaluate C# expressions and statements dynamically.

Usage is very simple, you must reference the `gmcs.exe' assembly, this contains the C# Eval, then you invoke the CSharpEvaluator.Evaluate method, and get the results back.

The following is a small command line calculator that takes C# expressions:

using Mono.CSharp;
using System;

class MyCalculator {
	static void Main (string [] args)
	{
		Console.WriteLine (CSharpEvaluator.Evaluate (args [0] + ";"));
	}
}
	

Compile the above, and execute:

$ mono calculator.exe '1+2'
3
	

There are a number of overload methods for Evaluate that give more control over how things are evaluated. The csharp command is now written entirely using the CSharpEvaluator API. The code is now pretty simple: pretty printing of values, dealing with partial input, loading startup files (if any) and import the default namespaces.

A few uses that come to mind:

  • Use C# as a scripting language for your application.
  • Use it for startup scripts of your own application (similar to .emacs, but with C# instead).
  • Use it to explore the state of your application live.
  • Use it to debug your application as it is running.
  • Embed the compiler on Silverlight and run C# on your web browser, similar to how Jimmy did it for Ruby.
  • Embed it into your app and expose it as a service that you can connect to, and do it live!

The four or five public methods of the API are documented in the source using C# doc tags. When Mono 2.2 goes out, we will publish docs for them.

As we announced back in April, Mono's C# compiler is now licensed under the MIT X11 license, so you can embed at will.

Manhole

Joe Shaw mentioned a few days ago that it would be nice to support something like Twisted's Manhole where your application is listening on a port and then you can connect to it and debug it. It should take a dozen lines to write it, but I am heading out for dinner now.

But if I were to do it, I would probably make the csharp command (all 240 lines of it) support a --server command line option and have it connect to the server and send strings over the wire instead of executing locally. That way you get to use the awesome getline.cs command line editor and history locally and let the server run the code.

Getting Your Hands on This

To enjoy this hack, you have to either wait for Mono 2.2 or install Mono from SVN, all of the code is checked in.

Update: Clarification

Since it was not obvious, we do support C# 3.0, which includes the entire LINQ stack in the above expression evaluator:

using Mono.CSharp;
using System.Collections;
using System;

class X {
	static void Main (string [] args)
	{
		Evaluator.Run ("using System; using System.Linq;");
		bool ress;
		object res;
		string s = Evaluator.Evaluate (
			"from x in System.IO.Directory.GetFiles (\"/etc\") where x.Length < 10 select x;",
			out res, out ress);

		foreach (var v in (IEnumerable) res){
			Console.Write (v);
			Console.Write (' ');
		}
	}
}

The above uses a LINQ expression, and this is the result in my system (files whose full pathname is less than 10 characters):

/etc/motd /etc/mtab /etc/raw /etc/rpc 
Posted on 10 Sep 2008 by Miguel de Icaza
This is a personal web page. Things said here do not represent the position of my employer.