diff options
author | Den Shabalin <den.shabalin@gmail.com> | 2013-11-01 17:14:20 +0100 |
---|---|---|
committer | Den Shabalin <den.shabalin@gmail.com> | 2013-11-12 14:04:42 +0100 |
commit | d89bfbbaa4d86cd9ebd2dfd874ae4a3509533df0 (patch) | |
tree | a05d81542356dc0e25f3e18d211139095b5bf2b3 /src/compiler | |
parent | c3e766e0b255f8fc202d027406c7efd76c82b49d (diff) | |
download | scala-d89bfbbaa4d86cd9ebd2dfd874ae4a3509533df0.tar.gz scala-d89bfbbaa4d86cd9ebd2dfd874ae4a3509533df0.tar.bz2 scala-d89bfbbaa4d86cd9ebd2dfd874ae4a3509533df0.zip |
change intermidiate representation of for loop enumerators
Encode values into real trees rather than non-tree case classes.
This is needed for re-usability of desugaring code between quasiquotes
and parser.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/TreeGen.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 32 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 91 |
3 files changed, 85 insertions, 48 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala index 28b127698f..d4ac21a6b8 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala @@ -53,13 +53,6 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { NewFromConstructor(constructor, expr) } - // annotate the expression with @unchecked - def mkUnchecked(expr: Tree): Tree = atPos(expr.pos) { - // This can't be "Annotated(New(UncheckedClass), expr)" because annotations - // are very picky about things and it crashes the compiler with "unexpected new". - Annotated(New(scalaDot(UncheckedClass.name), Nil), expr) - } - // Builds a tree of the form "{ lhs = rhs ; lhs }" def mkAssignAndReturn(lhs: Symbol, rhs: Tree): Tree = { def lhsRef = if (lhs.owner.isClass) Select(This(lhs.owner), lhs) else Ident(lhs) @@ -263,7 +256,4 @@ abstract class TreeGen extends scala.reflect.internal.TreeGen with TreeDSL { val stats1 = if (stats.isEmpty) List(Literal(Constant(()))) else stats mkNew(Nil, noSelfType, stats1, NoPosition, NoPosition) } - - def mkSyntheticParam(pname: TermName) = - ValDef(Modifiers(PARAM | SYNTHETIC), pname, TypeTree(), EmptyTree) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 0bf4d5426e..4641422132 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1394,7 +1394,7 @@ self => newLinesOpt() if (in.token == YIELD) { in.nextToken() - makeForYield(enums, expr()) + makeFor(enums, Yield(expr())) } else { makeFor(enums, expr()) } @@ -1700,22 +1700,25 @@ self => * | val Pattern1 `=' Expr * }}} */ - def enumerators(): List[Enumerator] = { - val enums = new ListBuffer[Enumerator] - generator(enums, eqOK = false) + def enumerators(): List[Tree] = { + val enums = new ListBuffer[Tree] + enums ++= enumerator(isFirst = true) while (isStatSep) { in.nextToken() - if (in.token == IF) enums += makeFilter(in.offset, guard()) - else generator(enums, eqOK = true) + enums ++= enumerator(isFirst = false) } enums.toList } + def enumerator(isFirst: Boolean, allowNestedIf: Boolean = true): List[Tree] = + if (in.token == IF && !isFirst) makeFilter(in.offset, guard()) :: Nil + else generator(!isFirst, allowNestedIf) + /** {{{ * Generator ::= Pattern1 (`<-' | `=') Expr [Guard] * }}} */ - def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) { + def generator(eqOK: Boolean, allowNestedIf: Boolean = true): List[Tree] = { val start = in.offset val hasVal = in.token == VAL if (hasVal) @@ -1733,10 +1736,19 @@ self => if (hasEq && eqOK) in.nextToken() else accept(LARROW) val rhs = expr() - enums += makeGenerator(r2p(start, point, in.lastOffset max start), pat, hasEq, rhs) - // why max above? IDE stress tests have shown that lastOffset could be less than start, + + def loop(): List[Tree] = + if (in.token != IF) Nil + else makeFilter(in.offset, guard()) :: loop() + + val tail = + if (allowNestedIf) loop() + else Nil + + // why max? IDE stress tests have shown that lastOffset could be less than start, // I guess this happens if instead if a for-expression we sit on a closing paren. - while (in.token == IF) enums += makeFilter(in.offset, guard()) + val genPos = r2p(start, point, in.lastOffset max start) + makeGenerator(genPos, pat, hasEq, rhs) :: tail } def makeFilter(start: Offset, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.end), tree) diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 5af279a62a..227d54f072 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -212,7 +212,7 @@ abstract class TreeBuilder { } /** Create tree for for-comprehension generator <val pat0 <- rhs0> */ - def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Enumerator = { + def makeGenerator(pos: Position, pat: Tree, valeq: Boolean, rhs: Tree): Tree = { val pat1 = patvarTransformer.transform(pat) val rhs1 = if (valeq || treeInfo.isVarPatternDeep(pat)) rhs @@ -228,10 +228,54 @@ abstract class TreeBuilder { def makeSyntheticTypeParam(pname: TypeName, bounds: Tree) = TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, Nil, bounds) - abstract class Enumerator { def pos: Position } - case class ValFrom(pos: Position, pat: Tree, rhs: Tree) extends Enumerator - case class ValEq(pos: Position, pat: Tree, rhs: Tree) extends Enumerator - case class Filter(pos: Position, test: Tree) extends Enumerator + object ValFrom { + def apply(pos: Position, pat: Tree, rhs: Tree): Tree = + Apply(Ident(nme.LARROWkw).updateAttachment(ForAttachment), + List(pat, rhs)).setPos(pos) + + def unapply(tree: Tree): Option[(Position, Tree, Tree)] = tree match { + case app @ Apply(id @ Ident(nme.LARROWkw), List(pat, rhs)) + if id.hasAttachment[ForAttachment.type] => + Some((app.pos, pat, rhs)) + case _ => None + } + } + + object ValEq { + def apply(pos: Position, pat: Tree, rhs: Tree): Tree = + Assign(pat, rhs).updateAttachment(ForAttachment).setPos(pos) + + def unapply(tree: Tree): Option[(Position, Tree, Tree)] = tree match { + case ass @ Assign(pat, rhs) + if tree.hasAttachment[ForAttachment.type] => + Some((ass.pos, pat, rhs)) + case _ => None + } + } + + object Filter { + def apply(pos: Position, tree: Tree) = + Apply(Ident(nme.IFkw).updateAttachment(ForAttachment), List(tree)).setPos(pos) + + def unapply(tree: Tree): Option[(Position, Tree)] = tree match { + case app @ Apply(id @ Ident(nme.IFkw), List(cond)) + if id.hasAttachment[ForAttachment.type] => + Some((app.pos, cond)) + case _ => None + } + } + + object Yield { + def apply(tree: Tree): Tree = + Apply(Ident(nme.YIELDkw).updateAttachment(ForAttachment), List(tree)) + + def unapply(tree: Tree): Option[Tree] = tree match { + case Apply(id @ Ident(nme.YIELDkw), List(tree)) + if id.hasAttachment[ForAttachment.type] => + Some(tree) + case _ => None + } + } /** Create tree for for-comprehension <for (enums) do body> or * <for (enums) yield body> where mapName and flatMapName are chosen @@ -281,7 +325,11 @@ abstract class TreeBuilder { * @param enums The enumerators in the for expression * @param body The body of the for expression */ - private def makeFor(mapName: TermName, flatMapName: TermName, enums: List[Enumerator], body: Tree): Tree = { + def makeFor(enums: List[Tree], sugarBody: Tree)(implicit fresh: FreshNameCreator): Tree = { + val (mapName, flatMapName, body) = sugarBody match { + case Yield(tree) => (nme.map, nme.flatMap, tree) + case _ => (nme.foreach, nme.foreach, sugarBody) + } /* make a closure pat => body. * The closure is assigned a transparent position with the point at pos.point and @@ -326,19 +374,16 @@ abstract class TreeBuilder { r2p(genpos.start, genpos.point, end) } -// val result = enums match { case ValFrom(pos, pat, rhs) :: Nil => makeCombination(closurePos(pos), mapName, rhs, pat, body) case ValFrom(pos, pat, rhs) :: (rest @ (ValFrom(_, _, _) :: _)) => makeCombination(closurePos(pos), flatMapName, rhs, pat, - makeFor(mapName, flatMapName, rest, body)) + makeFor(rest, sugarBody)) case ValFrom(pos, pat, rhs) :: Filter(_, test) :: rest => - makeFor(mapName, flatMapName, - ValFrom(pos, pat, makeCombination(rhs.pos union test.pos, nme.withFilter, rhs, pat.duplicate, test)) :: rest, - body) + makeFor(ValFrom(pos, pat, makeCombination(rhs.pos union test.pos, nme.withFilter, rhs, pat.duplicate, test)) :: rest, sugarBody) case ValFrom(pos, pat, rhs) :: rest => - val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile(_.isInstanceOf[ValEq]) + val valeqs = rest.take(definitions.MaxTupleArity - 1).takeWhile { ValEq.unapply(_).nonEmpty } assert(!valeqs.isEmpty) val rest1 = rest.drop(valeqs.length) val pats = valeqs map { case ValEq(_, pat, _) => pat } @@ -347,27 +392,17 @@ abstract class TreeBuilder { val defpats = pats map makeBind val pdefs = (defpats, rhss).zipped flatMap makePatDef val ids = (defpat1 :: defpats) map makeValue - val rhs1 = makeForYield( + val rhs1 = makeFor( List(ValFrom(pos, defpat1, rhs)), - Block(pdefs, atPos(wrappingPos(ids)) { makeTupleTerm(ids) }) setPos wrappingPos(pdefs)) + Yield(Block(pdefs, atPos(wrappingPos(ids)) { makeTupleTerm(ids) }) setPos wrappingPos(pdefs))) val allpats = (pat :: pats) map (_.duplicate) val vfrom1 = ValFrom(r2p(pos.start, pos.point, rhs1.pos.end), atPos(wrappingPos(allpats)) { makeTupleTerm(allpats) } , rhs1) - makeFor(mapName, flatMapName, vfrom1 :: rest1, body) + makeFor(vfrom1 :: rest1, sugarBody) case _ => EmptyTree //may happen for erroneous input } -// println("made for "+result) -// result } - /** Create tree for for-do comprehension <for (enums) body> */ - def makeFor(enums: List[Enumerator], body: Tree): Tree = - makeFor(nme.foreach, nme.foreach, enums, body) - - /** Create tree for for-yield comprehension <for (enums) yield body> */ - def makeForYield(enums: List[Enumerator], body: Tree): Tree = - makeFor(nme.map, nme.flatMap, enums, body) - /** Create tree for a pattern alternative */ def makeAlternative(ts: List[Tree]): Tree = { def alternatives(t: Tree): List[Tree] = t match { @@ -416,11 +451,11 @@ abstract class TreeBuilder { } /** Create tree for pattern definition <val pat0 = rhs> */ - def makePatDef(pat: Tree, rhs: Tree): List[Tree] = + def makePatDef(pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] = makePatDef(Modifiers(0), pat, rhs) /** Create tree for pattern definition <mods val pat0 = rhs> */ - def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree): List[Tree] = matchVarPattern(pat) match { + def makePatDef(mods: Modifiers, pat: Tree, rhs: Tree)(implicit fresh: FreshNameCreator): List[Tree] = matchVarPattern(pat) match { case Some((name, tpt)) => List(atPos(pat.pos union rhs.pos) { ValDef(mods, name.toTermName, tpt, rhs) @@ -460,7 +495,7 @@ abstract class TreeBuilder { rhs1, List( atPos(pat1.pos) { - CaseDef(pat1, EmptyTree, makeTupleTerm(vars map (_._1) map Ident.apply)) + CaseDef(pat1, EmptyTree, gen.mkTuple(vars map (_._1) map Ident.apply)) } )) } |