diff --git a/library/collection/List.scala b/library/collection/List.scala index baf9622fe27a5bfeb8bcb16131d38cd0532c580e..c7a38dc6388be2db68adbf2d4a54fb5d42b1bc24 100644 --- a/library/collection/List.scala +++ b/library/collection/List.scala @@ -493,8 +493,8 @@ sealed abstract class List[T] { } -@ignore object List { + @ignore def apply[T](elems: T*): List[T] = { var l: List[T] = Nil[T]() for (e <- elems) { diff --git a/src/main/scala/leon/codegen/CompilationUnit.scala b/src/main/scala/leon/codegen/CompilationUnit.scala index 8f79149b9eb3290209ede19c6b7afb11410af3f0..f42ce69b468dbd960bb0786b01220448e96a1165 100644 --- a/src/main/scala/leon/codegen/CompilationUnit.scala +++ b/src/main/scala/leon/codegen/CompilationUnit.scala @@ -402,20 +402,23 @@ class CompilationUnit(val ctx: LeonContext, /** Traverses the program to find all definitions, and stores those in global variables */ def init() { // First define all classes/ methods/ functions - for (u <- program.units; m <- u.modules) { - val (parents, children) = m.algebraicDataTypes.toSeq.unzip - for ( cls <- parents ++ children.flatten ++ m.singleCaseClasses) { + for (u <- program.units) { + + val (parents, children) = u.algebraicDataTypes.toSeq.unzip + + for ( cls <- parents ++ children.flatten ++ u.singleCaseClasses) { defineClass(cls) for (meth <- cls.methods) { defToModuleOrClass += meth -> cls } } - defineClass(m) - for(funDef <- m.definedFunctions) { - defToModuleOrClass += funDef -> m + for (m <- u.modules) { + defineClass(m) + for(funDef <- m.definedFunctions) { + defToModuleOrClass += funDef -> m + } } - } } diff --git a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala index cc27bbc3b6c43418f40a065cdcba6ecfc984d374..abe7d0ac0351bb9d2c81208e73daadde207fbfa9 100644 --- a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala +++ b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala @@ -15,6 +15,7 @@ import purescala.Definitions.{ Import => LeonImport, _ } + import purescala.Expressions.{Expr => LeonExpr, This => LeonThis, _} import purescala.Types.{TypeTree => LeonType, _} import purescala.Common._ @@ -85,7 +86,7 @@ trait CodeExtraction extends ASTExtractors { sealed class ImpureCodeEncounteredException(pos: Position, msg: String, ot: Option[Tree]) extends Exception(msg) { def emit() { val debugInfo = if (ctx.findOptionOrDefault(SharedOptions.optDebug) contains utils.DebugSectionTrees) { - ot.map { t => + ot.map { t => val strWr = new java.io.StringWriter() new global.TreePrinter(new java.io.PrintWriter(strWr)).printTree(t) " (Tree: "+strWr.toString+" ; Class: "+t.getClass+")" @@ -111,52 +112,20 @@ trait CodeExtraction extends ASTExtractors { } // Simple case classes to capture the representation of units/modules after discovering them. - case class TempModule(name : Identifier, trees : List[Tree], isStandalone : Boolean) - case class TempUnit( - name : String, - pack : PackageRef, - modules : List[TempModule], + case class ScalaUnit( + name : String, + pack : PackageRef, imports : List[Import], + defs : List[Tree], isPrintable : Boolean - ) - - class Extraction(units: List[CompilationUnit]) { - - private var currentFunDef: FunDef = null - - //This is a bit misleading, if an expr is not mapped then it has no owner, if it is mapped to None it means - //that it can have any owner - private var owners: Map[Identifier, Option[FunDef]] = Map() - - - - def toPureScala(tree: Tree)(implicit dctx: DefContext): Option[LeonExpr] = { - try { - Some(extractTree(tree)) - } catch { - case e: ImpureCodeEncounteredException => - e.emit() - None - } - } + ) - // This one never fails, on error, it returns Untyped - def toPureScalaType(tpt: Type)(implicit dctx: DefContext, pos: Position): LeonType = { - try { - extractType(tpt) - } catch { - case e: ImpureCodeEncounteredException => - e.emit() - Untyped - } - } + class Extraction(units: List[CompilationUnit]) { - case class DefContext( - tparams: Map[Symbol, TypeParameter] = Map(), - vars: Map[Symbol, () => LeonExpr] = Map(), - mutableVars: Map[Symbol, () => LeonExpr] = Map(), - isExtern: Boolean = false - ) { + case class DefContext(tparams: Map[Symbol, TypeParameter] = Map(), + vars: Map[Symbol, () => LeonExpr] = Map(), + mutableVars: Map[Symbol, () => LeonExpr] = Map(), + isExtern: Boolean = false){ def union(that: DefContext) = { copy(this.tparams ++ that.tparams, @@ -180,176 +149,242 @@ trait CodeExtraction extends ASTExtractors { } } - def isIgnored(s: Symbol) = { + private var currentFunDef: FunDef = null + + //This is a bit misleading, if an expr is not mapped then it has no owner, if it is mapped to None it means + //that it can have any owner + private var owners: Map[Identifier, Option[FunDef]] = Map() + + // This one never fails, on error, it returns Untyped + def leonType(tpt: Type)(implicit dctx: DefContext, pos: Position): LeonType = { + try { + extractType(tpt) + } catch { + case e: ImpureCodeEncounteredException => + e.emit() + Untyped + } + } + + private def isIgnored(s: Symbol) = { (annotationsOf(s) contains "ignore") || s.fullName.toString.endsWith(".main") } - - def extractUnits: List[UnitDef] = { + + private def isLibrary(u: CompilationUnit) = Build.libFiles contains u.source.file.absolute.path + + def extractProgram: Option[Program] = { try { - def isLib(u : CompilationUnit) = Build.libFiles contains u.source.file.absolute.path - - val templates: List[TempUnit] = units.reverseMap { u => u.body match { - - // Unit with a single package object - case PackageDef(refTree, List(PackageDef(inner, List(ExObjectDef(n, templ))))) if n == "package" => - // File name without extension - val unitName = extractPackageRef(inner).mkString("$") + "$package" - val id = FreshIdentifier(unitName + "$standalone") - TempUnit(unitName, - extractPackageRef(refTree) ++ extractPackageRef(inner), - List(TempModule(id, templ.body, true)), - imports.getOrElse(refTree, Nil), - !isLib(u) - ) + val scalaUnits = units.map { u => u.body match { + // package object + case PackageDef(refTree, List(PackageDef(inner, body))) => + val name = extractPackageRef(inner).mkString("$") + val pack = extractPackageRef(refTree) ++ extractPackageRef(inner) + val imps = imports.getOrElse(refTree, Nil) + ScalaUnit(name, pack, imps, body, !isLibrary(u)) + + // normal package case pd@PackageDef(refTree, lst) => + val name = u.source.file.name.replaceFirst("[.][^.]+$", "") + val pack = extractPackageRef(refTree) + val imps = imports.getOrElse(refTree, Nil) - var standaloneDefs = List[Tree]() + ScalaUnit(name, pack, imps, lst, !isLibrary(u)) - val modules = lst.flatMap { + case _ => + outOfSubsetError(u.body, "Unnexpected Unit body") + }} - case t if isIgnored(t.symbol) => - None + // Phase 1, we discover and define objects/classes/types + for (unit <- scalaUnits) collectClassSymbols(unit.defs) - case po@ExObjectDef(n, templ) if n == "package" => - outOfSubsetError(po, "No other definitions are allowed in a file with a package object.") + // Phase 2, build scafolding program with empty bodies + val leonUnits = scalaUnits.map { createLeonUnit } - case ExObjectDef(n, templ) if n != "package" => - Some(TempModule(FreshIdentifier(n), templ.body, false)) + // Phase 3, define bodies of all functions/methods + for (unit <- scalaUnits) fillLeonUnit(unit) - /* - case d @ ExCompanionObjectSynthetic(_, sym, templ) => - // Find default param. implementations - templ.body foreach { - case ExDefaultValueFunction(sym, _, _, _, owner, index, _) => - val namePieces = sym.toString.reverse.split("\\$", 3).reverse map { _.reverse } - assert(namePieces.length == 3 && namePieces(0)== "$lessinit$greater" && namePieces(1) == "default") // FIXME : maybe $lessinit$greater? - val index = namePieces(2).toInt - val theParam = sym.companionClass.paramss.head(index - 1) - paramsToDefaultValues += theParam -> body - case _ => - } - None - */ + val pgm0 = Program(leonUnits) - case d@ExAbstractClass(_, _, _) => - standaloneDefs ::= d - None + // Phase 4, resolve imports + val leonUnits1 = for ((sunit, lunit) <- scalaUnits zip leonUnits) yield { + val imports = sunit.imports.flatMap(i => extractImport(i, lunit)(pgm0)) + lunit.copy(imports = imports) + } - case d@ExCaseClass(_, _, _, _) => - standaloneDefs ::= d - None + val pgm1 = Program(leonUnits1) - case d@ExCaseClassSyntheticJunk() => - None + Some(pgm1) + } catch { + case icee: ImpureCodeEncounteredException => + icee.emit() + None + } + } - case cd: ClassDef => - outOfSubsetError(cd, "Found class that is not an abstract class nor a case class") - None + private def collectClassSymbols(defs: List[Tree]) { + // We collect all defined classes + for (t <- defs) t match { + case t if isIgnored(t.symbol) => + // ignore - case other => - outOfSubsetError(other, "Expected: top-level object/class.") - None - } + case ExAbstractClass(o2, sym, tmpl) => + seenClasses += sym -> ((Nil, tmpl)) - // File name without extension - val unitName = u.source.file.name.replaceFirst("[.][^.]+$", "") - val finalModules = - if (standaloneDefs.isEmpty) modules - else { - val id = FreshIdentifier(unitName + "$standalone") - TempModule(id, standaloneDefs, true) :: modules - } + case ExCaseClass(o2, sym, args, tmpl) => + seenClasses += sym -> ((args, tmpl)) - TempUnit(unitName, - extractPackageRef(refTree), - finalModules, - imports.getOrElse(refTree, Nil), - !isLib(u) - ) - }} + case ExObjectDef(n, templ) => + for (t <- templ.body) t match { + case t if isIgnored(t.symbol) => + // ignore - // Phase 1, we detect objects/classes/types - for (temp <- templates; mod <- temp.modules) collectClassSymbols(mod.trees) - - // Phase 2, we collect functions signatures - for (temp <- templates; mod <- temp.modules) collectFunSigs(mod.trees) + case ExAbstractClass(_, sym, tmpl) => + seenClasses += sym -> ((Nil, tmpl)) - // Phase 3, we collect classes/types' definitions - for (temp <- templates; mod <- temp.modules) extractClassDefs(mod.trees) + case ExCaseClass(_, sym, args, tmpl) => + seenClasses += sym -> ((args, tmpl)) - // Phase 4, we collect methods' definitions - for (temp <- templates; mod <- temp.modules) extractMethodDefs(mod.trees) + case _ => + } - // Phase 5, we collect function definitions - for (temp <- templates; mod <- temp.modules) extractFunDefs(mod.trees) + case _ => + } + } - // Phase 6, we create modules and extract bodies - for (temp <- templates; mod <- temp.modules) extractObjectDef(mod.name, mod.trees, mod.isStandalone) - - // Phase 7, we wrap modules in units - // We first form the units without valid imports - val withoutImports = for (TempUnit(name,pack,mods,imps,isPrintable) <- templates) yield { - ( UnitDef( - FreshIdentifier(name), - for( TempModule(nm,_,_) <- mods) yield objects2Objects(nm), - pack, Nil, isPrintable - ) - , imps - ) - } - - // Just doing this so everything is in the same program and searches work properly - val _ = Program(FreshIdentifier("__program"), withoutImports map { _._1 }) - - // With the aid of formed units, we extract the correct imports - val objPerPack = objects2Objects map { _._2 } groupBy { packageOf(_)} - withoutImports map { case (u, imps) => - u.copy(imports = { - // Extract imports from source - val extracted = imps flatMap { extractImport(_, u,withoutImports map { _._1}) } - // Add extra imports for contents of standalone objects - val packs = u.pack :: extracted. collect { case PackageImport(pack) => pack } - val additional = objPerPack. collect { - case (p,obs) if packs contains p => - obs filter { _.isStandalone} map WildcardImport - }.flatten - extracted ++ additional - }) - } + private def createLeonUnit(u: ScalaUnit): UnitDef = { + val ScalaUnit(name, pack, imports, defs, isPrintable) = u - } catch { - case icee: ImpureCodeEncounteredException => - icee.emit() - Nil - } + val leonDefs = defs flatMap { t => t match { + case t if isIgnored(t.symbol) => + // ignore + None + + case ExAbstractClass(o2, sym, _) => + Some(getClassDef(sym, t.pos)) + + case ExCaseClass(o2, sym, args, _) => + Some(getClassDef(sym, t.pos)) + + case ExObjectDef(n, templ) => + // Module + val id = FreshIdentifier(n) + val leonDefs = templ.body.flatMap { t => t match { + case t if isIgnored(t.symbol) => + // ignore + None + + case ExAbstractClass(_, sym, _) => + Some(getClassDef(sym, t.pos)) + + case ExCaseClass(_, sym, _, _) => + Some(getClassDef(sym, t.pos)) + + // Functions + case ExFunctionDef(sym, _, _, _, _) => + Some(defineFunDef(sym)(DefContext())) + + // Default value functions + case ExDefaultValueFunction(sym, _, _, _ ,_ , _, _) => + val fd = defineFunDef(sym)(DefContext()) + fd.addAnnotation("synthetic") + + Some(fd) + + // Lazy vals + case ExLazyAccessorFunction(sym, _, _) => + Some(defineFieldFunDef(sym, true)(DefContext())) + + // Normal vals + case ExFieldDef(sym, _, _) => + Some(defineFieldFunDef(sym, false)(DefContext())) + + case ExCaseClassSyntheticJunk() => None + case ExConstructorDef() => None + case ExLazyFieldDef() => None + case ExFieldAccessorFunction() => None + case d if (d.symbol.isImplicit && d.symbol.isSynthetic) => None + case tree => + println(tree) + outOfSubsetError(tree, "Don't know what to do with this. Not purescala?"); + }} + Some(LeonModuleDef(id, leonDefs, id.name == "package")) + + case ExCaseClassSyntheticJunk() => None + case ExConstructorDef() => None + case d if (d.symbol.isImplicit && d.symbol.isSynthetic) => None + case tree => + println(tree) + outOfSubsetError(tree, "Don't know what to do with this. Not purescala?"); + }} + + // we only resolve imports once we have the full program + UnitDef(FreshIdentifier(name), pack, Nil, leonDefs, isPrintable) } - - - - private def getSelectChain(e : Tree) : List[String] = { - def rec (e : Tree) : List[Name] = e match { + + private def fillLeonUnit(u: ScalaUnit): Unit = { + for (t <- u.defs) t match { + case t if isIgnored(t.symbol) => + // ignore + + case ExAbstractClass(_, sym, tpl) => + for (t <- tpl.body) { + extractFunOrMethodBody(Some(sym), t) + } + + case ExCaseClass(_, sym, _, tpl) => + for (t <- tpl.body) { + extractFunOrMethodBody(Some(sym), t) + } + + case ExObjectDef(n, templ) => + for (t <- templ.body) t match { + case t if isIgnored(t.symbol) => + // ignore + None + + case ExAbstractClass(_, sym, tpl) => + for (t <- tpl.body) { + extractFunOrMethodBody(Some(sym), t) + } + + case ExCaseClass(_, sym, _, tpl) => + for (t <- tpl.body) { + extractFunOrMethodBody(Some(sym), t) + } + + case t => + extractFunOrMethodBody(None, t) + + } + case _ => + } + } + + private def getSelectChain(e: Tree): List[String] = { + def rec(e: Tree): List[Name] = e match { case Select(q, name) => name :: rec(q) case Ident(name) => List(name) case EmptyTree => List() - case _ => ctx.reporter.internalError("getSelectChain: unexpected Tree:\n" + e.toString) - } + case _ => + ctx.reporter.internalError("getSelectChain: unexpected Tree:\n" + e.toString) + } rec(e).reverseMap(_.toString) } - - private def extractPackageRef(refPath : RefTree) : PackageRef = - (getSelectChain(refPath.qualifier) :+ refPath.name.toString) match { - // Make sure to drop "<empty>" package - case List("<empty>") => List() - case other => other - } - - private def extractImport(i : Import, current : UnitDef, units : List[UnitDef]) : Seq[ LeonImport ] = i match { case Import(expr, sels) => + + private def extractPackageRef(refPath: RefTree): PackageRef = { + (getSelectChain(refPath.qualifier) :+ refPath.name.toString).filter(_ != "<empty>") + } + + private def extractImport(i: Import, current: UnitDef)(implicit pgm: Program): Seq[LeonImport] = { + val Import(expr, sels) = i import DefOps._ - - val prefix = getSelectChain(expr) + + val prefix = getSelectChain(expr) + val allSels = sels map { prefix :+ _.name.toString } + // Make a different import for each selector at the end of the chain allSels flatMap { selectors => assert(selectors.nonEmpty) @@ -357,14 +392,14 @@ trait CodeExtraction extends ASTExtractors { case "_" => (selectors.dropRight(1), true) case _ => (selectors, false) } - - val theDef = searchByFullNameRelative(thePath mkString ".", current, reliableVisibility = false) - + + val theDef = searchRelative(thePath.mkString("."), current).headOption + (isWild, theDef) match { - case (true, Some(df)) => Some(WildcardImport(df)) - case (false,Some(df)) => Some(SingleImport(df)) - case (true, None) => Some(PackageImport(thePath)) - case (false,None) => None // import comes from a Scala library or something... + case (true, Some(df)) => Some(WildcardImport(df)) + case (false, Some(df)) => Some(SingleImport(df)) + case (true, None) => Some(PackageImport(thePath)) + case (false, None) => None // import comes from a Scala library or something... } } } @@ -396,40 +431,10 @@ trait CodeExtraction extends ASTExtractors { outOfSubsetError(pos, "Class "+className+" is not a case class") } } - - private var paramsToDefaultValues = Map[Symbol,FunDef]() - private def collectClassSymbols(defs: List[Tree]) { - // We collect all defined classes - for (t <- defs) t match { - case t if isIgnored(t.symbol) => - // ignore - - case ExAbstractClass(o2, sym, tmpl) => - seenClasses += sym -> ((Nil, tmpl)) - - case ExCaseClass(o2, sym, args, tmpl) => - seenClasses += sym -> ((args, tmpl)) - case _ => - } - } - - private def extractClassDefs(defs: List[Tree]) { - // We collect all defined classes - for (t <- defs) t match { - case t if isIgnored(t.symbol) => - // ignore - - case ExAbstractClass(o2, sym, _) => - getClassDef(sym, t.pos) - - case ExCaseClass(o2, sym, args, _) => - getClassDef(sym, t.pos) + private var paramsToDefaultValues = Map[Symbol,FunDef]() - case _ => - } - } def getClassDef(sym: Symbol, pos: Position): LeonClassDef = { classesToClasses.get(sym) match { @@ -440,9 +445,6 @@ trait CodeExtraction extends ASTExtractors { extractClassDef(sym, args, tmpl) } else { - if (sym.name.toString == "synthesis") { - new Exception().printStackTrace() - } outOfSubsetError(pos, "Class "+sym.fullName+" not defined?") } } @@ -471,7 +473,7 @@ trait CodeExtraction extends ASTExtractors { ) { // Search tmpl to find the function that includes this parameter val paramOwner = defs.collectFirst(matcher).get - + // assumes single argument list if(paramOwner.paramss.length != 1) { outOfSubsetError(paramOwner.pos, "Multiple argument lists for a function are not allowed") @@ -479,8 +481,7 @@ trait CodeExtraction extends ASTExtractors { val theParam = paramOwner.paramss.head(index) paramsToDefaultValues += (theParam -> fd) } - - + def extractClassDef(sym: Symbol, args: Seq[(Symbol, ValDef)], tmpl: Template): LeonClassDef = { val id = FreshIdentifier(sym.name.toString).setPos(sym.pos) @@ -527,7 +528,7 @@ trait CodeExtraction extends ASTExtractors { val fields = args.map { case (symbol, t) => val tpt = t.tpt - val tpe = toPureScalaType(tpt.tpe)(defCtx, sym.pos) + val tpe = leonType(tpt.tpe)(defCtx, sym.pos) LeonValDef(FreshIdentifier(symbol.name.toString, tpe).setPos(t.pos)).setPos(t.pos) } @@ -577,45 +578,47 @@ trait CodeExtraction extends ASTExtractors { cd.registerMethod(fd) // Default values for parameters - case t@ ExDefaultValueFunction(fsym, _, _, _, owner, index, _) => + case t@ ExDefaultValueFunction(fsym, _, _, _, owner, index, _) => val fd = defineFunDef(fsym)(defCtx) fd.addAnnotation("synthetic") - + isMethod += fsym methodToClass += fd -> cd - cd.registerMethod(fd) - val matcher : PartialFunction[Tree, Symbol] = { + cd.registerMethod(fd) + val matcher: PartialFunction[Tree, Symbol] = { case ExFunctionDef(ownerSym, _ ,_ ,_, _) if ownerSym.name.toString == owner => ownerSym - } + } registerDefaultMethod(tmpl.body, matcher, index, fd ) - - + // Lazy fields case t @ ExLazyAccessorFunction(fsym, _, _) => if (parent.isDefined) { - outOfSubsetError(t, "Only hierarchy roots can define lazy fields") + outOfSubsetError(t, "Only hierarchy roots can define lazy fields") } + val fd = defineFieldFunDef(fsym, true)(defCtx) isMethod += fsym methodToClass += fd -> cd cd.registerMethod(fd) - + // normal fields case t @ ExFieldDef(fsym, _, _) => - // we will be using the accessor method of this field everywhere - val fsymAsMethod = fsym if (parent.isDefined) { outOfSubsetError(t, "Only hierarchy roots can define fields") } + + // we will be using the accessor method of this field everywhere + val fsymAsMethod = fsym val fd = defineFieldFunDef(fsymAsMethod, false)(defCtx) isMethod += fsymAsMethod methodToClass += fd -> cd cd.registerMethod(fd) + case _ => } @@ -631,7 +634,7 @@ trait CodeExtraction extends ASTExtractors { val nctx = dctx.copy(tparams = dctx.tparams ++ tparams.toMap) val newParams = sym.info.paramss.flatten.map{ sym => - val ptpe = toPureScalaType(sym.tpe)(nctx, sym.pos) + val ptpe = leonType(sym.tpe)(nctx, sym.pos) val newID = FreshIdentifier(sym.name.toString, ptpe).setPos(sym.pos) owners += (newID -> None) LeonValDef(newID).setPos(sym.pos) @@ -639,7 +642,7 @@ trait CodeExtraction extends ASTExtractors { val tparamsDef = tparams.map(t => TypeParameterDef(t._2)) - val returnType = toPureScalaType(sym.info.finalResultType)(nctx, sym.pos) + val returnType = leonType(sym.info.finalResultType)(nctx, sym.pos) val name = sym.name.toString @@ -658,160 +661,83 @@ trait CodeExtraction extends ASTExtractors { val nctx = dctx.copy(tparams = dctx.tparams) - val returnType = toPureScalaType(sym.info.finalResultType)(nctx, sym.pos) + val returnType = leonType(sym.info.finalResultType)(nctx, sym.pos) val name = sym.name.toString val fieldType = if (isLazy) DefType.LazyFieldDef else DefType.StrictFieldDef - + val fd = new FunDef(FreshIdentifier(name).setPos(sym.pos), Seq(), returnType, Seq(), fieldType) fd.setPos(sym.pos) fd.addAnnotation(annotationsOf(sym).toSeq : _*) - + defsToDefs += sym -> fd fd } - - - - private def collectFunSigs(defs: List[Tree]) = { - // We collect defined function bodies - for (d <- defs) d match { - case t if isIgnored(t.symbol) => - //ignore - case ExFunctionDef(sym, _, _, _, _) => - defineFunDef(sym)(DefContext()) - - case t @ ExDefaultValueFunction(sym, _, _, _, owner, index, _) => { - - val fd = defineFunDef(sym)(DefContext()) - fd.addAnnotation("synthetic") - val matcher : PartialFunction[Tree, Symbol] = { - case ExFunctionDef(ownerSym, _ ,_ ,_, _) if ownerSym.name.toString == owner => ownerSym - } - registerDefaultMethod(defs, matcher, index, fd) - - } - case ExLazyAccessorFunction(sym, _, _) => - defineFieldFunDef(sym,true)(DefContext()) - - case ExFieldDef(sym, _, _) => - defineFieldFunDef(sym, false)(DefContext()) - - case _ => - } - } + private def extractFunOrMethodBody(ocsym: Option[Symbol], t: Tree) { - private def extractMethodDefs(defs: List[Tree]) = { - // We collect defined function bodies - def extractFromClass(csym: Symbol, tmpl: Template) { - val cd = classesToClasses(csym) + val ctparamsMap = ocsym match { + case Some(csym) => + val cd = classesToClasses(csym) - val ctparams = csym.tpe match { - case TypeRef(_, _, tps) => - extractTypeParams(tps).map(_._1) - case _ => - Nil - } - - val ctparamsMap = ctparams zip cd.tparams.map(_.tp) - - for (d <- tmpl.body) d match { - case t if isIgnored(t.symbol) => - //ignore - - case ExFunctionDef(sym, tparams, params, _, body) => - val fd = defsToDefs(sym) - - val tparamsMap = (tparams zip fd.tparams.map(_.tp)).toMap ++ ctparamsMap - - if(body != EmptyTree) { - extractFunBody(fd, params, body)(DefContext(tparamsMap)) - } - - // Default value functions - case ExDefaultValueFunction(sym, tparams, params, _, _, _, body) => - val fd = defsToDefs(sym) - - val tparamsMap = (tparams zip fd.tparams.map(_.tp)).toMap ++ ctparamsMap - - if(body != EmptyTree) { - extractFunBody(fd, params, body)(DefContext(tparamsMap)) - } - - // Lazy fields - case t @ ExLazyAccessorFunction(sym, _, body) => - val fd = defsToDefs(sym) - val tparamsMap = ctparamsMap - - if(body != EmptyTree) { - extractFunBody(fd, Seq(), body)(DefContext(tparamsMap.toMap)) - } - - // normal fields - case t @ ExFieldDef(sym, _, body) => // if !sym.isSynthetic && !sym.isAccessor => - val fd = defsToDefs(sym) - val tparamsMap = ctparamsMap - - if(body != EmptyTree) { - extractFunBody(fd, Seq(), body)(DefContext(tparamsMap.toMap)) - } - - case _ => - - } - } - for (d <- defs) d match { - case t if isIgnored(t.symbol) => - // ignore - - case ExAbstractClass(_, csym, tmpl) => - extractFromClass(csym, tmpl) + val ctparams = csym.tpe match { + case TypeRef(_, _, tps) => + extractTypeParams(tps).map(_._1) + case _ => + Nil + } - case ExCaseClass(_, csym, _, tmpl) => - extractFromClass(csym, tmpl) + ctparams zip cd.tparams.map(_.tp) - case _ => + case None => + Map[Symbol, TypeParameter]() } - } - private def extractFunDefs(defs: List[Tree]) = { - // We collect defined function bodies - for (d <- defs) d match { + t match { case t if isIgnored(t.symbol) => - // ignore + //ignore - case ExFunctionDef(sym, tparams, params, _, body) => - // Methods val fd = defsToDefs(sym) - val tparamsMap = (tparams zip fd.tparams.map(_.tp)).toMap + val tparamsMap = (tparams zip fd.tparams.map(_.tp)).toMap ++ ctparamsMap - extractFunBody(fd, params, body)(DefContext(tparamsMap)) + if(body != EmptyTree) { + extractFunBody(fd, params, body)(DefContext(tparamsMap)) + } - case ExDefaultValueFunction(sym, tparams, params, _ ,_ , _, body) => - // Default value functions + // Default value functions + case ExDefaultValueFunction(sym, tparams, params, _, _, _, body) => val fd = defsToDefs(sym) - val tparamsMap = (tparams zip fd.tparams.map(_.tp)).toMap + val tparamsMap = (tparams zip fd.tparams.map(_.tp)).toMap ++ ctparamsMap - extractFunBody(fd, params, body)(DefContext(tparamsMap)) - - case ExLazyAccessorFunction(sym, _, body) => - // Lazy vals + if(body != EmptyTree) { + extractFunBody(fd, params, body)(DefContext(tparamsMap)) + } + + // Lazy fields + case t @ ExLazyAccessorFunction(sym, _, body) => val fd = defsToDefs(sym) - extractFunBody(fd, Seq(), body)(DefContext()) + val tparamsMap = ctparamsMap - case ExFieldDef(sym, tpe, body) => - // Normal vals + if(body != EmptyTree) { + extractFunBody(fd, Seq(), body)(DefContext(tparamsMap.toMap)) + } + + // normal fields + case t @ ExFieldDef(sym, _, body) => // if !sym.isSynthetic && !sym.isAccessor => val fd = defsToDefs(sym) - extractFunBody(fd, Seq(), body)(DefContext()) - + val tparamsMap = ctparamsMap + + if(body != EmptyTree) { + extractFunBody(fd, Seq(), body)(DefContext(tparamsMap.toMap)) + } + case _ => } } @@ -826,71 +752,22 @@ trait CodeExtraction extends ASTExtractors { } } - var objects2Objects = Map[Identifier, LeonModuleDef]() - - private def extractObjectDef(id : Identifier, defs: List[Tree], isStandalone : Boolean) { - - val newDefs = defs.flatMap { - case t if isIgnored(t.symbol) => - None - - case ExAbstractClass(o2, sym, _) => - Some(classesToClasses(sym)) - - case ExCaseClass(o2, sym, args, _) => - Some(classesToClasses(sym)) - - // Taking accessor functions will duplicate work for strict fields, but we need them in case of lazy fields - case ExFunctionDef(sym, tparams, params, _, body) => - Some(defsToDefs(sym)) - case ExDefaultValueFunction(sym, _, _, _, _, _, _) => - Some(defsToDefs(sym)) - case ExLazyAccessorFunction(sym, _, _) => - Some(defsToDefs(sym)) - case ExFieldDef(sym, _, _) => - Some(defsToDefs(sym)) - - case _ => - None - } - - // We check nothing else is polluting the object - for (t <- defs) t match { - case ExCaseClassSyntheticJunk() => - case ExAbstractClass(_,_,_) => - case ExCaseClass(_,_,_,_) => - case ExConstructorDef() => - case ExFunctionDef(_, _, _, _, _) => - case ExLazyAccessorFunction(_, _, _) => - case ExDefaultValueFunction(_, _, _, _, _, _, _ ) => - case ExFieldDef(_,_,_) => - case ExLazyFieldDef() => - case ExFieldAccessorFunction() => - case d if isIgnored(d.symbol) || (d.symbol.isImplicit && d.symbol.isSynthetic) => - case tree => - println(tree) - outOfSubsetError(tree, "Don't know what to do with this. Not purescala?"); - } - - objects2Objects += id -> LeonModuleDef(id, newDefs, isStandalone) - } - + //var objects2Objects = Map[Identifier, LeonModuleDef]() private def extractFunBody(funDef: FunDef, params: Seq[ValDef], body0 : Tree)(dctx: DefContext): FunDef = { currentFunDef = funDef - + // Find defining function for params with default value for ((s,vd) <- params zip funDef.params) { vd.defaultValue = paramsToDefaultValues.get(s.symbol) } - + val newVars = for ((s, vd) <- params zip funDef.params) yield { s.symbol -> (() => Variable(vd.id)) } val fctx = dctx.withNewVars(newVars).copy(isExtern = funDef.annotations("extern")) - // If this is a lazy field definition, drop the assignment/ accessing val body = if (funDef.defType == DefType.LazyFieldDef) { body0 match { @@ -928,7 +805,7 @@ trait CodeExtraction extends ASTExtractors { NoTree(funDef.returnType) } - funDef.fullBody = finalBody + funDef.fullBody = finalBody // Post-extraction sanity checks @@ -951,12 +828,12 @@ trait CodeExtraction extends ASTExtractors { private def extractPattern(p: Tree, binder: Option[Identifier] = None)(implicit dctx: DefContext): (Pattern, DefContext) = p match { case b @ Bind(name, t @ Typed(pat, tpt)) => - val newID = FreshIdentifier(name.toString, extractType(tpt)).setPos(b.pos).setOwner(currentFunDef) + val newID = FreshIdentifier(name.toString, extractType(tpt)).setPos(b.pos) val pctx = dctx.withNewVar(b.symbol -> (() => Variable(newID))) extractPattern(t, Some(newID))(pctx) case b @ Bind(name, pat) => - val newID = FreshIdentifier(name.toString, extractType(b)).setPos(b.pos).setOwner(currentFunDef) + val newID = FreshIdentifier(name.toString, extractType(b)).setPos(b.pos) val pctx = dctx.withNewVar(b.symbol -> (() => Variable(newID))) extractPattern(pat, Some(newID))(pctx) @@ -1077,7 +954,7 @@ trait CodeExtraction extends ASTExtractors { val closure = post.getType match { case BooleanType => - val resId = FreshIdentifier("res", b.getType).setPos(post).setOwner(currentFunDef) + val resId = FreshIdentifier("res", b.getType).setPos(post) Lambda(Seq(LeonValDef(resId)), post).setPos(post) case _ => post } @@ -1085,7 +962,7 @@ trait CodeExtraction extends ASTExtractors { Ensuring(b, closure) case t @ ExHoldsExpression(body) => - val resId = FreshIdentifier("holds", BooleanType).setPos(current.pos).setOwner(currentFunDef) + val resId = FreshIdentifier("holds", BooleanType).setPos(current.pos) val post = Lambda(Seq(LeonValDef(resId)), Variable(resId)).setPos(current.pos) val b = extractTreeOrNoTree(body) @@ -1158,7 +1035,7 @@ trait CodeExtraction extends ASTExtractors { case ExValDef(vs, tpt, bdy) => val binderTpe = extractType(tpt) - val newID = FreshIdentifier(vs.name.toString, binderTpe).setOwner(currentFunDef) + val newID = FreshIdentifier(vs.name.toString, binderTpe) val valTree = extractTree(bdy) if(valTree.getType.isInstanceOf[ArrayType]) { @@ -1193,7 +1070,7 @@ trait CodeExtraction extends ASTExtractors { val oldCurrentFunDef = currentFunDef - val funDefWithBody = extractFunBody(fd, params, b)(newDctx.copy(mutableVars = Map())).setOwner(oldCurrentFunDef) + val funDefWithBody = extractFunBody(fd, params, b)(newDctx.copy(mutableVars = Map())) currentFunDef = oldCurrentFunDef @@ -1212,7 +1089,7 @@ trait CodeExtraction extends ASTExtractors { case ExVarDef(vs, tpt, bdy) => { val binderTpe = extractType(tpt) - val newID = FreshIdentifier(vs.name.toString, binderTpe).setOwner(currentFunDef) + val newID = FreshIdentifier(vs.name.toString, binderTpe) val valTree = extractTree(bdy) if(valTree.getType.isInstanceOf[ArrayType]) { @@ -1349,7 +1226,7 @@ trait CodeExtraction extends ASTExtractors { val newOracles = oracles map { case (tpt, sym) => val aTpe = extractType(tpt) val oTpe = oracleType(ops.pos, aTpe) - val newID = FreshIdentifier(sym.name.toString, oTpe).setOwner(currentFunDef) + val newID = FreshIdentifier(sym.name.toString, oTpe) owners += (newID -> None) newID } diff --git a/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala b/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala index c4131034a5c215890de58a4042f9dff945f969ec..461f145019edf1c136e896065d8402174052099b 100644 --- a/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala +++ b/src/main/scala/leon/frontends/scalac/ExtractionPhase.scala @@ -69,8 +69,13 @@ object ExtractionPhase extends LeonPhase[List[String], Program] { compiler.leonExtraction.setImports(compiler.saveImports.imports ) - val pgm = Program(FreshIdentifier("__program"), compiler.leonExtraction.compiledUnits) - pgm + compiler.leonExtraction.compiledProgram match { + case Some(pgm) => + pgm + + case None => + ctx.reporter.fatalError("Failed to extract Leon program.") + } } else { ctx.reporter.fatalError("No input program.") } diff --git a/src/main/scala/leon/frontends/scalac/LeonExtraction.scala b/src/main/scala/leon/frontends/scalac/LeonExtraction.scala index fbb0f598058a5286666b80176ffbd0e975ea84ee..1de899e28f9e0e8a755bc48d3047a87ec947fcda 100644 --- a/src/main/scala/leon/frontends/scalac/LeonExtraction.scala +++ b/src/main/scala/leon/frontends/scalac/LeonExtraction.scala @@ -20,8 +20,8 @@ trait LeonExtraction extends SubComponent with CodeExtraction { this.imports = imports } - def compiledUnits = { - new Extraction(units).extractUnits + def compiledProgram = { + new Extraction(units).extractProgram } def newPhase(prev: scala.tools.nsc.Phase): StdPhase = new Phase(prev) diff --git a/src/main/scala/leon/purescala/DefOps.scala b/src/main/scala/leon/purescala/DefOps.scala index a9796942b62f452c3eb02a742279075bf66210c6..7817438dfd039b751d09aef633f5aa6b0bc62634 100644 --- a/src/main/scala/leon/purescala/DefOps.scala +++ b/src/main/scala/leon/purescala/DefOps.scala @@ -8,75 +8,77 @@ import ExprOps.{preMap, postMap, functionCallsOf} object DefOps { - def packageOf(df: Definition): PackageRef = { + def packageOf(df: Definition)(implicit pgm: Program): PackageRef = { df match { case _ : Program => List() - case u : UnitDef => u.pack - case _ => df.owner map packageOf getOrElse List() + case u : UnitDef => u.pack + case _ => unitOf(df).map(_.pack).getOrElse(List()) } } - def unitOf(df: Definition): Option[UnitDef] = df match { + def unitOf(df: Definition)(implicit pgm: Program): Option[UnitDef] = df match { case p : Program => None case u : UnitDef => Some(u) - case other => other.owner flatMap unitOf + case other => pgm.units.find(_.containsDef(df)) } - def moduleOf(df: Definition): Option[ModuleDef] = df match { + def moduleOf(df: Definition)(implicit pgm: Program): Option[ModuleDef] = df match { case p : Program => None case m : ModuleDef => Some(m) - case other => other.owner flatMap moduleOf - } - - def programOf(df: Definition): Option[Program] = { - df match { - case p : Program => Some(p) - case other => other.owner flatMap programOf + case other => unitOf(df).flatMap { u => + u.modules.find(_.containsDef(df)) } } - def pathFromRoot(df: Definition): List[Definition] ={ - def rec(df : Definition) : List[Definition] = df.owner match { - case Some(owner) => df :: rec(owner) - case None => List(df) - } - rec(df).reverse + def pathFromRoot(df: Definition)(implicit pgm: Program): List[Definition] ={ + def rec(from: Definition): List[Definition] = { + from :: (if (from == df) { + Nil + } else { + from.subDefinitions.find { sd => (sd eq df) || sd.containsDef(df) } match { + case Some(sd) => + rec(sd) + case None => + Nil + } + }) + } + rec(pgm) } - def unitsInPackage(p: Program, pack : PackageRef) = p.units filter { _.pack == pack } + def unitsInPackage(p: Program, pack: PackageRef) = p.units filter { _.pack == pack } - def isImportedBy(df : Definition, i : Import) : Boolean = - i.importedDefs contains df + //def isImportedBy(df: Definition, i: Import) : Boolean = { + // i.importedDefs contains df + //} - def isImportedBy(df : Definition, is: Seq[Import]) : Boolean = - is exists {isImportedBy(df,_)} + //def isImportedBy(df : Definition, is: Seq[Import]) : Boolean = { + // is exists {isImportedBy(df,_)} + //} - def leastCommonAncestor(df1 : Definition, df2 : Definition) : Definition = { - (pathFromRoot(df1) zip pathFromRoot(df2)) - .takeWhile{case (df1,df2) => df1 eq df2} - .last._1 + def leastCommonAncestor(df1: Definition, df2: Definition)(implicit pgm: Program): Definition = { + (pathFromRoot(df1) zip pathFromRoot(df2)).takeWhile { + case (df1, df2) => df1 eq df2 + }.last._1 } /** Returns the set of definitions directly visible from the current definition * Definitions that are shadowed by others are not returned. */ - def visibleDefsFrom(df : Definition) : Set[Definition] = { + def visibleDefsFrom(df: Definition)(implicit pgm: Program): Set[Definition] = { var toRet = Map[String,Definition]() val asList = (pathFromRoot(df).reverse flatMap { _.subDefinitions }) ++ { - programOf(df) match { - case None => List() - case Some(p) => unitsInPackage(p, packageOf(df)) flatMap { _.subDefinitions } - } + unitsInPackage(pgm, packageOf(df)) flatMap { _.subDefinitions } } ++ - programOf(df).toList ++ + List(pgm) ++ ( for ( u <- unitOf(df).toSeq; imp <- u.imports; impDf <- imp.importedDefs - ) yield impDf + ) yield impDf ) - for ( + for ( df <- asList; name = df.id.toString ) { @@ -85,30 +87,31 @@ object DefOps { toRet.values.toSet } - def visibleFunDefsFrom(df: Definition): Set[FunDef] = { + def visibleFunDefsFrom(df: Definition)(implicit pgm: Program): Set[FunDef] = { visibleDefsFrom(df).collect { case fd: FunDef => fd } } - def funDefsFromMain(p: Program): Set[FunDef] = { - p.units.filter(_.isMainUnit).toSet.flatMap{ (u: UnitDef) => + def funDefsFromMain(implicit pgm: Program): Set[FunDef] = { + pgm.units.filter(_.isMainUnit).toSet.flatMap{ (u: UnitDef) => u.definedFunctions } } - def visibleFunDefsFromMain(p: Program): Set[FunDef] = { + def visibleFunDefsFromMain(implicit p: Program): Set[FunDef] = { p.units.filter(_.isMainUnit).toSet.flatMap{ (u: UnitDef) => visibleFunDefsFrom(u) ++ u.definedFunctions } } /** Returns true for strict superpackage */ - def isSuperPackageOf(p1:PackageRef, p2 : PackageRef) = - (p2.length > p1.length) && + def isSuperPackageOf(p1:PackageRef, p2 : PackageRef) = { + (p2.length > p1.length) && ( (p1 zip p2 takeWhile { case (n1,n2) => n1 == n2 }).length == p1.length ) - - def packageAsVisibleFrom(df : Definition, p : PackageRef) = { + } + + def packageAsVisibleFrom(df: Definition, p: PackageRef)(implicit pgm: Program) = { val visiblePacks = packageOf(df) +: (unitOf(df).toSeq.flatMap(_.imports) collect { case PackageImport(pack) => pack }) val bestSuper = visiblePacks filter { pack => pack == p || isSuperPackageOf(pack,p)} match { @@ -118,8 +121,8 @@ object DefOps { p drop bestSuper.length } - // This assumes base and target are in the same program - def pathAsVisibleFrom(base : Definition, target : Definition) : (PackageRef, List[Definition]) = { + /* + private def pathAsVisibleFrom(base: Definition, target: Definition)(implicit pgm: Program): (PackageRef, List[Definition]) = { val rootPath = pathFromRoot(target) val ancestor = leastCommonAncestor(base, target) val pth = rootPath dropWhile { _.owner != Some(ancestor) } @@ -137,20 +140,136 @@ object DefOps { (pack, finalPath) } + */ + + private def pathToString(path: List[Definition]): String = { + val expandPack = path.flatMap { + case p: Program => + Nil + case u: UnitDef => + u.pack + case m: ModuleDef if m.isPackageObject => + Nil + case d => + List(d.id.name) + } + + expandPack.mkString(".") + } + + def fullName(df: Definition)(implicit pgm: Program): String = { + pathToString(pathFromRoot(df)) + } + + private def nameToParts(name: String) = { + name.split("\\.").toList map scala.reflect.NameTransformer.encode + } + + def searchWithin(name: String, within: Definition): Seq[Definition] = { + searchWithin(nameToParts(name), within) + } - def fullName(df: Definition, fromProgram: Option[Program] = None): String = - fromProgram orElse programOf(df) match { - case None => df.id.name - case Some(p) => - val (pr, ds) = pathAsVisibleFrom(p, df) - - (pr ::: ds.flatMap{ - case _: UnitDef => None - case m: ModuleDef if m.isStandalone => None - case d => Some(d.id.name) - }).mkString(".") + def searchWithin(ns: List[String], within: Definition): Seq[Definition] = { + (ns, within) match { + case (ns, p: Program) => + p.units.flatMap { u => + searchWithin(ns, u) + } + + case (ns, u: UnitDef) => + if (ns.startsWith(u.pack)) { + val rest = ns.drop(u.pack.size) + + u.defs.flatMap { + case d: ModuleDef if d.isPackageObject => + searchWithin(rest, d) + + case d => + rest match { + case n :: ns => + if (d.id.name == n) { + searchWithin(ns, d) + } else { + Nil + } + case Nil => + List(u) + } + } + } else { + Nil + } + + case (Nil, d) => List(d) + case (n :: ns, d) => + d.subDefinitions.filter(_.id.name == n).flatMap { sd => + searchWithin(ns, sd) + } } + } + + def searchRelative(name: String, from: Definition)(implicit pgm: Program): Seq[Definition] = { + val names = nameToParts(name) + val path = pathFromRoot(from) + + searchRelative(names, path.reverse) + } + + private case class ImportPath(ls: List[String], wild: Boolean) + + private def resolveImports(imports: List[ImportPath], names: List[String]): List[List[String]] = { + def resolveImport(i: ImportPath): Option[List[String]] = { + if (!i.wild && names.startsWith(i.ls.last)) { + Some(i.ls ++ names.tail) + } else if (i.wild) { + Some(i.ls ++ names) + } else { + None + } + } + + imports.flatMap(resolveImport) + } + + private def searchRelative(names: List[String], rpath: List[Definition])(implicit pgm: Program): Seq[Definition] = { + (names, rpath) match { + case (n :: ns, d :: ds) => + (d match { + case p: Program => + searchWithin(names, p) + + case u: UnitDef => + val imports = u.imports.map { + case PackageImport(ls) => ImportPath(ls, true) + case SingleImport(d) => ImportPath(nameToParts(fullName(d)), false) + case WildcardImport(d) => ImportPath(nameToParts(fullName(d)), true) + }.toList + val inModules = d.subDefinitions.filter(_.id.name == n).flatMap { sd => + searchWithin(ns, sd) + } + + val namesImported = resolveImports(imports, names) + val nameWithPackage = u.pack ++ names + + val allNames = namesImported :+ nameWithPackage + + allNames.foldLeft(inModules) { _ ++ searchRelative(_, ds) } + + case d => + if (n == d.id.name) { + searchWithin(ns, d) + } else { + searchWithin(n :: ns, d) + } + }) ++ searchRelative(names, ds) + + case _ => + Nil + } + } + + /* def searchByFullName ( fullName : String, p : Program, @@ -159,7 +278,7 @@ object DefOps { ) = searchByFullNameRelative(fullName, p, reliableVisibility,exploreStandalones) - def searchByFullNameRelative( + private def searchByFullNameRelative( fullName : String, base : Definition, reliableVisibility : Boolean = true, // Unset this if imports have not yet been set correctly @@ -264,6 +383,7 @@ object DefOps { } } + */ /* @@ -319,24 +439,19 @@ object DefOps { val newP = p.copy(units = for (u <- p.units) yield { u.copy( - modules = for (m <- u.modules) yield { - m.copy(defs = for (df <- m.defs) yield { - df match { - case f : FunDef => - val newF = fdMap(f) - newF.fullBody = replaceCalls(newF.fullBody) - newF - case c : ClassDef => - // val oldMethods = c.methods - // c.clearMethods() - // for (m <- oldMethods) { - // c.registerMethod(functionToFunction.get(m).map{_.to}.getOrElse(m)) - // } - c - case d => - d - } + defs = u.defs.map { + case m : ModuleDef => + m.copy(defs = for (df <- m.defs) yield { + df match { + case f : FunDef => + val newF = fdMap(f) + newF.fullBody = replaceCalls(newF.fullBody) + newF + case d => + d + } }) + case d => d }, imports = u.imports map { case SingleImport(fd : FunDef) => @@ -353,18 +468,20 @@ object DefOps { var found = false val res = p.copy(units = for (u <- p.units) yield { u.copy( - modules = for (m <- u.modules) yield { - val newdefs = for (df <- m.defs) yield { - df match { - case `after` => - found = true - after +: fds.toSeq - case d => - Seq(d) + defs = u.defs.map { + case m: ModuleDef => + val newdefs = for (df <- m.defs) yield { + df match { + case `after` => + found = true + after +: fds.toSeq + case d => + Seq(d) + } } - } - m.copy(defs = newdefs.flatten) + m.copy(defs = newdefs.flatten) + case d => d } ) }) diff --git a/src/main/scala/leon/purescala/Definitions.scala b/src/main/scala/leon/purescala/Definitions.scala index c19c7383fa2602171d834db56934d849ee1c8571..280a7ae39d6594290c12154628ffd906ade139a0 100644 --- a/src/main/scala/leon/purescala/Definitions.scala +++ b/src/main/scala/leon/purescala/Definitions.scala @@ -16,30 +16,30 @@ object Definitions { val id: Identifier - def owner = id.owner - def setOwner(owner : Definition) : this.type = { id.owner = Some(owner); this } - var origOwner : Option[Definition] = None // The definition/scope enclosing this definition def subDefinitions : Seq[Definition] // The enclosed scopes/definitions by this definition + + def containsDef(df: Definition): Boolean = { + subDefinitions.exists { sd => + sd == df || sd.containsDef(df) + } + } + override def hashCode : Int = id.hashCode override def equals(that : Any) : Boolean = that match { case t : Definition => t.id == this.id case _ => false } - override def copiedFrom(o : Tree) : this.type = { - super.copiedFrom(o) - o match { - case df : Definition if df.owner.isDefined => - this.setOwner(df.owner.get) - case _ => - this - } - - } - def setSubDefOwners() = for (df <- subDefinitions) df.setOwner(this) - + def writeScalaFile(filename: String) { + import java.io.FileWriter + import java.io.BufferedWriter + val fstream = new FileWriter(filename) + val out = new BufferedWriter(fstream) + out.write(ScalaPrinter(this)) + out.close() + } } /** @@ -59,14 +59,17 @@ object Definitions { // Warning: the variable will not have the same type as the ValDef, but // the Identifier type is enough for all use cases in Leon def toVariable : Variable = Variable(id) - - setSubDefOwners() } /** A wrapper for a program. For now a program is simply a single object. The * name is meaningless and we just use the package name as id. */ - case class Program(id: Identifier, units: List[UnitDef]) extends Definition { + case class Program(units: List[UnitDef]) extends Definition { + val id = FreshIdentifier("program") + origOwner = None + + lazy val library = Library(this) + def subDefinitions = units def definedFunctions = units.flatMap(_.definedFunctions) @@ -74,7 +77,11 @@ object Definitions { def classHierarchyRoots = units.flatMap(_.classHierarchyRoots) def algebraicDataTypes = units.flatMap(_.algebraicDataTypes).toMap def singleCaseClasses = units.flatMap(_.singleCaseClasses) - def modules = units.flatMap(_.modules) + def modules = { + units.flatMap(_.defs.collect { + case md: ModuleDef => md + }) + } lazy val callGraph = new CallGraph(this) @@ -85,32 +92,19 @@ object Definitions { def duplicate = { copy(units = units.map{_.duplicate}) } - - lazy val library = Library(this) - def writeScalaFile(filename: String) { - import java.io.FileWriter - import java.io.BufferedWriter - val fstream = new FileWriter(filename) - val out = new BufferedWriter(fstream) - out.write(ScalaPrinter(this)) - out.close() - } - setSubDefOwners() + def lookupAll(name: String) = DefOps.searchWithin(name, this) + def lookup(name: String) = lookupAll(name).headOption } object Program { - lazy val empty : Program = Program( - FreshIdentifier("empty"), - Nil - ) + lazy val empty: Program = Program(Nil) } case class TypeParameterDef(tp: TypeParameter) extends Definition { def subDefinitions = Seq() def freshen = TypeParameterDef(tp.freshen) val id = tp.id - setSubDefOwners() } /** A package as a path of names */ @@ -118,18 +112,20 @@ object Definitions { abstract class Import extends Definition { def subDefinitions = Nil - - def importedDefs = this match { - case PackageImport(pack) => { - import DefOps._ + + def importedDefs(implicit pgm: Program) = this match { + case PackageImport(pack) => // Ignore standalone modules, assume there are extra imports for them - programOf(this) map { unitsInPackage(_,pack) } getOrElse List() - } - case SingleImport(imported) => List(imported) - case WildcardImport(imported) => imported.subDefinitions + DefOps.unitsInPackage(pgm, pack) + + case SingleImport(imported) => + List(imported) + + case WildcardImport(imported) => + imported.subDefinitions } } - + // import pack._ case class PackageImport(pack : PackageRef) extends Import { val id = FreshIdentifier("import " + (pack mkString ".")) @@ -143,47 +139,64 @@ object Definitions { val id = FreshIdentifier(s"import ${df.id.toString}._") } - case class UnitDef( id: Identifier, - modules : Seq[ModuleDef], pack : PackageRef, imports : Seq[Import], + defs : Seq[Definition], isMainUnit : Boolean // false for libraries/imports ) extends Definition { - def subDefinitions = modules ++ imports + def subDefinitions = defs - def definedFunctions = modules.flatMap(_.definedFunctions) - def definedClasses = modules.flatMap(_.definedClasses) - def classHierarchyRoots = modules.flatMap(_.classHierarchyRoots) - def algebraicDataTypes = modules.flatMap(_.algebraicDataTypes) - def singleCaseClasses = modules.flatMap(_.singleCaseClasses) + def definedFunctions = defs.flatMap{ + case m: ModuleDef => m.definedFunctions + case _ => Nil + } + + def definedClasses = defs.flatMap { + case c: ClassDef => List(c) + case m: ModuleDef => m.definedClasses + case _ => Nil + } + + def classHierarchyRoots = { + definedClasses.filter(!_.hasParent) + } + + def algebraicDataTypes = { + definedClasses.collect { + case ccd: CaseClassDef if ccd.hasParent => ccd + }.groupBy(_.parent.get.classDef) + } + + def singleCaseClasses = { + definedClasses.collect { + case ccd: CaseClassDef if !ccd.hasParent => ccd + } + } def duplicate = { - copy(modules = modules map { _.duplicate } ) + copy(defs = defs map { + case cd: ClassDef => cd.duplicate + case m: ModuleDef => m.duplicate + case d => d + }) } - - def writeScalaFile(filename: String) { - import java.io.FileWriter - import java.io.BufferedWriter - val fstream = new FileWriter(filename) - val out = new BufferedWriter(fstream) - out.write(ScalaPrinter(this)) - out.close() + + def modules = defs.collect { + case md: ModuleDef => md } - - setSubDefOwners() } object UnitDef { def apply(id: Identifier, modules : Seq[ModuleDef]) : UnitDef = - UnitDef(id,modules, Nil,Nil,true) + UnitDef(id,Nil, Nil, modules,true) } /** Objects work as containers for class definitions, functions (def's) and * val's. */ - case class ModuleDef(id: Identifier, defs : Seq[Definition], isStandalone : Boolean) extends Definition { + case class ModuleDef(id: Identifier, defs: Seq[Definition], isPackageObject: Boolean) extends Definition { def subDefinitions = defs @@ -208,9 +221,6 @@ object Definitions { case cd: ClassDef => cd.duplicate case other => other }) - - setSubDefOwners() - } /** Useful because case classes and classes are somewhat unified in some @@ -239,7 +249,6 @@ object Definitions { def registerMethod(fd: FunDef) = { _methods = _methods ::: List(fd) - fd.setOwner(this) } def clearMethods() { @@ -296,7 +305,6 @@ object Definitions { val isCaseObject = false lazy val singleCaseClasses : Seq[CaseClassDef] = Nil - setSubDefOwners() } /** Case classes/objects. */ @@ -311,7 +319,6 @@ object Definitions { def setFields(fields: Seq[ValDef]) { _fields = fields - _fields foreach { _.setOwner(this)} } @@ -327,7 +334,6 @@ object Definitions { } lazy val singleCaseClasses : Seq[CaseClassDef] = if (hasParent) Nil else Seq(this) - setSubDefOwners() } @@ -364,7 +370,6 @@ object Definitions { def fullBody = fullBody_ def fullBody_= (e : Expr) { fullBody_ = e - nestedFuns map {_.setOwner(this)} } def body: Option[Expr] = withoutSpec(fullBody) @@ -439,7 +444,6 @@ object Definitions { def isRecursive(p: Program) = p.callGraph.transitiveCallees(this) contains this - setSubDefOwners() // Deprecated, old API @deprecated("Use .body instead", "2.3") def implementation : Option[Expr] = body diff --git a/src/main/scala/leon/purescala/ExprOps.scala b/src/main/scala/leon/purescala/ExprOps.scala index 9f1dfccc44670e2ed5c2378edf2d29bc49cf88d8..b043da9ac1fcdae8271419544e3aea9d3e192688 100644 --- a/src/main/scala/leon/purescala/ExprOps.scala +++ b/src/main/scala/leon/purescala/ExprOps.scala @@ -1955,19 +1955,17 @@ object ExprOps { (fds.values.toSet, res2) } - def isListLiteral(e: Expr): Option[(TypeTree, List[Expr])] = e match { + def isListLiteral(e: Expr)(implicit pgm: Program): Option[(TypeTree, List[Expr])] = e match { case CaseClass(CaseClassType(classDef, Seq(tp)), Nil) => for { - p <- programOf(classDef) - leonNil <- p.library.Nil + leonNil <- pgm.library.Nil if classDef == leonNil } yield { (tp, Nil) } case CaseClass(CaseClassType(classDef, Seq(tp)), Seq(hd, tl)) => for { - p <- programOf(classDef) - leonCons <- p.library.Cons + leonCons <- pgm.library.Cons if classDef == leonCons (_, tlElems) <- isListLiteral(tl) } yield { diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala index 61bb1650e9a99a1e747b1188e3d16a1f4e359a7f..8b5b3cf240957a1d7cf0aab08a0fa1aad27157b9 100644 --- a/src/main/scala/leon/purescala/Extractors.scala +++ b/src/main/scala/leon/purescala/Extractors.scala @@ -8,6 +8,7 @@ import Common._ import Types._ import Constructors._ import ExprOps._ +import Definitions.Program object Extractors { @@ -179,11 +180,10 @@ object Extractors { } object StringLiteral { - def unapply(e: Expr): Option[String] = e match { + def unapply(e: Expr)(implicit pgm: Program): Option[String] = e match { case CaseClass(cct, args) => for { - p <- DefOps.programOf(cct.classDef) - libS <- p.library.String + libS <- pgm.library.String if cct.classDef == libS (_, chars) <- isListLiteral(args.head) if chars.forall(_.isInstanceOf[CharLiteral]) diff --git a/src/main/scala/leon/purescala/FunctionClosure.scala b/src/main/scala/leon/purescala/FunctionClosure.scala index 8f77e8812e172a362b7ffa46086fa4045b020cce..1eed1d4842d668231538e47aaf01d263823390a4 100644 --- a/src/main/scala/leon/purescala/FunctionClosure.scala +++ b/src/main/scala/leon/purescala/FunctionClosure.scala @@ -15,6 +15,7 @@ object FunctionClosure extends TransformationPhase { val name = "Function Closure" val description = "Closing function with its scoping variables" + // TODO: Rewrite this phase /* I know, that's a lot of mutable variables */ private var pathConstraints: List[Expr] = Nil private var enclosingLets: List[(Identifier, Expr)] = Nil @@ -24,24 +25,25 @@ object FunctionClosure extends TransformationPhase { def apply(ctx: LeonContext, program: Program): Program = { - val newUnits = program.units.map { u => u.copy(modules = u.modules map { m => - pathConstraints = Nil - enclosingLets = Nil - newFunDefs = Map() - topLevelFuns = Set() - parent = null - - val funDefs = m.definedFunctions - funDefs.foreach(fd => { - parent = fd - pathConstraints = fd.precondition.toList - fd.body = fd.body.map(b => functionClosure(b, fd.params.map(_.id).toSet, Map(), Map())) - }) + val newUnits = program.units.map { u => u.copy(defs = u.defs map { + case m: ModuleDef => + pathConstraints = Nil + enclosingLets = Nil + newFunDefs = Map() + topLevelFuns = Set() + parent = null + + val funDefs = m.definedFunctions + funDefs.foreach(fd => { + parent = fd + pathConstraints = fd.precondition.toList + fd.body = fd.body.map(b => functionClosure(b, fd.params.map(_.id).toSet, Map(), Map())) + }) - ModuleDef(m.id, m.defs ++ topLevelFuns, m.isStandalone ) + ModuleDef(m.id, m.defs ++ topLevelFuns, m.isPackageObject ) + case cd => cd })} - val res = Program(program.id, newUnits) - res + Program(newUnits) } private def functionClosure(expr: Expr, bindedVars: Set[Identifier], id2freshId: Map[Identifier, Identifier], fd2FreshFd: Map[FunDef, (FunDef, Seq[Variable])]): Expr = expr match { @@ -61,8 +63,6 @@ object FunctionClosure extends TransformationPhase { val newFunDef = new FunDef(newFunId, fd.tparams, fd.returnType, newValDefs, fd.defType).copiedFrom(fd) topLevelFuns += newFunDef newFunDef.addAnnotation(fd.annotations.toSeq:_*) //TODO: this is still some dangerous side effects - newFunDef.setOwner(parent) - fd .setOwner(parent) newFunDef.orig = Some(fd) def introduceLets(expr: Expr, fd2FreshFd: Map[FunDef, (FunDef, Seq[Variable])]): Expr = { diff --git a/src/main/scala/leon/purescala/FunctionMapping.scala b/src/main/scala/leon/purescala/FunctionMapping.scala index 19d16c2b13fb27819f26c7e58f090d47af7dc231..c7a31c61500a144f531dc7963ed87b0c963a400e 100644 --- a/src/main/scala/leon/purescala/FunctionMapping.scala +++ b/src/main/scala/leon/purescala/FunctionMapping.scala @@ -33,24 +33,26 @@ abstract class FunctionMapping extends TransformationPhase { val newP = program.copy(units = for (u <- program.units) yield { u.copy( - modules = for (m <- u.modules) yield { - m.copy(defs = for (df <- m.defs) yield { - df match { - case f : FunDef => - val newF = functionToFunction.get(f).map{_.to}.getOrElse(f) - newF.fullBody = replaceCalls(f.fullBody) - newF - case c : ClassDef => - // val oldMethods = c.methods - // c.clearMethods() - // for (m <- oldMethods) { - // c.registerMethod(functionToFunction.get(m).map{_.to}.getOrElse(m)) - // } - c - case d => - d - } - }) + defs = u.defs map { + case m: ModuleDef => + m.copy(defs = for (df <- m.defs) yield { + df match { + case f : FunDef => + val newF = functionToFunction.get(f).map{_.to}.getOrElse(f) + newF.fullBody = replaceCalls(f.fullBody) + newF + case c : ClassDef => + // val oldMethods = c.methods + // c.clearMethods() + // for (m <- oldMethods) { + // c.registerMethod(functionToFunction.get(m).map{_.to}.getOrElse(m)) + // } + c + case d => + d + } + }) + case d => d }, imports = u.imports map { case SingleImport(fd : FunDef) => diff --git a/src/main/scala/leon/purescala/MethodLifting.scala b/src/main/scala/leon/purescala/MethodLifting.scala index c93f8fe9c6396de0b12a1adda037b2ad84049f86..f033681b2937046213aa07ff75f4908870242bf2 100644 --- a/src/main/scala/leon/purescala/MethodLifting.scala +++ b/src/main/scala/leon/purescala/MethodLifting.scala @@ -14,117 +14,79 @@ import TypeOps.instantiateType object MethodLifting extends TransformationPhase { val name = "Method Lifting" - val description = "Translate methods into top-level functions" + val description = "Translate methods into functions of the companion object" def apply(ctx: LeonContext, program: Program): Program = { + // First we create the appropriate functions from methods: - var mdToFds = Map[FunDef, FunDef]() - - for { - cd <- program.classHierarchyRoots - if cd.methods.nonEmpty - fd <- cd.methods - } { - // We import class type params and freshen them - val ctParams = cd.tparams map { _.freshen } - val tparamsMap = cd.tparams.zip(ctParams map { _.tp }).toMap - - val id = FreshIdentifier(cd.id.name+"$"+fd.id.name).setPos(fd.id) - val recType = classDefToClassType(cd, ctParams.map(_.tp)) - val retType = instantiateType(fd.returnType, tparamsMap) - val fdParams = fd.params map { vd => - val newId = FreshIdentifier(vd.id.name, instantiateType(vd.id.getType, tparamsMap)) - ValDef(newId).setPos(vd.getPos) + var mdToFds = Map[FunDef, FunDef]() + + val newUnits = for (u <- program.units) yield { + var fdsOf = Map[String, Set[FunDef]]() + + // 1) Create one function for each method + for { cd <- u.classHierarchyRoots if cd.methods.nonEmpty; fd <- cd.methods } { + // We import class type params and freshen them + val ctParams = cd.tparams map { _.freshen } + val tparamsMap = cd.tparams.zip(ctParams map { _.tp }).toMap + + val id = fd.id.freshen + val recType = classDefToClassType(cd, ctParams.map(_.tp)) + val retType = instantiateType(fd.returnType, tparamsMap) + val fdParams = fd.params map { vd => + val newId = FreshIdentifier(vd.id.name, instantiateType(vd.id.getType, tparamsMap)) + ValDef(newId).setPos(vd.getPos) + } + val paramsMap = fd.params.zip(fdParams).map{case (x,y) => (x.id, y.id)}.toMap + + val receiver = FreshIdentifier("this", recType).setPos(cd.id) + + val nfd = new FunDef(id, ctParams ++ fd.tparams, retType, ValDef(receiver) +: fdParams, fd.defType) + nfd.copyContentFrom(fd) + nfd.setPos(fd) + nfd.fullBody = postMap{ + case This(ct) if ct.classDef == cd => Some(receiver.toVariable) + case _ => None + }(instantiateType(nfd.fullBody, tparamsMap, paramsMap)) + + mdToFds += fd -> nfd + fdsOf += cd.id.name -> (fdsOf.getOrElse(cd.id.name, Set()) + nfd) } - val paramsMap = fd.params.zip(fdParams).map{case (x,y) => (x.id, y.id)}.toMap - - val receiver = FreshIdentifier("$this", recType).setPos(cd.id) - val nfd = new FunDef(id, ctParams ++ fd.tparams, retType, ValDef(receiver) +: fdParams, fd.defType) - nfd.copyContentFrom(fd) - nfd.setPos(fd) - nfd.fullBody = instantiateType(nfd.fullBody, tparamsMap, paramsMap) + // 2) Place functions in existing companions: + val defs = u.defs map { + case md: ModuleDef if fdsOf contains md.id.name => + val fds = fdsOf(md.id.name) + fdsOf -= md.id.name + ModuleDef(md.id, md.defs ++ fds, false) + case d => d + } - mdToFds += fd -> nfd - } + // 3) Create missing companions + val newCompanions = for ((name, fds) <- fdsOf) yield { + ModuleDef(FreshIdentifier(name), fds.toSeq, false) + } - def translateMethod(fd: FunDef) = { - val (nfd, rec) = mdToFds.get(fd) match { - case Some(nfd) => - (nfd, Some(() => Variable(nfd.params.head.id))) - case None => - (fd, None) + // 4) Remove methods in classes + for (cd <- u.definedClasses) { + cd.clearMethods } - nfd.fullBody = removeMethodCalls(rec)(nfd.fullBody) - nfd + u.copy(defs = defs ++ newCompanions) } - def removeMethodCalls(rec: Option[() => Expr])(e: Expr): Expr = { - postMap{ - case th: This => - rec match { - case Some(r) => - Some(r().setPos(th)) - case None => - ctx.reporter.fatalError("`this` used out of a method context?!?") - } - case mi @ MethodInvocation(rec, cd, tfd, args) => - rec match { - case IsTyped(rec, ct: ClassType) => - Some(FunctionInvocation(mdToFds(tfd.fd).typed(ct.tps ++ tfd.tps), rec +: args).setPos(mi)) - case _ => - ctx.reporter.fatalError("MethodInvocation on a non-class receiver !?!") - } + val pgm = Program(newUnits) + + // 5) Replace method calls with function calls + for (fd <- pgm.definedFunctions) { + fd.fullBody = postMap{ + case mi @ MethodInvocation(IsTyped(rec, ct: ClassType), cd, tfd, args) => + Some(FunctionInvocation(mdToFds(tfd.fd).typed(ct.tps ++ tfd.tps), rec +: args).setPos(mi)) case _ => None - }(e) + }(fd.fullBody) } - val modsToMods = ( for { - u <- program.units - m <- u.modules - } yield (m, { - // We remove methods from class definitions and add corresponding functions - val newDefs = m.defs.flatMap { - case acd: AbstractClassDef if acd.methods.nonEmpty => - acd +: acd.methods.map(translateMethod) - - case ccd: CaseClassDef if ccd.methods.nonEmpty => - ccd +: ccd.methods.map(translateMethod) - - case fd: FunDef => - List(translateMethod(fd)) - - case d => - List(d) - } - - // finally, we clear methods from classes - m.defs.foreach { - case cd: ClassDef => - cd.clearMethods() - case _ => - } - ModuleDef(m.id, newDefs, m.isStandalone ) - })).toMap - - val newUnits = program.units map { u => u.copy( - - imports = u.imports flatMap { - case s@SingleImport(c : ClassDef) => - // If a class is imported, also add the "methods" of this class - s :: ( c.methods map { md => SingleImport(mdToFds(md))}) - // If importing a ModuleDef, update to new ModuleDef - case SingleImport(m : ModuleDef) => List(SingleImport(modsToMods(m))) - case WildcardImport(m : ModuleDef) => List(WildcardImport(modsToMods(m))) - case other => List(other) - }, - - modules = u.modules map modsToMods - - )} - - Program(program.id, newUnits) + pgm } } diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala index ee545d9ab73cbdff03a15f89d86f0ec355799a8b..a21149b594f9da1509b5e3edbc298d7ce31ee1c8 100644 --- a/src/main/scala/leon/purescala/PrettyPrinter.scala +++ b/src/main/scala/leon/purescala/PrettyPrinter.scala @@ -132,19 +132,19 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe } def printWithPath(df: Definition)(implicit ctx : PrinterContext) { - ctx.scope match { - case Some(scope) => - try { - val (pack, defPath) = pathAsVisibleFrom(scope, df) - val toPrint = pack ++ (defPath collect { case df if !df.isInstanceOf[UnitDef] => df.id}) - p"${nary(toPrint, ".")}" - } catch { - // If we did not manage to find the path, just print the id - case _ : NoSuchElementException => p"${df.id}" - } - case None => + //ctx.scope match { + // case Some(scope) => + // try { + // val (pack, defPath) = pathAsVisibleFrom(scope, df) + // val toPrint = pack ++ (defPath collect { case df if !df.isInstanceOf[UnitDef] => df.id}) + // p"${nary(toPrint, ".")}" + // } catch { + // // If we did not manage to find the path, just print the id + // case _ : NoSuchElementException => p"${df.id}" + // } + // case None => p"${df.id}" - } + //} } @@ -233,30 +233,30 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe p"""|?($es)""" } case e @ CaseClass(cct, args) => - isListLiteral(e) match { - case Some((tpe, elems)) => - val chars = elems.collect{case CharLiteral(ch) => ch} - if (chars.length == elems.length && tpe == CharType) { - // String literal - val str = chars mkString "" - val q = '"' - p"$q$str$q" - } else { - val elemTps = leastUpperBound(elems.map(_.getType)) - if (elemTps == Some(tpe)) { - p"List($elems)" - } else { - p"List[$tpe]($elems)" - } - } - - case None => + //isListLiteral(e) match { + // case Some((tpe, elems)) => + // val chars = elems.collect{case CharLiteral(ch) => ch} + // if (chars.length == elems.length && tpe == CharType) { + // // String literal + // val str = chars mkString "" + // val q = '"' + // p"$q$str$q" + // } else { + // val elemTps = leastUpperBound(elems.map(_.getType)) + // if (elemTps == Some(tpe)) { + // p"List($elems)" + // } else { + // p"List[$tpe]($elems)" + // } + // } + + // case None => if (cct.classDef.isCaseObject) { p"$cct" } else { p"$cct($args)" } - } + //} @@ -539,31 +539,32 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe } // Definitions - case Program(id, units) => + case Program(units) => p"""${nary(units filter {_.isMainUnit}, "\n\n")}""" + //p"""${nary(units, "\n\n")}""" - case UnitDef(id,modules,pack,imports,_) => + case UnitDef(id,pack, imports, defs,_) => if (pack.nonEmpty){ p"""|package ${pack mkString "."} |""" } p"""|${nary(imports,"\n")} - |${nary(modules,"\n\n")} + |${nary(defs,"\n\n")} |""" case PackageImport(pack) => - import leon.purescala.DefOps._ - val newPack = ( for ( - scope <- ctx.scope; - unit <- unitOf(scope); - currentPack = unit.pack - ) yield { - if (isSuperPackageOf(currentPack,pack)) - pack drop currentPack.length - else - pack - }).getOrElse(pack) - p"import ${nary(newPack,".")}._" + //import leon.purescala.DefOps._ + //val newPack = ( for ( + // scope <- ctx.scope; + // unit <- unitOf(scope); + // currentPack = unit.pack + //) yield { + // if (isSuperPackageOf(currentPack,pack)) + // pack drop currentPack.length + // else + // pack + //}).getOrElse(pack) + p"import ${nary(pack,".")}._" case SingleImport(df) => p"import "; printWithPath(df) @@ -686,13 +687,7 @@ class PrettyPrinter(opts: PrinterOptions, val sb: StringBuffer = new StringBuffe val fid = tfd.fd.id - val maybeClassName = fid.name.substring(0, cd.id.name.length) - - val fname = if (maybeClassName == cd.id.name) { - fid.name.substring(cd.id.name.length + 1) // +1 to also remove $ - } else { - fid.name - } + val fname = fid.name val decoded = scala.reflect.NameTransformer.decode(fname) @@ -793,12 +788,12 @@ abstract class PrettyPrinterFactory { def apply(tree: Tree, opts: PrinterOptions = PrinterOptions(), scope : Option[Definition] = None): String = { val printer = create(opts) - val scope_ = (tree, scope) match { - // Try to find a scope, if we are given none. - case (df : Definition, None) => df.owner - case _ => None - } - val ctx = PrinterContext(tree, None, scope_, opts.baseIndent, printer) +// val scope_ = (tree, scope) match { +// // Try to find a scope, if we are given none. +// case (df : Definition, None) => df.owner +// case _ => None +// } + val ctx = PrinterContext(tree, None, scope, opts.baseIndent, printer) printer.pp(tree)(ctx) printer.toString } diff --git a/src/main/scala/leon/purescala/RestoreMethods.scala b/src/main/scala/leon/purescala/RestoreMethods.scala index 87bd92e6428022c32025a6734dd41e77a2df41d7..61c85d389c0805e0ba7937f8f1af9767f69b0c31 100644 --- a/src/main/scala/leon/purescala/RestoreMethods.scala +++ b/src/main/scala/leon/purescala/RestoreMethods.scala @@ -20,6 +20,8 @@ object RestoreMethods extends TransformationPhase { * New functions are returned, whereas classes are mutated */ def apply(ctx : LeonContext, p : Program) = { + p + /* var fd2Md = Map[FunDef, FunDef]() var whoseMethods = Map[ClassDef, Seq[FunDef]]() @@ -57,9 +59,9 @@ object RestoreMethods extends TransformationPhase { } } - /** + / ** * Substitute a function in an expression with the respective new method - */ + * / def substituteMethods = preMapOnFunDef ({ case FunctionInvocation(tfd,args) if fd2Md contains tfd.fd => { val md = fd2Md.get(tfd.fd).get // the method we are substituting @@ -74,9 +76,9 @@ object RestoreMethods extends TransformationPhase { case _ => None }, true) _ - /** + / ** * Renew that function map by applying subsituteMethods on its values to obtain correct functions - */ + * / val fd2MdFinal = fd2Md.mapValues(substituteMethods) val oldFuns = fd2MdFinal.map{ _._1 }.toSet @@ -136,7 +138,7 @@ object RestoreMethods extends TransformationPhase { } )}) - + */ } } diff --git a/src/main/scala/leon/utils/Library.scala b/src/main/scala/leon/utils/Library.scala index 920a45b5060cde5508c8acaa4279c8cc14cbf02e..aa9e60f4b95eae7b621238ba01ea94614d253a0b 100644 --- a/src/main/scala/leon/utils/Library.scala +++ b/src/main/scala/leon/utils/Library.scala @@ -5,23 +5,23 @@ package utils import purescala.Definitions._ import purescala.Types._ -import purescala.DefOps.searchByFullName +import purescala.DefOps._ case class Library(pgm: Program) { - lazy val List = lookup("leon.collection.List") collect { case acd : AbstractClassDef => acd } - lazy val Cons = lookup("leon.collection.Cons") collect { case ccd : CaseClassDef => ccd } - lazy val Nil = lookup("leon.collection.Nil") collect { case ccd : CaseClassDef => ccd } + lazy val List = lookup("leon.collection.List").collect{ case acd : AbstractClassDef => acd }.headOption + lazy val Cons = lookup("leon.collection.Cons").collect { case ccd : CaseClassDef => ccd }.headOption + lazy val Nil = lookup("leon.collection.Nil").collect { case ccd : CaseClassDef => ccd }.headOption - lazy val Option = lookup("leon.lang.Option") collect { case acd : AbstractClassDef => acd } - lazy val Some = lookup("leon.lang.Some") collect { case ccd : CaseClassDef => ccd } - lazy val None = lookup("leon.lang.None") collect { case ccd : CaseClassDef => ccd } + lazy val Option = lookup("leon.lang.Option").collect { case acd : AbstractClassDef => acd }.headOption + lazy val Some = lookup("leon.lang.Some").collect { case ccd : CaseClassDef => ccd }.headOption + lazy val None = lookup("leon.lang.None").collect { case ccd : CaseClassDef => ccd }.headOption - lazy val String = lookup("leon.lang.string.String") collect { case ccd : CaseClassDef => ccd } + lazy val String = lookup("leon.lang.string.String").collect { case ccd : CaseClassDef => ccd }.headOption - lazy val setToList = lookup("leon.collection.setToList") collect { case fd : FunDef => fd } - - def lookup(name: String): Option[Definition] = { - searchByFullName(name, pgm) + lazy val setToList = lookup("leon.collection.setToList").collect { case fd : FunDef => fd }.headOption + + def lookup(name: String): Seq[Definition] = { + pgm.lookupAll(name) } def optionType(tp: TypeTree) = AbstractClassType(Option.get, Seq(tp)) diff --git a/src/main/scala/leon/utils/UnitElimination.scala b/src/main/scala/leon/utils/UnitElimination.scala index a8728346c71fecafadda56c760e12c7173a5cde8..0af3318395d518743208ce3c7777c3c774354bea 100644 --- a/src/main/scala/leon/utils/UnitElimination.scala +++ b/src/main/scala/leon/utils/UnitElimination.scala @@ -19,32 +19,35 @@ object UnitElimination extends TransformationPhase { private var id2FreshId: Map[Identifier, Identifier] = Map() def apply(ctx: LeonContext, pgm: Program): Program = { - val newUnits = pgm.units map { u => u.copy(modules = u.modules.map { m => - fun2FreshFun = Map() - val allFuns = m.definedFunctions - //first introduce new signatures without Unit parameters - allFuns.foreach(fd => { - if(fd.returnType != UnitType && fd.params.exists(vd => vd.getType == UnitType)) { - val freshFunDef = new FunDef(FreshIdentifier(fd.id.name), fd.tparams, fd.returnType, fd.params.filterNot(vd => vd.getType == UnitType), fd.defType).setPos(fd) - freshFunDef.addAnnotation(fd.annotations.toSeq:_*) - fun2FreshFun += (fd -> freshFunDef) - } else { - fun2FreshFun += (fd -> fd) //this will make the next step simpler - } - }) + val newUnits = pgm.units map { u => u.copy(defs = u.defs.map { + case m: ModuleDef => + fun2FreshFun = Map() + val allFuns = m.definedFunctions + //first introduce new signatures without Unit parameters + allFuns.foreach(fd => { + if(fd.returnType != UnitType && fd.params.exists(vd => vd.getType == UnitType)) { + val freshFunDef = new FunDef(FreshIdentifier(fd.id.name), fd.tparams, fd.returnType, fd.params.filterNot(vd => vd.getType == UnitType), fd.defType).setPos(fd) + freshFunDef.addAnnotation(fd.annotations.toSeq:_*) + fun2FreshFun += (fd -> freshFunDef) + } else { + fun2FreshFun += (fd -> fd) //this will make the next step simpler + } + }) - //then apply recursively to the bodies - val newFuns = allFuns.collect{ case fd if fd.returnType != UnitType => - val newFd = fun2FreshFun(fd) - newFd.fullBody = removeUnit(fd.fullBody) - newFd - } + //then apply recursively to the bodies + val newFuns = allFuns.collect{ case fd if fd.returnType != UnitType => + val newFd = fun2FreshFun(fd) + newFd.fullBody = removeUnit(fd.fullBody) + newFd + } - ModuleDef(m.id, m.definedClasses ++ newFuns, m.isStandalone ) + ModuleDef(m.id, m.definedClasses ++ newFuns, m.isPackageObject ) + case d => + d })} - Program(pgm.id, newUnits) + Program(newUnits) } private def simplifyType(tpe: TypeTree): TypeTree = tpe match { diff --git a/src/main/scala/leon/xlang/XLangAnalysisPhase.scala b/src/main/scala/leon/xlang/XLangAnalysisPhase.scala index 28ff7349b5d586b2156537d1b31e4e8179b067e6..2828a220fbcee0c6ffd470cbc3d1431513c45c1c 100644 --- a/src/main/scala/leon/xlang/XLangAnalysisPhase.scala +++ b/src/main/scala/leon/xlang/XLangAnalysisPhase.scala @@ -37,11 +37,11 @@ object XLangAnalysisPhase extends LeonPhase[Program, VerificationReport] { } var subFunctionsOf = Map[FunDef, Set[FunDef]]().withDefaultValue(Set()) - pgm2.definedFunctions.foreach { fd => fd.owner match { - case Some(p : FunDef) => - subFunctionsOf += p -> (subFunctionsOf(p) + fd) - case _ => - }} + //pgm2.definedFunctions.foreach { fd => fd.owner match { + // case Some(p : FunDef) => + // subFunctionsOf += p -> (subFunctionsOf(p) + fd) + // case _ => + //}} val newOptions = ctx.options map { @@ -78,10 +78,11 @@ object XLangAnalysisPhase extends LeonPhase[Program, VerificationReport] { val newResults = for ((vc, ovr) <- vr.results) yield { if(functionWasLoop(vc.fd)) { val nvc = VC(vc.condition, - vc.fd.owner match { - case Some(fd: FunDef) => fd - case _ => vc.fd - }, + vc.fd, + //vc.fd.owner match { + // case Some(fd: FunDef) => fd + // case _ => vc.fd + //}, vc.kind.underlying match { case VCKinds.Postcondition => VCXLangKinds.InvariantPost case VCKinds.Precondition => VCXLangKinds.InvariantInd diff --git a/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala b/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala index f34d82dee639a7052cfcb9adc314b0bf7f4c4a63..1f00e411f8864613f38903512334388c898b2fea 100644 --- a/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala +++ b/src/test/scala/leon/test/evaluators/EvaluatorsTests.scala @@ -40,7 +40,7 @@ class EvaluatorsTests extends leon.test.LeonTestSuite { private def mkCall(name : String, args : Expr*)(implicit p : Program) = { val fn = s"Program.$name" - searchByFullName(fn, p) match { + p.lookup(fn) match { case Some(fd: FunDef) => FunctionInvocation(fd.typed, args.toSeq) case _ => @@ -49,7 +49,7 @@ class EvaluatorsTests extends leon.test.LeonTestSuite { } private def mkCaseClass(name : String, args : Expr*)(implicit p : Program) = { - searchByFullName("Program."+name, p) match { + p.lookup("Program."+name) match { case Some(ccd: CaseClassDef) => CaseClass(CaseClassType(ccd, Nil), args.toSeq) case _ => diff --git a/src/test/scala/leon/test/purescala/DefOpsTests.scala b/src/test/scala/leon/test/purescala/DefOpsTests.scala index 0f6d2465cb4b7531e3465d7c73d8b8368e050bd3..ece376ccab14563e71d984514fca1b14f5076c3d 100644 --- a/src/test/scala/leon/test/purescala/DefOpsTests.scala +++ b/src/test/scala/leon/test/purescala/DefOpsTests.scala @@ -66,36 +66,38 @@ private [purescala] object DefOpsHelper extends LeonTestSuite { """ object InEmpty { def arrayLookup(a : Array[Int], i : Int) = a(i) } """ ) - val program = parseStrings(test1) - val fooC = searchByFullName("foo.bar.baz.Foo.fooC",program) + implicit val program = parseStrings(test1) + lazy val fooC = program.lookup("foo.bar.baz.Foo.fooC") } class DefOpsTests extends LeonTestSuite { import DefOpsHelper._ - test("Find base definition"){assert(fooC.isDefined)} + test("Find base definition"){ + assert(fooC.isDefined) + } test("Least common ancestor"){ - val x = searchByFullName("foo.bar.baz.x",program) + val x = program.lookup("foo.bar.baz.x") assert(x.isDefined) - assert(leastCommonAncestor(x.get,fooC.get) == program) - val fooClass = searchByFullName("foo.bar.baz.Foo.FooC",program) + assert(leastCommonAncestor(x.get, fooC.get) == program) + val fooClass = program.lookup("foo.bar.baz.Foo.FooC") assert (fooClass.isDefined) assert(leastCommonAncestor(fooC.get, fooClass.get).id.name == "Foo") } test("In empty package") { val name = "InEmpty.arrayLookup" - val df = searchByFullName(name,program) + val df = program.lookup(name) assert(df.isDefined) assert{fullName(df.get) == name } } // Search by full name - def mustFind(name : String, msg : String) = test(msg) {assert(searchByFullNameRelative(name,fooC.get).isDefined) } - def mustFail(name : String, msg : String) = test(msg) {assert(searchByFullNameRelative(name,fooC.get).isEmpty) } + def mustFind(name: String, msg: String) = test(msg) {assert(searchRelative(name, fooC.get).nonEmpty) } + def mustFail(name: String, msg: String) = test(msg) {assert(searchRelative(name, fooC.get).isEmpty) } mustFind("fooC", "Find yourself") mustFind("FooC", "Find a definition in the same scope 1") diff --git a/src/test/scala/leon/test/solvers/UnrollingSolverTests.scala b/src/test/scala/leon/test/solvers/UnrollingSolverTests.scala index 17fb42fa16cf5b72a3ff068869849b1eede57cdb..121101041a2fc6cfde07820341998f116b0b24f4 100644 --- a/src/test/scala/leon/test/solvers/UnrollingSolverTests.scala +++ b/src/test/scala/leon/test/solvers/UnrollingSolverTests.scala @@ -23,7 +23,6 @@ class UnrollingSolverTests extends LeonTestSuite { fDef.postcondition = Some(Lambda(Seq(ValDef(fres)), GreaterThan(Variable(fres), InfiniteIntegerLiteral(0)))) private val program = Program( - FreshIdentifier("Minimal"), List(UnitDef( FreshIdentifier("Minimal"), List(ModuleDef(FreshIdentifier("Minimal"), Seq(fDef), false)) diff --git a/src/test/scala/leon/test/solvers/z3/FairZ3SolverTests.scala b/src/test/scala/leon/test/solvers/z3/FairZ3SolverTests.scala index cab248d9b342186dc3b286ba386c94fedf04ec92..544d9cd4ae663bfcd5e102ef3464d26c49e37d26 100644 --- a/src/test/scala/leon/test/solvers/z3/FairZ3SolverTests.scala +++ b/src/test/scala/leon/test/solvers/z3/FairZ3SolverTests.scala @@ -42,7 +42,6 @@ class FairZ3SolverTests extends LeonTestSuite { fDef.body = Some(Plus(Variable(fx), InfiniteIntegerLiteral(1))) private val minimalProgram = Program( - FreshIdentifier("Minimal"), List(UnitDef( FreshIdentifier("Minimal"), List(ModuleDef(FreshIdentifier("Minimal"), Seq(fDef), false) diff --git a/src/test/scala/leon/test/solvers/z3/FairZ3SolverTestsNewAPI.scala b/src/test/scala/leon/test/solvers/z3/FairZ3SolverTestsNewAPI.scala index 58d88cbdf8fa41226bf7345792ce518b3d04af2f..a6ae287369fdc5b7d1c540ec289c46dfa2b062db 100644 --- a/src/test/scala/leon/test/solvers/z3/FairZ3SolverTestsNewAPI.scala +++ b/src/test/scala/leon/test/solvers/z3/FairZ3SolverTestsNewAPI.scala @@ -51,7 +51,6 @@ class FairZ3SolverTestsNewAPI extends LeonTestSuite { fDef.body = Some(Plus(Variable(fx), InfiniteIntegerLiteral(1))) private val minimalProgram = Program( - FreshIdentifier("Minimal"), List(UnitDef( FreshIdentifier("Minimal"), List(ModuleDef(FreshIdentifier("Minimal"), Seq(fDef), false) diff --git a/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala b/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala index cb78580356700e05b0350289cefd819f31cb027d..b59e7437a89ef0a0befdf75a181cc50511c6ee49 100644 --- a/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala +++ b/src/test/scala/leon/test/solvers/z3/UninterpretedZ3SolverTests.scala @@ -48,7 +48,6 @@ class UninterpretedZ3SolverTests extends LeonTestSuite { gDef.body = Some(Plus(Variable(fx), InfiniteIntegerLiteral(1))) private val minimalProgram = Program( - FreshIdentifier("Minimal"), List(UnitDef( FreshIdentifier("Minimal"), List(ModuleDef(FreshIdentifier("Minimal"), Seq(fDef), false) diff --git a/src/test/scala/leon/test/verification/VerificationRegression.scala b/src/test/scala/leon/test/verification/VerificationRegression.scala index 5b559d5b54d2ea9e976982587deca6d2f22787d1..55030f8713ca386c79b0359345f6db9cc84561ba 100644 --- a/src/test/scala/leon/test/verification/VerificationRegression.scala +++ b/src/test/scala/leon/test/verification/VerificationRegression.scala @@ -42,10 +42,10 @@ trait VerificationRegression extends LeonTestSuite { val ast = extraction.run(ctx)(files) val programs = { val (user, lib) = ast.units partition { _.isMainUnit } - user map { u => Program(u.id.freshen, u :: lib) } + user map { u => (u.id, Program(u :: lib)) } } - for (p <- programs; options <- optionVariants) { - test(f"${nextInt()}%3d: ${p.id.name} ${options.mkString(" ")}") { + for ((id, p) <- programs; options <- optionVariants) { + test(f"${nextInt()}%3d: ${id.name} ${options.mkString(" ")}") { val ctx = createLeonContext(options: _*) val report = pipeBack.run(ctx)(p) block(Output(report, ctx.reporter))