diff options
author | Paul Phillips <paulp@improving.org> | 2013-09-18 07:48:57 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-09-18 12:13:06 -0700 |
commit | f7a315adf63fdac2a7f95f87b88e03d4139af863 (patch) | |
tree | 6486f3d8f7bb4a462497b170ab84c65784669b29 /src/reflect | |
parent | 1c8bbd7ec5b8859f75abfbc4e70482dede2b7007 (diff) | |
download | scala-f7a315adf63fdac2a7f95f87b88e03d4139af863.tar.gz scala-f7a315adf63fdac2a7f95f87b88e03d4139af863.tar.bz2 scala-f7a315adf63fdac2a7f95f87b88e03d4139af863.zip |
SI-7854, SI-6768 better parsing/positioning in parser
The parser hole I found while working on the generated positions
serves as the umbrella for a host of improvements. Upgraded
positions assigned during some specific challenging situations mostly
involving the creation of synthetic trees, e.g. for comprehensions
and closures. While doing so improved some error messages.
Eliminated some of the most glaring duplication in the parser.
It's written like there is some payoff associated with being
spectacularly imperative. Not so far.
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeGen.scala | 67 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/TreeInfo.scala | 7 |
2 files changed, 35 insertions, 39 deletions
diff --git a/src/reflect/scala/reflect/internal/TreeGen.scala b/src/reflect/scala/reflect/internal/TreeGen.scala index 72e1ee107b..a8af3e0f0e 100644 --- a/src/reflect/scala/reflect/internal/TreeGen.scala +++ b/src/reflect/scala/reflect/internal/TreeGen.scala @@ -280,7 +280,7 @@ abstract class TreeGen extends macros.TreeBuilder { /** Builds a tuple */ def mkTuple(elems: List[Tree]): Tree = - if (elems.isEmpty) Literal(Constant(())) + if (elems.isEmpty) mkUnit() else Apply( Select(mkAttributedRef(TupleClass(elems.length).caseModule), nme.apply), elems) @@ -326,8 +326,7 @@ abstract class TreeGen extends macros.TreeBuilder { * body * } */ - def mkTemplate(parents: List[Tree], self: ValDef, constrMods: Modifiers, - vparamss: List[List[ValDef]], body: List[Tree], superPos: Position = NoPosition): Template = { + def mkTemplate(parents: List[Tree], self: ValDef, constrMods: Modifiers, vparamss: List[List[ValDef]], body: List[Tree], superPos: Position = NoPosition): Template = { /* Add constructor to template */ // create parameters for <init> as synthetic trees. @@ -398,51 +397,41 @@ abstract class TreeGen extends macros.TreeBuilder { * @param npos the position of the new * @param cpos the position of the anonymous class starting with parents */ - def mkNew(parents: List[Tree], self: ValDef, stats: List[Tree], - npos: Position, cpos: Position): Tree = - if (parents.isEmpty) - mkNew(List(scalaAnyRefConstr), self, stats, npos, cpos) - else if (parents.tail.isEmpty && stats.isEmpty) { - // `Parsers.template` no longer differentiates tpts and their argss - // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil) - // instead of parents = Ident(C), argss = Nil as before - // this change works great for things that are actually templates - // but in this degenerate case we need to perform postprocessing - val app = treeInfo.dissectApplied(parents.head) - atPos(npos union cpos) { New(app.callee, app.argss) } - } else { - val x = tpnme.ANON_CLASS_NAME - atPos(npos union cpos) { - Block( - List( - atPos(cpos) { - ClassDef( - Modifiers(FINAL), x, Nil, - mkTemplate(parents, self, NoMods, ListOfNil, stats, cpos.focus)) - }), - atPos(npos) { - New( - Ident(x) setPos npos.focus, - Nil) - } - ) - } + def mkNew(parents: List[Tree], self: ValDef, stats: List[Tree], npos: Position, cpos: Position): Tree = { + def enclosingPos = wrappingPos(cpos, parents ::: List(self) ::: stats) + def upos = cpos union npos + def anonTemplate = atPos(cpos)(mkTemplate(parents, self, NoMods, ListOfNil, stats, cpos)) + def anonClass = atPos(anonTemplate.pos.makeTransparent)(ClassDef(Modifiers(FINAL), tpnme.ANON_CLASS_NAME, Nil, anonTemplate)) + def anonNew = atPos(npos)(New(Ident(tpnme.ANON_CLASS_NAME) setPos cpos.focus, Nil)) + + // `Parsers.template` no longer differentiates tpts and their argss + // e.g. `C()` will be represented as a single tree Apply(Ident(C), Nil) + // instead of parents = Ident(C), argss = Nil as before + // this change works great for things that are actually templates + // but in this degenerate case we need to perform postprocessing + parents match { + case Nil => mkNew(List(scalaAnyRefConstr), self, stats, npos, cpos) + case treeInfo.AppliedArgs(callee, argss) :: Nil if stats.isEmpty => atPos(upos)(New(callee, argss)) + case _ => atPos(upos)(mkBlock(anonClass :: anonNew :: Nil)) } + } /** Create a tree representing the function type (argtpes) => restpe */ def mkFunctionTypeTree(argtpes: List[Tree], restpe: Tree): Tree = AppliedTypeTree(rootScalaDot(newTypeName("Function" + argtpes.length)), argtpes ::: List(restpe)) + def mkUnit() = Literal(Constant(())) + /** Create block of statements `stats` */ - def mkBlock(stats: List[Tree]): Tree = - if (stats.isEmpty) Literal(Constant(())) - else if (!stats.last.isTerm) Block(stats, Literal(Constant(()))) - else if (stats.length == 1) stats.head - else Block(stats.init, stats.last) + def mkBlock(stats: List[Tree]): Tree = stats match { + case stats if stats.isEmpty || !stats.last.isTerm => mkBlock(stats :+ mkUnit()) + case stat :: Nil => stat + case stats => Block(stats.init, stats.last) + } def mkTreeOrBlock(stats: List[Tree]) = stats match { - case Nil => EmptyTree + case Nil => EmptyTree case head :: Nil => head - case _ => gen.mkBlock(stats) + case _ => gen.mkBlock(stats) } } diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala index 34fe0afb1a..1b763b8632 100644 --- a/src/reflect/scala/reflect/internal/TreeInfo.scala +++ b/src/reflect/scala/reflect/internal/TreeInfo.scala @@ -773,6 +773,13 @@ abstract class TreeInfo { unapply(dissectApplied(tree)) } + object AppliedArgs { + def unapply(tree: Tree): Some[(Tree, List[List[Tree]])] = tree match { + case Apply(AppliedArgs(fn, argss), args) => Some((fn, argss :+ args)) + case _ => Some((tree, Nil)) + } + } + /** Locates the synthetic Apply node corresponding to an extractor's call to * unapply (unwrapping nested Applies) and returns the fun part of that Apply. */ |