diff --git a/src/main/scala/leon/purescala/Extractors.scala b/src/main/scala/leon/purescala/Extractors.scala index 304f242e7ed0cd814a506d309d80b26ed3a4a939..f331a1c8f3b4f298783baf0b506772abe50a7ed2 100644 --- a/src/main/scala/leon/purescala/Extractors.scala +++ b/src/main/scala/leon/purescala/Extractors.scala @@ -10,11 +10,24 @@ import Constructors._ object Extractors { + /** Operator Extractor to extract any Expression in a consistent way + * + * You can match on any Leon Expr, and then get both a Seq[Expr] of + * subterms and a builder fonction that take a Seq of subterm (os same + * length) and rebuild the original node. + * + * Those extractors do not perform any syntactic simplifications. They + * rebuild the node using the case class (not the constructor that perform + * simplifications). The rationals behind this decision is to have core + * tools for performing tree transformations that are very predictable, if + * one need to simplify the tree, it is easy to write/call a simplification + * function that would simply apply the constructor for each node. + */ object Operator extends TreeExtractor[Expr] { def unapply(expr: Expr): Option[(Seq[Expr], (Seq[Expr]) => Expr)] = expr match { /* Unary operators */ case Not(t) => - Some((Seq(t), (es: Seq[Expr]) => not(es.head))) + Some((Seq(t), (es: Seq[Expr]) => Not(es.head))) case Choose(expr) => Some((Seq(expr), (es: Seq[Expr]) => Choose(es.head))) case UMinus(t) => @@ -40,11 +53,11 @@ object Extractors { case SetCardinality(t) => Some((Seq(t), (es: Seq[Expr]) => SetCardinality(es.head))) case CaseClassSelector(cd, e, sel) => - Some((Seq(e), (es: Seq[Expr]) => caseClassSelector(cd, es.head, sel))) + Some((Seq(e), (es: Seq[Expr]) => CaseClassSelector(cd, es.head, sel))) case IsInstanceOf(e, ct) => Some((Seq(e), (es: Seq[Expr]) => IsInstanceOf(es.head, ct))) case AsInstanceOf(e, ct) => - Some((Seq(e), (es: Seq[Expr]) => asInstOf(es.head, ct))) + Some((Seq(e), (es: Seq[Expr]) => AsInstanceOf(es.head, ct))) case TupleSelect(t, i) => Some((Seq(t), (es: Seq[Expr]) => TupleSelect(es.head, i))) case ArrayLength(a) => @@ -79,15 +92,15 @@ object Extractors { } )) case Equals(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => equality(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => Equals(es(0), es(1))) case Implies(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => implies(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => Implies(es(0), es(1))) case Plus(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => plus(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => Plus(es(0), es(1))) case Minus(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => minus(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => Minus(es(0), es(1))) case Times(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => times(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => Times(es(0), es(1))) case Division(t1, t2) => Some(Seq(t1, t2), (es: Seq[Expr]) => Division(es(0), es(1))) case Remainder(t1, t2) => @@ -103,11 +116,11 @@ object Extractors { case GreaterEquals(t1, t2) => Some(Seq(t1, t2), (es: Seq[Expr]) => GreaterEquals(es(0), es(1))) case BVPlus(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => plus(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => BVPlus(es(0), es(1))) case BVMinus(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => minus(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => BVMinus(es(0), es(1))) case BVTimes(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => times(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => BVTimes(es(0), es(1))) case BVDivision(t1, t2) => Some(Seq(t1, t2), (es: Seq[Expr]) => BVDivision(es(0), es(1))) case BVRemainder(t1, t2) => @@ -125,11 +138,11 @@ object Extractors { case BVLShiftRight(t1, t2) => Some(Seq(t1, t2), (es: Seq[Expr]) => BVLShiftRight(es(0), es(1))) case RealPlus(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => plus(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => RealPlus(es(0), es(1))) case RealMinus(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => minus(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => RealMinus(es(0), es(1))) case RealTimes(t1, t2) => - Some(Seq(t1, t2), (es: Seq[Expr]) => times(es(0), es(1))) + Some(Seq(t1, t2), (es: Seq[Expr]) => RealTimes(es(0), es(1))) case RealDivision(t1, t2) => Some(Seq(t1, t2), (es: Seq[Expr]) => RealDivision(es(0), es(1))) case StringConcat(t1, t2) => @@ -180,8 +193,8 @@ object Extractors { case mi @ MethodInvocation(rec, cd, tfd, args) => Some((rec +: args, as => MethodInvocation(as.head, cd, tfd, as.tail))) case fa @ Application(caller, args) => Some(caller +: args, as => Application(as.head, as.tail)) case CaseClass(cd, args) => Some((args, CaseClass(cd, _))) - case And(args) => Some((args, and)) - case Or(args) => Some((args, or)) + case And(args) => Some((args, es => And(es))) + case Or(args) => Some((args, es => Or(es))) case SubString(t1, a, b) => Some((t1::a::b::Nil, es => SubString(es(0), es(1), es(2)))) case FiniteSet(els, base) => Some((els.toSeq, els => FiniteSet(els.toSet, base))) @@ -228,7 +241,7 @@ object Extractors { elsOrdered, es => finiteArray(indexes.zip(es).toMap, None, tpe) )) - case Tuple(args) => Some((args, tupleWrap)) + case Tuple(args) => Some((args, es => Tuple(es))) case IfExpr(cond, thenn, elze) => Some(( Seq(cond, thenn, elze), { case Seq(c, t, e) => IfExpr(c, t, e) } @@ -242,7 +255,7 @@ object Extractors { case GuardedCase(b, _, _) => i += 2; GuardedCase(b, es(i - 2), es(i - 1)) } - matchExpr(es.head, newcases).copiedFrom(m) + MatchExpr(es.head, newcases) } )) case Passes(in, out, cases) => Some(( @@ -255,7 +268,7 @@ object Extractors { case GuardedCase(b, _, _) => i += 2; GuardedCase(b, es(i - 2), es(i - 1)) } - passes(in, out, newcases) + Passes(in, out, newcases) } } )) diff --git a/src/test/scala/leon/integration/grammars/SimilarToSuite.scala b/src/test/scala/leon/integration/grammars/SimilarToSuite.scala index b61d6cb942348b8b6821c0a915e8e3415ee3b987..7f4f625be8bee3fcea8fef8f16ce6b973d49ed5f 100644 --- a/src/test/scala/leon/integration/grammars/SimilarToSuite.scala +++ b/src/test/scala/leon/integration/grammars/SimilarToSuite.scala @@ -227,8 +227,8 @@ class SimilarToSuite extends LeonTestSuiteWithProgram with ExpressionsDSL { merge(Node(v1, Leaf(), Leaf()), h1) ), (List(h1, h2), - GreaterThan(rank(h1), Plus(rank(h2), bi(1))), - GreaterThan(rank(h1), rank(h2)) + GreaterThan(rank(h1), Plus(rank(h2), bi(42))), + GreaterThan(rank(h1), Minus(Plus(rank(h2), bi(42)), bi(1))) ) ) diff --git a/src/test/scala/leon/test/helpers/ExpressionsDSL.scala b/src/test/scala/leon/test/helpers/ExpressionsDSL.scala index 91b77284cc16518a4b86e0bdcb5ad7e98230061f..7c6de266e523f46f94281a556dda2f2d691e783a 100644 --- a/src/test/scala/leon/test/helpers/ExpressionsDSL.scala +++ b/src/test/scala/leon/test/helpers/ExpressionsDSL.scala @@ -103,4 +103,8 @@ self: Assertions => trait ExpressionsDSL extends ExpressionsDSLVariables with ExpressionsDSLProgram with ExpressionsDSLVariables_a { self: Assertions => + + implicit def int2IntLit(i: Int): IntLiteral = IntLiteral(i) + implicit def bigInt2IntegerLit(i: BigInt): InfiniteIntegerLiteral = InfiniteIntegerLiteral(i) + } diff --git a/src/test/scala/leon/unit/purescala/ExtractorsSuite.scala b/src/test/scala/leon/unit/purescala/ExtractorsSuite.scala new file mode 100644 index 0000000000000000000000000000000000000000..8c99385b44d688c2c190a5cbc182b82d16a533de --- /dev/null +++ b/src/test/scala/leon/unit/purescala/ExtractorsSuite.scala @@ -0,0 +1,41 @@ +/* Copyright 2009-2016 EPFL, Lausanne */ + +package leon.unit.xlang + +import org.scalatest._ + +import leon.test.helpers.ExpressionsDSL +import leon.purescala.Common._ +import leon.purescala.Expressions._ +import leon.purescala.Extractors._ + +class ExtractorsSuite extends FunSuite with ExpressionsDSL { + + test("Extractors do not simplify basic arithmetic") { + val e1 = BVPlus(1, 1) + val e2 = e1 match { + case Operator(es, builder) => builder(es) + } + assert(e1 === e2) + + val e3 = Times(x, BigInt(1)) + val e4 = e3 match { + case Operator(es, builder) => builder(es) + } + assert(e3 === e4) + } + + ignore("Extractors of NonemptyArray with sparse elements") { + val a1 = NonemptyArray(Map(0 -> x, 3 -> y, 5 -> z), Some((BigInt(0), BigInt(10)))) + + val a2 = a1 match { + case Operator(es, builder) => { + assert(es === Seq(x, y, z, InfiniteIntegerLiteral(0), InfiniteIntegerLiteral(10))) + builder(es) + } + } + + assert(a2 === a1) + } + +}