diff --git a/src/main/scala/leon/codegen/CodeGenPhase.scala b/src/main/scala/leon/codegen/CodeGenPhase.scala
index e2fb321c6dbf9251d0531a0d46c533e412a41bcd..cd2df91d2cd90f6c75415e0ef37fcf7ef439af6c 100644
--- a/src/main/scala/leon/codegen/CodeGenPhase.scala
+++ b/src/main/scala/leon/codegen/CodeGenPhase.scala
@@ -15,45 +15,13 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] {
   def run(ctx : LeonContext)(p : Program) : CompilationResult = {
     import CodeGeneration._
 
-    // This sets up an environment where all classes and all functions have names.
-    implicit val env = CompilationEnvironment.fromProgram(p)
-
-    for((parent,children) <- p.algebraicDataTypes) {
-      val acf = compileAbstractClassDef(p, parent)
-      val ccfs = children.map(c => compileCaseClassDef(p, c))
-    } 
-
-    val mainClassName = defToJVMName(p, p.mainObject)
-    val cf = new ClassFile(mainClassName, None)
-    cf.addDefaultConstructor
-
-    cf.setFlags((
-      CLASS_ACC_SUPER |
-      CLASS_ACC_PUBLIC |
-      CLASS_ACC_FINAL
-    ).asInstanceOf[U2])
-
-    // This assumes that all functions of a given program get compiled
-    // as methods of a single class file.
-    for(funDef <- p.definedFunctions;
-        (_,mn,_) <- env.funDefToMethod(funDef)) {
-
-      val m = cf.addMethod(
-        typeToJVM(funDef.returnType),
-        mn,
-        funDef.args.map(a => typeToJVM(a.tpe)) : _*
-      )
-      m.setFlags((
-        METHOD_ACC_PUBLIC |
-        METHOD_ACC_FINAL |
-        METHOD_ACC_STATIC
-      ).asInstanceOf[U2])
- 
-      CodeGeneration.compileFunDef(funDef, m.codeHandler)
+    CompilationUnit.compileProgram(p) match {
+      case Some(unit) => 
+        unit.writeClassFiles()
+        CompilationResult(successful = true)
+      case None =>
+        CompilationResult(successful = false)
     }
 
-    cf.writeToFile(mainClassName + ".class")
-
-    CompilationResult(successful = true)
   } 
 }
diff --git a/src/main/scala/leon/codegen/CodeGeneration.scala b/src/main/scala/leon/codegen/CodeGeneration.scala
index 9800b10596d1de0c1ee86793e7b79500511126c1..a036dd71b1d6051bcb1578f2af83ff65bf6fe959 100644
--- a/src/main/scala/leon/codegen/CodeGeneration.scala
+++ b/src/main/scala/leon/codegen/CodeGeneration.scala
@@ -46,7 +46,7 @@ object CodeGeneration {
     ch.freeze
   }
 
-  private def mkExpr(e : Expr, ch : CodeHandler)(implicit env : CompilationEnvironment) {
+  private[codegen] def mkExpr(e : Expr, ch : CodeHandler)(implicit env : CompilationEnvironment) {
     e match {
       case Variable(id) =>
         val slot = slotFor(id)
@@ -151,7 +151,7 @@ object CodeGeneration {
     }
   }
 
-  private def mkBranch(cond : Expr, then : String, elze : String, ch : CodeHandler)(implicit env : CompilationEnvironment) {
+  private[codegen] def mkBranch(cond : Expr, then : String, elze : String, ch : CodeHandler)(implicit env : CompilationEnvironment) {
     cond match {
       case BooleanLiteral(true) =>
         ch << Goto(then)
@@ -189,22 +189,22 @@ object CodeGeneration {
         mkExpr(l, ch)
         mkExpr(r, ch)
         ch << If_ICmpLt(then) << Goto(elze) 
-      
+
       case GreaterThan(l,r) =>
         mkExpr(l, ch)
         mkExpr(r, ch)
         ch << If_ICmpGt(then) << Goto(elze) 
-      
+
       case LessEquals(l,r) =>
         mkExpr(l, ch)
         mkExpr(r, ch)
         ch << If_ICmpLe(then) << Goto(elze) 
-      
+
       case GreaterEquals(l,r) =>
         mkExpr(l, ch)
         mkExpr(r, ch)
         ch << If_ICmpGe(then) << Goto(elze) 
-      
+
       // WARNING !!! mkBranch delegates to mkExpr, and mkExpr delegates to mkBranch !
       // That means, between the two of them, they'd better know what to generate !
       case other =>
@@ -213,7 +213,7 @@ object CodeGeneration {
     }
   }
 
-  private def slotFor(id : Identifier)(implicit env : CompilationEnvironment) : Int = {
+  private[codegen] def slotFor(id : Identifier)(implicit env : CompilationEnvironment) : Int = {
     env.varToLocal(id).getOrElse {
       throw CompilationException("Unknown variable : " + id)
     }
diff --git a/src/main/scala/leon/codegen/CompilationUnit.scala b/src/main/scala/leon/codegen/CompilationUnit.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d16128a2246ffaa6309ce11e6ec059ceac6f4158
--- /dev/null
+++ b/src/main/scala/leon/codegen/CompilationUnit.scala
@@ -0,0 +1,133 @@
+package leon
+package codegen
+
+import purescala.Common._
+import purescala.Definitions._
+import purescala.Trees._
+import purescala.TypeTrees._
+
+import cafebabe._
+import cafebabe.AbstractByteCodes._
+import cafebabe.ByteCodes._
+import cafebabe.ClassFileTypes._
+import cafebabe.Flags._
+
+import CodeGeneration._
+
+class CompilationUnit(val p: Program, val mainClass: ClassFile, implicit val env: CompilationEnvironment) {
+  val mainClassName = defToJVMName(p, p.mainObject)
+
+  val loader = new CafebabeClassLoader
+
+  def writeClassFiles() {
+    mainClass.writeToFile(mainClassName + ".class")
+  }
+
+  private var _nextExprId = 0
+  def nextExprId = {
+    _nextExprId += 1
+    _nextExprId
+  }
+
+  def groundExprToJava(e: Expr): AnyRef = {
+    null
+  }
+
+  def javaToGroundExpr(e: AnyRef): Expr = {
+    null
+  }
+
+  def compileExpression(e: Expr, args: Seq[Identifier]): CompiledExpression = {
+
+    val id = nextExprId
+
+    val cName = "Leon$CodeGen$Expr$"+id
+
+    val cf = new ClassFile(cName, None)
+    cf.setFlags((
+      CLASS_ACC_PUBLIC |
+      CLASS_ACC_FINAL
+    ).asInstanceOf[U2])
+
+    cf.addDefaultConstructor
+
+    val m = cf.addMethod(
+      typeToJVM(e.getType),
+      "eval",
+      args.map(a => typeToJVM(a.getType)) : _*
+    )
+
+    m.setFlags((
+      METHOD_ACC_PUBLIC |
+      METHOD_ACC_FINAL |
+      METHOD_ACC_STATIC
+    ).asInstanceOf[U2])
+
+    val ch = m.codeHandler
+
+    val newMapping    = args.zipWithIndex.toMap
+
+    val exprToCompile = purescala.TreeOps.matchToIfThenElse(e)
+
+    mkExpr(e, ch)(env.withVars(newMapping))
+
+    e.getType match {
+      case Int32Type | BooleanType =>
+        ch << IRETURN
+
+      case UnitType | TupleType(_)  | SetType(_) | MapType(_, _) => 
+        ch << ARETURN
+
+      case other =>
+        throw CompilationException("Unsupported return type : " + other)
+    }
+
+    ch.freeze
+
+    loader.register(cf)
+
+    new CompiledExpression(this, cf, args)
+  }
+}
+
+object CompilationUnit {
+  def compileProgram(p: Program): Option[CompilationUnit] = {
+    implicit val env = CompilationEnvironment.fromProgram(p)
+
+    for((parent,children) <- p.algebraicDataTypes) {
+      val acf = compileAbstractClassDef(p, parent)
+      val ccfs = children.map(c => compileCaseClassDef(p, c))
+    } 
+
+    val mainClassName = defToJVMName(p, p.mainObject)
+    val cf = new ClassFile(mainClassName, None)
+    cf.addDefaultConstructor
+
+    cf.setFlags((
+      CLASS_ACC_SUPER |
+      CLASS_ACC_PUBLIC |
+      CLASS_ACC_FINAL
+    ).asInstanceOf[U2])
+
+    // This assumes that all functions of a given program get compiled
+    // as methods of a single class file.
+    for(funDef <- p.definedFunctions;
+        (_,mn,_) <- env.funDefToMethod(funDef)) {
+
+      val m = cf.addMethod(
+        typeToJVM(funDef.returnType),
+        mn,
+        funDef.args.map(a => typeToJVM(a.tpe)) : _*
+      )
+      m.setFlags((
+        METHOD_ACC_PUBLIC |
+        METHOD_ACC_FINAL |
+        METHOD_ACC_STATIC
+      ).asInstanceOf[U2])
+ 
+      compileFunDef(funDef, m.codeHandler)
+    }
+
+    Some(new CompilationUnit(p, cf, env))
+  }
+}
diff --git a/src/main/scala/leon/codegen/CompiledExpression.scala b/src/main/scala/leon/codegen/CompiledExpression.scala
new file mode 100644
index 0000000000000000000000000000000000000000..c14b03c802a6c7d6ae20d3891fcf6d1207ff0af1
--- /dev/null
+++ b/src/main/scala/leon/codegen/CompiledExpression.scala
@@ -0,0 +1,27 @@
+package leon
+package codegen
+
+import purescala.Common._
+import purescala.Definitions._
+import purescala.Trees._
+import purescala.TypeTrees._
+
+import cafebabe._
+import cafebabe.AbstractByteCodes._
+import cafebabe.ByteCodes._
+import cafebabe.ClassFileTypes._
+import cafebabe.Flags._
+
+class CompiledExpression(unit: CompilationUnit, cf: ClassFile, argsDecl: Seq[Identifier]) {
+
+  def eval(args: Seq[Expr]): Expr = {
+    val cl = unit.loader.loadClass(cf.className)
+    val obj = cl.newInstance()
+    val meth = cl.getMethods()(0)
+
+    val res = meth.invoke(obj, args.map(unit.groundExprToJava))
+
+    unit.javaToGroundExpr(res)
+  }
+
+}