From 958a90a8d0094878246e3fa191f48fd510b45e26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mika=C3=ABl=20Mayer?= <mikael.mayer@epfl.ch>
Date: Mon, 18 Apr 2016 14:29:56 +0200
Subject: [PATCH] Added basic map to string support Corrected bug with unicode
 chars in the build.sbt

---
 build.sbt                                     |  2 +-
 library/collection/List.scala                 | 13 +++++++++-
 library/lang/Map.scala                        |  5 ++++
 .../leon/evaluators/RecursiveEvaluator.scala  | 14 +++++++++++
 src/main/scala/leon/utils/Library.scala       |  2 ++
 testcases/stringrender/MapRender.scala        | 25 +++++++++++++++++++
 6 files changed, 59 insertions(+), 2 deletions(-)
 create mode 100644 testcases/stringrender/MapRender.scala

diff --git a/build.sbt b/build.sbt
index 111613dd1..618d4f2ba 100644
--- a/build.sbt
+++ b/build.sbt
@@ -111,7 +111,7 @@ sourceGenerators in Compile <+= Def.task {
                       |object Build {
                       |  val baseDirectory = \"\"\"${baseDirectory.value.toString}\"\"\"
                       |  val libFiles = List(
-                      |    ${libFiles.mkString("\"\"\"", "\"\"\",\n    \"\"\"", "\"\"\"")}
+                      |    ${libFiles.mkString("\"\"\"", "\"\"\",\n    \"\"\"", "\"\"\"").replaceAll("\\\\"+"u","\\\\\"\"\"+\"\"\"u")}
                       |  )
                       |}""".stripMargin)
   Seq(build)
diff --git a/library/collection/List.scala b/library/collection/List.scala
index 69c30d39f..61089979b 100644
--- a/library/collection/List.scala
+++ b/library/collection/List.scala
@@ -552,7 +552,6 @@ sealed abstract class List[T] {
   def toSet: Set[T] = foldLeft(Set[T]()){ 
     case (current, next) => current ++ Set(next)
   }
-
 }
 
 @isabelle.constructor(name = "List.list.Cons")
@@ -577,6 +576,18 @@ object List {
     else Cons[T](x, fill[T](n-1)(x))
   } ensuring(res => (res.content == (if (n <= BigInt(0)) Set.empty[T] else Set(x))) &&
                     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 rec(l: List[A]): String = l match {
+      case Nil() => ""
+      case Cons(a, b) => mid + f(a) + rec(b)
+    }
+    pre + (l match {
+      case Nil() => ""
+      case Cons(a, b) => f(a) + rec(b)
+    }) + post
+  }
 }
 
 @library
diff --git a/library/lang/Map.scala b/library/lang/Map.scala
index 2a08449cc..5f6ee3baf 100644
--- a/library/lang/Map.scala
+++ b/library/lang/Map.scala
@@ -12,6 +12,11 @@ object Map {
   def apply[A,B](elems: (A,B)*) = {
     new Map[A,B](scala.collection.immutable.Map[A,B](elems : _*))
   }
+  
+  @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
+  }
 }
 
 @ignore
diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
index 4d70063fb..28843738b 100644
--- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
+++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
@@ -107,6 +107,20 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
          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)) }
+      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 res = pre_str + mp_map.map{ case (k, v) =>
+        (e(application(fk, Seq(k))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) }) +
+        inkv_str +
+        (e(application(fv, Seq(v))) match { case StringLiteral(s) => s case _ => throw EvalError(typeErrorMsg(k, StringType)) })}.mkString(betweenkv_str) + post_str
+      
+      StringLiteral(res)
+
     case FunctionInvocation(tfd, args) =>
       if (gctx.stepsLeft < 0) {
         throw RuntimeError("Exceeded number of allocated methods calls ("+gctx.maxSteps+")")
diff --git a/src/main/scala/leon/utils/Library.scala b/src/main/scala/leon/utils/Library.scala
index 6bff50527..1fc502212 100644
--- a/src/main/scala/leon/utils/Library.scala
+++ b/src/main/scala/leon/utils/Library.scala
@@ -26,6 +26,8 @@ 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 }
+
   def lookup(name: String): Seq[Definition] = {
     pgm.lookupAll(name)
   }
diff --git a/testcases/stringrender/MapRender.scala b/testcases/stringrender/MapRender.scala
new file mode 100644
index 000000000..a5b27ad09
--- /dev/null
+++ b/testcases/stringrender/MapRender.scala
@@ -0,0 +1,25 @@
+import leon.collection._
+import leon.collection.List
+import leon.lang._
+import leon.proof.check
+import leon.lang.synthesis._
+import scala.language.postfixOps
+import leon.annotation._
+
+object MapRender {
+  
+  def f(i: Int): Map[Int, Int] = {
+    Map(1 -> i)
+  } ensuring {
+    (m: Map[Int, Int]) => m(1) == 2
+  }
+  
+  def g(m: Map[Int, Int]): Boolean = {
+    !m.contains(0) || !m.contains(1)
+  } holds
+  
+  def mapIntIntToString(in : Map[Int, Int]): String =  {
+    Map.mkString(in, "MyMap(\n  "," -> ", ",\n  ", ")", (i:Int) => i.toString, (i:Int) => i.toString)
+  }
+}
+
-- 
GitLab