Thursday, March 30, 2006

A C# interpreter in 50 lines of code

With all the hype around scripting languages these days, here's my contribution. A C# line interpreter. The principe is simple: append the code to a string and evaluate it when a return statement is added. This is some magic we can do with the System.CodeDom and System.Reflection namespace. Not quite has dynamic has ruby or python, but better then nothing...

Run it. Type some c# code, each line will be compiled instantly, type a return something; to restart the session.

Here's an example:
Instant C#, hack some code...
>>> string cool = "wow that's cool!";
>>> cool = cool.ToUpper();
>>> return cool;
WOW THAT'S COOL!
>>>




using System;
using System.Reflection;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
 
public class InstantCSharp
{
    private StringBuilder _code = new StringBuilder();
    ICodeCompiler compiler = new CSharpCodeProvider().CreateCompiler();
    CompilerParameters parameters = new CompilerParameters();
 
    public static void Main()
    {
        new InstantCSharp().Start();
    }
 
    public InstantCSharp()
    {
        parameters.GenerateInMemory = true;
        parameters.ReferencedAssemblies.Add("System.dll");
    }
 
    public void Start()
    {
        Console.WriteLine("Instant C#, hack some code...");
 
        string cmd = ReadCmd();
 
        while (cmd != null)
        {
            object obj = Run(cmd);
            if (obj != null) Console.WriteLine(obj);
            cmd = ReadCmd();
        }
    }
 
    private static string ReadCmd()
    {
        Console.Write(">>> ");
        return Console.ReadLine();
    }
 
    private object Run(string cmd)
    {
        string code;
        string returnline = null;
        bool haserrors = false;
 
        if (!cmd.StartsWith("return"))
        {
            returnline = "return null;";
        }
 
        code = @"
            using System;
            public class Runner
            {
                public object Run()
                {
                    " + _code.ToString() + cmd + returnline + @"
                }
            }";
 
        CompilerResults compiled =
            compiler.CompileAssemblyFromSource(parameters, code);
 
        foreach (CompilerError e in compiled.Errors)
        {
            Console.WriteLine(e.ErrorText);
            if (!e.IsWarning) haserrors = true;
        }    
        if (haserrors) return null;
 
        object obj = compiled.CompiledAssembly.CreateInstance("Runner");
        object returned = compiled.CompiledAssembly.GetType("Runner")
            .InvokeMember(
                "Run",
                BindingFlags.InvokeMethod,
                null, obj, new object[] {}
            );    
 
        _code.Append(cmd); // All ok so include the line
        if (returnline == null) // A return call means end of the session
            _code = new StringBuilder();
 
        return returned;
    }
 
}

4 Comments:

Anonymous Anonymous said...

G'day - I notice you're using some inline styles there. If you add "overflow: auto" to the list, your code section will no longer overflow its box in Firefox/Mozilla. Sadly, nothing much can be done to fix it in IE6...

: Bat :

4:56 p.m.  
Blogger MAC said...

Fixed! thx

5:18 p.m.  
Anonymous Anonymous said...

http://tramadol-sqllt.blogspot.com/
Ciao!

9:55 p.m.  
Anonymous Anonymous said...

http://didrex-moza.blogspot.com/
See you.

7:58 a.m.  

Post a Comment

<< Home