diff --git a/src/main/scala/leon/codegen/CodeGenPhase.scala b/src/main/scala/leon/codegen/CodeGenPhase.scala index bdc717c1d37aaf69b3979652016e44cb2dca2572..e2fb321c6dbf9251d0531a0d46c533e412a41bcd 100644 --- a/src/main/scala/leon/codegen/CodeGenPhase.scala +++ b/src/main/scala/leon/codegen/CodeGenPhase.scala @@ -15,15 +15,16 @@ 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) - val cName = programToClassName(p) - - for((p,cs) <- p.algebraicDataTypes) { - // val acf = new ClassFile(p.... + for((parent,children) <- p.algebraicDataTypes) { + val acf = compileAbstractClassDef(p, parent) + val ccfs = children.map(c => compileCaseClassDef(p, c)) } - val cf = new ClassFile(cName, None) + val mainClassName = defToJVMName(p, p.mainObject) + val cf = new ClassFile(mainClassName, None) cf.addDefaultConstructor cf.setFlags(( @@ -51,7 +52,7 @@ object CodeGenPhase extends LeonPhase[Program,CompilationResult] { CodeGeneration.compileFunDef(funDef, m.codeHandler) } - cf.writeToFile(cName + ".class") + 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 47fe2062f74283a11d1e5b4825677a4275ae5498..2410b8025a248b23ede9758628ebc815f83c3045 100644 --- a/src/main/scala/leon/codegen/CodeGeneration.scala +++ b/src/main/scala/leon/codegen/CodeGeneration.scala @@ -7,15 +7,22 @@ import purescala.Trees._ import purescala.TypeTrees._ import cafebabe._ -import cafebabe.ByteCodes._ import cafebabe.AbstractByteCodes._ +import cafebabe.ByteCodes._ +import cafebabe.ClassFileTypes._ +import cafebabe.Flags._ object CodeGeneration { - def programToClassName(p : Program) : String = "Leon$CodeGen$" + p.mainObject.id.uniqueName + def defToJVMName(p : Program, d : Definition) : String = "Leon$CodeGen$" + d.id.uniqueName def typeToJVM(tpe : TypeTree)(implicit env : CompilationEnvironment) : String = tpe match { case Int32Type => "I" + case BooleanType => "Z" + + case c : ClassType => + env.classDefToName(c.classDef).map(n => "L" + n + ";").getOrElse("Unsupported class " + c.id) + case _ => throw CompilationException("Unsupported type : " + tpe) } @@ -170,4 +177,68 @@ object CodeGeneration { throw CompilationException("Unknown variable : " + id) } } + + def compileAbstractClassDef(p : Program, acd : AbstractClassDef)(implicit env : CompilationEnvironment) : ClassFile = { + val cName = defToJVMName(p, acd) + + val cf = new ClassFile(cName, None) + cf.setFlags(( + CLASS_ACC_SUPER | + CLASS_ACC_PUBLIC | + CLASS_ACC_ABSTRACT + ).asInstanceOf[U2]) + + cf.addDefaultConstructor + + //cf.writeToFile(cName + ".class") + cf + } + + def compileCaseClassDef(p : Program, ccd : CaseClassDef)(implicit env : CompilationEnvironment) : ClassFile = { + assert(ccd.hasParent) + + val cName = defToJVMName(p, ccd) + val pName = defToJVMName(p, ccd.parent.get) + + val cf = new ClassFile(cName, Some(pName)) + cf.setFlags(( + CLASS_ACC_SUPER | + CLASS_ACC_PUBLIC | + CLASS_ACC_FINAL + ).asInstanceOf[U2]) + + if(ccd.fields.isEmpty) { + cf.addDefaultConstructor + } else { + val namesTypes = ccd.fields.map { vd => (vd.id.name, typeToJVM(vd.tpe)) } + + for((nme, jvmt) <- namesTypes) { + val fh = cf.addField(jvmt, nme) + fh.setFlags(( + FIELD_ACC_PUBLIC | + FIELD_ACC_FINAL + ).asInstanceOf[U2]) + } + + val cmh = cf.addConstructor(namesTypes.map(_._2).toList).codeHandler + + cmh << ALoad(0) << InvokeSpecial(pName, cafebabe.Defaults.constructorName, "()V") + + var c = 1 + for((nme, jvmt) <- namesTypes) { + cmh << ALoad(0) + cmh << (jvmt match { + case "I" | "Z" => ILoad(c) + case _ => ALoad(c) + }) + cmh << PutField(cName, nme, jvmt) + c += 1 + } + cmh << RETURN + cmh.freeze + } + + //cf.writeToFile(cName + ".class") + cf + } } diff --git a/src/main/scala/leon/codegen/CompilationEnvironment.scala b/src/main/scala/leon/codegen/CompilationEnvironment.scala index 2bec36229355f8f1c82ba171336df49314ea219c..355caea9138420d0c5306effb511b7098107f9e6 100644 --- a/src/main/scala/leon/codegen/CompilationEnvironment.scala +++ b/src/main/scala/leon/codegen/CompilationEnvironment.scala @@ -10,6 +10,8 @@ abstract class CompilationEnvironment() { // - a mapping of function defs to class + method name // - a mapping of class defs to class names // - a mapping of class fields to fields + + def classDefToName(classDef : ClassTypeDef) : Option[String] def funDefToMethod(funDef : FunDef) : Option[(String,String,String)] @@ -18,6 +20,7 @@ abstract class CompilationEnvironment() { /** Augment the environment with new local var. mappings. */ def withVars(pairs : Map[Identifier,Int]) = { new CompilationEnvironment { + def classDefToName(classDef : ClassTypeDef) = self.classDefToName(classDef) def funDefToMethod(funDef : FunDef) = self.funDefToMethod(funDef) def varToLocal(v : Identifier) = pairs.get(v).orElse(self.varToLocal(v)) } @@ -25,20 +28,21 @@ abstract class CompilationEnvironment() { } object CompilationEnvironment { - - lazy val empty = new CompilationEnvironment { - def funDefToMethod(funDef : FunDef) = None - def varToLocal(v : Identifier) = None - } - def fromProgram(p : Program) : CompilationEnvironment = { import CodeGeneration.typeToJVM // This should change: it should contain the case classes before // we go and generate function signatures. - implicit val env = empty + implicit val initial = new CompilationEnvironment { + private val cNames : Map[ClassTypeDef,String] = + p.definedClasses.map(c => (c, CodeGeneration.defToJVMName(p, c))).toMap - val className = CodeGeneration.programToClassName(p) + def classDefToName(classDef : ClassTypeDef) = cNames.get(classDef) + def funDefToMethod(funDef : FunDef) = None + def varToLocal(v : Identifier) = None + } + + val className = CodeGeneration.defToJVMName(p, p.mainObject) val fs = p.definedFunctions.filter(_.hasImplementation) @@ -49,8 +53,8 @@ object CompilationEnvironment { }).toMap new CompilationEnvironment { + def classDefToName(classDef : ClassTypeDef) = initial.classDefToName(classDef) def funDefToMethod(funDef : FunDef) = fMap.get(funDef) - def varToLocal(v : Identifier) = None } } diff --git a/unmanaged/32/cafebabe_2.9.2-1.2.jar b/unmanaged/32/cafebabe_2.9.2-1.2.jar index ccfc6ff432dfbae28dbb6508948a4a87dc52524f..66e18c2577b7570e01e67c4f8cdb94eafd934682 100644 Binary files a/unmanaged/32/cafebabe_2.9.2-1.2.jar and b/unmanaged/32/cafebabe_2.9.2-1.2.jar differ