From b55ae300ea62ad59eb718df2688742a180cbc384 Mon Sep 17 00:00:00 2001 From: Regis Blanc <regwblanc@gmail.com> Date: Wed, 20 Jan 2016 13:48:21 +0100 Subject: [PATCH] xlang does not work with mutually recursive functions --- .../xlang/ImperativeCodeElimination.scala | 153 +++++++----------- 1 file changed, 62 insertions(+), 91 deletions(-) diff --git a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala index b6c5f9036..01472565e 100644 --- a/src/main/scala/leon/xlang/ImperativeCodeElimination.scala +++ b/src/main/scala/leon/xlang/ImperativeCodeElimination.scala @@ -28,9 +28,9 @@ object ImperativeCodeElimination extends UnitPhase[Program] { } } - /** varsInScope refers to variable declared in the same level scope. - * Typically, when entering a nested function body, the scope should be - * reset to empty */ + /* varsInScope refers to variable declared in the same level scope. + Typically, when entering a nested function body, the scope should be + reset to empty */ private case class State( parent: FunDef, varsInScope: Set[Identifier], @@ -39,14 +39,12 @@ object ImperativeCodeElimination extends UnitPhase[Program] { def withVar(i: Identifier) = copy(varsInScope = varsInScope + i) def withFunDef(fd: FunDef, nfd: FunDef, ids: List[Identifier]) = copy(funDefsMapping = funDefsMapping + (fd -> (nfd, ids))) - def withFunDefs(fdNfd: Seq[(FunDef, (FunDef, List[Identifier]))]) = - copy(funDefsMapping = funDefsMapping ++ fdNfd) } - /** Returns a "scope" consisting of purely functional code that defines potentially needed - * new variables (val, not var) and a mapping for each modified variable (var, not val :) ) - * to their new name defined in the scope. The first returned valued is the value of the expression - * that should be introduced as such in the returned scope (the val already refers to the new names) */ + //return a "scope" consisting of purely functional code that defines potentially needed + //new variables (val, not var) and a mapping for each modified variable (var, not val :) ) + //to their new name defined in the scope. The first returned valued is the value of the expression + //that should be introduced as such in the returned scope (the val already refers to the new names) private def toFunction(expr: Expr)(implicit state: State): (Expr, Expr => Expr, Map[Identifier, Identifier]) = { import state._ expr match { @@ -145,7 +143,7 @@ object ImperativeCodeElimination extends UnitPhase[Program] { ).setPos(wh) ) - val newExpr = LetDef(List(whileFunDef), FunctionInvocation(whileFunDef.typed, Seq()).setPos(wh)).setPos(wh) + val newExpr = LetDef(Seq(whileFunDef), FunctionInvocation(whileFunDef.typed, Seq()).setPos(wh)).setPos(wh) toFunction(newExpr) case Block(Seq(), expr) => @@ -219,95 +217,67 @@ object ImperativeCodeElimination extends UnitPhase[Program] { case LetDef(fds, b) => - def fdsWithoutSideEffects = { - for(fd <- fds) { - fd.body.foreach { bd => - val (fdRes, fdScope, _) = toFunction(bd) - fd.body = Some(fdScope(fdRes)) - } + + if(fds.size > 1) { + sys.error("Xlang does not support mutually recursive functions") + } + + val fd = fds.head + + def fdWithoutSideEffects = { + fd.body.foreach { bd => + val (fdRes, fdScope, _) = toFunction(bd) + fd.body = Some(fdScope(fdRes)) } val (bodyRes, bodyScope, bodyFun) = toFunction(b) - (bodyRes, (b2: Expr) => LetDef(fds, bodyScope(b2)).setPos(fds.head).copiedFrom(expr), bodyFun) + (bodyRes, (b2: Expr) => LetDef(Seq(fd), bodyScope(b2)).setPos(fd).copiedFrom(expr), bodyFun) } - if(fds.forall(_.body.isEmpty)) fdsWithoutSideEffects - else { - val modified_vars: Seq[(FunDef, List[Identifier])] = for(fd <- fds; bd <- fd.body) yield { + + fd.body match { + case Some(bd) => { + val modifiedVars: List[Identifier] = collect[Identifier]({ case Assignment(v, _) => Set(v) case FunctionInvocation(tfd, _) => state.funDefsMapping.get(tfd.fd).map(p => p._2.toSet).getOrElse(Set()) case _ => Set() })(bd).intersect(state.varsInScope).toList - (fd, modifiedVars) - } - if(modified_vars.forall(_._2.isEmpty)) fdsWithoutSideEffects else { - val freshNames: Seq[(FunDef, Seq[Identifier])] = modified_vars.map(fdmv => (fdmv._1, fdmv._2.map(id => id.freshen))) - - val newParams: Seq[(FunDef, Seq[ValDef])] = freshNames.map(fdfn => (fdfn._1, fdfn._1.params ++ fdfn._2.map(n => ValDef(n)))) - - val freshVarDecls: Seq[(FunDef, List[Identifier])] = freshNames.map(id => (id._1, id._2.map(_.freshen).toList)) - - val rewritingMap: Map[Identifier, Identifier] = - (modified_vars.zip(freshVarDecls).map{ - case ((fd, md), (_, fv)) => (fd, md.zip(fv).toMap) - }).map(_._2).foldLeft(Map[Identifier, Identifier]())(_ ++ _) - - //TODO: - - val freshBody: Seq[Option[Expr]] = for(fd <- fds) yield { - fd.body.map(bd => - preMap({ - case Assignment(v, e) => rewritingMap.get(v).map(nv => Assignment(nv, e)) - case Variable(id) => rewritingMap.get(id).map(nid => Variable(nid)) - case _ => None - })(bd)) - } - - val wrappedBody = freshBody.zip(freshNames).zip(freshVarDecls).map{ - case ((freshBodyOpt, (_, freshNames)), (_, freshVarDecls)) => - freshBodyOpt.map(freshBody => freshNames.zip(freshVarDecls).foldLeft(freshBody)((body, p) => { - LetVar(p._2, Variable(p._1), body) - }))} - - val newReturnType = for((fd, modifiedVars) <- modified_vars) - yield TupleType(fd.returnType :: modifiedVars.map(_.getType)) - - val newFds = for(((fd, newParams), newReturnType) <- newParams.zip(newReturnType)) - yield { - val newFd = new FunDef(fd.id.freshen, fd.tparams, newParams, newReturnType).setPos(fd) - newFd.addFlags(fd.flags) - (fd, newFd) - } - - val mappingToAdd: Seq[(FunDef, (FunDef, List[Identifier]))] = - for(((fd, newFd), (_, freshVarDecls)) <- newFds.zip(freshVarDecls)) yield (fd -> ((newFd, freshVarDecls.toList))) - - //Seq[Option[(fdRes, fdScope, fdFun)]] = - val fdsResScopeFun = for(wrappedBodyOpt <- wrappedBody) yield { - wrappedBodyOpt.map(wrappedBody => + + if(modifiedVars.isEmpty) fdWithoutSideEffects else { + + val freshNames: List[Identifier] = modifiedVars.map(id => id.freshen) + + val newParams: Seq[ValDef] = fd.params ++ freshNames.map(n => ValDef(n)) + val freshVarDecls: List[Identifier] = freshNames.map(id => id.freshen) + + val rewritingMap: Map[Identifier, Identifier] = + modifiedVars.zip(freshVarDecls).toMap + val freshBody = + preMap({ + case Assignment(v, e) => rewritingMap.get(v).map(nv => Assignment(nv, e)) + case Variable(id) => rewritingMap.get(id).map(nid => Variable(nid)) + case _ => None + })(bd) + val wrappedBody = freshNames.zip(freshVarDecls).foldLeft(freshBody)((body, p) => { + LetVar(p._2, Variable(p._1), body) + }) + + val newReturnType = TupleType(fd.returnType :: modifiedVars.map(_.getType)) + + val newFd = new FunDef(fd.id.freshen, fd.tparams, newParams, newReturnType).setPos(fd) + newFd.addFlags(fd.flags) + + val (fdRes, fdScope, fdFun) = toFunction(wrappedBody)( - State(state.parent, Set(), - state.funDefsMapping.map{ - case (fd, (nfd, mvs)) => - (fd, (nfd, mvs.map(v => rewritingMap.getOrElse(v, v))))} ++ mappingToAdd) + State(state.parent, + Set(), + state.funDefsMapping.map{case (fd, (nfd, mvs)) => (fd, (nfd, mvs.map(v => rewritingMap.getOrElse(v, v))))} + + (fd -> ((newFd, freshVarDecls)))) ) - ) - } - - val newRes= for((optFdsResScopeFun, (_, freshVarDecls)) <- fdsResScopeFun.zip(freshVarDecls)) yield { - for((fdRes, fdScope, fdFun) <- optFdsResScopeFun) yield { - Tuple(fdRes :: freshVarDecls.map(vd => fdFun(vd).toVariable)) - } - } - val newbody = for((optFdsResScopeFun, newRes) <- fdsResScopeFun.zip(newRes)) yield { - for(newRes <- newRes; - (fdRes, fdScope, fdFun) <- optFdsResScopeFun) yield { - fdScope(newRes) - } - } - val fdForState = for(((((fd, newFd), optNewbody), (_, modifiedVars)), (_, freshNames)) - <- newFds.zip(newbody).zip(modified_vars).zip(freshNames)) yield { - newFd.body = optNewbody + val newRes = Tuple(fdRes :: freshVarDecls.map(vd => fdFun(vd).toVariable)) + val newBody = fdScope(newRes) + + newFd.body = Some(newBody) newFd.precondition = fd.precondition.map(prec => { replace(modifiedVars.zip(freshNames).map(p => (p._1.toVariable, p._2.toVariable)).toMap, prec) }) @@ -325,11 +295,12 @@ object ImperativeCodeElimination extends UnitPhase[Program] { postBody) Lambda(Seq(newRes), newBody).setPos(post) }) - (fd, (newFd, modifiedVars)) + + val (bodyRes, bodyScope, bodyFun) = toFunction(b)(state.withFunDef(fd, newFd, modifiedVars)) + (bodyRes, (b2: Expr) => LetDef(Seq(newFd), bodyScope(b2)).copiedFrom(expr), bodyFun) } - val (bodyRes, bodyScope, bodyFun) = toFunction(b)(state.withFunDefs(fdForState)) - (bodyRes, (b2: Expr) => LetDef(newFds.map(_._1), bodyScope(b2)).copiedFrom(expr), bodyFun) } + case None => fdWithoutSideEffects } case c @ Choose(b) => -- GitLab