From e8e1b598eb7ee8641c279e197bb8a1d46a75e949 Mon Sep 17 00:00:00 2001
From: Etienne Kneuss <ekneuss@gmail.com>
Date: Fri, 29 May 2015 18:31:05 +0200
Subject: [PATCH] Implement char comparison (<,<=,>,>=)

---
 .../leon/evaluators/RecursiveEvaluator.scala      |  4 ++++
 .../leon/frontends/scalac/CodeExtraction.scala    | 15 ++++++++++++++-
 .../scala/leon/solvers/smtlib/SMTLIBSolver.scala  |  7 +++++++
 .../scala/leon/solvers/z3/AbstractZ3Solver.scala  |  4 ++++
 .../purescala/invalid/CharCompare.scala           |  5 +++++
 5 files changed, 34 insertions(+), 1 deletion(-)
 create mode 100644 src/test/resources/regression/verification/purescala/invalid/CharCompare.scala

diff --git a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
index d5bf1facf..86e6ef578 100644
--- a/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
+++ b/src/main/scala/leon/evaluators/RecursiveEvaluator.scala
@@ -356,6 +356,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
       (e(l), e(r)) match {
         case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 < i2)
         case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 < i2)
+        case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 < c2)
         case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type))
       }
 
@@ -363,6 +364,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
       (e(l), e(r)) match {
         case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 > i2)
         case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 > i2)
+        case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 > c2)
         case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type))
       }
 
@@ -370,6 +372,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
       (e(l), e(r)) match {
         case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 <= i2)
         case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 <= i2)
+        case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 <= c2)
         case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type))
       }
 
@@ -377,6 +380,7 @@ abstract class RecursiveEvaluator(ctx: LeonContext, prog: Program, maxSteps: Int
       (e(l), e(r)) match {
         case (IntLiteral(i1), IntLiteral(i2)) => BooleanLiteral(i1 >= i2)
         case (InfiniteIntegerLiteral(i1), InfiniteIntegerLiteral(i2)) => BooleanLiteral(i1 >= i2)
+        case (CharLiteral(c1), CharLiteral(c2)) => BooleanLiteral(c1 >= c2)
         case (le,re) => throw EvalError(typeErrorMsg(le, Int32Type))
       }
 
diff --git a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
index ce7661ceb..b37b6672f 100644
--- a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
+++ b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala
@@ -1715,7 +1715,20 @@ trait CodeExtraction extends ASTExtractors {
 
             case (IsTyped(a1, mt1: MapType), "++", List(IsTyped(a2, mt2: MapType)))  if mt1 == mt2 =>
               MapUnion(a1, a2)
-              
+
+            // Char operations
+            case (IsTyped(a1, CharType), ">", List(IsTyped(a2, CharType))) =>
+              GreaterThan(a1, a2)
+
+            case (IsTyped(a1, CharType), ">=", List(IsTyped(a2, CharType))) =>
+              GreaterEquals(a1, a2)
+
+            case (IsTyped(a1, CharType), "<", List(IsTyped(a2, CharType))) =>
+              LessThan(a1, a2)
+
+            case (IsTyped(a1, CharType), "<=", List(IsTyped(a2, CharType))) =>
+              LessEquals(a1, a2)
+
             case (_, name, _) =>
               outOfSubsetError(tr, "Unknown call to "+name)
           }
diff --git a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
index c0dbf1e9a..3df3f89e5 100644
--- a/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
+++ b/src/main/scala/leon/solvers/smtlib/SMTLIBSolver.scala
@@ -651,18 +651,22 @@ abstract class SMTLIBSolver(val context: LeonContext,
       case LessThan(a,b) => a.getType match {
         case Int32Type => FixedSizeBitVectors.SLessThan(toSMT(a), toSMT(b))
         case IntegerType => Ints.LessThan(toSMT(a), toSMT(b))
+        case CharType => FixedSizeBitVectors.SLessThan(toSMT(a), toSMT(b))
       }
       case LessEquals(a,b) => a.getType match {
         case Int32Type => FixedSizeBitVectors.SLessEquals(toSMT(a), toSMT(b))
         case IntegerType => Ints.LessEquals(toSMT(a), toSMT(b))
+        case CharType => FixedSizeBitVectors.SLessEquals(toSMT(a), toSMT(b))
       }
       case GreaterThan(a,b) => a.getType match {
         case Int32Type => FixedSizeBitVectors.SGreaterThan(toSMT(a), toSMT(b))
         case IntegerType => Ints.GreaterThan(toSMT(a), toSMT(b))
+        case CharType => FixedSizeBitVectors.SGreaterThan(toSMT(a), toSMT(b))
       }
       case GreaterEquals(a,b) => a.getType match {
         case Int32Type => FixedSizeBitVectors.SGreaterEquals(toSMT(a), toSMT(b))
         case IntegerType => Ints.GreaterEquals(toSMT(a), toSMT(b))
+        case CharType => FixedSizeBitVectors.SGreaterEquals(toSMT(a), toSMT(b))
       }
       case BVPlus(a,b) => FixedSizeBitVectors.Add(toSMT(a), toSMT(b))
       case BVMinus(a,b) => FixedSizeBitVectors.Sub(toSMT(a), toSMT(b))
@@ -701,6 +705,9 @@ abstract class SMTLIBSolver(val context: LeonContext,
     case (_, UnitType) =>
       UnitLiteral()
 
+    case (FixedSizeBitVectors.BitVectorConstant(n, b), CharType) if b == BigInt(32) =>
+      CharLiteral(n.toInt.toChar)
+
     case (SHexadecimal(h), CharType) =>
       CharLiteral(h.toInt.toChar)
 
diff --git a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
index 4a5e6ed57..42d53fc24 100644
--- a/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
+++ b/src/main/scala/leon/solvers/z3/AbstractZ3Solver.scala
@@ -596,18 +596,22 @@ trait AbstractZ3Solver
       case LessThan(l, r) => l.getType match {
         case IntegerType => z3.mkLT(rec(l), rec(r))
         case Int32Type => z3.mkBVSlt(rec(l), rec(r))
+        case CharType => z3.mkBVSlt(rec(l), rec(r))
       }
       case LessEquals(l, r) => l.getType match {
         case IntegerType => z3.mkLE(rec(l), rec(r))
         case Int32Type => z3.mkBVSle(rec(l), rec(r))
+        case CharType => z3.mkBVSle(rec(l), rec(r))
       }
       case GreaterThan(l, r) => l.getType match {
         case IntegerType => z3.mkGT(rec(l), rec(r))
         case Int32Type => z3.mkBVSgt(rec(l), rec(r))
+        case CharType => z3.mkBVSgt(rec(l), rec(r))
       }
       case GreaterEquals(l, r) => l.getType match {
         case IntegerType => z3.mkGE(rec(l), rec(r))
         case Int32Type => z3.mkBVSge(rec(l), rec(r))
+        case CharType => z3.mkBVSge(rec(l), rec(r))
       }
 
       case c @ CaseClass(ct, args) =>
diff --git a/src/test/resources/regression/verification/purescala/invalid/CharCompare.scala b/src/test/resources/regression/verification/purescala/invalid/CharCompare.scala
new file mode 100644
index 000000000..8dade4ccc
--- /dev/null
+++ b/src/test/resources/regression/verification/purescala/invalid/CharCompare.scala
@@ -0,0 +1,5 @@
+import leon.lang._
+
+object foo {
+  def cmp(c1: Char, c2: Char): Boolean = { c1 < c2 }.holds
+}
-- 
GitLab