summaryrefslogtreecommitdiff
path: root/src/reflect
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-09-18 07:48:57 -0700
committerPaul Phillips <paulp@improving.org>2013-09-18 12:13:06 -0700
commitf7a315adf63fdac2a7f95f87b88e03d4139af863 (patch)
tree6486f3d8f7bb4a462497b170ab84c65784669b29 /src/reflect
parent1c8bbd7ec5b8859f75abfbc4e70482dede2b7007 (diff)
downloadscala-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.scala67
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala7
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.
*/