diff --git a/.classpath b/.classpath deleted file mode 100644 index 3d4833db062fe3d5d9e8433867b0a1e54ac308a5..0000000000000000000000000000000000000000 --- a/.classpath +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<classpath> - <classpathentry kind="src" path="src"/> - <classpathentry kind="src" path="tests"/> - <classpathentry kind="src" path="examples"/> - <classpathentry kind="con" path="ch.epfl.lamp.sdt.launching.SCALA_CONTAINER"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="lib" path="/usr/local/scala/lib/scala-compiler.jar" sourcepath="/usr/local/scala/src/scala-compiler-src.jar"/> - <classpathentry kind="lib" path="lib/scalatest-0.9.5.jar"/> - <classpathentry kind="lib" path="lib/specs-1.5.0.jar"/> - <classpathentry kind="lib" path="lib/ScalaCheck-1.5.jar" sourcepath="lib/ScalaCheck-1.5-src.jar"/> - <classpathentry combineaccessrules="false" kind="src" path="/scalacheck-read-only"/> - <classpathentry kind="output" path="bin"/> -</classpath> diff --git a/.project b/.project deleted file mode 100644 index 53529d627c0b2637d820297752aebcafb12c5757..0000000000000000000000000000000000000000 --- a/.project +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>funcheck</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>ch.epfl.lamp.sdt.core.scalabuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>ch.epfl.lamp.sdt.core.scalanature</nature> - <nature>org.eclipse.jdt.core.javanature</nature> - </natures> -</projectDescription> diff --git a/README b/README index 769062a34496e3b344c3463eb0ab9814533bcff6..56ba85a654d7672fca2b64cb6acef4e35e3cf021 100644 --- a/README +++ b/README @@ -1,3 +1,31 @@ +This README file is outdated. + +Don't read it unless you're looking for an excuse to procrastinate. + +PS + + + + + + + + + + + + + + + + + + + + + + + ================================================================================ === FUNCHECK PLUGIN === ================================================================================ diff --git a/oldsrc/funcheck/lib/Specs.scala b/oldsrc/funcheck/lib/Specs.scala new file mode 100644 index 0000000000000000000000000000000000000000..1f3167cb6c596e518bb44d3fc47aa6455e317103 --- /dev/null +++ b/oldsrc/funcheck/lib/Specs.scala @@ -0,0 +1,26 @@ +package funcheck.lib + +object Specs { + + /** + * this is used to annotate the (unique) class method + * that will be used by our funcheck plugin to + * automagically define a class generator that can be used + * by ScalaCheck to create test cases. + */ + class generator extends StaticAnnotation + + implicit def extendedBoolean(b: => Boolean) = new { + def ==>(p: => Boolean) = Specs ==> (b,p) + } + + def forAll[A](f: A => Boolean): Boolean = { + Console.err.println("Warning: ignored forAll. Are you using the funcheck plugin?") + true + // error("\"forAll\" combinator is currently unsupported by plugin.") + } + + + /** Implication */ + def ==>(ifz: => Boolean, then: => Boolean): Boolean = !ifz || then +} diff --git a/oldsrc/funcheck/scalacheck/FilterGeneratorAnnotations.scala b/oldsrc/funcheck/scalacheck/FilterGeneratorAnnotations.scala new file mode 100644 index 0000000000000000000000000000000000000000..be3aaae44058a9b2512607ff7e309d0c981a7265 --- /dev/null +++ b/oldsrc/funcheck/scalacheck/FilterGeneratorAnnotations.scala @@ -0,0 +1,69 @@ +package funcheck.scalacheck + +import scala.tools.nsc.Global + +/** + * A tree traverser which filter the trees elements that contain the + * <code>@generator</code> annotation, defined in <code>funcheck.lib.Specs</code> + * module. + * + * Note: For the moment this is working only for <code>ClassDef</code> and + * <code>DefDef</code> tree elements. + * + * This trait is meant to be used with the <code>FilterTreeTraverser</code> + * class, available in the <code>scala.tools.nsc.ast.Trees</code> trait. + * + * + * Usage Example: + * + * new FilterTreeTraverser(filterTreesWithGeneratorAnnotation(unit)) + * + * where <code>unit</code> is the current Compilation Unit. + */ +trait FilterGeneratorAnnotations { + val global: Global + // [[INFO]] "hasAttribute" is "hasAnnotation" in future compiler release 2.8 + import global._ + + /** Funcheck <code>@generator</code> annotation. */ + private lazy val generator: Symbol = definitions.getClass("funcheck.lib.Specs.generator") + + + /** + * Check for <code>@generator</code> annotation only for class and method + * definitions. A class is considered to be annotated if either the class itself + * has the annotation, or if the class inherit from an annotated abstract class. + */ + def filterTreesWithGeneratorAnnotation(Unit: CompilationUnit)(tree: Tree): Boolean = { + lazy val sym = tree.symbol + tree match { + case cd: ClassDef => isAbstractClass(sym) || + sym.hasAttribute(generator) || + abstractSuperClassHasGeneratorAnnotation(sym.superClass) + case d: DefDef => sym.hasAttribute(generator) + case _ => false + } + } + + + /** Return true if the class (or superclass) symbol is flagged as being ABSTRACT and contains + * the <code>@generator</code> annotation.*/ + private def abstractSuperClassHasGeneratorAnnotation(superclass: Symbol): Boolean = { + //require(superclass.isInstanceOf[ClassSymbol], "expected ClassSymbol, found "+superclass) + superclass match { + case NoSymbol => false + case cs: ClassSymbol => + (isAbstractClass(cs) && cs.hasAttribute(generator)) || + abstractSuperClassHasGeneratorAnnotation(cs.superClass) + case _ => + assert(false, "expected ClassSymbol, found "+superclass) + false + } + } + + private def isAbstractClass(s: Symbol): Boolean = s match { + case cs: ClassSymbol => cs.hasFlag(scala.tools.nsc.symtab.Flags.ABSTRACT) + case _ => false + } + +} \ No newline at end of file diff --git a/oldsrc/funcheck/scalacheck/ForAllTransformer.scala b/oldsrc/funcheck/scalacheck/ForAllTransformer.scala new file mode 100644 index 0000000000000000000000000000000000000000..4d02d6cca707ae4039ba8970a02fc65ad5cb3733 --- /dev/null +++ b/oldsrc/funcheck/scalacheck/ForAllTransformer.scala @@ -0,0 +1,200 @@ +package funcheck.scalacheck + +import scala.tools.nsc.transform.TypingTransformers +import scala.tools.nsc.util.NoPosition +import funcheck.util.FreshNameCreator + +/** Takes care of mapping Specs.forAll methods calls to + * ScalaCheck org.scalacheck.Prop.forAll. + */ +trait ForAllTransformer extends TypingTransformers + with ScalaCheck + with FreshNameCreator +{ + import global._ + + private lazy val specsModule: Symbol = definitions.getModule("funcheck.lib.Specs") + + + + def forAllTransform(unit: CompilationUnit): Unit = + unit.body = new ForAllTransformer(unit).transform(unit.body) + + + + + class ForAllTransformer(unit: CompilationUnit) + extends TypingTransformer(unit) + { + + override def transform(tree: Tree): Tree = { + curTree = tree + + tree match { + /* XXX: This only works for top-level forAll. Nested forAll are not handled by the current version*/ + case Apply(TypeApply(s: Select, _), rhs @ List(f @ Function(vparams,body))) if isSelectOfSpecsMethod(s.symbol, "forAll") => + atOwner(currentOwner) { + assert(vparams.size == 1, "funcheck.Specs.forAll properties are expected to take a single (tuple) parameter") + + val v @ ValDef(mods,name,vtpt,vinit) = vparams.head + + vtpt.tpe match { + // the type of the (single, by the above assumption) function parameter + // will tell us what are the generators needed. In fact, we need to manually + // provide the generators since despite the generators that we create are + // implicit definitions, funcheck is hooking after the typechecking phase + // and implicit definition are solved at typechecking. Therefore the need + // of manually provide every single parameter to the org.scalacheck.Prop.forAll + // method. + // This is actually one of the major limitations of this plugin since it is not + // really quite flexible. For a future work it might be a good idea to rethink + // how this problem can be fixed (an idea could be to inject the code and actuate + // the forall conversion and then typecheck the whole program from zero). + case tpe @ TypeRef(_,value,vtpes) => + var fun: Function = { + if(vtpes.size <= 1) { + // if there is less than one parameter then the function tree can be injected + // without (almost) no modificcation because it matches what Scalacheck Prop.forAll + // expects + f + } + else { + // Transforming a pair into a list of arguments (this is what ScalaCheck Prop.forAll expects) + + // create a fresh name for each parameter declared parametric type + val freshNames = vtpes.map(i => fresh.newName(NoPosition,"v")) + + val funSym = tree.symbol + + val subst = for { i <- 0 to vtpes.size-1} yield { + val toSym = funSym.newValueParameter(funSym.pos, freshNames(i)).setInfo(vtpes(i)) + + val from = Select(v, v.symbol.tpe.decl("_"+(i+1))) + val to = ValDef(toSym, EmptyTree) setPos (tree.pos) + + (from, to) + } + + + val valdefs = subst.map(_._2).toList + val fun = localTyper.typed { + val newBody = new MyTreeSubstituter(subst.map(p => p._1.symbol).toList, valdefs.map(v => Ident(v.symbol)).toList).transform(resetAttrs(body)) + Function(valdefs, newBody) + }.asInstanceOf[Function] + + + new ChangeOwnerTraverser(funSym, fun.symbol).traverse(fun); + new ForeachTreeTraverser({t: Tree => t setPos tree.pos}).traverse(fun) + fun + } + } + + // Prop.forall(function , where function is of the form (v1,v2,...,vn) => expr(v1,v2,..,vn)) + val prop = Prop.forAll(List(transform(fun))) + + + // the following are the list of (implicit) parameters that need to be provided + // when calling Prop.forall + + var buf = new collection.mutable.ListBuffer[Tree]() + + val blockValSym = newSyntheticValueParam(fun.symbol, definitions.BooleanClass.typeConstructor) + + val fun2 = localTyper.typed { + val body = Prop.propBoolean(resetAttrs(Ident(blockValSym))) + Function(List(ValDef(blockValSym, EmptyTree)), body) + }.asInstanceOf[Function] + + + new ChangeOwnerTraverser(fun.symbol, fun2.symbol).traverse(fun2); + new ForeachTreeTraverser({t: Tree => t setPos tree.pos}).traverse(fun2) + + buf += Block(Nil,fun2) + + + if(vtpes.size <= 1) { + buf += resetAttrs(Arbitrary.arbitrary(tpe)) + buf += resetAttrs(Shrink.shrinker(tpe)) + } else { + for { tpe <- vtpes } { + buf += resetAttrs(Arbitrary.arbitrary(tpe)) + buf += resetAttrs(Shrink.shrinker(tpe)) + } + } + + + import posAssigner.atPos // for filling in tree positions + + + val property = localTyper.typed { + atPos(tree.pos) { + Apply(prop, buf.toList) + } + } + + + + localTyper.typed { + atPos(tree.pos) { + Test.isPassed(Test.check(property)) + } + } + + + case t => + assert(false, "expected ValDef of type TypeRef, found "+t) + tree + } + } + + /** Delegates the recursive traversal of the tree. */ + case _ => super.transform(tree) + } + + } + + class ChangeOwnerTraverser(val oldowner: Symbol, val newowner: Symbol) extends Traverser { + override def traverse(tree: Tree) { + if (tree != null && tree.symbol != null && tree.symbol != NoSymbol && tree.symbol.owner == oldowner) + tree.symbol.owner = newowner; + super.traverse(tree) + } + } + + /** Synthetic value parameters when parameter symbols are not available + */ + final def newSyntheticValueParam(owner: Symbol, argtype: Type): Symbol = { + var cnt = 0 + def freshName() = { cnt += 1; newTermName("x$" + cnt) } + def param(tp: Type) = + owner.newValueParameter(owner.pos, freshName()).setFlag(scala.tools.nsc.symtab.Flags.SYNTHETIC).setInfo(tp) + param(argtype) + } + + private def isSelectOfSpecsMethod(s: Symbol, method: String): Boolean = + s == specsModule.tpe.decl(method) + + + + /** Quick (and dirty) hack for enabling tree substitution for pair elements. + * Specifically, this allow to map pair accesses such as p._1 to a new variable 'x' + * ([p._1 |-> x, p._2 |-> y, ..., p._n |-> z]) + */ + class MyTreeSubstituter(from: List[Symbol], to: List[Tree]) extends TreeSubstituter(from,to) { + override def transform(tree: Tree): Tree = tree match { + // Useful for substutite values like p._1 where 'p' is a pair + // Inherithed 'TreeSubstituter' cannot handle this + case Select(Ident(_), name) => + def subst(from: List[Symbol], to: List[Tree]): Tree = + if (from.isEmpty) tree + else if (tree.symbol == from.head) to.head + else subst(from.tail, to.tail); + subst(from, to) + case _ => + super.transform(tree) + } + } + + } + +} diff --git a/oldsrc/funcheck/scalacheck/GeneratorDefDefInjector.scala b/oldsrc/funcheck/scalacheck/GeneratorDefDefInjector.scala new file mode 100644 index 0000000000000000000000000000000000000000..c10b26a4da803ac9339395559d2beccbdedce90d --- /dev/null +++ b/oldsrc/funcheck/scalacheck/GeneratorDefDefInjector.scala @@ -0,0 +1,33 @@ +package funcheck.scalacheck + +import scala.tools.nsc.transform.TypingTransformers + +trait GeneratorDefDefInjector extends TypingTransformers { + import global._ + + def injectGenDefDefs(injecting: List[DefDef], unit: CompilationUnit): Unit = + unit.body = new GenDefDefTransformer(injecting, unit).transform(unit.body) + + class GenDefDefTransformer(injecting: List[DefDef], unit: CompilationUnit) + extends /*Code Injection*/ TypingTransformer(unit) + { + override def transform(tree: Tree): Tree = { + curTree = tree + tree match { + + case impl @ Template(parents, self, body) => + atOwner(currentOwner) { + val newBody: List[Tree] = body ::: (injecting.map(localTyper.typed(_))) + val cd = copy.Template(impl, parents, self, newBody) + cd + } + + /** Delegates the recursive traversal of the tree. */ + case _ => super.transform(tree) + } + } + + } +} + + \ No newline at end of file diff --git a/oldsrc/funcheck/scalacheck/ScalaCheck.scala b/oldsrc/funcheck/scalacheck/ScalaCheck.scala new file mode 100644 index 0000000000000000000000000000000000000000..5fda350475928a39149fe31e90cd797e85fa18dc --- /dev/null +++ b/oldsrc/funcheck/scalacheck/ScalaCheck.scala @@ -0,0 +1,786 @@ +package funcheck.scalacheck + +import scala.tools.nsc.Global +import scala.tools.nsc.util.NoPosition +import funcheck.util.FreshNameCreator + +/** + * Utilitarity class that is used as a factory for creating Tree nodes for method + * calls of classes and modules in the <code>org.scalacheck</code> package. + */ +trait ScalaCheck extends FreshNameCreator { + val global: Global + import global._ + + trait GenericScalaCheckModule { + /** Symbol for a module definition. */ + protected val moduleSym: Symbol + /** Symbol for the module's companion class definition. */ + protected lazy val classSym = moduleSym.linkedClassOfModule + + /** + * <p> + * Take a <code>symbol</code> and method <code>name</code> and return the associated + * method's symbol. + * </p> + * <p> + * Note: if <code>symbol</code> does not contain a method named </code>name</code>, the + * returned symbol will be a <code>NoSymbol</code>. + * </p> + * + * @param symbol A module/class symbol, + * @param name A name of the method that should be part of the declared members of the <code>symbol</code>. + * @return The symbol for the method 'symbol.name' or <code>NoSymbol</code> if the <code>symbol</code> does + * not have a member named <code>name</code>. + */ + private def symDecl(symbol: Symbol, name: String) = symbol.tpe.decl(name) + + /** Identical to symDecl(symbol: Symbol, name: String), but uses a Name object + * instead of a String for the <code>name</code>.*/ + private def symDecl(symbol: Symbol, name: Name) = symbol.tpe.decl(name) + + /** Retrieve the constructor Symbol for the passes <code>cs</code> ClassSymbol. */ + private def constructorDecl(cs: ClassSymbol) = symDecl(cs, nme.CONSTRUCTOR) + + /** + * <p> + * Take a method <code>name</code> and return the associated module method's symbol. + * </p> + * <p> + * Note: if module does not contain a method named </code>name</code>, the + * returned symbol will be a <code>NoSymbol</code>. + * </p> + * + * @param name A name of the method that should be part of the declared members of the module. + * @return The symbol for the method 'module.name' or <code>NoSymbol</code> if the module does + * not have a member named <code>name</code>. + */ + protected def modDecl(method: String) = symDecl(moduleSym, method) + + /** + * <p> + * Take a method <code>name</code> and return the associated (module's) companion class method's symbol. + * </p> + * <p> + * Note: if class does not contain a method named </code>name</code>, the + * returned symbol will be a <code>NoSymbol</code>. + * </p> + * + * @param name A name of the method that should be part of the declared members of the class. + * @return The symbol for the method 'class.name' or <code>NoSymbol</code> if the class does + * not have a member named <code>name</code>. + */ + protected def classDecl(method: String) = symDecl(classSym, method) + + /** + * <p> + * Take an <code>instance</code> symbol and a <code>method</code> name and return + * valid Scala Tree node of the form 'instance.method'. + * </p> + * <p> + * The precondition for this method to execute is that the <code>instance</code> Symbol + * contains in its members the selected <code>method</code>, otherwise calling this routine + * will throw an exception. + * </p> + * + * @param instance The Symbol for the instance whose <code>method</code> is selected. + * @param method The name of the selected method. + * @return A Scala valid Select Tree node of the form 'instance.method'. + * + */ + protected def select(instance: Symbol, method: String): Select = { + require(instance.tpe.decl(method) != NoSymbol) + Select(Ident(instance), symDecl(instance,method)) + } + + /** + * <p> + * Apply <code>arg</code> to the passed <code>method</code> contained in the + * <code>moduleSym</code> module and return a valid Scala Tree node of the + * form 'module.method(arg)'. + * </p> + * <p> + * The precondition for this method to execute is that the module Symbol + * contains in its members the passed <code>method</code>, otherwise calling + * this routine will throw an exception. + * </p> + * + * @param method The name of the selected method. + * @args The arguments to which the <code>method</code> is applied to. + * @return A Scala valid Apply Tree node of the form 'moduleSym.method(arg)'. + * + */ + protected def moduleApply(method: String, args: List[Tree]): Apply = + apply(select(moduleSym,method), args) + + /** Calls <code>moduleApply</code> and wraps the passed <code>arg</code> into a + * List, i.e., moduleApply(method, List(arg).*/ + protected def moduleApply(method: String, arg: Tree): Apply = moduleApply(method,List(arg)) + + /** + * <p> + * Generic apply. Applies <code>select</code> to the passed list of <code>arguments</code>. + * and return a valid Scala Tree Apply Node of the form 'select(arg1,arg2,...,argN)'. + * </p> + * <p> + * Note: No check is performed to ensure that <code>select</code> can accept + * the passed list of <code>arguments</code> + * </p> + * + * @param select The left hand side of the application. + * @param arguments The arguments of the application. + * @return A Scala valid Apply Tree node of the form 'select(arg1, arg32, ..., argN)' + */ + protected def apply(select: Tree, arguments: List[Tree]): Apply = + Apply(select, arguments) + + /** Calls <code>apply</code> and wraps the passed <code>arg</code> into a List, + * i.e., apply(select, List(arg)). */ + protected def apply(select: Tree, argument: Tree): Apply = + apply(select, List(argument)) + } + + + /** Module for creating scalac Tree nodes for calling methods of the + * <code>org.scalacheck.Gen</code> class and module.*/ + object Gen extends GenericScalaCheckModule { + + /** Symbol for the <code>org.scalacheck.Gen</code> module definition. */ + override protected lazy val moduleSym = definitions.getModule("org.scalacheck.Gen") + + /** + * Apply <code>polyTpe</code> to the polymorphic type <code>org.scalacheck.Gen</code>. + * + * @param polyTpe the type to be applied to <code>org.scalacheck.Gen</code>. + * @return The polymorphic type resulting from applying <code>polyTpe</code> + * to the polymorphic type <code>org.scalacheck.Gen</code>, i.e., + * <code>Gen[polyTpe]</code>. + */ + private def applyType(polyTpe: Type) = appliedType(classSym.tpe, List(polyTpe)) + + + /** + * This creates a Tree node for the call <code>org.scalacheck.Gen.value[T](rhs)</code>, + * where the polymorphic type <code>T</code> will be inferred during the next + * typer phase (this usually means that the typer has to be called explictly, + * so it is the developer duty to ensure that this happen at some point). + */ + def value(rhs: Tree): Tree = moduleApply("value", rhs) + + + /** + * This creates a Tree node for the call <code>org.scalacheck.Gen.oneOf[T](generators)</code>, + * where the polymorphic type <code>T</code> will be inferred during the next + * typer phase (this usually means that the typer has to be called explictly, + * so it is the developer duty to ensure that this happen at some point). + */ + def oneOf(generators: List[Symbol]): Tree = + moduleApply("oneOf", generators.map(Ident(_))) + + + def lzy(generator: Tree): Tree = moduleApply("lzy", generator) + + /** + * This creates a Tree node for the call <code>org.scalacheck.Gen.flatMap[T](body)</code>, + * where the polymorphic type <code>T</code> will be inferred during the next + * typer phase (this usually means that the typer has to be called explictly, + * so it is the developer duty to ensure that this happen at some point). + */ + def flatMap(qualifier: Tree, body: Tree): Tree = + apply(Select(qualifier, classDecl("flatMap")), body) + + + /** + * This creates a Tree node for the call <code>org.scalacheck.Gen.map[T](rhs)</code>, + * where the polymorphic type <code>T</code> will be inferred during the next + * typer phase (this usually means that the typer has to be called explictly, + * so it is the developer duty to ensure that this happen at some point). + */ + def map(qualifier: Tree, body: Tree): Tree = + apply(Select(qualifier, classDecl("map")), body) + + + + /** + * Utilitary method for creating a method symbol for a <code>org.scalacheck.Gen</codee> + * generator method. + * + * @param owner The owner of the method (DefDef) which will use the returned method symbol. + * @param genName The name of the method symbol (which will also be the name of the method). + * @param retTpe The method's returning type. + * @return The method symbol for a generator method. + */ + def createGenDefSymbol(owner: Symbol, genName: String, retTpe: Type): Symbol = { + // returning type of the new method, i.e., Gen["retTpe"] + val genDefRetTpe = applyType(retTpe) + + // create a symbol for the generator method that will be created next + owner.newMethod(owner.pos,genName).setInfo(PolyType(List(), genDefRetTpe)) + } + + + + /** + * Map that stores for each @generator annotated ClassDef or DefDef the automatically + * generated DefDef for creating instances of the <code>org.scalacheck.Gen</code> class. + * The <code>Type</code> that is associated to the DefDef is either the type of the + * ClassDef or the returning type of the DefDef. + */ + private val tpe2listGen = scala.collection.mutable.Map.empty[Type, List[DefDef]] + private val tpe2listGenSym = scala.collection.mutable.Map.empty[Type, List[Symbol]] + + /** + * Add the <code>gen</code> generator DefDef declaration to the list of + * generators for <code>tpe</code>. + * + * @param tpe The type of elements generated by the <code>gen</code>. + * @param gen The DefDef declaration for the generator method. + */ + def +[T](map: collection.mutable.Map[Type, List[T]], key: Type, value: T): Unit = map.get(key) match { + case None => map += key -> List(value) + case Some(values) => map += key -> (value :: values) + } + + /** List of generator DefDef symbols for a given type <code>tpe</code>*/ + def genSymbolsForType(tpe: Type): List[Symbol] = tpe2listGenSym.get(tpe) match { + case None => Nil + case Some(symbols) => symbols + } + + /** + * Second Pass: Create symbols for the generator DefDef that will be created + * durind the Third Pass. + */ + def createGenDefDef(klasses: List[ClassDef], defs: List[DefDef]): List[DefDef] = { + val generable: List[(Symbol,Tree)] = createGenDefSyms(klasses, defs) + + for { (genSym, genTree) <- generable } genTree match { + case cd: ClassDef => + val tpe = cd.symbol.tpe + Gen + (tpe2listGen, tpe, Gen.createGenDef(cd, genSym)) + + case d: DefDef => + val tpe = d.tpt.symbol.tpe + val generated = DefDef(genSym, Modifiers(0), List(), rhsGenDef(Ident(d.name))(d)(genSym)) + Gen + (tpe2listGen, tpe, generated) + } + + // flatten into single list values of Gen.tpe2listGen + (List[DefDef]() /: Gen.tpe2listGen.values) { + case (xs, xss) => xs ::: xss + } + } + + + /** + * Create method symbols for each <code>@generator</code> annotated ClassDef + * and DefDef. + */ + private def createGenDefSyms(klasses: List[ClassDef], defs: List[DefDef]): List[(Symbol, Tree)] = { + + val genKlasses: List[(Symbol, ClassDef)] = for(klass <- klasses) yield { + val genName = fresh.newName(NoPosition, "gen"+klass.name) + val tpe = klass.symbol.tpe + val genSym = createGenDefSymbol(klass.symbol.enclClass.owner, genName, tpe) + + Gen + (tpe2listGenSym, tpe, genSym) + + (genSym, klass) + } + + val genDefs: List[(Symbol, DefDef)] = for(d <- defs) yield { + val genName = fresh.newName(NoPosition, "gen"+d.name) + val tpe = d.tpt.symbol.tpe + val genSym = createGenDefSymbol(d.symbol.owner, genName, tpe) + + Gen + (tpe2listGenSym, tpe, genSym) + + (genSym, d) + } + + genKlasses ::: genDefs + } + + + + def createGenDef(cd: ClassDef, genDef: Symbol): DefDef = { + val d: DefDef = getConstructorOf(cd) + val DefDef(_,_,_,vparamss,retTpe,_) = d + assert(vparamss.size <= 1, "currying is not supported. Change signature of "+cd.symbol) + + + if(cd.symbol.hasFlag(scala.tools.nsc.symtab.Flags.ABSTRACT)) { + val generators = retTpe.symbol.children.toList.map(s => genSymbolsForType(s.tpe)).flatMap(v=>v) + DefDef(genDef, Modifiers(0), List(), Gen.lzy(Gen.oneOf(generators))) + } + else { + + val constrObj = resetAttrs(d.tpt.duplicate) + val instance = Select(New(constrObj), nme.CONSTRUCTOR) + + assert(d.tpt.isInstanceOf[TypeTree]) + + val body = rhsGenDef(instance)(d)(genDef) + DefDef(genDef, Modifiers(0), List(), body) + } + } + + + /** <code>base</code> is either + * - Select(New(tpe),constructor) [constructor] + * - Ident(name) [method call] + */ + private def rhsGenDef(base: Tree)(d: DefDef)(extOwner: Symbol): Tree = { + val DefDef(_,name,_,vparamss,retTpe,_) = d + assert(vparamss.size <= 1, "currying is not supported. Change signature of "+d.symbol) + // XXX: quick fix to force creation of arbitrary objects for each data type, this should be refactored!! + Arbitrary.arbitrary(retTpe.asInstanceOf[TypeTree]) + + if(vparamss.head.isEmpty) + Gen.value(Apply(base, Nil)) + + else { + var owner = extOwner + + val paramssTpe: List[ValDef] = vparamss.flatMap(v=>v).map(p => + ValDef(Modifiers(0), fresh.newName(NoPosition, "v"), resetAttrs(p.tpt.duplicate), EmptyTree)) + + + var last = true + + + val z :Tree = Apply(base, paramssTpe.map(p => Ident(p.name))) + val body = (paramssTpe :\ z) { + case (param,apply) => { + val body = Function(List(param), apply) + body.symbol.owner = owner + owner = body.symbol + //XXX: it is not flatMap in general. fix this!! + if(last) { + last = false + Gen.map(Arbitrary.arbitrary(param.tpt.asInstanceOf[TypeTree]), body) + } else + Gen.flatMap(Arbitrary.arbitrary(param.tpt.asInstanceOf[TypeTree]), body) + } + } + + + Gen.lzy(body) + } + } + + + + private def getConstructorOf(cd: ClassDef): DefDef = { + val Template(parents, self, body) = cd.impl + var dd: DefDef = null + for { b <- body } b match { + case d @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => dd = d + case _ => ; + } + dd + } ensuring (res => res != null) + + + + } + + + + /** Module for creating scalac Tree nodes for calling methods of the + * <code>org.scalacheck.Arbitrary</code> class and module.*/ + object Arbitrary extends GenericScalaCheckModule { + + + /** Symbol for the <code>org.scalacheck.Arbitrary</code> module definition. */ + override protected lazy val moduleSym = definitions.getModule("org.scalacheck.Arbitrary") + + /** Symbol for the <code>org.scalacheck.Arbitrary.arbInt</code> method definition. */ + private val arbInt = select(moduleSym, "arbInt") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbBool</code> method definition. */ + private val arbBool = select(moduleSym, "arbBool") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbLong</code> method definition. */ + private val arbLong = select(moduleSym, "arbLong") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbThrowable</code> method definition. */ + private val arbThrowable = select(moduleSym, "arbThrowable") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbDouble</code> method definition. */ + private val arbDouble = select(moduleSym, "arbDouble") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbChar</code> method definition. */ + private val arbChar = select(moduleSym, "arbChar") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbString</code> method definition. */ + private val arbString = select(moduleSym, "arbString") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbOption</code> method definition. */ + private val arbOption = select(moduleSym, "arbOption") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbImmutableMap</code> method definition. */ + private val arbImmutableMap = select(moduleSym, "arbImmutableMap") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbList</code> method definition. */ + private val arbList = select(moduleSym, "arbList") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbArray</code> method definition. */ + private val arbArray = select(moduleSym, "arbArray") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbSet</code> method definition. */ + private val arbSet = select(moduleSym, "arbSet") + /** Symbol for the <code>org.scalacheck.Arbitrary.arbTuple2</code> method definition. */ + private val arbTuple2 = select(moduleSym, "arbTuple2") + + //[[TODO]] + //lazy val arbMultiSet = Select(Ident(arbitraryModule), arbitraryModule.tpe.decl("arbMultiSet")) + + + + /** Map that stores <code>org.scalacheck.Arbitrary.arbitrary[Type]</code> calls. */ + protected val tpe2arbApp = scala.collection.mutable.Map.empty[Type,Tree] + + + // initialize map with ScalaCheck built-in types that are part of our PureScala language + import definitions._ + tpe2arbApp += IntClass.typeConstructor -> arbInt + tpe2arbApp += BooleanClass.typeConstructor -> arbBool + tpe2arbApp += LongClass.typeConstructor -> arbLong + tpe2arbApp += ThrowableClass.typeConstructor -> arbThrowable + tpe2arbApp += DoubleClass.typeConstructor -> arbDouble + tpe2arbApp += CharClass.typeConstructor -> arbChar + tpe2arbApp += StringClass.typeConstructor -> arbString // XXX: NOT WORKING + tpe2arbApp += OptionClass.typeConstructor -> arbOption + + //lazy val ImmutableMapClass: Symbol = definitions.getClass(newTypeName("scala.collection.immutable.Map")) + //lazy val ImmutableSetClass: Symbol = definitions.getClass(newTypeName("scala.collection.immutable.Set")) + + //tpe2arbApp += ImmutableMapClass.typeConstructor -> arbImmutableMap + tpe2arbApp += ListClass.typeConstructor -> arbList + tpe2arbApp += ArrayClass.typeConstructor -> arbArray + //tpe2arbApp += ImmutableSetClass.typeConstructor -> arbSet + tpe2arbApp += TupleClass(2).typeConstructor -> arbTuple2 + + /** + * Apply <code>polyTpe</code> to the polymorphic type <code>org.scalacheck.Arbitrary</code>. + * + * @param polyTpe the type to be applied to <code>org.scalacheck.Arbitrary</code>. + * @return The polymorphic type resulting from applying <code>polyTpe</code> + * to the polymorphic type <code>org.scalacheck.Arbitrary</code>, i.e., + * <code>Arbitrary[polyTpe]</code>. + */ + private def applyType(tpe: Type) = appliedType(classSym.tpe, List(tpe)) + + /** + * Creates a Tree node for the call <code>org.scalacheck.Arbitrary.apply[T](generator)</code>, + * where the polymorphic type <code>T</code> will be inferred during the next + * typer phase (this usually means that the typer has to be called explictly, + * so it is the developer duty to ensure that this happen at some point). + */ + def apply(generator: Tree): Tree = moduleApply("apply", generator) + + def arbitrary(tpe: Type): Tree = tpe2arbApp.get(tpe) match { + case Some(arbTree) => arbTree + case None => + val TypeRef(_,sym,params) = tpe + apply(arbitrary(sym.typeConstructor), params.map(arbitrary(_))) + } + + + /** + * + */ + def arbitrary(polyTpe: TypeTree): Apply = { + val symbol = polyTpe.symbol + val tpe = symbol.tpe + tpe2arbApp.get(tpe) match { + case Some(arb) => applyArbitrary(arb) + case None => arbitrary(symbol) + } + } + + /** Map that stores not built-in <code>org.scalacheck.Arbitrary</code> DefDef definitions. */ + private val tpe2arbDefDef = scala.collection.mutable.Map.empty[Type,DefDef] + + def getArbitraryDefDefs: List[DefDef] = tpe2arbDefDef.values.toList + + def arbitrary(tpeSym: Symbol): Apply = { + require(tpe2arbApp.get(tpeSym.tpe).isEmpty, "Arbitrary.arbitrary["+tpeSym.tpe+"] is already in the map") + + val owner = tpeSym.toplevelClass + val arbName = fresh.newName(NoPosition,"arb"+tpeSym.name) + val tpe = tpeSym.tpe + + val arbDef = createArbitraryDefSymbol(owner, arbName, tpe) + + + val genNames = Gen.genSymbolsForType(tpe) + + + val generated = DefDef(arbDef, Modifiers(0), List(), Arbitrary(Gen.oneOf(genNames))) + tpe2arbDefDef += tpe -> generated + + val result = applyArbitrary(Ident(arbDef)) + tpe2arbApp += tpe -> Ident(arbDef) + + result + + } + + + protected def applyArbitrary(param: Tree): Apply = + apply(select(moduleSym, "arbitrary"), param) + + + /** + * Utilitary method for creating a method symbol for a <code>org.scalacheck.Arbitrary</codee> + * generator method. + * + * @param owner The owner of the method (DefDef) which will use the returned method symbol. + * @param arbName The name of the method symbol (which will also be the name of the method). + * @param retTpe The method's returning type. + * @return The method symbol for a generator method. + */ + def createArbitraryDefSymbol(owner: Symbol, arbName: String, retTpe: Type): Symbol = { + // returning type of the new method, i.e., Arbitrary["retTpe"] + val arbRetTpe = applyType(retTpe) + + // Create the DefDef for the new Arbitrary object + val arbDef = owner.newMethod(owner.pos, arbName).setInfo(PolyType(List(), arbRetTpe)) + // Implicit only because of ScalaCheck rational (not really needed since we are injecting code) + arbDef.setFlag(scala.tools.nsc.symtab.Flags.IMPLICIT) + + arbDef + } + } + + object Prop extends GenericScalaCheckModule { + + /** Symbol for the <code>org.scalacheck.Prop</code> module definition. */ + override protected lazy val moduleSym = definitions.getModule("org.scalacheck.Prop") + + + def forAll(props: List[Tree]): Apply = + moduleApply("forAll", props) + + def forAll(prop: Tree): Apply = forAll(List(prop)) + + def ==>(ifz: Tree, then: Tree): Apply = moduleApply("==>", List(ifz,propBoolean(then))) + + def propBoolean(prop: Tree): Apply = moduleApply("propBoolean", List(prop)) + + } + + + object Shrink extends GenericScalaCheckModule { + + /** Symbol for the <code>org.scalacheck.Shrink</code> module definition. */ + override protected lazy val moduleSym = definitions.getModule("org.scalacheck.Shrink") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkInt</code> method definition. */ + private val shrinkInt = select(moduleSym, "shrinkInt") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkString</code> method definition. */ + private val shrinkString = select(moduleSym, "shrinkString") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkOption</code> method definition. */ + private val shrinkOption = select(moduleSym, "shrinkOption") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkList</code> method definition. */ + private val shrinkList = select(moduleSym, "shrinkList") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkSet</code> method definition. */ + private val shrinkArray = select(moduleSym, "shrinkArray") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkSet</code> method definition. */ + private val shrinkSet = select(moduleSym, "shrinkSet") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple2</code> method definition. */ + private val shrinkTuple2 = select(moduleSym, "shrinkTuple2") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple3</code> method definition. */ + private val shrinkTuple3 = select(moduleSym, "shrinkTuple3") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple4</code> method definition. */ + private val shrinkTuple4 = select(moduleSym, "shrinkTuple4") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple5</code> method definition. */ + private val shrinkTuple5 = select(moduleSym, "shrinkTuple5") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple6</code> method definition. */ + private val shrinkTuple6 = select(moduleSym, "shrinkTuple6") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple7</code> method definition. */ + private val shrinkTuple7 = select(moduleSym, "shrinkTuple7") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple8</code> method definition. */ + private val shrinkTuple8 = select(moduleSym, "shrinkTuple8") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkTuple9</code> method definition. */ + private val shrinkTuple9 = select(moduleSym, "shrinkTuple9") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntList</code> method definition. */ + private val shrinkIntList = select(moduleSym, "shrinkIntList") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanList</code> method definition. */ + private val shrinkBooleanList = select(moduleSym, "shrinkBooleanList") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleList</code> method definition. */ + private val shrinkDoubleList = select(moduleSym, "shrinkDoubleList") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringList</code> method definition. */ + private val shrinkStringList = select(moduleSym, "shrinkStringList") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntArray</code> method definition. */ + private val shrinkIntArray = select(moduleSym, "shrinkIntArray") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanArray</code> method definition. */ + private val shrinkBooleanArray = select(moduleSym, "shrinkBooleanArray") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleArray</code> method definition. */ + private val shrinkDoubleArray = select(moduleSym, "shrinkDoubleArray") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringArray</code> method definition. */ + private val shrinkStringArray = select(moduleSym, "shrinkStringArray") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntSet</code> method definition. */ + private val shrinkIntSet = select(moduleSym, "shrinkIntSet") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanSet</code> method definition. */ + private val shrinkBooleanSet = select(moduleSym, "shrinkBooleanSet") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleSet</code> method definition. */ + private val shrinkDoubleSet = select(moduleSym, "shrinkDoubleSet") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringSet</code> method definition. */ + private val shrinkStringSet = select(moduleSym, "shrinkStringSet") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntOption</code> method definition. */ + private val shrinkIntOption = select(moduleSym, "shrinkIntOption") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanOption</code> method definition. */ + private val shrinkBooleanOption= select(moduleSym, "shrinkBooleanOption") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleOption</code> method definition. */ + private val shrinkDoubleOption = select(moduleSym, "shrinkDoubleOption") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringOption</code> method definition. */ + private val shrinkStringOption = select(moduleSym, "shrinkStringOption") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntTuple2</code> method definition. */ + private val shrinkIntTuple2 = select(moduleSym, "shrinkIntTuple2") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanTuple2</code> method definition. */ + private val shrinkBooleanTuple2= select(moduleSym, "shrinkBooleanTuple2") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleTuple2</code> method definition. */ + private val shrinkDoubleTuple2 = select(moduleSym, "shrinkDoubleTuple2") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringTuple2</code> method definition. */ + private val shrinkStringTuple2 = select(moduleSym, "shrinkStringTuple2") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntTuple3</code> method definition. */ + private val shrinkIntTuple3 = select(moduleSym, "shrinkIntTuple3") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanTuple3</code> method definition. */ + private val shrinkBooleanTuple3= select(moduleSym, "shrinkBooleanTuple3") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleTuple3</code> method definition. */ + private val shrinkDoubleTuple3 = select(moduleSym, "shrinkDoubleTuple3") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringTuple3</code> method definition. */ + private val shrinkStringTuple3 = select(moduleSym, "shrinkStringTuple3") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkIntTuple4</code> method definition. */ + private val shrinkIntTuple4 = select(moduleSym, "shrinkIntTuple4") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkBooleanTuple4</code> method definition. */ + private val shrinkBooleanTuple4= select(moduleSym, "shrinkBooleanTuple4") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkDoubleTuple4</code> method definition. */ + private val shrinkDoubleTuple4 = select(moduleSym, "shrinkDoubleTuple4") + /** Symbol for the <code>org.scalacheck.Shrink.shrinkStringTuple4</code> method definition. */ + private val shrinkStringTuple4 = select(moduleSym, "shrinkStringTuple4") + + /** Symbol for the <code>org.scalacheck.Shrink.shrinkAny</code> method definition. + * This is a generic shrinker which does not shrink whatever object is passed to it. + */ + private val shrinkAny = select(moduleSym, "shrinkAny") + + def shrinker(tpe: Type): Select = tpe2shrinker.getOrElse(tpe, shrinkAny) + + private val tpe2shrinker: Map[Type, Select] = { + import definitions._ + val SetClass: Symbol = definitions.getClass("scala.collection.immutable.Set") + + def apply(container: Type)(parametric: Type): Type = + appliedType(container, List(parametric)) + + def listOf(tpe: Type): Type = apply(ListClass.typeConstructor)(tpe) + def arrayOf(tpe: Type): Type = apply(ArrayClass.typeConstructor)(tpe) + def setOf(tpe: Type): Type = apply(SetClass.typeConstructor)(tpe) + def optionOf(tpe: Type): Type = apply(OptionClass.typeConstructor)(tpe) + def tupleOf(arity: Int, tpe: Type): Type = apply(TupleClass(arity).typeConstructor)(tpe) + + val IntListTpe = listOf(IntClass.typeConstructor) + val BooleanListTpe = listOf(BooleanClass.typeConstructor) + val DoubleListTpe = listOf(DoubleClass.typeConstructor) + val StringListTpe = listOf(StringClass.typeConstructor) + + val IntArrayTpe = arrayOf(IntClass.typeConstructor) + val BooleanArrayTpe = arrayOf(BooleanClass.typeConstructor) + val DoubleArrayTpe = arrayOf(DoubleClass.typeConstructor) + val StringArrayTpe = arrayOf(StringClass.typeConstructor) + + val IntSetTpe = setOf(IntClass.typeConstructor) + val BooleanSetTpe = setOf(BooleanClass.typeConstructor) + val DoubleSetTpe = setOf(DoubleClass.typeConstructor) + val StringSetTpe = setOf(StringClass.typeConstructor) + + val IntOptionTpe = optionOf(IntClass.typeConstructor) + val BooleanOptionTpe = optionOf(BooleanClass.typeConstructor) + val DoubleOptionTpe = optionOf(DoubleClass.typeConstructor) + val StringOptionTpe = optionOf(StringClass.typeConstructor) + + val IntTuple2Tpe = tupleOf(2, IntClass.typeConstructor) + val BooleanTuple2Tpe = tupleOf(2, BooleanClass.typeConstructor) + val DoubleTuple2Tpe = tupleOf(2, DoubleClass.typeConstructor) + val StringTuple2Tpe = tupleOf(2, StringClass.typeConstructor) + + val IntTuple3Tpe = tupleOf(3, IntClass.typeConstructor) + val BooleanTuple3Tpe = tupleOf(3, BooleanClass.typeConstructor) + val DoubleTuple3Tpe = tupleOf(3, DoubleClass.typeConstructor) + val StringTuple3Tpe = tupleOf(3, StringClass.typeConstructor) + + val IntTuple4Tpe = tupleOf(4, IntClass.typeConstructor) + val BooleanTuple4Tpe = tupleOf(4, BooleanClass.typeConstructor) + val DoubleTuple4Tpe = tupleOf(4, DoubleClass.typeConstructor) + val StringTuple4Tpe = tupleOf(4, StringClass.typeConstructor) + + Map( + IntClass.typeConstructor -> shrinkInt, + StringClass.typeConstructor -> shrinkString, + OptionClass.typeConstructor -> shrinkOption, + ListClass.typeConstructor -> shrinkList, + ArrayClass.typeConstructor -> shrinkArray, + SetClass.typeConstructor -> shrinkSet, + TupleClass(2).typeConstructor -> shrinkTuple2, + TupleClass(3).typeConstructor -> shrinkTuple3, + TupleClass(4).typeConstructor -> shrinkTuple4, + TupleClass(5).typeConstructor -> shrinkTuple5, + TupleClass(6).typeConstructor -> shrinkTuple6, + TupleClass(7).typeConstructor -> shrinkTuple7, + TupleClass(8).typeConstructor -> shrinkTuple8, + TupleClass(9).typeConstructor -> shrinkTuple9, + IntListTpe -> shrinkIntList, + BooleanListTpe -> shrinkBooleanList, + DoubleListTpe -> shrinkDoubleList, + StringListTpe -> shrinkStringList, + IntArrayTpe -> shrinkIntArray, + BooleanArrayTpe -> shrinkBooleanArray, + DoubleArrayTpe -> shrinkDoubleArray, + StringArrayTpe -> shrinkStringArray, + IntSetTpe -> shrinkIntSet, + BooleanSetTpe -> shrinkBooleanSet, + DoubleSetTpe -> shrinkDoubleSet, + StringSetTpe -> shrinkStringSet, + IntOptionTpe -> shrinkIntOption, + BooleanOptionTpe -> shrinkBooleanOption, + DoubleOptionTpe -> shrinkDoubleOption, + StringOptionTpe -> shrinkStringOption, + IntTuple2Tpe -> shrinkIntTuple2, + BooleanTuple2Tpe -> shrinkBooleanTuple2, + DoubleTuple2Tpe -> shrinkDoubleTuple2, + StringTuple2Tpe -> shrinkStringTuple2, + IntTuple3Tpe -> shrinkIntTuple3, + BooleanTuple3Tpe -> shrinkBooleanTuple3, + DoubleTuple3Tpe -> shrinkDoubleTuple3, + StringTuple3Tpe -> shrinkStringTuple3, + IntTuple4Tpe -> shrinkIntTuple4, + BooleanTuple4Tpe -> shrinkBooleanTuple4, + DoubleTuple4Tpe -> shrinkDoubleTuple4, + StringTuple4Tpe -> shrinkStringTuple4 + ) + } + } + + + object ConsoleReporter extends GenericScalaCheckModule { + /** Symbol for the <code>org.scalacheck.ConsoleReporter</code> module definition. */ + override protected lazy val moduleSym = definitions.getModule("org.scalacheck.ConsoleReporter") + + def testStatsEx(testRes: Tree): Tree = testStatsEx("", testRes) + + def testStatsEx(msg: String, testRes: Tree): Tree = + Apply(select(moduleSym, "testStatsEx"), List(Literal(msg), testRes)) + } + + object Test extends GenericScalaCheckModule { + /** Symbol for the <code>org.scalacheck.Test</code> module definition. */ + override protected lazy val moduleSym = definitions.getModule("org.scalacheck.Test") + + def check(prop: Tree): Tree = moduleApply("check", prop) + + def isPassed(res: Tree): Tree = Select(res, "passed") + } + +} diff --git a/oldsrc/funcheck/scalacheck/ScalaCheckIntegrator.scala b/oldsrc/funcheck/scalacheck/ScalaCheckIntegrator.scala new file mode 100644 index 0000000000000000000000000000000000000000..c212589ad9acaad69f4cf98d6f018c95a110db73 --- /dev/null +++ b/oldsrc/funcheck/scalacheck/ScalaCheckIntegrator.scala @@ -0,0 +1,31 @@ +package funcheck.scalacheck + +import scala.tools.nsc.{Global, SubComponent} + + +trait ScalaCheckIntegrator extends ScalaCheck + with FilterGeneratorAnnotations + with GeneratorDefDefInjector + with ForAllTransformer +{ + val global: Global + import global._ + + + def createGeneratorDefDefs(unit: CompilationUnit): (List[DefDef], List[DefDef]) = { + val filteredGenTree = new FilterTreeTraverser(filterTreesWithGeneratorAnnotation(unit)) + filteredGenTree.traverse(unit.body) + + val klasses = collection.mutable.Set.empty[ClassDef] + val defs = collection.mutable.Set.empty[DefDef] + + for {tree <- filteredGenTree.hits} tree match { + case c: ClassDef => klasses + c + case d: DefDef => defs + d + } + + (Gen.createGenDefDef(klasses.toList,defs.toList), Arbitrary.getArbitraryDefDefs) + } + + +} diff --git a/oldsrc/funcheck/util/FreshNameCreator.scala b/oldsrc/funcheck/util/FreshNameCreator.scala new file mode 100644 index 0000000000000000000000000000000000000000..3e51a5e4206c392a8bc92818f51f8df277dabcae --- /dev/null +++ b/oldsrc/funcheck/util/FreshNameCreator.scala @@ -0,0 +1,5 @@ +package funcheck.util + +trait FreshNameCreator { + var fresh: scala.tools.nsc.util.FreshNameCreator +} diff --git a/oldsrc/scala/collection/Multiset.scala b/oldsrc/scala/collection/Multiset.scala new file mode 100644 index 0000000000000000000000000000000000000000..23c6255bbf986f683991e5f3682e3373909b26d9 --- /dev/null +++ b/oldsrc/scala/collection/Multiset.scala @@ -0,0 +1,81 @@ +package scala.collection + + +trait Multiset[A] extends (A => Int) with Collection[A]{ + + /** Returns the number of elements in this multiset. + * + * @return number of multiset elements. + */ + def size: Int + + /** This method allows multisets to be interpreted as predicates. + * It returns <code>0</code>, iff this multiset does not contain + * element <code>elem</code>, or <code>N</code> where <code>N</code> + * is the number of occurences of <code>elem</code> in this multiset. + * + * @param elem the element to check for membership. + * @return <code>0</code> iff <code>elem</code> is not contained in + * this multiset, or <code>N</code> where <code>N</code> + * is the number of occurences of <code>elem</code> in this + * multiset. + */ + def apply(elem: A): Int + + /** Checks if this set contains element <code>elem</code>. + * + * @param elem the element to check for membership. + * @return <code>true</code> iff <code>elem</code> is not contained in + * this multiset. + */ + def contains(elem: A): Boolean = apply(elem) > 0 + + /** Checks if this multiset is empty. + * + * @return <code>true</code> iff there is no element in the multiset. + */ + override def isEmpty: Boolean = size == 0 + + /** Checks if this multiset is a subset of set <code>that</code>. + * + * @param that another multiset. + * @return <code>true</code> iff the other multiset is a superset of + * this multiset. + * todo: rename to isSubsetOf + */ + def subsetOf(that: Multiset[A]): Boolean = + forall(e => this(e) <= that(e)) + + /** + * This method is an alias for <code>intersect</code>. It computes an + * intersection with set that. It removes all the elements + * <code>that</code> are not present in that. + */ + def ** (that: Multiset[A]): Multiset[A] + + /** @return this multiset as set. */ + def asSet: Set[A] + + + //structural equality + /** Compares this multiset with another object and returns true, iff the + * other object is also a multiset which contains the same elements as + * this multiset, with the same cardinality. + * + * @param that the other object + * @note not necessarily run-time type safe. + * @return <code>true</code> iff this multiset and the other multiset + * contain the same elements, with same cardinality. + */ + override def equals(that: Any): Boolean = that match { + case other: Multiset[_] => other.size == this.size && subsetOf(other.asInstanceOf[Multiset[A]]) + case _ => false + } + + /** Defines the prefix of this object's <code>toString</code> representation. + */ + override protected def stringPrefix : String = "Multiset" + + + override def toString = elements.mkString(stringPrefix + "(", ", ", ")") +} diff --git a/oldsrc/scala/collection/immutable/EmptyMultiset.scala b/oldsrc/scala/collection/immutable/EmptyMultiset.scala new file mode 100644 index 0000000000000000000000000000000000000000..c688a80f35626282b9dd2b8f9a01b4110a15a54c --- /dev/null +++ b/oldsrc/scala/collection/immutable/EmptyMultiset.scala @@ -0,0 +1,24 @@ +package scala.collection.immutable + +class EmptyMultiset[A] extends Multiset[A] with Helper[A]{ + + def empty[C]: Multiset[C] = new EmptyMultiset[C] + + override def size: Int = 0 + + override def apply(elem: A): Int = 0 + + override def contains(elem: A): Boolean = false + + override def intersect (that: collection.Multiset[A]): Multiset[A] = empty + + override def ++ (elems: Iterable[A]): Multiset[A] = iterable2multiset(elems) + + override def +++ (elems: Iterable[A]): Multiset[A] = this ++ elems + + override def --(elems: Iterable[A]): Multiset[A] = empty + + override def elements: Iterator[A] = Iterator.empty + + override def asSet: Set[A] = new EmptySet[A] +} diff --git a/oldsrc/scala/collection/immutable/HashMultiset.scala b/oldsrc/scala/collection/immutable/HashMultiset.scala new file mode 100644 index 0000000000000000000000000000000000000000..ac53f935923a789ee37438cd830219c418e0e50b --- /dev/null +++ b/oldsrc/scala/collection/immutable/HashMultiset.scala @@ -0,0 +1,79 @@ +package scala.collection.immutable + +object HashMultiset { + + /** The empty multiset of this type. */ + def empty[A]: Multiset[A] = new EmptyMultiset[A] + + /** The canonical factory for this type */ + def apply[A](elems: A*) = empty[A] ++ elems +} + +class HashMultiset[A] private[immutable] (private val map: Map[A,Int]) extends Multiset[A] with Helper[A] { + + def empty[C]: Multiset[C] = new EmptyMultiset[C] + + override def size: Int = map.values.foldLeft(0)((a,b) => a+b) + + override def apply(elem: A): Int = map.getOrElse(elem,0) + + override def intersect (that: collection.Multiset[A]): Multiset[A] = { + def inner(entries: List[A], result: Map[A,Int]): Map[A,Int] = entries match { + case Nil => result + case elem :: rest => inner(rest, result.update(elem, min(this(elem),that(elem)))) + } + + new HashMultiset[A](inner(asSet.toList,new HashMap[A,Int].empty)) + } + + + override def ++ (elems: Iterable[A]): Multiset[A] = { + val that = iterable2multiset(elems) + + def inner(entries: List[A], result: Map[A,Int]): Map[A,Int] = entries match { + case Nil => result + case elem :: rest => + inner(rest, result.update(elem,max(result.getOrElse(elem,0),that(elem)))) + } + + new HashMultiset[A](inner(that.asSet.toList, map)) + } + + + override def +++ (elems: Iterable[A]): Multiset[A] = { + def inner(entries: List[A], result: Map[A,Int]): Map[A,Int] = entries match { + case Nil => result + case elem :: rest => + inner(rest, result.update(elem,result.getOrElse(elem,0)+1)) + } + + new HashMultiset[A](inner(elems.toList,map)) + } + + override def --(elems: Iterable[A]): Multiset[A] = { + val that = iterable2multiset(elems) + def inner(entries: List[A], result: Map[A,Int]): Map[A,Int] = entries match { + case Nil => result + case elem :: rest => + val diff = result.getOrElse(elem,0) - that(elem) + if(diff > 0) + inner(rest, result.update(elem,diff)) + else + inner(rest, result - elem) + } + + new HashMultiset[A](inner(that.asSet.toList,map)) + } + + override def elements: Iterator[A] = { + def inner(entries: List[A], result: List[A]): List[A] = entries match { + case Nil => result + case elem :: rest => + inner(rest, result ::: int2list(elem, this(elem))) + } + + inner(map.keys.toList, Nil).elements + } + + override def asSet: Set[A] = Set.empty[A] ++ map.keys +} diff --git a/oldsrc/scala/collection/immutable/Helper.scala b/oldsrc/scala/collection/immutable/Helper.scala new file mode 100644 index 0000000000000000000000000000000000000000..100c9772587891b1590c7eae12c60700ea0969f1 --- /dev/null +++ b/oldsrc/scala/collection/immutable/Helper.scala @@ -0,0 +1,24 @@ +package scala.collection.immutable + +private[immutable] trait Helper[A] { + + protected def int2list[C](elem: C, times: Int): List[C] = { + require(times >= 0) + if(times == 0) + Nil + else + elem :: int2list(elem,times-1) + } ensuring (res => res.size == times) + + protected def iterable2multiset(elems: Iterable[A]): Multiset[A] = { + def inner(elems: List[A], result: Map[A,Int]): Map[A,Int] = elems match { + case Nil => result + case elem :: tail => inner(tail, result.update(elem, result.getOrElse(elem,0) + 1)) + } + new HashMultiset[A](inner(elems.toList,new scala.collection.immutable.HashMap[A,Int].empty)) + } + + protected def min(a: Int, b: Int): Int = if(a <= b) a else b + protected def max(a: Int, b: Int): Int = if(a < b) b else a + +} diff --git a/oldsrc/scala/collection/immutable/Multiset.scala b/oldsrc/scala/collection/immutable/Multiset.scala new file mode 100644 index 0000000000000000000000000000000000000000..6a4c89d85c888a154179de29e7f6e0270d440126 --- /dev/null +++ b/oldsrc/scala/collection/immutable/Multiset.scala @@ -0,0 +1,43 @@ +package scala.collection.immutable + + +object Multiset { + /** The empty set of this type */ + def empty[A]: Multiset[A] = new EmptyMultiset[A] + + /** The canonical factory for this type */ + def apply[A](elems: A*): Multiset[A] = empty[A] +++ elems + +} + +trait Multiset[A] extends AnyRef with collection.Multiset[A]{ + + /** This method is an alias for <code>intersect</code>. + * It computes an intersection with multiset <code>that</code>. + * It removes all the elements that are not present in <code>that</code>. + * + * @param that the multiset to intersect with + */ + final override def ** (that: collection.Multiset[A]): Multiset[A] = intersect(that) + + /** + * This method computes an intersection with multiset that. It removes all + * the elements that are not present in that. + */ + def intersect (that: collection.Multiset[A]): Multiset[A] + + // A U elems (max) + def ++ (elems: Iterable[A]): Multiset[A] + + // A U elems (sum) + def +++ (elems: Iterable[A]): Multiset[A] + + // A \ {elems} + def --(elems: Iterable[A]): Multiset[A] + + // A U {elems} + final def + (elems: A*): Multiset[A] = this ++ elems + + // A \ {elems} + final def - (elems: A*): Multiset[A] = this -- elems +} diff --git a/testcases/README b/testcases/README new file mode 100644 index 0000000000000000000000000000000000000000..020435430314d78ec6d7d0a373bfc6b8b1bc538f --- /dev/null +++ b/testcases/README @@ -0,0 +1,2 @@ +Anything that's in this directory needs to be parsable by FunCheck, otherwise +it will make me angry.