From f987afe55e6d4f71c7e9ad10d1ca9f6120dc1132 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 16 Mar 2012 00:46:21 -0700 Subject: More uniformity for the parser. Type application and operator notation could not formerly be mixed. Now they can, as the grammar has always suggested. --- .../scala/tools/nsc/ast/parser/Parsers.scala | 33 ++++++++++++++++------ .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 20 +++++++++---- 2 files changed, 39 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index ccebcfa54d..cd64c49b47 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -126,7 +126,7 @@ self => val global: Global import global._ - case class OpInfo(operand: Tree, operator: Name, offset: Offset) + case class OpInfo(operand: Tree, operator: Name, targs: List[Tree], offset: Offset) class SourceFileParser(val source: SourceFile) extends Parser { @@ -789,7 +789,7 @@ self => val rPos = top.pos val end = if (rPos.isDefined) rPos.endOrPoint else opPos.endOrPoint top = atPos(start, opinfo.offset, end) { - makeBinop(isExpr, opinfo.operand, opinfo.operator, top, opPos) + makeBinop(isExpr, opinfo.operand, opinfo.operator, top, opPos, opinfo.targs) } } top @@ -1440,6 +1440,17 @@ self => } } + def advanceStack(base: List[OpInfo], top: Tree): Tree = { + val newTop = reduceStack(true, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) + val op = in.name + val pos = in.offset + ident() + val targs = if (in.token == LBRACKET) exprTypeArgs() else Nil + opstack ::= OpInfo(newTop, op, targs, pos) + + newTop + } + /** {{{ * PostfixExpr ::= InfixExpr [Id [nl]] * InfixExpr ::= PrefixExpr @@ -1451,22 +1462,21 @@ self => var top = prefixExpr() while (isIdent) { - top = reduceStack(true, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) - val op = in.name - opstack = OpInfo(top, op, in.offset) :: opstack - ident() + top = advanceStack(base, top) newLineOptWhenFollowing(isExprIntroToken) + if (isExprIntro) { val next = prefixExpr() if (next == EmptyTree) return reduceStack(true, base, top, 0, true) top = next - } else { + } + else { val topinfo = opstack.head opstack = opstack.tail val od = stripParens(reduceStack(true, base, topinfo.operand, 0, true)) return atPos(od.pos.startOrPoint, topinfo.offset) { - Select(od, topinfo.operator.encode) + applyTypeArgs(Select(od, topinfo.operator.encode), topinfo.targs) } } } @@ -1806,7 +1816,7 @@ self => top = reduceStack( false, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) val op = in.name - opstack = OpInfo(top, op, in.offset) :: opstack + opstack = OpInfo(top, op, Nil, in.offset) :: opstack ident() top = simplePattern() } @@ -1896,6 +1906,11 @@ self => def exprTypeArgs() = outPattern.typeArgs() def exprSimpleType() = outPattern.simpleType() + def applyTypeArgs(sel: Tree, targs: List[Tree]): Tree = ( + if (targs.isEmpty) sel + else atPos(sel.pos)(TypeApply(sel, targs)) + ) + /** Default entry points into some pattern contexts. */ def pattern(): Tree = noSeq.pattern() def patterns(): List[Tree] = noSeq.patterns() diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 661f893c59..87251b4cc9 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -174,7 +174,14 @@ abstract class TreeBuilder { } /** Create tree representing (unencoded) binary operation expression or pattern. */ - def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position): Tree = { + def makeBinop(isExpr: Boolean, left: Tree, op: TermName, right: Tree, opPos: Position, targs: List[Tree] = Nil): Tree = { + require(isExpr || targs.isEmpty, ((left, op, targs, right))) + + def mkSel(t: Tree) = { + val sel = atPos(opPos union t.pos)(Select(stripParens(t), op.encode)) + if (targs.isEmpty) sel else atPos(left.pos)(TypeApply(sel, targs)) + } + def mkNamed(args: List[Tree]) = if (isExpr) args map { case a @ Assign(id @ Ident(name), rhs) => @@ -187,14 +194,17 @@ abstract class TreeBuilder { } if (isExpr) { if (treeInfo.isLeftAssoc(op)) { - Apply(atPos(opPos union left.pos) { Select(stripParens(left), op.encode) }, arguments) - } else { + Apply(mkSel(left), arguments) + } + else { val x = freshTermName() Block( List(ValDef(Modifiers(SYNTHETIC), x, TypeTree(), stripParens(left))), - Apply(atPos(opPos union right.pos) { Select(stripParens(right), op.encode) }, List(Ident(x)))) + Apply(mkSel(right), List(Ident(x))) + ) } - } else { + } + else { Apply(Ident(op.encode), stripParens(left) :: arguments) } } -- cgit v1.2.3