diff --git a/library/leon/collection/List.scala b/library/leon/collection/List.scala index 5803bbf993def9d80019a7f7839860cf249db729..a7bf09527b530d64e1f29811f7074ef764ae694e 100644 --- a/library/leon/collection/List.scala +++ b/library/leon/collection/List.scala @@ -575,15 +575,15 @@ object List { res.size == (if (n <= BigInt(0)) BigInt(0) else n)) @library - def mkString[A](l: List[A], pre: String, mid: String, post: String, f : A => String) = { + def mkString[A](l: List[A], mid: String, f : A => String) = { def rec(l: List[A]): String = l match { case Nil() => "" case Cons(a, b) => mid + f(a) + rec(b) } - pre + (l match { + l match { case Nil() => "" case Cons(a, b) => f(a) + rec(b) - }) + post + } } } diff --git a/library/leon/lang/Bag.scala b/library/leon/lang/Bag.scala index 2825bd1fa4d5ca5136adb9dd0afc391b10ca5cbb..6a6be20a4a2622d4877872c2c44e91dc6a958270 100644 --- a/library/leon/lang/Bag.scala +++ b/library/leon/lang/Bag.scala @@ -11,6 +11,13 @@ object Bag { def apply[T](elems: (T, BigInt)*) = { new Bag[T](scala.collection.immutable.Map[T, BigInt](elems : _*)) } + + @extern @library + def mkString[A](bag: Bag[A], infix: String, f: A => String) = { + bag.theBag.flatMap{ case (k, v) => + List.range(1, v.toString.toInt).map(_ => f(k)) + }.toList.sorted.mkString(infix) + } } @ignore diff --git a/library/leon/lang/Map.scala b/library/leon/lang/Map.scala index 5f6ee3bafd5d77be79d80025a506e649a31220e8..ce66a93d553c068eaf5e3dc66b37e3fbb9abc500 100644 --- a/library/leon/lang/Map.scala +++ b/library/leon/lang/Map.scala @@ -14,8 +14,8 @@ object Map { } @extern @library - def mkString[A, B](map: Map[A, B], pre: String, inkv: String, betweenkv: String, post: String, fA : A => String, fB: B => String) = { - pre + map.theMap.map{ case (k, v) => fA(k) + inkv + fB(v)}.mkString(betweenkv) + post + def mkString[A, B](map: Map[A, B], inkv: String, betweenkv: String, fA : A => String, fB: B => String) = { + map.theMap.map{ case (k, v) => fA(k) + inkv + fB(v)}.toList.sorted.mkString(betweenkv) } } diff --git a/library/leon/lang/Set.scala b/library/leon/lang/Set.scala index 351af3f6abb256229cfe27d3a13ce7ad9c191e17..6e973258c711aa109822568dbb7cab5a2fe2b23a 100644 --- a/library/leon/lang/Set.scala +++ b/library/leon/lang/Set.scala @@ -11,6 +11,11 @@ object Set { def apply[T](elems: T*) = { new Set[T](scala.collection.immutable.Set[T](elems : _*)) } + + @extern @library + def mkString[A](map: Set[A], infix: String, fA : A => String) = { + map.theSet.map(fA).toList.sorted.mkString(infix) + } } @ignore diff --git a/src/main/scala/leon/evaluators/AbstractEvaluator.scala b/src/main/scala/leon/evaluators/AbstractEvaluator.scala index 2b105aaefc2767ae090e4ed8344c264e543cfcc9..b0c113dfa07d9f8a69d91f1d2c027c13589994a0 100644 --- a/src/main/scala/leon/evaluators/AbstractEvaluator.scala +++ b/src/main/scala/leon/evaluators/AbstractEvaluator.scala @@ -62,6 +62,28 @@ class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvalu /** True if Application(Lambda(), ...) have to be simplified. */ var evaluateApplications = true + // Used to make the final mkString for maps, sets, and bags. First column is the key to sort the expression on, second are the values and third are the trees. + protected def mkString(elements: List[(String, Expr, Expr)], infix: (Expr, Expr)): (Expr, Expr) = { + val (infix_value, infix_tree) = infix + val (sorting_key, elements_value, elements_tree) = elements.sortBy(f => f._1).unzip3 + + val fst = infix_value match { + case StringLiteral(v) if elements_value.forall(_.isInstanceOf[StringLiteral]) => + StringLiteral(elements_value.map(_.asInstanceOf[StringLiteral].value).mkString(v)) + case infix_value => + elements_value match { + case Nil => StringLiteral("") + case a::q => q.foldLeft(a: Expr){ case (a, s) => StringConcat(StringConcat(a, infix_value), s) } + } + } + + val snd = elements_tree match { + case Nil => StringLiteral("") + case a::q => q.foldLeft(a){ case (a, s) => StringConcat(StringConcat(a, infix_tree), s) } + } + (fst, snd) + } + protected def e(expr: Expr)(implicit rctx: RC, gctx: GC): (Expr, Expr) = { implicit def aToC: AbstractEvaluator.this.underlying.RC = DefaultRecContext(rctx.mappings.filter{ case (k, v) => ExprOps.isValue(v) }) expr match { @@ -92,6 +114,59 @@ class AbstractEvaluator(ctx: LeonContext, prog: Program) extends ContextualEvalu case Some(Some((c, mappings))) => e(c.rhs)(rctx.withNewVars2(mappings), gctx) case _ => throw RuntimeError("MatchError(Abstract evaluation): "+escrut.asString+" did not match any of the cases :\n" + cases.mkString("\n")) } + + case FunctionInvocation(TypedFunDef(fd, Seq(ta, tb)), Seq(mp, inkv, betweenkv, fk, fv)) if fd == program.library.mapMkString.get => + val (inkv_str, inkv_tree) = e(inkv) + val infix = e(betweenkv) + val (mp_map, mp_tree) = e(mp) match { + case (FiniteMap(theMap, keyType, valueType), t) => (theMap, t) + case (e, f) => + println("First argument is not a finite map: " + e) + throw EvalError(typeErrorMsg(mp, MapType(ta, tb))) + } + + val res1 = mp_map.toList.map{ case (k, v) => + val (kvalue, ktree) = e(application(fk, Seq(k))) + val (vvalue, vtree) = e(application(fv, Seq(v))) + val abs_value = StringConcat(StringConcat(ktree, inkv_tree), vtree) + kvalue match { + case StringLiteral(k) => + if(ExprOps.isValue(vvalue) && ExprOps.isValue(inkv_str)) { + underlying.e(StringConcat(StringConcat(kvalue, inkv_str), vvalue)) match { + case sl@StringLiteral(s) => (s, sl, abs_value) + case e => throw RuntimeError("Not a string literal: " + e) + } + } else { + (k, StringConcat(StringConcat(kvalue, inkv_str), vvalue), abs_value) + } + case _ => + throw RuntimeError("cannot infer the order on which to print the map " + mp_map) + } + } + + mkString(res1, infix) + + case FunctionInvocation(TypedFunDef(fd, Seq(ta)), Seq(mp, inf, f)) if fd == program.library.setMkString.get => + val infix = e(inf) + val (mp_set, mp_tree) = e(mp) match { case (FiniteSet(elems, valueType), t) => (elems, t) case _ => throw EvalError(typeErrorMsg(mp, SetType(ta))) } + + val res = mp_set.toList.map{ case v => + e(application(f, Seq(v))) match { case (sl@StringLiteral(s), t) => (s, sl, t) + case _ => throw EvalError(typeErrorMsg(v, StringType)) } } + + mkString(res, infix) + + case FunctionInvocation(TypedFunDef(fd, Seq(ta)), Seq(mp, inf, f)) if fd == program.library.bagMkString.get => + val infix = e(inf) + val (mp_bag, mp_tree) = e(mp) match { case (FiniteBag(elems, valueType), t) => (elems, t) case _ => throw EvalError(typeErrorMsg(mp, SetType(ta))) } + + val res = mp_bag.toList.flatMap{ case (k, v) => + val fk = (e(application(f, Seq(k))) match { case (sl@StringLiteral(s), t) => (s, sl, t) case _ => throw EvalError(typeErrorMsg(k, StringType)) }) + val times = (e(v)) match { case (InfiniteIntegerLiteral(i), t) => i case _ => throw EvalError(typeErrorMsg(k, IntegerType)) } + List.fill(times.toString.toInt)(fk) + } + + mkString(res, infix) case FunctionInvocation(tfd, args) => if (gctx.stepsLeft < 0) { diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala index a709de91fdf5af88ff64fa9393dd0a25e2d122dc..f5536ee98318c4b9a2005a2af3bd82b8d0b3d71e 100644 --- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala +++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala @@ -111,23 +111,42 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, val bank: Eva case _ => throw EvalError(typeErrorMsg(input, StringType)) } - case FunctionInvocation(TypedFunDef(fd, Seq(ta, tb)), Seq(mp, pre, inkv, betweenkv, post, fk, fv)) if fd == program.library.mapMkString.get => - val pre_str = e(pre) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(pre, StringType)) } + case FunctionInvocation(TypedFunDef(fd, Seq(ta, tb)), Seq(mp, inkv, betweenkv, fk, fv)) if fd == program.library.mapMkString.get => val inkv_str = e(inkv) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(inkv, StringType)) } - val post_str = e(post) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(post, StringType)) } val betweenkv_str = e(betweenkv) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(betweenkv, StringType)) } - val (mp_map, keyType, valueType) = e(mp) match { case FiniteMap(theMap, keyType, valueType) => (theMap, keyType, valueType) case _ => throw EvalError(typeErrorMsg(mp, MapType(ta, tb))) } + val mp_map = e(mp) match { case FiniteMap(theMap, keyType, valueType) => theMap case _ => throw EvalError(typeErrorMsg(mp, MapType(ta, tb))) } - val res = pre_str + mp_map.map{ case (k, v) => + val res = mp_map.map{ case (k, v) => (e(application(fk, Seq(k))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) + inkv_str + (v match { case CaseClass(some, Seq(v)) if some == program.library.Some.get.typed(Seq(tb)) => (e(application(fv, Seq(v))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) case _ => throw EvalError(typeErrorMsg(v, program.library.Some.get.typed(Seq(tb)))) - })}.mkString(betweenkv_str) + post_str + })}.toList.sorted.mkString(betweenkv_str) StringLiteral(res) + + case FunctionInvocation(TypedFunDef(fd, Seq(ta)), Seq(mp, inf, f)) if fd == program.library.setMkString.get => + val inf_str = e(inf) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(inf, StringType)) } + val mp_set = e(mp) match { case FiniteSet(elems, valueType) => elems case _ => throw EvalError(typeErrorMsg(mp, SetType(ta))) } + + val res = mp_set.map{ case v => + e(application(f, Seq(v))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(v, StringType)) } }.toList.sorted.mkString(inf_str) + + StringLiteral(res) + + case FunctionInvocation(TypedFunDef(fd, Seq(ta)), Seq(mp, inf, f)) if fd == program.library.bagMkString.get => + val inf_str = e(inf) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(inf, StringType)) } + val mp_bag = e(mp) match { case FiniteBag(elems, valueType) => elems case _ => throw EvalError(typeErrorMsg(mp, SetType(ta))) } + + val res = mp_bag.flatMap{ case (k, v) => + val fk = (e(application(f, Seq(k))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) + val times = (e(v)) match { case InfiniteIntegerLiteral(i) => i case _ => throw EvalError(typeErrorMsg(k, IntegerType)) } + List.range(1, times.toString.toInt).map(_ => fk) + }.toList.sorted.mkString(inf_str) + + StringLiteral(res) case FunctionInvocation(tfd, args) => if (gctx.stepsLeft < 0) { diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala index b812bcf573bf5c9d8cbb3942c15b4f4056b15e5d..5bb663fd1224101008920d68071fd421c6306f09 100644 --- a/src/main/scala/leon/purescala/PrettyPrinter.scala +++ b/src/main/scala/leon/purescala/PrettyPrinter.scala @@ -219,7 +219,12 @@ class PrettyPrinter(opts: PrinterOptions, case Tuple(exprs) => p"($exprs)" case TupleSelect(t, i) => p"$t._$i" case NoTree(tpe) => p"<empty tree>[$tpe]" - case Choose(pred) => p"choose($pred)" + case Choose(pred) => + val choose = (for{scope <- getScope + program <- opgm } + yield simplifyPath("leon" :: "lang" :: "synthesis" :: "choose" :: Nil, scope, false)(program)) + .getOrElse("leon.lang.synthesis.choose") + p"$choose($pred)" case e @ Error(tpe, err) => p"""error[$tpe]("$err")""" case AsInstanceOf(e, ct) => p"""$e.asInstanceOf[$ct]""" case IsInstanceOf(e, cct) => @@ -330,7 +335,7 @@ class PrettyPrinter(opts: PrinterOptions, case RealDivision(l,r) => optP { p"$l / $r" } case fs @ FiniteSet(rs, _) => p"{${rs.toSeq}}" case fs @ FiniteBag(rs, _) => p"{$rs}" - case fm @ FiniteMap(rs, _, _) => p"{$rs}" + case fm @ FiniteMap(rs, _, _) => p"{${rs.toSeq}}" case Not(ElementOfSet(e,s)) => p"$e \u2209 $s" case ElementOfSet(e,s) => p"$e \u2208 $s" case SubsetOf(l,r) => p"$l \u2286 $r" diff --git a/src/main/scala/leon/purescala/ScalaPrinter.scala b/src/main/scala/leon/purescala/ScalaPrinter.scala index 40dcbdab8188f71988d78e58ffb200224de57891..393c38ad356796e4007220146317bb46ef0c62bb 100644 --- a/src/main/scala/leon/purescala/ScalaPrinter.scala +++ b/src/main/scala/leon/purescala/ScalaPrinter.scala @@ -25,7 +25,6 @@ class ScalaPrinter(opts: PrinterOptions, case _ => true })) case Not(Equals(l, r)) => optP { p"$l != $r" } - case Choose(pred) => p"choose($pred)" case s @ FiniteSet(rss, t) => p"Set[$t](${rss.toSeq})" case SetAdd(s,e) => optP { p"$s + $e" } @@ -36,14 +35,14 @@ class ScalaPrinter(opts: PrinterOptions, case SetCardinality(s) => p"$s.size" case SubsetOf(subset,superset) => p"$subset.subsetOf($superset)" - case b @ FiniteBag(els, t) => p"Bag[$t]($els)" + case b @ FiniteBag(els, t) => p"Bag[$t](${els.toSeq})" case BagAdd(s,e) => optP { p"$s + $e" } case BagUnion(l,r) => optP { p"$l ++ $r" } case BagDifference(l,r) => optP { p"$l -- $r" } case BagIntersection(l,r) => optP { p"$l & $r" } case MapUnion(l,r) => optP { p"$l ++ $r" } - case m @ FiniteMap(els, k, v) => p"Map[$k,$v]($els)" + case m @ FiniteMap(els, k, v) => p"Map[$k,$v](${els.toSeq})" case InfiniteIntegerLiteral(v) => p"BigInt($v)" case a@FiniteArray(elems, oDef, size) => diff --git a/src/main/scala/leon/purescala/TypeOps.scala b/src/main/scala/leon/purescala/TypeOps.scala index 546e5726382d814ba533dc3de87241c7517e0f99..e43c882c234d55f68b14b13aff1187fbd6d74b3e 100644 --- a/src/main/scala/leon/purescala/TypeOps.scala +++ b/src/main/scala/leon/purescala/TypeOps.scala @@ -80,6 +80,7 @@ object TypeOps extends GenTreeOps[TypeTree] { case (_: TupleType, _: TupleType) | (_: SetType, _: SetType) | (_: MapType, _: MapType) | + (_: BagType, _: BagType) | (_: FunctionType, _: FunctionType) => val NAryType(ts1, _) = tpe diff --git a/src/main/scala/leon/utils/Library.scala b/src/main/scala/leon/utils/Library.scala index 1fc502212b66d709d8dcd41efc726b264e59dec2..3e9b99c88d12c58fbc090f38eed387ddae582d75 100644 --- a/src/main/scala/leon/utils/Library.scala +++ b/src/main/scala/leon/utils/Library.scala @@ -27,6 +27,10 @@ case class Library(pgm: Program) { lazy val escape = lookup("leon.lang.StrOps.escape").collectFirst { case fd : FunDef => fd } lazy val mapMkString = lookup("leon.lang.Map.mkString").collectFirst { case fd : FunDef => fd } + + lazy val setMkString = lookup("leon.lang.Set.mkString").collectFirst { case fd : FunDef => fd } + + lazy val bagMkString = lookup("leon.lang.Bag.mkString").collectFirst { case fd : FunDef => fd } def lookup(name: String): Seq[Definition] = { pgm.lookupAll(name)