As a viability test, I hacked out a simple REPL program in ~10 minutes that supports command-line evaluation of C# expressions and statements.
Here's the basic usage:
> 1 + 2 + 3
6
> DateTime.Now.ToString("T")
4:12:36 PM
To support cross-expression variables, I defined two built-in functions, Set and Get:
> Set("x", 32)
32
> Get("x")
32
And to support invoking arbitrary blocks, there's an Invoke function that evals a void(void) delegate:
> Invoke(delegate { for (int i = 0; i < 6; i++) Console.WriteLine(i); })
0
1
2
3
4
5
Here's the code - compile it as a console app under Whidbey Beta 2 and party on!
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.CodeDom;
using System.CodeDom.Compiler;
namespace csrepl {
class Program {
static string funcprefix = "using System;\r\n"
+ "public delegate void Proc();\r\n"
+ "public class Wrapper { \r\n"
+ " public static object Set(string name, object value) { \r\n"
+ " AppDomain.CurrentDomain.SetData(name, value);\r\n"
+ " return value; \r\n"
+ " }\r\n"
+ " public static object Get(string name) { \r\n"
+ " return AppDomain.CurrentDomain.GetData(name);\r\n"
+ " }\r\n"
+ " public static object Invoke(Proc proc) { \r\n"
+ " proc();\r\n"
+ " return null; \r\n"
+ " }\r\n"
+ " public static object Eval() { return \r\n";
static string funcsuffix = "; \r\n} }";
static string StringEval(string expr) {
string program = funcprefix + expr + funcsuffix;
ICodeCompiler compiler = CodeDomProvider.CreateProvider("C#").CreateCompiler();
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
CompilerResults results = compiler.CompileAssemblyFromSource(cp, program);
if (results.Errors.HasErrors) {
if (results.Errors[0].ErrorNumber == "CS0029")
return StringEval("Invoke(delegate { " + expr + "; })");
return results.Errors[0].ErrorText;
}
else {
Assembly assm = results.CompiledAssembly;
Type target = assm.GetType("Wrapper");
MethodInfo method = target.GetMethod("Eval");
object result = method.Invoke(null, null);
return result == null ? null : result.ToString();
}
}
static void Main(string[] args) {
while (true ) {
Console.Write("> ");
Console.Out.Flush();
string expr = Console.ReadLine();
if (expr == null)
break;
try {
string result = StringEval(expr);
Console.WriteLine(result);
}
catch (TargetInvocationException ex) {
Console.WriteLine(ex.InnerException.GetType().Name + ": " + ex.InnerException.Message);
}
catch (Exception ex) {
Console.WriteLine(ex.GetType().Name + ": " + ex.Message);
}
}
}
}
}
Posted
May 26 2005, 08:16 PM
by
don-box