diff options
author | Martin Odersky <odersky@gmail.com> | 2006-03-18 19:43:30 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2006-03-18 19:43:30 +0000 |
commit | 322068fb8a1eb871280b19199505c30d8a25848b (patch) | |
tree | 490d0c0f69c5306bb0591df66947c11796530796 /src/compiler/scala/tools/nsc/transform/UnCurry.scala | |
parent | 578b9226a6a755f89d14be1fb0138fc02a6ca6b7 (diff) | |
download | scala-322068fb8a1eb871280b19199505c30d8a25848b.tar.gz scala-322068fb8a1eb871280b19199505c30d8a25848b.tar.bz2 scala-322068fb8a1eb871280b19199505c30d8a25848b.zip |
1. Added a range method to Array.scala
2. Enabled extended implicit conversions
3. Implemented non-local returns
Diffstat (limited to 'src/compiler/scala/tools/nsc/transform/UnCurry.scala')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/UnCurry.scala | 88 |
1 files changed, 85 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index 82521b7568..88e911de37 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -6,6 +6,7 @@ package scala.tools.nsc.transform; import symtab.Flags._; +import scala.collection.mutable.HashMap /*<export>*/ /** - uncurry all symbol and tree types (@see UnCurryPhase) @@ -25,6 +26,7 @@ import symtab.Flags._; * (a_1:_*) => (a_1)g * - convert implicit method types to method types * - convert non-trivial catches in try statements to matches + * - convert non-local returns to throws with enclosing try statements. */ /*</export>*/ abstract class UnCurry extends InfoTransform { @@ -36,6 +38,8 @@ abstract class UnCurry extends InfoTransform { def newTransformer(unit: CompilationUnit): Transformer = new UnCurryTransformer(unit); override def changesBaseClasses = false; +// ------ Type transformation -------------------------------------------------------- + private val uncurry = new TypeMap { def apply(tp: Type): Type = tp match { case MethodType(formals, MethodType(formals1, restpe)) => @@ -74,7 +78,7 @@ abstract class UnCurry extends InfoTransform { } catch { case ex: Throwable => System.out.println("exception when traversing " + tree); - throw ex + throw ex } /* Is tree a reference `x' to a call by name parameter that neeeds to be converted to @@ -97,6 +101,75 @@ abstract class UnCurry extends InfoTransform { uncurry(tp) } +// ------- Handling non-local returns ------------------------------------------------- + + /** The type of a non-local return expression for given method */ + private def nonLocalReturnExceptionType(meth: Symbol) = + appliedType( + NonLocalReturnExceptionClass.typeConstructor, + List(meth.tpe.finalResultType)) + + /** A hashmap from method symbols to non-local return keys */ + private val nonLocalReturnKeys = new HashMap[Symbol, Symbol]; + + /** Return non-local return key for given method */ + private def nonLocalReturnKey(meth: Symbol) = nonLocalReturnKeys.get(meth) match { + case Some(k) => k + case None => + val k = meth.newValue(meth.pos, unit.fresh.newName("nonLocalReturnKey")) + .setFlag(SYNTHETIC).setInfo(ObjectClass.tpe) + nonLocalReturnKeys(meth) = k + k + } + + /** Generate a non-local return throw with given return expression from given method. + * I.e. for the method's non-local return key, generate: + * + * throw new NonLocalReturnException(key, expr) + */ + private def nonLocalReturnThrow(expr: Tree, meth: Symbol) = + localTyper.atOwner(currentOwner).typed { + Throw( + New( + TypeTree(nonLocalReturnExceptionType(meth)), + List(List(Ident(nonLocalReturnKey(meth)), expr)))) + } + + /** Transform (body, key) to: + * + * { + * val key = new Object() + * try { + * body + * } catch { + * case ex: NonLocalReturnException => + * if (ex.key().eq(key)) ex.value() + * else throw ex + * } + * } + */ + private def nonLocalReturnTry(body: Tree, key: Symbol, meth: Symbol) = { + localTyper.atOwner(currentOwner).typed { + val extpe = nonLocalReturnExceptionType(meth); + val ex = meth.newValue(body.pos, nme.ex) setInfo extpe; + val pat = Bind(ex, Typed(Ident(nme.WILDCARD), TypeTree(extpe))); + val rhs = + If( + Apply( + Select( + Apply(Select(Ident(ex), "key"), List()), + Object_eq), + List(Ident(key))), + Apply(Select(Ident(ex), "value"), List()), + Throw(Ident(ex))); + val keyDef = ValDef(key, New(TypeTree(ObjectClass.tpe), List(List()))) + val tryCatch = Try(body, List(CaseDef(pat, EmptyTree, rhs)), EmptyTree) + Block(List(keyDef), tryCatch) + } + } + +// ------ Transforming anonymous functions and by-name-arguments ---------------- + /* Transform a function node (x_1,...,x_n) => body of type FunctionN[T_1, .., T_N, R] to * * class $anon() extends Object() with FunctionN[T_1, .., T_N, R] with ScalaObject { @@ -200,6 +273,8 @@ abstract class UnCurry extends InfoTransform { } } +// ------ The tree transformers -------------------------------------------------------- + def mainTransform(tree: Tree): Tree = { def withNeedLift(needLift: Boolean)(f: => Tree): Tree = { @@ -327,7 +402,11 @@ abstract class UnCurry extends InfoTransform { } tree match { case DefDef(mods, name, tparams, vparamss, tpt, rhs) => - copy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs); + val rhs1 = nonLocalReturnKeys.get(tree.symbol) match { + case None => rhs + case Some(k) => atPos(rhs.pos)(nonLocalReturnTry(rhs, k, tree.symbol)) + } + copy.DefDef(tree, mods, name, tparams, List(List.flatten(vparamss)), tpt, rhs1); case Try(body, catches, finalizer) => if (catches forall treeInfo.isCatchCase) tree else { @@ -343,7 +422,7 @@ abstract class UnCurry extends InfoTransform { Match(Ident(exname), cases)) } if (settings.debug.value) log("rewrote try: " + catches + " ==> " + catchall); - val catches1 = typer.atOwner(currentOwner).typedCases( + val catches1 = localTyper.atOwner(currentOwner).typedCases( tree, List(catchall), ThrowableClass.tpe, WildcardType); copy.Try(tree, body, catches1, finalizer) } @@ -357,6 +436,9 @@ abstract class UnCurry extends InfoTransform { applyUnary(tree) case TypeApply(_, _) => applyUnary(tree) + case Return(expr) if (tree.symbol != currentOwner.enclMethod) => + if (settings.debug.value) log("non local return in "+tree.symbol+" from "+currentOwner.enclMethod) + atPos(tree.pos)(nonLocalReturnThrow(expr, tree.symbol)) case _ => tree } |