From 95e3848ecf7d528856f379cd894ddeb272cd25d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=C3=ABl=20Mayer?= <mikael.mayer@epfl.ch> Date: Fri, 6 May 2016 11:22:09 +0200 Subject: [PATCH] Fixed code extraction issues for bigLength and bigSubstring Fixed compilation issue in String.scala Made sure (...).substring(start) is extracted as a lset in order to not recompute the body twice (and adapted the pretty-printer) --- library/lang/package.scala | 10 +++--- library/theories/String.scala | 2 +- .../leon/frontends/scalac/ASTExtractors.scala | 33 +++++++++++++++++++ .../frontends/scalac/CodeExtraction.scala | 30 ++++++++++++----- .../scala/leon/purescala/PrettyPrinter.scala | 6 ++++ 5 files changed, 68 insertions(+), 13 deletions(-) diff --git a/library/lang/package.scala b/library/lang/package.scala index c10c02582..9c3c72d42 100644 --- a/library/lang/package.scala +++ b/library/lang/package.scala @@ -70,10 +70,12 @@ package object lang { } implicit class StringDecorations(val underlying: String) { - @ignore - def bigLength = BigInt(underlying.length) - @ignore - def bigsubstring(start: BigInt, end: BigInt): String = underlying.substring(start.toInt, end.toInt) + @ignore @inline + def bigLength() = BigInt(underlying.length) + @ignore @inline + def bigSubstring(start: BigInt): String = underlying.substring(start.toInt) + @ignore @inline + def bigSubstring(start: BigInt, end: BigInt): String = underlying.substring(start.toInt, end.toInt) } @ignore diff --git a/library/theories/String.scala b/library/theories/String.scala index 745501578..8057c2d2a 100644 --- a/library/theories/String.scala +++ b/library/theories/String.scala @@ -11,7 +11,7 @@ sealed abstract class String { }) ensuring (_ >= 0) def sizeI: Int = this match { - case StringCons(_, tail) => 1 + tail.length + case StringCons(_, tail) => 1 + tail.sizeI case StringNil() => 0 } diff --git a/src/main/scala/leon/frontends/scalac/ASTExtractors.scala b/src/main/scala/leon/frontends/scalac/ASTExtractors.scala index 45ddea6ad..02a58ad29 100644 --- a/src/main/scala/leon/frontends/scalac/ASTExtractors.scala +++ b/src/main/scala/leon/frontends/scalac/ASTExtractors.scala @@ -185,6 +185,39 @@ trait ASTExtractors { case _ => None } } + + /** Matches the `bigLength` expression at the end of any string expression, and returns the expression.*/ + object ExBigLengthExpression { + def unapply(tree: Apply) : Option[Tree] = tree match { + case Apply(Select( + Apply(ExSelected("leon", "lang", "package", "StringDecorations"), stringExpr :: Nil), + ExNamed("bigLength")), Nil) + => Some(stringExpr) + case _ => None + } + } + + /** Matches the `bigSubstring` method at the end of any string expression, and returns the expression and the start index expression.*/ + object ExBigSubstringExpression { + def unapply(tree: Apply) : Option[(Tree, Tree)] = tree match { + case Apply(Select( + Apply(ExSelected("leon", "lang", "package", "StringDecorations"), stringExpr :: Nil), + ExNamed("bigSubstring")), startExpr :: Nil) + => Some(stringExpr, startExpr) + case _ => None + } + } + + /** Matches the `bigSubstring` expression at the end of any string expression, and returns the expression, the start and end index expressions.*/ + object ExBigSubstring2Expression { + def unapply(tree: Apply) : Option[(Tree, Tree, Tree)] = tree match { + case Apply(Select( + Apply(ExSelected("leon", "lang", "package", "StringDecorations"), stringExpr :: Nil), + ExNamed("bigSubstring")), startExpr :: endExpr :: Nil) + => Some(stringExpr, startExpr, endExpr) + case _ => None + } + } /** Matches an implication `lhs ==> rhs` and returns (lhs, rhs)*/ object ExImplies { diff --git a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala index 9c3e4b393..e37ce4c98 100644 --- a/src/main/scala/leon/frontends/scalac/CodeExtraction.scala +++ b/src/main/scala/leon/frontends/scalac/CodeExtraction.scala @@ -1195,6 +1195,23 @@ trait CodeExtraction extends ASTExtractors { Ensuring(output_expr, post) + case t @ ExBigLengthExpression(input) => + val input_expr = extractTreeOrNoTree(input).setPos(input.pos) + StringBigLength(input_expr) + case t @ ExBigSubstringExpression(input, start) => + val input_expr = extractTreeOrNoTree(input).setPos(input.pos) + val start_expr = extractTreeOrNoTree(start).setPos(start.pos) + val s = FreshIdentifier("s", StringType) + let(s, input_expr, + BigSubString(Variable(s), start_expr, StringBigLength(Variable(s))) + ) + + case t @ ExBigSubstring2Expression(input, start, end) => + val input_expr = extractTreeOrNoTree(input).setPos(input.pos) + val start_expr = extractTreeOrNoTree(start).setPos(start.pos) + val end_expr = extractTreeOrNoTree(end).setPos(end.pos) + BigSubString(input_expr, start_expr, end_expr) + case ExAssertExpression(contract, oerr) => val const = extractTree(contract) val b = rest.map(extractTreeOrNoTree).getOrElse(UnitLiteral()) @@ -1728,17 +1745,14 @@ trait CodeExtraction extends ASTExtractors { StringConcat(converter(a1), a2) case (IsTyped(a1, StringType), "length", List()) => StringLength(a1) - case (IsTyped(a1, StringType), "bigLength", List()) => - StringBigLength(a1) case (IsTyped(a1, StringType), "substring", List(IsTyped(start, Int32Type))) => - SubString(a1, start, StringLength(a1)) + val s = FreshIdentifier("s", StringType) + let(s, a1, + SubString(Variable(s), start, StringLength(Variable(s))) + ) case (IsTyped(a1, StringType), "substring", List(IsTyped(start, Int32Type), IsTyped(end, Int32Type))) => SubString(a1, start, end) - case (IsTyped(a1, StringType), "bigSubstring", List(IsTyped(start, IntegerType))) => - BigSubString(a1, start, StringBigLength(a1)) - case (IsTyped(a1, StringType), "bigSubstring", List(IsTyped(start, IntegerType), IsTyped(end, IntegerType))) => - BigSubString(a1, start, end) - + //BigInt methods case (IsTyped(a1, IntegerType), "+", List(IsTyped(a2, IntegerType))) => Plus(a1, a2) diff --git a/src/main/scala/leon/purescala/PrettyPrinter.scala b/src/main/scala/leon/purescala/PrettyPrinter.scala index bda0e0612..b812bcf57 100644 --- a/src/main/scala/leon/purescala/PrettyPrinter.scala +++ b/src/main/scala/leon/purescala/PrettyPrinter.scala @@ -86,6 +86,12 @@ class PrettyPrinter(opts: PrinterOptions, case Variable(id) => p"$id" + + case Let(id, expr, SubString(Variable(id2), start, StringLength(Variable(id3)))) if id == id2 && id2 == id3 => + p"$expr.substring($start)" + + case Let(id, expr, BigSubString(Variable(id2), start, StringLength(Variable(id3)))) if id == id2 && id2 == id3 => + p"$expr.bigSubstring($start)" case Let(b,d,e) => p"""|val $b = $d -- GitLab