diff options
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala | 63 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 1978 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/ast/parser/Scanners.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 22 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/javac/JavaScanners.scala | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | src/compiler/scala/tools/nsc/util/CharArrayReader.scala | 171 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/util/CharArrayReader1.scala | 107 | ||||
-rwxr-xr-x | src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala | 134 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala | 74 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/Position.scala | 20 |
12 files changed, 1225 insertions, 1365 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 3771ede167..4422a8b1ba 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -12,7 +12,7 @@ import java.nio.charset._ import compat.Platform.currentTime import scala.tools.nsc.io.{SourceReader, AbstractFile} import scala.tools.nsc.reporters._ -import scala.tools.nsc.util.{ClassPath, SourceFile, BatchSourceFile} +import scala.tools.nsc.util.{ClassPath, SourceFile, BatchSourceFile, OffsetPosition} import scala.collection.mutable.{HashSet, HashMap, ListBuffer} @@ -118,6 +118,8 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable def inform(msg: String) = Console.err.println(msg) def inform[T](msg: String, value: T): T = { inform(msg+value); value } + def rangePos(source: SourceFile, start: Int, mid: Int, end: Int) = OffsetPosition(source, mid) + //reporter.info(null, msg, true) def informProgress(msg: String) = diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index b1a0f4c49e..1367b37729 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -111,7 +111,11 @@ trait Trees { def tpe = rawtpe def tpe_=(t: Type) = rawtpe = t - def setPos(pos: Position): this.type = { rawpos = pos; this } + def setPos(pos: Position): this.type = { + rawpos = pos; + this + } + def setType(tp: Type): this.type = { /*assert(kindingIrrelevant(tp) || !kindStar || !tp.isHigherKinded, tp+" should not be higher-kinded");*/ @@ -857,6 +861,8 @@ trait Trees { case class ExistentialTypeTree(tpt: Tree, whereClauses: List[Tree]) extends TypTree + case class Parens(args: List[Tree]) extends Tree // only used during parsing + trait StubTree extends Tree { def underlying : AnyRef override def equalsStructure0(that: Tree)(f : (Tree,Tree) => Boolean): Boolean = this eq that @@ -1597,6 +1603,8 @@ trait Trees { traverse(lo); traverse(hi) case ExistentialTypeTree(tpt, whereClauses) => traverse(tpt); traverseTrees(whereClauses) + case Parens(ts) => + traverseTrees(ts) case tree : StubTree => } diff --git a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala index 87955b9e31..5d6ba35a9f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/MarkupParsers.scala @@ -7,7 +7,7 @@ package scala.tools.nsc.ast.parser import scala.collection.mutable -import scala.tools.nsc.util.{Position,NoPosition,SourceFile,CharArrayReader1} +import scala.tools.nsc.util.{Position,NoPosition,SourceFile,CharArrayReader} import scala.xml.{Text, TextBuffer} import SourceFile.{SU,LF} import scala.annotation.switch @@ -38,11 +38,11 @@ trait MarkupParsers {self: Parsers => import Tokens.{EMPTY, LBRACE, RBRACE} final val preserveWS = presWS - var input : CharArrayReader1 = _ + var input : CharArrayReader = _ - import parser.{symbXMLBuilder => handle, i2p} + import parser.{symbXMLBuilder => handle, o2p, r2p} - def pos : Int = input.charOffset + def curOffset : Int = input.charOffset - 1 var tmppos : Position = NoPosition def ch = input.ch /** this method assign the next character to ch and advances in input */ @@ -82,17 +82,18 @@ trait MarkupParsers {self: Parsers => /*[Duplicate]*/ def xAttributes = { var aMap = new mutable.HashMap[String, Tree]() while (xml.Parsing.isNameStart(ch)) { + val start = curOffset val key = xName xEQ val delim = ch - val pos1 = pos + val mid = curOffset val value: /* AttribValue[*/Tree/*]*/ = ch match { case '"' | '\'' => nextch val tmp = xAttributeValue(delim) nextch try { - handle.parseAttribute(pos1, tmp) + handle.parseAttribute(r2p(start, mid, curOffset), tmp) } catch { case e => reportSyntaxError("error parsing attribute value") @@ -174,6 +175,7 @@ trait MarkupParsers {self: Parsers => * see [15] */ /*[Duplicate]*/ def xCharData: Tree = { + val start = curOffset xToken('[') xToken('C') xToken('D') @@ -181,7 +183,7 @@ trait MarkupParsers {self: Parsers => xToken('T') xToken('A') xToken('[') - val pos1 = pos + val mid = curOffset val sb: StringBuilder = new StringBuilder() while (true) { if (ch==']' && @@ -189,7 +191,7 @@ trait MarkupParsers {self: Parsers => { sb.append(ch); nextch; ch == '>' }) { sb.length = sb.length - 2 nextch - return handle.charData(pos1, sb.toString()) + return handle.charData(r2p(start, mid, curOffset), sb.toString()) } else if (ch == SU) throw TruncatedXML else @@ -200,7 +202,7 @@ trait MarkupParsers {self: Parsers => } def xUnparsed: Tree = { - val pos1 = pos + val start = curOffset val sb: StringBuilder = new StringBuilder() while (true) { if (ch=='<' && @@ -220,7 +222,7 @@ trait MarkupParsers {self: Parsers => { sb.append(ch); nextch; ch == '>' }) { sb.length = sb.length - "</xml:unparsed".length nextch - return handle.unparsed(pos1, sb.toString()) + return handle.unparsed(r2p(start, start, curOffset), sb.toString()) } else if (ch == SU) { throw TruncatedXML } else sb.append(ch) @@ -264,6 +266,7 @@ trait MarkupParsers {self: Parsers => * see [15] */ /*[Duplicate]*/ def xComment: Tree = { + val start = curOffset - 2 // ? right so ? val sb: StringBuilder = new StringBuilder() xToken('-') xToken('-') @@ -272,7 +275,7 @@ trait MarkupParsers {self: Parsers => sb.length = sb.length - 1 nextch xToken('>') - return handle.comment(pos, sb.toString()) + return handle.comment(r2p(start, start, curOffset), sb.toString()) } else if (ch == SU) { throw TruncatedXML } else sb.append(ch) @@ -360,7 +363,7 @@ trait MarkupParsers {self: Parsers => if (xEmbeddedBlock) ts.append(xEmbeddedExpr) else { - tmppos = pos + tmppos = o2p(curOffset) ch match { case '<' => // end tag, cdata, comment, pi or child node nextch @@ -384,25 +387,26 @@ trait MarkupParsers {self: Parsers => * | xmlTag1 '/' '>' */ /*[Duplicate]*/ def element: Tree = { - val pos1 = pos + val start = curOffset val (qname, attrMap) = xTag if (ch == '/') { // empty element xToken('/') xToken('>') - handle.element(pos1, qname, attrMap, new mutable.ListBuffer[Tree]) + handle.element(r2p(start, start, curOffset), qname, attrMap, new mutable.ListBuffer[Tree]) } else { // handle content xToken('>') if (qname == "xml:unparsed") return xUnparsed - debugLastStartElement.push((pos1, qname)) + debugLastStartElement.push((start, qname)) val ts = content xEndTag(qname) debugLastStartElement.pop + val pos = r2p(start, start, curOffset) qname match { - case "xml:group" => handle.group(pos1, ts) - case _ => handle.element(pos1, qname, attrMap, ts) + case "xml:group" => handle.group(pos, ts) + case _ => handle.element(pos, qname, attrMap, ts) } } } @@ -520,7 +524,8 @@ trait MarkupParsers {self: Parsers => //val pos = s.currentPos var tree:Tree = null val ts = new mutable.ArrayBuffer[Tree]() - tmppos = (pos) // Iuli: added this line, as it seems content_LT uses tmppos when creating trees + val start = curOffset + tmppos = o2p(curOffset) // Iuli: added this line, as it seems content_LT uses tmppos when creating trees // assert(ch == '<') // nextch content_LT(ts) @@ -541,7 +546,7 @@ trait MarkupParsers {self: Parsers => ts.append(element) xSpaceOpt } - tree = handle.makeXMLseq((pos), ts) + tree = handle.makeXMLseq(r2p(start, start, curOffset), ts) } else { input = parser.in assert(ts.length == 1) @@ -582,7 +587,7 @@ trait MarkupParsers {self: Parsers => tree } catch { case c @ TruncatedXML => - parser.syntaxError(pos - 1, c.getMessage) + parser.syntaxError(curOffset, c.getMessage) EmptyTree case c @ (MissingEndTagException | ConfusedAboutBracesException) => @@ -634,12 +639,12 @@ trait MarkupParsers {self: Parsers => /* private def init { ch = s.in.ch - pos = s.in.cpos + curOffset = s.in.ccurOffset } */ def reportSyntaxError(str: String) = { - parser.syntaxError(pos - 1, "in XML literal: " + str) + parser.syntaxError(curOffset, "in XML literal: " + str) nextch } /* @@ -652,14 +657,14 @@ trait MarkupParsers {self: Parsers => * | Name [S] '/' '>' */ def xPattern: Tree = { - val pos1 = pos + var start = curOffset val qname = xName - debugLastStartElement.push((pos1, qname)) + debugLastStartElement.push((start, qname)) xSpaceOpt if (ch == '/') { // empty tag nextch xToken('>') - return handle.makeXMLpat(pos1, qname, new mutable.ArrayBuffer[Tree]()) + return handle.makeXMLpat(r2p(start, start, curOffset), qname, new mutable.ArrayBuffer[Tree]()) } // else: tag with content @@ -667,7 +672,7 @@ trait MarkupParsers {self: Parsers => var ts = new mutable.ArrayBuffer[Tree] var exit = false while (! exit) { - val pos2 = pos + val start1 = curOffset if (xEmbeddedBlock) { ts ++= xScalaPatterns } else @@ -690,15 +695,15 @@ trait MarkupParsers {self: Parsers => case SU => throw TruncatedXML - case _ => // teMaxt - appendText(pos2, ts, xText) + case _ => // text + appendText(r2p(start1, start1, curOffset), ts, xText) // here xEmbeddedBlock might be true; //if( xEmbeddedBlock ) throw new ApplicationError("after:"+text); // assert } } xEndTag(qname) debugLastStartElement.pop - handle.makeXMLpat(pos1, qname, ts) + handle.makeXMLpat(r2p(start, start, curOffset), qname, ts) } } /* class MarkupParser */ diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 1fc1382ee8..6c795b66d0 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -52,13 +52,12 @@ import Tokens._ */ trait Parsers extends Scanners with MarkupParsers { self => - val global : Global + val global: Global import global._ private val glob: global.type = global - import global.posAssigner.atPos - case class OpInfo(operand: Tree, operator: Name, pos: Int) + case class OpInfo(operand: Tree, operator: Name, offset: Offset) class UnitParser(val unit: global.CompilationUnit) extends Parser { val in = new UnitScanner(unit) @@ -67,17 +66,20 @@ self => def freshName(pos: Position, prefix: String): Name = unit.fresh.newName(pos, prefix) - implicit def i2p(offset: Int): Position = new OffsetPosition(unit.source,offset) + def o2p(offset: Int): Position = new OffsetPosition(unit.source,offset) + def r2p(start: Int, mid: Int, end: Int): Position = rangePos(unit.source, start, mid, end) - def warning(pos: Int, msg: String) { unit.warning(pos, msg) } + def warning(offset: Int, msg: String) { unit.warning(o2p(offset), msg) } def incompleteInputError(msg: String) { - unit.incompleteInputError(unit.source.asInstanceOf[BatchSourceFile].content.length - 1, msg) + unit.incompleteInputError(o2p(unit.source.asInstanceOf[BatchSourceFile].content.length - 1), msg) } - def deprecationWarning(pos: Int, msg: String) { - unit.deprecationWarning(pos, msg) + + def deprecationWarning(offset: Int, msg: String) { + unit.deprecationWarning(o2p(offset), msg) } - def syntaxError(pos: Int, msg: String) { unit.error(pos, msg) } + + def syntaxError(offset: Int, msg: String) { unit.error(o2p(offset), msg) } /** the markup parser */ lazy val xmlp = new MarkupParser(this, true) @@ -86,61 +88,38 @@ self => val global: self.global.type = self.global def freshName(prefix: String): Name = UnitParser.this.freshName(NoPosition, prefix) } + def xmlLiteral : Tree = xmlp.xLiteral - def xmlLiteralPattern : Tree = xmlp.xLiteralPattern - } - class ScanOnly(unit: global.CompilationUnit) extends UnitParser(unit) { - override def parse(): Tree = { - while (in.token != EOF) in.nextToken - null - } + def xmlLiteralPattern : Tree = xmlp.xLiteralPattern } - // parser constants, here so they don't pollute parser debug listing - private object ParserConfiguration { - final val Local = 0 - final val InBlock = 1 - final val InTemplate = 2 - final val MINUS: Name = "-" - final val PLUS : Name = "+" - final val BANG : Name = "!" - final val TILDE: Name = "~" - final val AMP : Name = "&" - final val SLASH: Name = "/" - final val STAR : Name = "*" - final val BAR : Name = "|" - final val LT : Name = "<" - } + final val Local = 0 + final val InBlock = 1 + final val InTemplate = 2 + final val MINUS: Name = "-" + final val PLUS : Name = "+" + final val BANG : Name = "!" + final val TILDE: Name = "~" + final val AMP : Name = "&" + final val SLASH: Name = "/" + final val STAR : Name = "*" + final val BAR : Name = "|" + final val LT : Name = "<" abstract class Parser { - ParserConfiguration.hashCode - import ParserConfiguration._ val in: Scanner //val unit : CompilationUnit //import in.ScanPosition - protected def freshName(pos: Position, prefix: String): Name - protected def posToReport: Int = in.offset - - protected implicit def i2p(offset: Int): Position + def freshName(pos: Position, prefix: String): Name + def o2p(offset: Int): Position + def r2p(start: Int, mid: Int, end: Int): Position //private implicit def p2i(pos: Position) = pos.offset.get - private def inToken = in.token - private def inSkipToken = in.skipToken() - private def inNextToken = in.nextToken() - private def inCurrentPos = in.offset - private def inNextTokenCode : Int = in.next.token - private def inName = in.name - private def charVal = in.charVal - private def intVal(isNegated: Boolean) = in.intVal(isNegated).asInstanceOf[Int] - private def longVal(isNegated: Boolean) = in.intVal(isNegated) - private def floatVal(isNegated: Boolean) = in.floatVal(isNegated).asInstanceOf[Float] - private def doubleVal(isNegated: Boolean) = in.floatVal(isNegated) - private def stringVal = in.strVal - /** whether a non-continuable syntax error has been seen */ //private var syntaxErrorSeen = false - private var lastErrorPos : Int = -1 + + private var lastErrorOffset : Int = -1 object treeBuilder extends TreeBuilder { val global: self.global.type = self.global @@ -203,20 +182,27 @@ self => placeholderTypes = List() var t = op if (!placeholderTypes.isEmpty && t.isInstanceOf[AppliedTypeTree]) { - t = ExistentialTypeTree(t, placeholderTypes.reverse) + t = atPos(t.pos) { ExistentialTypeTree(t, placeholderTypes.reverse) } placeholderTypes = List() } placeholderTypes = placeholderTypes ::: savedPlaceholderTypes t } + def isWildcard(t: Tree): Boolean = t match { + case Ident(name1) => !placeholderParams.isEmpty && name1 == placeholderParams.head.name + case Typed(t1, _) => isWildcard(t1) + case Annotated(t1, _) => isWildcard(t1) + case _ => false + } + /* ------------- ERROR HANDLING ------------------------------------------- */ protected def skip() { var nparens = 0 var nbraces = 0 while (true) { - inToken match { + in.token match { case EOF => return case SEMI => @@ -236,82 +222,59 @@ self => nbraces += 1 case _ => } - inNextToken + in.nextToken() } } - def warning(pos: Int, msg: String): Unit + def warning(offset: Int, msg: String): Unit def incompleteInputError(msg: String): Unit - def deprecationWarning(pos: Int, msg: String): Unit + def deprecationWarning(offset: Int, msg: String): Unit private def syntaxError(pos: Position, msg: String, skipIt: Boolean) { pos.offset match { case None => syntaxError(msg,skipIt) case Some(offset) => syntaxError(offset, msg, skipIt) } } - def syntaxError(pos: Int, msg: String): Unit + def syntaxError(offset: Int, msg: String): Unit def syntaxError(msg: String, skipIt: Boolean) { - syntaxError(inCurrentPos, msg, skipIt) + syntaxError(in.offset, msg, skipIt) } - def syntaxError(pos: Int, msg: String, skipIt: Boolean) { - if (pos > lastErrorPos) { - syntaxError(pos, msg) + def syntaxError(offset: Int, msg: String, skipIt: Boolean) { + if (offset > lastErrorOffset) { + syntaxError(offset, msg) // no more errors on this token. - lastErrorPos = inCurrentPos + lastErrorOffset = in.offset } if (skipIt) skip() } - def warning(msg: String) { warning(inCurrentPos, msg) } + def warning(msg: String) { warning(in.offset, msg) } def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) { - val inToken = this.inToken - if (inToken == EOF) + if (in.token == EOF) incompleteInputError(msg) else - syntaxError(inCurrentPos, msg, skipIt) - } - // unused. - /* Commented out because the comment says it is unused. - Probably eliminate eventually. GAW 2008.05.01 - def mismatch(expected: Int, found: Int) { - val posToReport = this.posToReport - val msg = - ScannerConfiguration.token2string(expected) + " expected but " + - ScannerConfiguration.token2string(found) + " found." - - if (found == EOF) - incompleteInputError(msg) - else - syntaxError(posToReport, msg, true) + syntaxError(in.offset, msg, skipIt) } - */ /** Consume one token of the specified type, or * signal an error if it is not there. */ def accept(token: Int): Int = { - val pos = inCurrentPos - if (inToken != token) { - val posToReport = - //if (inCurrentPos.line(unit.source).get(0) > in.lastPos.line(unit.source).get(0)) - // in.lastPos - //else - inCurrentPos + val offset = in.offset + if (in.token != token) { val msg = - token2string(token) + " expected but " +token2string(inToken) + " found." + token2string(token) + " expected but " +token2string(in.token) + " found." - if (inToken == EOF) - incompleteInputError(msg) - else - syntaxError(posToReport, msg, true) + if (in.token == EOF) incompleteInputError(msg) + else syntaxError(in.offset, msg, true) } - if (inToken == token) inNextToken - pos + if (in.token == token) in.nextToken() + offset } def surround[T](open: Int, close: Int)(f: => T, orElse: T): T = { - val wasOpened = inToken == open + val wasOpened = in.token == open accept(open) if (wasOpened) { val ret = f @@ -324,42 +287,58 @@ self => * nl = `\n' // where allowed */ def acceptStatSep(): Boolean = - if (inToken == NEWLINE || inToken == NEWLINES) { inNextToken; true } + if (in.token == NEWLINE || in.token == NEWLINES) { in.nextToken(); true } else { - val ret = inToken == SEMI + val ret = in.token == SEMI accept(SEMI) ret } - def errorTypeTree = TypeTree().setType(ErrorType).setPos((inCurrentPos)) - def errorTermTree = Literal(Constant(null)).setPos((inCurrentPos)) - def errorPatternTree = Ident(nme.WILDCARD).setPos((inCurrentPos)) + def errorTypeTree = TypeTree().setType(ErrorType).setPos(o2p(in.offset)) + def errorTermTree = Literal(Constant(null)).setPos(o2p(in.offset)) + def errorPatternTree = Ident(nme.WILDCARD).setPos(o2p(in.offset)) + + /** Check that type parameter is not by name T* */ + def checkNotByName(t: Tree) = t match { + case AppliedTypeTree(Select(_, n), _) if (n == nme.BYNAME_PARAM_CLASS_NAME.toTypeName) => + syntaxError(t.pos, "no by-name parameter type allowed here", false) + case _ => + } + + /** Check that tree is a legal clause of a forSome */ + def checkLegalExistential(t: Tree) = t match { + case TypeDef(_, _, _, TypeBoundsTree(_, _)) | + ValDef(_, _, _, EmptyTree) | EmptyTree => + ; + case _ => + syntaxError(t.pos, "not a legal existential clause", false) + } /* -------------- TOKEN CLASSES ------------------------------------------- */ - def isModifier: Boolean = inToken match { + def isModifier: Boolean = in.token match { case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT | LAZY => true case _ => false } - def isLocalModifier: Boolean = inToken match { + def isLocalModifier: Boolean = in.token match { case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY => true case _ => false } - def isDefIntro: Boolean = inToken match { + def isDefIntro: Boolean = in.token match { case VAL | VAR | DEF | TYPE | OBJECT | CASEOBJECT | CLASS | CASECLASS | TRAIT => true case _ => false } - def isDclIntro: Boolean = inToken match { + def isDclIntro: Boolean = in.token match { case VAL | VAR | DEF | TYPE => true case _ => false } - def isIdent = inToken == IDENTIFIER || inToken == BACKQUOTED_IDENT + def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT def isExprIntroToken(token: Int): Boolean = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | @@ -369,7 +348,7 @@ self => case _ => false } - def isExprIntro: Boolean = isExprIntroToken(inToken) + def isExprIntro: Boolean = isExprIntroToken(in.token) def isTypeIntroToken(token: Int): Boolean = token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | @@ -377,12 +356,12 @@ self => case _ => false } - def isTypeIntro: Boolean = isTypeIntroToken(inToken) + def isTypeIntro: Boolean = isTypeIntroToken(in.token) def isStatSep(token: Int): Boolean = token == NEWLINE || token == NEWLINES || token == SEMI - def isStatSep: Boolean = isStatSep(inToken) + def isStatSep: Boolean = isStatSep(in.token) /* --------- COMMENT AND ATTRIBUTE COLLECTION ----------------------------- */ @@ -397,6 +376,15 @@ self => /* ---------- TREE CONSTRUCTION ------------------------------------------- */ + def atPos[T <: Tree](offset: Int)(t: T): T = + posAssigner.atPos(r2p(offset, offset, in.lastOffset))(t) + def atPos[T <: Tree](start: Int, mid: Int)(t: T): T = + posAssigner.atPos(r2p(start, mid, in.lastOffset))(t) + def atPos[T <: Tree](start: Int, mid: Int, end: Int)(t: T): T = + posAssigner.atPos(r2p(start, mid, end))(t) + def atPos[T <: Tree](pos: Position)(t: T): T = + posAssigner.atPos(pos)(t) + /** Convert tree to formal parameter list */ def convertToParams(tree: Tree): List[ValDef] = tree match { @@ -408,59 +396,44 @@ self => /** Convert tree to formal parameter */ - def convertToParam(tree: Tree): ValDef = - atPos(tree.pos) { - def removeAsPlaceholder(name: Name) { - placeholderParams = placeholderParams filter (_.name != name) - } - tree match { - case Ident(name) => - removeAsPlaceholder(name) - ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree) - case Typed(tree @ Ident(name), tpe) if (tpe.isType) => // get the ident! - removeAsPlaceholder(name) - ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree).setPos(tree.pos) - case _ => - syntaxError(tree.pos, "not a legal formal parameter", false) - ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree, EmptyTree) - } + def convertToParam(tree: Tree): ValDef = atPos(tree.pos) { + def removeAsPlaceholder(name: Name) { + placeholderParams = placeholderParams filter (_.name != name) + } + tree match { + case Ident(name) => + removeAsPlaceholder(name) + ValDef(Modifiers(Flags.PARAM), name, TypeTree(), EmptyTree) + case Typed(tree @ Ident(name), tpe) if (tpe.isType) => // get the ident! + removeAsPlaceholder(name) + ValDef(Modifiers(Flags.PARAM), name, tpe, EmptyTree) + case _ => + syntaxError(tree.pos, "not a legal formal parameter", false) + ValDef(Modifiers(Flags.PARAM), nme.ERROR, errorTypeTree, EmptyTree) } + } /** Convert (qual)ident to type identifier */ - def convertToTypeId(tree: Tree): Tree = tree match { - case Ident(name) => - Ident(name.toTypeName).setPos(tree.pos) - case Select(qual, name) => - Select(qual, name.toTypeName).setPos(tree.pos) - case _ => - syntaxError(tree.pos, "identifier expected", false) - errorTypeTree - } - - /** make closure from tree staring with a `.' */ - def makeDotClosure(tree: Tree): Tree = { - val pname = freshName(tree.pos, "x$") - def insertParam(tree: Tree): Tree = atPos(tree.pos) { - tree match { - case Ident(name) => - Select(Ident(pname), name) - case Select(qual, name) => - Select(insertParam(qual), name) - case Apply(fn, args) => - Apply(insertParam(fn), args) - case TypeApply(fn, args) => - TypeApply(insertParam(fn), args) - case _ => - syntaxError(tree.pos, "cannot convert to closure", false) - errorTermTree - } + def convertToTypeId(tree: Tree): Tree = atPos(tree.pos) { + tree match { + case Ident(name) => + Ident(name.toTypeName) + case Select(qual, name) => + Select(qual, name.toTypeName) + case _ => + syntaxError(tree.pos, "identifier expected", false) + errorTypeTree } - Function(List(makeSyntheticParam(pname)), insertParam(tree)) } /* --------- OPERAND/OPERATOR STACK --------------------------------------- */ + /** modes for infix types */ + object InfixMode extends Enumeration { + val FirstOp, LeftOp, RightOp = Value + } + var opstack: List[OpInfo] = Nil def precedence(operator: Name): Int = @@ -490,23 +463,24 @@ self => if (size > max) syntaxError("too many "+kind+", maximum = "+max, false) } - def checkAssoc(pos: Int, op: Name, leftAssoc: Boolean) = + def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = if (treeInfo.isLeftAssoc(op) != leftAssoc) syntaxError( - pos, "left- and right-associative operators with same precedence may not be mixed", false) + offset, "left- and right-associative operators with same precedence may not be mixed", false) def reduceStack(isExpr: Boolean, base: List[OpInfo], top0: Tree, prec: Int, leftAssoc: Boolean): Tree = { var top = top0 if (opstack != base && precedence(opstack.head.operator) == prec) - checkAssoc(opstack.head.pos, opstack.head.operator, leftAssoc) + checkAssoc(opstack.head.offset, opstack.head.operator, leftAssoc) while (opstack != base && (prec < precedence(opstack.head.operator) || - (leftAssoc && prec == precedence(opstack.head.operator)))) { - top = atPos(opstack.head.pos) { - makeBinop(isExpr, opstack.head.operand, opstack.head.operator, top) - } + leftAssoc && prec == precedence(opstack.head.operator))) { + val opinfo = opstack.head opstack = opstack.tail + top = atPos(opinfo.operand.pos.start, opinfo.offset) { + makeBinop(isExpr, opinfo.operand, opinfo.operator, top) + } } top } @@ -514,88 +488,87 @@ self => /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ def ident(): Name = - if (inToken == IDENTIFIER || inToken == BACKQUOTED_IDENT) { - val name = inName.encode - inNextToken + if (in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT) { + val name = in.name.encode + in.nextToken() name } else { accept(IDENTIFIER) nme.ERROR } - def selector(t: Tree): Tree = - atPos(inCurrentPos)(Select(t, ident())) + def selector(t: Tree): Tree = { + val mid = in.offset + Select(t, ident()) setPos r2p(t.pos.start, mid, in.lastOffset) + } /** Path ::= StableId * | [Ident `.'] this * AnnotType ::= Path [`.' type] */ def path(thisOK: Boolean, typeOK: Boolean): Tree = { + val start = in.offset var t: Tree = null - if (inToken == THIS) { - t = atPos(inSkipToken) { This(nme.EMPTY.toTypeName) } - if (!thisOK || inToken == DOT) { - t = selectors(t, typeOK, accept(DOT)) + if (in.token == THIS) { + in.nextToken() + t = atPos(start) { This(nme.EMPTY.toTypeName) } + if (!thisOK || in.token == DOT) { + t = selectors(t, typeOK, accept(DOT)) } - } else if (inToken == SUPER) { - // val pos = inCurrentPos - val pos = inSkipToken - val (mix,usePos) = mixinQualifierOpt(pos) - t = atPos(usePos) { - Super(nme.EMPTY.toTypeName, mix) - } - t = atPos(accept(DOT)) { selector(t) } - if (inToken == DOT) - t = selectors(t, typeOK, inSkipToken) + } else if (in.token == SUPER) { + in.nextToken() + t = atPos(start) { Super(nme.EMPTY.toTypeName, mixinQualifierOpt()) } + accept(DOT) + t = selector(t) + if (in.token == DOT) t = selectors(t, typeOK, in.skipToken()) } else { - val i = atPos(inCurrentPos) { - if (inToken == BACKQUOTED_IDENT) new BackQuotedIdent(ident()) - else Ident(ident()) + val tok = in.token + val name = ident() + t = atPos(start) { + if (tok == BACKQUOTED_IDENT) new BackQuotedIdent(name) + else Ident(name) } - t = i - if (inToken == DOT) { - val pos = inSkipToken - if (inToken == THIS) { - inNextToken - t = atPos(i.pos) { This(i.name.toTypeName) } - if (!thisOK || inToken == DOT) + if (in.token == DOT) { + val dotOffset = in.skipToken() + if (in.token == THIS) { + in.nextToken() + t = atPos(start) { This(name.toTypeName) } + if (!thisOK || in.token == DOT) t = selectors(t, typeOK, accept(DOT)) - } else if (inToken == SUPER) { - inNextToken - val (mix,pos) = mixinQualifierOpt(i.pos) - t = atPos(pos) { Super(i.name.toTypeName, mix) } - t = atPos(accept(DOT)) {selector(t)} - if (inToken == DOT) - t = selectors(t, typeOK, inSkipToken) + } else if (in.token == SUPER) { + in.nextToken() + t = atPos(start) { Super(name.toTypeName, mixinQualifierOpt()) } + accept(DOT) + t = selector(t) + if (in.token == DOT) t = selectors(t, typeOK, in.skipToken()) } else { - t = selectors(t, typeOK, pos) + t = selectors(t, typeOK, dotOffset) } } } t } - def selectors(t: Tree, typeOK: Boolean, pos : Int): Tree = - if (typeOK && inToken == TYPE) { - inNextToken - atPos(pos) { SingletonTypeTree(t) } + def selectors(t: Tree, typeOK: Boolean, dotOffset: Int): Tree = + if (typeOK && in.token == TYPE) { + in.nextToken() + atPos(t.pos.start, dotOffset) { SingletonTypeTree(t) } } else { - val t1 = atPos(pos) { selector(t); } - if (inToken == DOT) { selectors(t1, typeOK, inSkipToken) } + val t1 = selector(t) + if (in.token == DOT) { selectors(t1, typeOK, in.skipToken()) } else t1 } /** MixinQualifier ::= `[' Id `]' */ - def mixinQualifierOpt(pos: Position): (Name, Position) = - if (inToken == LBRACKET) { - inNextToken - val pos = inCurrentPos + def mixinQualifierOpt(): Name = + if (in.token == LBRACKET) { + in.nextToken() val name = ident().toTypeName accept(RBRACKET) - (name, pos) + name } else { - (nme.EMPTY.toTypeName, pos) + nme.EMPTY.toTypeName } /** StableId ::= Id @@ -608,106 +581,79 @@ self => /** QualId ::= Id {`.' Id} */ def qualId(): Tree = { - val id = atPos(inCurrentPos) { Ident(ident()) } - if (inToken == DOT) { selectors(id, false, inSkipToken) } + val start = in.offset + val id = atPos(start) { Ident(ident()) } + if (in.token == DOT) { selectors(id, false, in.skipToken()) } else id } /** SimpleExpr ::= literal - * | symbol - * | null - */ - - def literal(isPattern: Boolean, isNegated: Boolean): Tree = { - def litToTree() = atPos(inCurrentPos) { - Literal( - inToken match { - case CHARLIT => Constant(charVal) - case INTLIT => Constant(intVal(isNegated)) - case LONGLIT => Constant(longVal(isNegated)) - case FLOATLIT => Constant(floatVal(isNegated)) - case DOUBLELIT => Constant(doubleVal(isNegated)) - case STRINGLIT | SYMBOLLIT => Constant(stringVal) - case TRUE => Constant(true) - case FALSE => Constant(false) - case NULL => Constant(null) - case _ => - syntaxErrorOrIncomplete("illegal literal", true) - null - }) - } - - val isSymLit = inToken == SYMBOLLIT - val t = litToTree() - val pos = inSkipToken - if (isSymLit) { - atPos(pos) { - var symid = scalaDot(nme.Symbol) - Apply(symid, List(t)) + * | symbol + * | null + * @note The returned tree does not yet have a position + */ + def literal(isNegated: Boolean): Tree = { + val isSymLit = in.token == SYMBOLLIT + val t = Literal { + in.token match { + case CHARLIT => Constant(in.charVal) + case INTLIT => Constant(in.intVal(isNegated).toInt) + case LONGLIT => Constant(in.intVal(isNegated)) + case FLOATLIT => Constant(in.floatVal(isNegated).toFloat) + case DOUBLELIT => Constant(in.floatVal(isNegated)) + case STRINGLIT | SYMBOLLIT => Constant(in.strVal) + case TRUE => Constant(true) + case FALSE => Constant(false) + case NULL => Constant(null) + case _ => + syntaxErrorOrIncomplete("illegal literal", true) + Constant(null) } - } else { - t } + in.nextToken() + if (isSymLit) Apply(scalaDot(nme.Symbol), List(t)) else t } +/* ------------- NEW LINES ------------------------------------------------- */ + def newLineOpt() { - if (inToken == NEWLINE) inNextToken + if (in.token == NEWLINE) in.nextToken() } def newLinesOpt() { - if (inToken == NEWLINE || inToken == NEWLINES) - inNextToken + if (in.token == NEWLINE || in.token == NEWLINES) + in.nextToken() } def newLineOptWhenFollowedBy(token: Int) { // note: next is defined here because current == NEWLINE - if (inToken == NEWLINE && inNextTokenCode == token) newLineOpt() + if (in.token == NEWLINE && in.next.token == token) newLineOpt() } def newLineOptWhenFollowing(p: Int => Boolean) { // note: next is defined here because current == NEWLINE - if (inToken == NEWLINE && p(inNextTokenCode)) newLineOpt() + if (in.token == NEWLINE && p(in.next.token)) newLineOpt() } /* ------------- TYPES ---------------------------------------------------- */ /** TypedOpt ::= [`:' Type] - */ + */ def typedOpt(): Tree = - if (inToken == COLON) { inNextToken; typ() } + if (in.token == COLON) { in.nextToken(); typ() } else TypeTree() - /** RequiresTypedOpt ::= [requires AnnotType] - */ - def requiresTypeOpt(): Tree = - if (inToken == REQUIRES) { - deprecationWarning(inCurrentPos, "`requires T' has been deprecated; use `{ self: T => ...' instead") - inNextToken; annotType(false) - } else TypeTree() - /** Types ::= Type {`,' Type} - * (also eats trailing comma if it finds one) */ def types(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): List[Tree] = { - val ts = new ListBuffer[Tree] + argType(isPattern, isTypeApply, isFuncArg) - while (inToken == COMMA) { - val pos = inCurrentPos - inNextToken - if (inToken == RPAREN) { - deprecationWarning(pos, "Trailing commas have been deprecated") - return ts.toList - } else { - ts += argType(isPattern, isTypeApply, isFuncArg) - } + val ts = new ListBuffer[Tree] += argType(isPattern, isTypeApply, isFuncArg) + while (in.token == COMMA) { + in.nextToken() + ts += argType(isPattern, isTypeApply, isFuncArg) } ts.toList } - /** modes for infix types */ - object InfixMode extends Enumeration { - val FirstOp, LeftOp, RightOp = Value - } - /** Type ::= InfixType `=>' Type * | `(' [`=>' Type] `)' `=>' Type * | InfixType [ExistentialClause] @@ -717,47 +663,43 @@ self => def typ(): Tree = typ(false) def typ(isPattern: Boolean): Tree = placeholderTypeBoundary { + val start = in.offset val t = - if (inToken == LPAREN) { - val pos = inSkipToken - if (inToken == RPAREN) { - inNextToken - atPos(accept(ARROW)) { makeFunctionTypeTree(List(), typ(isPattern)) } + if (in.token == LPAREN) { + in.nextToken() + if (in.token == RPAREN) { + in.nextToken() + atPos(start, accept(ARROW)) { + makeFunctionTypeTree(List(), typ(isPattern)) + } } else { val ts = types(isPattern, false, true) accept(RPAREN) - if (inToken == ARROW) atPos(inSkipToken) { - makeFunctionTypeTree(ts, typ(isPattern)) - } - else { - for (t <- ts) t match { - case AppliedTypeTree(Select(_, n), _) - if (n == nme.BYNAME_PARAM_CLASS_NAME.toTypeName) => - syntaxError(t.pos, "no by-name parameter type allowed here", false) - case _ => + if (in.token == ARROW) + atPos(start, in.skipToken()) { + makeFunctionTypeTree(ts, typ(isPattern)) } - infixTypeRest(pos, annotTypeRest(pos, isPattern, makeTupleType(ts, true)), false, InfixMode.FirstOp) + else { + ts foreach checkNotByName + val tuple = atPos(start) { makeTupleType(ts, true) } + infixTypeRest( + compoundTypeRest( + annotTypeRest(simpleTypeRest(tuple, isPattern)), + isPattern), + isPattern, InfixMode.FirstOp) } } } else { infixType(isPattern, InfixMode.FirstOp) } - if (inToken == ARROW) - atPos(inSkipToken) { + if (in.token == ARROW) + atPos(start, in.skipToken()) { makeFunctionTypeTree(List(t), typ(isPattern)) } - else if (inToken == FORSOME) - atPos(inSkipToken) { + else if (in.token == FORSOME) + atPos(start, in.skipToken()) { val whereClauses = refinement() - for (wc <- whereClauses) { - wc match { - case TypeDef(_, _, _, TypeBoundsTree(_, _)) | - ValDef(_, _, _, EmptyTree) | EmptyTree => - ; - case _ => - syntaxError(wc.pos, "not a legal existential clause", false) - } - } + whereClauses foreach checkLegalExistential ExistentialTypeTree(t, whereClauses) } else t @@ -766,24 +708,19 @@ self => /** InfixType ::= CompoundType {id [nl] CompoundType} */ def infixType(isPattern: Boolean, mode: InfixMode.Value): Tree = placeholderTypeBoundary { - infixTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern, mode) + infixTypeRest(compoundType(isPattern), isPattern, mode) } - def infixTypeFirst(isPattern: Boolean): Tree = - if (inToken == LBRACE) scalaAnyRefConstr else annotType(isPattern) - - def infixTypeRest(pos: Int, t0: Tree, isPattern: Boolean, mode: InfixMode.Value): Tree = { - val t = compoundTypeRest(pos, t0, isPattern) - if (isIdent && inName != nme.STAR) { - val opPos = inCurrentPos - val leftAssoc = treeInfo.isLeftAssoc(inName) - if (mode == InfixMode.LeftOp) checkAssoc(opPos, inName, true) - else if (mode == InfixMode.RightOp) checkAssoc(opPos, inName, false) + def infixTypeRest(t: Tree, isPattern: Boolean, mode: InfixMode.Value): Tree = { + if (isIdent && in.name != nme.STAR) { + val opOffset = in.offset + val leftAssoc = treeInfo.isLeftAssoc(in.name) + if (mode != InfixMode.FirstOp) checkAssoc(opOffset, in.name, mode == InfixMode.LeftOp) val op = ident() newLineOptWhenFollowing(isTypeIntroToken) - def mkOp(t1: Tree) = atPos(opPos) { AppliedTypeTree(Ident(op.toTypeName), List(t, t1)) } + def mkOp(t1: Tree) = atPos(t.pos.start, opOffset) { AppliedTypeTree(Ident(op.toTypeName), List(t, t1)) } if (leftAssoc) - infixTypeRest(inCurrentPos, mkOp(compoundType(isPattern)), isPattern, InfixMode.LeftOp) + infixTypeRest(mkOp(compoundType(isPattern)), isPattern, InfixMode.LeftOp) else mkOp(infixType(isPattern, InfixMode.RightOp)) } else t @@ -792,17 +729,20 @@ self => /** CompoundType ::= AnnotType {with AnnotType} [Refinement] * | Refinement */ - def compoundType(isPattern: Boolean): Tree = - compoundTypeRest(inCurrentPos, infixTypeFirst(isPattern), isPattern) + def compoundType(isPattern: Boolean): Tree = { + val t = if (in.token == LBRACE) atPos(o2p(in.offset)) (scalaAnyRefConstr) + else annotType(isPattern) + compoundTypeRest(t, isPattern) + } - def compoundTypeRest(pos: Int, t: Tree, isPattern: Boolean): Tree = { - var ts = new ListBuffer[Tree] + t - while (inToken == WITH) { - inNextToken; ts += annotType(isPattern) + def compoundTypeRest(t: Tree, isPattern: Boolean): Tree = { + var ts = new ListBuffer[Tree] += t + while (in.token == WITH) { + in.nextToken(); ts += annotType(isPattern) } newLineOptWhenFollowedBy(LBRACE) - atPos(pos) { - if (inToken == LBRACE) { + atPos(t.pos.start) { + if (in.token == LBRACE) { // Warn if they are attempting to refine Unit; we can't be certain it's // scala.Unit they're refining because at this point all we have is an // identifier, but at a later stage we lose the ability to tell an empty @@ -820,54 +760,61 @@ self => } /** AnnotType ::= SimpleType {Annotation} - * SimpleType ::= SimpleType TypeArgs + */ + def annotType(isPattern: Boolean): Tree = placeholderTypeBoundary { + annotTypeRest(simpleType(isPattern)) + } + + def annotTypeRest(t: Tree): Tree = + (t /: annotations(false)) (makeAnnotated) + + /** SimpleType ::= SimpleType TypeArgs * | SimpleType `#' Id * | StableId * | Path `.' type * | `(' Types [`,'] `)' * | WildcardType */ - def annotType(isPattern: Boolean): Tree = placeholderTypeBoundary { - val pos = inCurrentPos - - val t: Tree = annotTypeRest(pos, isPattern, - if (inToken == LPAREN) { - inNextToken + def simpleType(isPattern: Boolean): Tree = { + val start = in.offset + val t = + if (in.token == LPAREN) { + in.nextToken() val ts = types(isPattern, false, false) accept(RPAREN) - atPos(pos) { makeTupleType(ts, true) } - } else if (inToken == USCORE) { - wildcardType(inSkipToken) - } else { - val r = path(false, true) - r match { - case SingletonTypeTree(_) => r - case _ => convertToTypeId(r) - } - }) - (t /: annotations(false)) (makeAnnotated) + atPos(start) { makeTupleType(ts, true) } + } else if (in.token == USCORE) { + wildcardType(in.skipToken()) + } else path(false, true) match { + case r @ SingletonTypeTree(_) => r + case r => convertToTypeId(r) + } + simpleTypeRest(t, isPattern) } - def annotTypeRest(pos: Int, isPattern: Boolean, t: Tree): Tree = - if (inToken == HASH) { - inSkipToken - val posId = inCurrentPos - val id = ident - annotTypeRest(pos, isPattern, atPos(posId) { SelectFromTypeTree(t, id.toTypeName) }) - } else if (inToken == LBRACKET) { - val usePos = if (t.pos != NoPosition) t.pos else i2p(pos) - annotTypeRest(pos, isPattern, atPos(usePos) { AppliedTypeTree(t, typeArgs(isPattern, false)) }) - } - else + def simpleTypeRest(t: Tree, isPattern: Boolean): Tree = + if (in.token == HASH) { + val hashOffset = in.skipToken() + val nameOffset = in.offset + val name = ident() + val sel = atPos(t.pos.start, if (name == nme.ERROR) hashOffset else nameOffset) { + SelectFromTypeTree(t, name.toTypeName) + } + simpleTypeRest(sel, isPattern) + } else if (in.token == LBRACKET) { + simpleTypeRest(atPos(t.pos.start) { AppliedTypeTree(t, typeArgs(isPattern, false)) }, isPattern) + } else { t + } /** WildcardType ::= `_' TypeBounds */ - def wildcardType(pos: Int) = { - val pname = freshName(pos, "_$").toTypeName - val param = atPos(pos) { makeSyntheticTypeParam(pname, typeBounds()) } + def wildcardType(start: Int) = { + val pname = freshName(o2p(start), "_$").toTypeName + val t = atPos(start) { Ident(pname) } + val param = atPos(start) { makeSyntheticTypeParam(pname, typeBounds()) } placeholderTypes = param :: placeholderTypes - Ident(pname) setPos pos + t } /** TypeArgs ::= `[' ArgType {`,' ArgType} `]' @@ -881,40 +828,38 @@ self => /** ArgType ::= Type */ - def argType(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): Tree = + def argType(isPattern: Boolean, isTypeApply: Boolean, isFuncArg: Boolean): Tree = { + val start = in.offset if (isPattern) { - if (inToken == USCORE) - if (inToken == SUBTYPE || inToken == SUPERTYPE) wildcardType(inSkipToken) - else atPos(inSkipToken) { Bind(nme.WILDCARD.toTypeName, EmptyTree) } - else if (inToken == IDENTIFIER && treeInfo.isVariableName(inName.toTypeName)) - atPos(inCurrentPos) { - Bind(ident().toTypeName, EmptyTree) - } - else { + if (in.token == USCORE) { + in.nextToken() + if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start) + else atPos(start) { Bind(nme.WILDCARD.toTypeName, EmptyTree) } + } else if (in.token == IDENTIFIER && treeInfo.isVariableName(in.name.toTypeName)) { + atPos(start) { Bind(ident().toTypeName, EmptyTree) } + } else { typ(true) } } else if (isFuncArg) { // copy-paste (with change) from def paramType - if (inToken == ARROW) - atPos(inSkipToken) { - AppliedTypeTree( - rootScalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) + if (in.token == ARROW) { + in.nextToken() + atPos(start) { + AppliedTypeTree(rootScalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) } - else { + } else { val t = typ() - if (isIdent && inName == STAR) { - inNextToken - atPos(t.pos) { - AppliedTypeTree( - rootScalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) + if (isIdent && in.name == STAR) { + in.nextToken() + atPos(start) { + AppliedTypeTree(rootScalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) } } else t } - } else if (isTypeApply) { - typ() } else { typ() } + } /* ----------- EXPRESSIONS ------------------------------------------------ */ @@ -926,24 +871,32 @@ self => } /** Exprs ::= Expr {`,' Expr} - * - * (also eats trailing comma if it finds one) */ def exprs(): List[Tree] = { - val ts = new ListBuffer[Tree] + expr() - while (inToken == COMMA) { - val pos = inCurrentPos - inNextToken - if (inToken == RPAREN) { - deprecationWarning(pos, "Trailing commas have been deprecated") - return ts.toList - } else { - ts += expr() - } + val ts = new ListBuffer[Tree] += expr() + while (in.token == COMMA) { + in.nextToken() + ts += expr() } ts.toList } + def condExpr(): Tree = { + if (in.token == LPAREN) { + in.nextToken() + val r = expr() + accept(RPAREN) + r + } else { + accept(LPAREN) + Literal(true) + } + } + + /* hook for IDE, unlike expression can be stubbed + * don't use for any tree that can be inspected in the parser! + */ + def statement(location: Int): Tree = expr(location) // !!! still needed? /** Expr ::= (Bindings | Id | `_') `=>' Expr * | Expr1 @@ -967,154 +920,141 @@ self => * | `:' `_' `*' */ def expr(): Tree = expr(Local) - /* hook for IDE, unlike expression can be stubbed - * don't use for any tree that can be inspected in the parser! - */ - def statement(location: Int): Tree = expr(location) + def expr(location: Int): Tree = { - def isWildcard(t: Tree): Boolean = t match { - case Ident(name1) if !placeholderParams.isEmpty && name1 == placeholderParams.head.name => true - case Typed(t1, _) => isWildcard(t1) - case Annotated(t1, _) => isWildcard(t1) - case _ => false - } var savedPlaceholderParams = placeholderParams placeholderParams = List() - var res = inToken match { - case IF => - val pos = inSkipToken - val cond = surround(LPAREN,RPAREN)(expr(),Literal(true)) + var res = expr0(location) + if (!placeholderParams.isEmpty && !isWildcard(res)) { + res = atPos(res.pos){ Function(placeholderParams.reverse, res) } + placeholderParams = List() + } + placeholderParams = placeholderParams ::: savedPlaceholderParams + res + } + + def expr0(location: Int): Tree = in.token match { + case IF => + atPos(in.skipToken()) { + val cond = condExpr() newLinesOpt() val thenp = expr() - val elsep = if (inToken == ELSE) { inNextToken; expr() } - else Literal(()) - atPos(pos) { If(cond, thenp, elsep) } - case TRY => - atPos(inSkipToken) { - val body = - if (inToken == LBRACE) surround(LBRACE, RBRACE)(block(), Literal(())) - else if (inToken == LPAREN) surround(LPAREN, RPAREN)(expr(), Literal(())) - else expr() - val catches = - if (inToken == CATCH) { - inNextToken - val cases = surround(LBRACE,RBRACE)(caseClauses(), Nil) - cases - } else Nil - val finalizer = - if (inToken == FINALLY) { inNextToken; expr() } - else EmptyTree - Try(body, catches, finalizer) - } - case WHILE => - val pos = inSkipToken - val lname: Name = freshName(pos, "while$") - val cond = surround(LPAREN,RPAREN)(expr(),Literal(true)) + val elsep = if (in.token == ELSE) { in.nextToken(); expr() } + else Literal(()) + If(cond, thenp, elsep) + } + case TRY => + atPos(in.skipToken()) { + val body = + if (in.token == LBRACE) surround(LBRACE, RBRACE)(block(), Literal(())) + else if (in.token == LPAREN) surround(LPAREN, RPAREN)(expr(), Literal(())) + else expr() + val catches = + if (in.token == CATCH) { + in.nextToken() + surround(LBRACE, RBRACE)(caseClauses(), Nil) + } else Nil + val finalizer = + if (in.token == FINALLY) { in.nextToken(); expr() } + else EmptyTree + Try(body, catches, finalizer) + } + case WHILE => + val start = in.offset + atPos(in.skipToken()) { + val lname: Name = freshName(o2p(start), "while$") + val cond = condExpr() newLinesOpt() val body = expr() - atPos(pos) { makeWhile(lname, cond, body) } - case DO => - val pos = inSkipToken - val lname: Name = freshName(pos, "doWhile$") + makeWhile(lname, cond, body) + } + case DO => + val start = in.offset + atPos(in.skipToken()) { + val lname: Name = freshName(o2p(start), "doWhile$") val body = expr() - if (isStatSep) inNextToken + if (isStatSep) in.nextToken() accept(WHILE) - val cond = surround(LPAREN,RPAREN)(expr(), Literal(true)) - atPos(pos) { makeDoWhile(lname, body, cond) } - case FOR => - atPos(inSkipToken) { - val startToken = inToken - val (open,close) = if (startToken == LBRACE) (LBRACE,RBRACE) else (LPAREN,RPAREN) - val enums = surround(open,close)(enumerators(), Nil) - newLinesOpt() - if (inToken == YIELD) { - inNextToken; makeForYield(enums, expr()) - } else makeFor(enums, expr()) - } - case RETURN => - atPos(inSkipToken) { - Return(if (isExprIntro) expr() else Literal(())) - } - case THROW => - atPos(inSkipToken) { - Throw(expr()) + val cond = condExpr() + makeDoWhile(lname, body, cond) + } + case FOR => + atPos(in.skipToken()) { + val (open, close) = if (in.token == LBRACE) (LBRACE, RBRACE) else (LPAREN, RPAREN) + val enums = surround(open, close)(enumerators(), Nil) + newLinesOpt() + if (in.token == YIELD) { + in.nextToken() + makeForYield(enums, expr()) + } else { + makeFor(enums, expr()) } - case DOT => - deprecationWarning(inCurrentPos, "`.f' has been deprecated; use `_.f' instead") - atPos(inSkipToken) { - if (isIdent) { - makeDotClosure(stripParens(simpleExpr())) - } else { - syntaxErrorOrIncomplete("identifier expected", true) - errorTermTree - } + } + case RETURN => + atPos(in.skipToken()) { + Return(if (isExprIntro) expr() else Literal(())) + } + case THROW => + atPos(in.skipToken()) { + Throw(expr()) + } + case _ => + var t = postfixExpr() + if (in.token == EQUALS) { + t match { + case Ident(_) | Select(_, _) | Apply(_, _) => + t = atPos(t.pos.start, in.skipToken()) { makeAssign(t, expr()) } + case _ => } - case _ => - var t = postfixExpr() - if (inToken == EQUALS) { - t match { - case Ident(_) | Select(_, _) | Apply(_, _) => - t = atPos(inSkipToken) { makeAssign(t, expr()) } - case _ => - } - } else if (inToken == COLON) { - t = stripParens(t) - val pos = inSkipToken - if (inToken == USCORE) { - //todo: need to handle case where USCORE is a wildcard in a type - val pos1 = inSkipToken - if (isIdent && inName == nme.STAR) { - inNextToken - t = atPos(pos) { - Typed(t, atPos(pos1) { Ident(nme.WILDCARD_STAR.toTypeName) }) - } - } else { - syntaxErrorOrIncomplete("`*' expected", true) + } else if (in.token == COLON) { + t = stripParens(t) + val colonPos = in.skipToken() + if (in.token == USCORE) { + //todo: need to handle case where USCORE is a wildcard in a type + val uscorePos = in.skipToken() + if (isIdent && in.name == nme.STAR) { + in.nextToken() + t = atPos(t.pos.start, colonPos) { + Typed(t, atPos(uscorePos) { Ident(nme.WILDCARD_STAR.toTypeName) }) } - } else if (in.token == AT) { - t = (t /: annotations(false)) (makeAnnotated) } else { - t = atPos(pos) { - val tpt = - if (location != Local) infixType(false, InfixMode.FirstOp) - else typ() - if (isWildcard(t)) - (placeholderParams: @unchecked) match { - case (vd @ ValDef(mods, name, _, _)) :: rest => - placeholderParams = copy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest - } - // this does not correspond to syntax, but is necessary to - // accept closures. We might restrict closures to be between {...} only! - Typed(t, tpt) - } + syntaxErrorOrIncomplete("`*' expected", true) } - } else if (inToken == MATCH) { - t = atPos(inSkipToken) { - val cases = surround(LBRACE,RBRACE)(caseClauses(), Nil) - Match(stripParens(t), cases) + } else if (in.token == AT) { + t = (t /: annotations(false)) (makeAnnotated) + } else { + t = atPos(t.pos.start, colonPos) { + val tpt = + if (location == Local) typ() else infixType(false, InfixMode.FirstOp) + if (isWildcard(t)) + (placeholderParams: @unchecked) match { + case (vd @ ValDef(mods, name, _, _)) :: rest => + placeholderParams = copy.ValDef(vd, mods, name, tpt.duplicate, EmptyTree) :: rest + } + // this does not correspond to syntax, but is necessary to + // accept closures. We might restrict closures to be between {...} only. + Typed(t, tpt) } } - // in order to allow anonymous functions as statements (as opposed to expressions) inside - // templates, we have to disambiguate them from self type declarations - bug #1565 - // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which - // may be impossible to distinguish from a self-type and so remains an error. (See #1564) - def lhsIsTypedParamList() = t match { - case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true - case _ => false + } else if (in.token == MATCH) { + t = atPos(t.pos.start, in.skipToken()) { + Match(stripParens(t), surround(LBRACE, RBRACE)(caseClauses(), Nil)) } - if (inToken == ARROW && (location != InTemplate || lhsIsTypedParamList)) { - t = atPos(inSkipToken) { - Function(convertToParams(t), if (location != InBlock) expr() else block()) - } + } + // in order to allow anonymous functions as statements (as opposed to expressions) inside + // templates, we have to disambiguate them from self type declarations - bug #1565 + // The case still missed is unparenthesized single argument, like "x: Int => x + 1", which + // may be impossible to distinguish from a self-type and so remains an error. (See #1564) + def lhsIsTypedParamList() = t match { + case Parens(xs) if xs forall (_.isInstanceOf[Typed]) => true + case _ => false + } + if (in.token == ARROW && (location != InTemplate || lhsIsTypedParamList)) { + t = atPos(t.pos.start, in.skipToken()) { + Function(convertToParams(t), if (location != InBlock) expr() else block()) } - stripParens(t) - } - if (!placeholderParams.isEmpty && !isWildcard(res)) { - res = atPos(res.pos){ Function(placeholderParams.reverse, res) } - placeholderParams = List() - } - placeholderParams = placeholderParams ::: savedPlaceholderParams - res + } + stripParens(t) } /** PostfixExpr ::= InfixExpr [Id [nl]] @@ -1125,10 +1065,9 @@ self => val base = opstack var top = prefixExpr() while (isIdent) { - top = reduceStack( - true, base, top, precedence(inName), treeInfo.isLeftAssoc(inName)) - val op = inName - opstack = OpInfo(top, op, inCurrentPos) :: opstack + top = reduceStack(true, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) + val op = in.name + opstack = OpInfo(top, op, in.offset) :: opstack ident() newLineOptWhenFollowing(isExprIntroToken) if (isExprIntro) { @@ -1136,9 +1075,10 @@ self => } else { val topinfo = opstack.head opstack = opstack.tail - return Select( - stripParens(reduceStack(true, base, topinfo.operand, 0, true)), - topinfo.operator.encode).setPos(topinfo.pos) + val od = stripParens(reduceStack(true, base, topinfo.operand, 0, true)) + return atPos(od.pos.start, topinfo.offset) { + Select(od, topinfo.operator.encode) + } } } reduceStack(true, base, top, 0, true) @@ -1148,28 +1088,19 @@ self => */ def prefixExpr(): Tree = { def unaryOp(): Name = "unary_" + ident() - if (isIdent && inName == MINUS) { - val name = unaryOp() - inToken match { - case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => literal(false, true) - case _ => atPos(inCurrentPos) { Select(stripParens(simpleExpr()), name) } + if (isIdent && in.name == MINUS) { + atPos(in.offset) { + val name = unaryOp() + in.token match { + case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => literal(true) + case _ => Select(stripParens(simpleExpr()), name) + } + } + } else if (isIdent && (in.name == PLUS || in.name == TILDE || in.name == BANG)) { + atPos(in.offset) { + val name = unaryOp() + Select(stripParens(simpleExpr()), name) } - } else if (isIdent && (inName == PLUS || inName == TILDE || inName == BANG)) { - val pos = inCurrentPos - val name = unaryOp() - atPos(pos) { Select(stripParens(simpleExpr()), name) } - } else if (isIdent && inName == AMP) { - deprecationWarning(inCurrentPos, "`&f' has been deprecated; use `f _' instead") - val pos = inCurrentPos - val name = ident() - atPos(pos) { Typed(stripParens(simpleExpr()), Function(List(), EmptyTree)) } -/* XX-LIFTING - } else if (settings.Xexperimental.value && isIdent && inName == SLASH) { - val pos = inSkipToken - val name = freshName() - liftedGenerators += ValFrom(pos, Bind(name, Ident(nme.WILDCARD)), simpleExpr()) - Ident(name) setPos pos -*/ } else { simpleExpr() } @@ -1188,60 +1119,64 @@ self => * | SimpleExpr1 ArgumentExprs */ def simpleExpr(): Tree = { - var t: Tree = null var canApply = true - inToken match { + val t = in.token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => - t = literal(false, false) - case XMLSTART => t = xmlLiteral() + atPos(in.offset) { literal(false) } + case XMLSTART => + xmlLiteral() case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => - t = path(true, false) + path(true, false) case USCORE => - val pos = inSkipToken - val pname = freshName(pos, "x$") - val param = atPos(pos){ makeSyntheticParam(pname) } - placeholderParams = param :: placeholderParams - t = atPos(pos) { Ident(pname) } + val start = in.offset + atPos(in.skipToken()) { + val pname = freshName(o2p(start), "x$") + val param = atPos(start){ makeSyntheticParam(pname) } + placeholderParams = param :: placeholderParams + Ident(pname) + } case LPAREN => - val pos = inSkipToken - val ts = if (inToken == RPAREN) List() else exprs() - accept(RPAREN) - t = Parens(ts) setPos (pos) + atPos(in.skipToken()) { + val ts = if (in.token == RPAREN) List() else exprs() + accept(RPAREN) + Parens(ts) + } case LBRACE => - t = blockExpr() canApply = false + blockExpr() case NEW => - t = atPos(inSkipToken) { + canApply = false + atPos(in.skipToken()) { val (parents, argss, self, stats) = template(false) makeNew(parents, self, stats, argss) } - canApply = false case _ => syntaxErrorOrIncomplete("illegal start of simple expression", true) - t = errorTermTree + errorTermTree } simpleExprRest(t, canApply) } def simpleExprRest(t: Tree, canApply: Boolean): Tree = { if (canApply) newLineOptWhenFollowedBy(LBRACE) - inToken match { + in.token match { case DOT => - simpleExprRest(atPos(inSkipToken) { selector(stripParens(t)) }, true) + in.nextToken() + simpleExprRest(selector(stripParens(t)), true) case LBRACKET => val t1 = stripParens(t) t1 match { case Ident(_) | Select(_, _) => - val pos = if (t1.pos == NoPosition) i2p(inCurrentPos) else t1.pos - simpleExprRest(atPos(pos) { TypeApply(t1, typeArgs(false, true)) }, true) + val tapp = atPos(t1.pos.start, in.offset) { + TypeApply(t1, typeArgs(false, true)) + } + simpleExprRest(tapp, true) case _ => t1 } case LPAREN | LBRACE if (canApply) => - // again, position should be on idetifier, not ( - var pos = if (t.pos == NoPosition) i2p(inCurrentPos) else t.pos - simpleExprRest(atPos(pos) { + val app = atPos(t.pos.start, in.offset) { // look for anonymous function application like (f _)(x) and // translate to (f _).apply(x), bug #460 val sel = t match { @@ -1251,9 +1186,12 @@ self => stripParens(t) } Apply(sel, argumentExprs()) - }, true) + } + simpleExprRest(app, true) case USCORE => - atPos(inSkipToken) { Typed(stripParens(t), Function(List(), EmptyTree)) } + atPos(t.pos.start, in.skipToken()) { + Typed(stripParens(t), Function(List(), EmptyTree)) + } case _ => t } @@ -1262,21 +1200,17 @@ self => /** ArgumentExprs ::= `(' [Exprs [`,']] `)' * | [nl] BlockExpr */ - def argumentExprs(): List[Tree] = { - if (inToken == LBRACE) { + def argumentExprs(): List[Tree] = + if (in.token == LBRACE) List(blockExpr()) - } else { - val ts = surround(LPAREN,RPAREN)(if (inToken == RPAREN) List() else exprs(), List()) - ts - } - } + else + surround(LPAREN, RPAREN)(if (in.token == RPAREN) List() else exprs(), List()) /** BlockExpr ::= `{' (CaseClauses | Block) `}' */ def blockExpr(): Tree = { - assert(inToken == LBRACE) val res = atPos(accept(LBRACE)) { // no need to surround - if (inToken == CASE) Match(EmptyTree, caseClauses()) + if (in.token == CASE) Match(EmptyTree, caseClauses()) else block() } accept(RBRACE) @@ -1284,6 +1218,7 @@ self => } /** Block ::= BlockStatSeq + * @note Return tree does not carry position. */ def block(): Tree = { makeBlock(blockStatSeq(new ListBuffer[Tree])) @@ -1294,7 +1229,7 @@ self => def caseClauses(): List[CaseDef] = { val ts = new ListBuffer[CaseDef] do { ts += caseClause() - } while (inToken == CASE) + } while (in.token == CASE) ts.toList } @@ -1306,14 +1241,14 @@ self => val gd = guard() makeCaseDef(pat, gd, caseBlock()) } - // IDE HOOK (so we can memoize case blocks) + // IDE HOOK (so we can memoize case blocks) // needed? def caseBlock(): Tree = atPos(accept(ARROW))(block()) /** Guard ::= if PostfixExpr */ def guard(): Tree = - if (inToken == IF) { inNextToken; stripParens(postfixExpr()) } + if (in.token == IF) { in.nextToken(); stripParens(postfixExpr()) } else EmptyTree /** Enumerators ::= Generator {semi Enumerator} @@ -1322,19 +1257,19 @@ self => * | val Pattern1 `=' Expr */ def enumerators(): List[Enumerator] = { - val newStyle = inToken != VAL // todo: deprecate old style - //if (!newStyle) - // deprecationWarning(inCurrentPos, "for (val x <- ... ) has been deprecated; use for (x <- ... ) instead") + val newStyle = in.token != VAL // todo: deprecate old style + if (!newStyle) + deprecationWarning(in.offset, "for (val x <- ... ) has been deprecated; use for (x <- ... ) instead") val enums = new ListBuffer[Enumerator] generator(enums, false) while (isStatSep) { - inNextToken + in.nextToken() if (newStyle) { - if (inToken == IF) enums += Filter(guard()) + if (in.token == IF) enums += makeFilter(in.offset, guard()) else generator(enums, true) } else { - if (inToken == VAL) generator(enums, true) - else enums += Filter(expr()) + if (in.token == VAL) generator(enums, true) + else enums += makeFilter(in.offset, expr()) } } enums.toList @@ -1343,16 +1278,19 @@ self => /** Generator ::= Pattern1 (`<-' | '=') Expr [Guard] */ def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) { - if (inToken == VAL) inNextToken - val pos = inCurrentPos; + val start = in.offset + if (in.token == VAL) in.nextToken() val pat = pattern1(false) - val tok = inToken - if (tok == EQUALS && eqOK) inNextToken + val mid = in.offset + val tok = in.token + if (tok == EQUALS && eqOK) in.nextToken() else accept(LARROW) - enums += makeGenerator(pos, pat, tok == EQUALS, expr) - if (inToken == IF) enums += Filter(guard()) + val rhs = expr() + enums += makeGenerator(r2p(start, mid, in.lastOffset), pat, tok == EQUALS, rhs) + if (in.token == IF) enums += makeFilter(in.offset, guard()) } - //def p2i(pos : ScanPosition) : Int; + + def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.mid, tree.pos.end), tree) /* -------- PATTERNS ------------------------------------------- */ @@ -1362,16 +1300,10 @@ self => * (also eats trailing comma if it finds one) */ def patterns(seqOK: Boolean): List[Tree] = { - val ts = new ListBuffer[Tree] + pattern(seqOK) - while (inToken == COMMA) { - val pos = inCurrentPos - inNextToken - if (inToken == RPAREN) { - deprecationWarning(pos, "Trailing commas have been deprecated") - return ts.toList - } else { - ts += pattern(seqOK) - } + val ts = new ListBuffer[Tree] += pattern(seqOK) + while (in.token == COMMA) { + in.nextToken() + ts += pattern(seqOK) } ts.toList } @@ -1380,14 +1312,14 @@ self => * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 } */ def pattern(seqOK: Boolean): Tree = { - val pos = inCurrentPos + val start = in.offset val t = pattern1(seqOK) - if (isIdent && inName == BAR) { - val ts = new ListBuffer[Tree] + t - while (isIdent && inName == BAR) { - inNextToken; ts += pattern1(seqOK) + if (isIdent && in.name == BAR) { + val ts = new ListBuffer[Tree] += t + while (isIdent && in.name == BAR) { + in.nextToken(); ts += pattern1(seqOK) } - atPos(pos) { makeAlternative(ts.toList) } + atPos(start) { makeAlternative(ts.toList) } } else t } @@ -1401,17 +1333,13 @@ self => * | [SeqPattern2] */ def pattern1(seqOK: Boolean): Tree = { - //if (false && /*disabled, no regexp matching*/ seqOK && !isExprIntro) { - //atPos(inCurrentPos) { Sequence(List()) } - //} else { - val p = pattern2(seqOK) - p match { - case Ident(name) if (treeInfo.isVarPattern(p) && inToken == COLON) => - atPos(inSkipToken) { Typed(p, compoundType(true)) } - case _ => - p - } - //} + val p = pattern2(seqOK) + p match { + case Ident(name) if (treeInfo.isVarPattern(p) && in.token == COLON) => + atPos(p.pos.start, in.skipToken()) { Typed(p, compoundType(true)) } + case _ => + p + } } /* Pattern2 ::= varid [ @ Pattern3 ] @@ -1421,14 +1349,15 @@ self => */ def pattern2(seqOK: Boolean): Tree = { val p = pattern3(seqOK) - if (inToken == AT) { + if (in.token == AT) { p match { case Ident(name) => if (name == nme.WILDCARD) { - inNextToken; pattern3(seqOK) + in.nextToken() + pattern3(seqOK) } else if (treeInfo.isVarPattern(p)) { - inNextToken - atPos(p.pos) { Bind(name, pattern3(seqOK)) } + in.nextToken() + atPos(p.pos.start) { Bind(name, pattern3(seqOK)) } } else { p } @@ -1446,14 +1375,14 @@ self => def pattern3(seqOK: Boolean): Tree = { val base = opstack var top = simplePattern(seqOK) - if (seqOK && isIdent && inName == STAR) - return atPos(inSkipToken)(Star(stripParens(top))) + if (seqOK && isIdent && in.name == STAR) + return atPos(top.pos.start, in.skipToken())(Star(stripParens(top))) - while (isIdent && inName != BAR) { + while (isIdent && in.name != BAR) { top = reduceStack( - false, base, top, precedence(inName), treeInfo.isLeftAssoc(inName)) - val op = inName - opstack = OpInfo(top, op, inCurrentPos) :: opstack + false, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) + val op = in.name + opstack = OpInfo(top, op, in.offset) :: opstack ident() top = simplePattern(seqOK) } @@ -1478,57 +1407,66 @@ self => * * XXX: Hook for IDE */ - def simplePattern(seqOK: Boolean): Tree = inToken match { - case IDENTIFIER | BACKQUOTED_IDENT | THIS => - var t = stableId() - inToken match { - case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => - t match { - case Ident(name) if name == nme.MINUS => - return literal(true, true) - case _ => - } - case _ => - } -/* not yet - if (inToken == LBRACKET) - atPos(inCurrentPos) { - val ts = typeArgs(true, false) - accept(LPAREN) - val ps = if (inToken == RPAREN) List() else patterns(true, false) + def simplePattern(seqOK: Boolean): Tree = { + val start = in.offset + in.token match { + case IDENTIFIER | BACKQUOTED_IDENT | THIS => + var t = stableId() + in.token match { + case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => + t match { + case Ident(name) if name == nme.MINUS => + return atPos(start) { literal(true) } + case _ => + } + case _ => + } + /* not yet + if (in.token == LBRACKET) + atPos(in.offset) { + val ts = typeArgs(true, false) + accept(LPAREN) + val ps = if (in.token == RPAREN) List() else patterns(true, false) + accept(RPAREN) + Apply(TypeApply(convertToTypeId(t), ts), ps) + } + else */ + if (in.token == LPAREN) + atPos(start, in.offset) { Apply(t, argumentPatterns()) } + else t + case USCORE => + in.nextToken() + atPos(start) { Ident(nme.WILDCARD) } + case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | + STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => + atPos(start) { literal(false) } + case LPAREN => + in.nextToken() + atPos(start) { + val ps = if (in.token == RPAREN) List() else patterns(false) accept(RPAREN) - Apply(TypeApply(convertToTypeId(t), ts), ps) + Parens(ps) } - else */ - if (inToken == LPAREN) { - atPos(t.pos) { Apply(t, argumentPatterns()) } - } else t - case USCORE => - atPos(inSkipToken) { Ident(nme.WILDCARD) } - case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | - STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => - literal(true, false) - case LPAREN => - val pos = inSkipToken - val ps = if (inToken == RPAREN) List() else patterns(false) - accept(RPAREN) - Parens(ps) setPos (pos) - case XMLSTART => - xmlLiteralPattern() - case _ => - syntaxErrorOrIncomplete("illegal start of simple pattern", true) - errorPatternTree + case XMLSTART => + xmlLiteralPattern() + case _ => + syntaxErrorOrIncomplete("illegal start of simple pattern", true) + errorPatternTree + } } def argumentPatterns(): List[Tree] = { accept(LPAREN) - val ps = if (inToken == RPAREN) List() else patterns(true) + val ps = if (in.token == RPAREN) List() else patterns(true) accept(RPAREN) ps } /* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */ + /** Drop `private' modifier when follwed by a qualifier. + * Conract `abstract' and `override' to ABSOVERRIDE + */ private def normalize(mods: Modifiers): Modifiers = if ((mods hasFlag Flags.PRIVATE) && mods.privateWithin != nme.EMPTY.toTypeName) mods &~ Flags.PRIVATE @@ -1538,8 +1476,8 @@ self => mods private def addMod(mods: Modifiers, mod: Long): Modifiers = { - if (mods hasFlag mod) syntaxError(inCurrentPos, "repeated modifier", false) - inNextToken + if (mods hasFlag mod) syntaxError(in.offset, "repeated modifier", false) + in.nextToken() mods | mod } @@ -1547,11 +1485,11 @@ self => */ def accessQualifierOpt(mods: Modifiers): Modifiers = { var result = mods - if (inToken == LBRACKET) { - inNextToken + if (in.token == LBRACKET) { + in.nextToken() if (mods.privateWithin != nme.EMPTY.toTypeName) syntaxError("duplicate private/protected qualifier", false) - result = if (inToken == THIS) { inNextToken; mods | Flags.LOCAL } + result = if (in.token == THIS) { in.nextToken(); mods | Flags.LOCAL } else Modifiers(mods.flags, ident().toTypeName) accept(RBRACKET) } @@ -1561,9 +1499,9 @@ self => /** AccessModifier ::= (private | protected) [AccessQualifier] */ def accessModifierOpt(): Modifiers = normalize { - inToken match { - case PRIVATE => inNextToken; accessQualifierOpt(Modifiers(Flags.PRIVATE)) - case PROTECTED => inNextToken; accessQualifierOpt(Modifiers(Flags.PROTECTED)) + in.token match { + case PRIVATE => in.nextToken(); accessQualifierOpt(Modifiers(Flags.PRIVATE)) + case PROTECTED => in.nextToken(); accessQualifierOpt(Modifiers(Flags.PROTECTED)) case _ => NoMods } } @@ -1574,7 +1512,7 @@ self => * | override */ def modifiers(): Modifiers = normalize { - def loop(mods: Modifiers): Modifiers = inToken match { + def loop(mods: Modifiers): Modifiers = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) case FINAL => @@ -1592,7 +1530,7 @@ self => case LAZY => loop(addMod(mods, Flags.LAZY)) case NEWLINE => - inNextToken + in.nextToken() loop(mods) case _ => mods @@ -1604,7 +1542,7 @@ self => * LocalModifier ::= abstract | final | sealed | implicit | lazy */ def localModifiers(): Modifiers = { - def loop(mods: Modifiers): Modifiers = inToken match { + def loop(mods: Modifiers): Modifiers = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) case FINAL => @@ -1626,8 +1564,8 @@ self => */ def annotations(skipNewLines: Boolean): List[Annotation] = { var annots = new ListBuffer[Annotation] - while (inToken == AT) { - inNextToken + while (in.token == AT) { + in.nextToken() annots += annotationExpr() if (skipNewLines) newLineOpt() } @@ -1639,31 +1577,33 @@ self => */ def annotationExpr(): Annotation = { def nameValuePair(): Tree = { - var pos = inCurrentPos - accept(VAL) - val aname = ident() - accept(EQUALS) - val rhs = stripParens(prefixExpr()) - atPos(pos) { ValDef(NoMods, aname, TypeTree(), rhs) } - } - val pos = inCurrentPos - var t: Tree = convertToTypeId(stableId()) - if (inToken == LBRACKET) - t = atPos(inCurrentPos)(AppliedTypeTree(t, typeArgs(false, false))) - val args = if (inToken == LPAREN) argumentExprs() else List() - newLineOptWhenFollowedBy(LBRACE) - val nameValuePairs: List[Tree] = if (inToken == LBRACE) { - inNextToken - val nvps = new ListBuffer[Tree] + nameValuePair() - while (inToken == COMMA) { - inNextToken - nvps += nameValuePair() + atPos(in.offset) { + accept(VAL) + val aname = ident() + accept(EQUALS) + val rhs = stripParens(prefixExpr()) + ValDef(NoMods, aname, TypeTree(), rhs) } - accept(RBRACE) - nvps.toList - } else List() - val constr = atPos(pos) { New(t, List(args)) } - Annotation(constr, nameValuePairs) setPos pos + } + atPos(in.offset) { + var t: Tree = convertToTypeId(stableId()) + if (in.token == LBRACKET) + t = AppliedTypeTree(t, typeArgs(false, false)) + val args = if (in.token == LPAREN) argumentExprs() else List() + newLineOptWhenFollowedBy(LBRACE) + val nameValuePairs: List[Tree] = if (in.token == LBRACE) { + in.nextToken() + val nvps = new ListBuffer[Tree] += nameValuePair() + while (in.token == COMMA) { + in.nextToken() + nvps += nameValuePair() + } + accept(RBRACE) + nvps.toList + } else List() + val constr = New(t, List(args)) + Annotation(constr, nameValuePairs) + } } /* -------- PARAMETERS ------------------------------------------- */ @@ -1681,73 +1621,70 @@ self => var implicitmod = 0 var caseParam = ofCaseClass def param(): ValDef = { - var pos = inCurrentPos - - { - val annots = annotations(false) - var mods = Modifiers(Flags.PARAM) - if (owner.isTypeName) { - mods = modifiers() | Flags.PARAMACCESSOR - if (mods.hasFlag(Flags.LAZY)) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", false) - if (inToken == VAL) { - inNextToken - } else if (inToken == VAR) { - mods = mods | Flags.MUTABLE - inNextToken - } else { - if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) - if (!(caseParam)) mods = mods | Flags.PRIVATE | Flags.LOCAL - } - if (caseParam) mods = mods | Flags.CASEACCESSOR + val start = in.offset + val annots = annotations(false) + var mods = Modifiers(Flags.PARAM) + if (owner.isTypeName) { + mods = modifiers() | Flags.PARAMACCESSOR + if (mods.hasFlag(Flags.LAZY)) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", false) + if (in.token == VAL) { + in.nextToken() + } else if (in.token == VAR) { + mods |= Flags.MUTABLE + in.nextToken() + } else if (!caseParam) { + mods |= Flags.PRIVATE | Flags.LOCAL } - val namePos = inCurrentPos - val name = ident() - if (name != nme.ERROR) pos = namePos - var bynamemod = 0 - val tpt = - if (settings.Xexperimental.value && !owner.isTypeName && inToken != COLON) { - TypeTree() - } else { // XX-METHOD-INFER - accept(COLON) - if (inToken == ARROW) { - if (owner.isTypeName && !mods.hasFlag(Flags.LOCAL)) - syntaxError( - inCurrentPos, - (if (mods.hasFlag(Flags.MUTABLE)) "`var'" else "`val'") + - " parameters may not be call-by-name", false) - else bynamemod = Flags.BYNAMEPARAM - } - paramType() + if (caseParam) { + mods |= Flags.CASEACCESSOR + } + } + val nameOffset = in.offset + val name = ident() + var bynamemod = 0 + val tpt = + if (settings.Xexperimental.value && !owner.isTypeName && in.token != COLON) { + TypeTree() + } else { // XX-METHOD-INFER + accept(COLON) + if (in.token == ARROW) { + if (owner.isTypeName && !mods.hasFlag(Flags.LOCAL)) + syntaxError( + in.offset, + (if (mods.hasFlag(Flags.MUTABLE)) "`var'" else "`val'") + + " parameters may not be call-by-name", false) + else bynamemod = Flags.BYNAMEPARAM } - atPos(pos){ - ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, EmptyTree) + paramType() } + atPos(start, if (name == nme.ERROR) start else nameOffset) { + ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, EmptyTree) } } def paramClause(): List[ValDef] = { val params = new ListBuffer[ValDef] - if (inToken != RPAREN) { - if (inToken == IMPLICIT) { + if (in.token != RPAREN) { + if (in.token == IMPLICIT) { if (!implicitViews.isEmpty) syntaxError("cannot have both view bounds `<%' and implicit parameters", false) - inNextToken + in.nextToken() implicitmod = Flags.IMPLICIT } params += param() - while (inToken == COMMA) { - inNextToken; params += param() + while (in.token == COMMA) { + in.nextToken(); params += param() } } params.toList } val vds = new ListBuffer[List[ValDef]] - val pos = inCurrentPos + val start = in.offset newLineOptWhenFollowedBy(LPAREN) - if (ofCaseClass && inToken != LPAREN) - deprecationWarning(inCurrentPos, "case classes without a parameter list have been deprecated;\n"+ + if (ofCaseClass && in.token != LPAREN) + deprecationWarning(in.offset, "case classes without a parameter list have been deprecated;\n"+ "use either case objects or case classes with `()' as parameter list.") - while (implicitmod == 0 && inToken == LPAREN) { - inNextToken + while (implicitmod == 0 && in.token == LPAREN) { + in.nextToken() vds += paramClause() accept(RPAREN) caseParam = false @@ -1757,28 +1694,28 @@ self => if (owner == nme.CONSTRUCTOR && (result.isEmpty || (!result.head.isEmpty && result.head.head.mods.hasFlag(Flags.IMPLICIT)))) - if (inToken == LBRACKET) - syntaxError(pos, "no type parameters allowed here", false) - else if(inToken == EOF) + if (in.token == LBRACKET) + syntaxError(in.offset, "no type parameters allowed here", false) + else if(in.token == EOF) incompleteInputError("auxiliary constructor needs non-implicit parameter list") else - syntaxError(pos, "auxiliary constructor needs non-implicit parameter list", false) + syntaxError(start, "auxiliary constructor needs non-implicit parameter list", false) addImplicitViews(owner, result, implicitViews) } /** ParamType ::= Type | `=>' Type | Type `*' */ def paramType(): Tree = - if (inToken == ARROW) - atPos(inSkipToken) { + if (in.token == ARROW) + atPos(in.skipToken()) { AppliedTypeTree( - rootScalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) + rootScalaDot(nme.BYNAME_PARAM_CLASS_NAME.toTypeName), List(typ())) } else { val t = typ() - if (isIdent && inName == STAR) { - inNextToken - atPos(t.pos) { + if (isIdent && in.name == STAR) { + in.nextToken() + atPos(t.pos.start, t.pos.mid) { AppliedTypeTree( rootScalaDot(nme.REPEATED_PARAM_CLASS_NAME.toTypeName), List(t)) } @@ -1794,38 +1731,40 @@ self => */ def typeParamClauseOpt(owner: Name, implicitViewBuf: ListBuffer[Tree]): List[TypeDef] = { def typeParam(): TypeDef = { + val start = in.offset var mods = Modifiers(Flags.PARAM) if (owner.isTypeName && isIdent) { - if (inName == PLUS) { - inNextToken - mods = mods | Flags.COVARIANT - } else if (inName == MINUS) { - inNextToken - mods = mods | Flags.CONTRAVARIANT + if (in.name == PLUS) { + in.nextToken() + mods |= Flags.COVARIANT + } else if (in.name == MINUS) { + in.nextToken() + mods |= Flags.CONTRAVARIANT } } - val pos = inCurrentPos + val nameOffset = in.offset val pname = - (if (inToken == USCORE) { // @M! also allow underscore - inNextToken + (if (in.token == USCORE) { // @M! also allow underscore + in.nextToken() nme.WILDCARD } else ident()).toTypeName - - val tparams = typeParamClauseOpt(pname, null) // @M TODO null --> no higher-order view bounds for now - val param = atPos(pos) { TypeDef(mods, pname, tparams, typeBounds()) } - if (inToken == VIEWBOUND && (implicitViewBuf ne null)) - implicitViewBuf += atPos(inSkipToken) { + val param = atPos(start, nameOffset) { + val tparams = typeParamClauseOpt(pname, null) // @M TODO null --> no higher-order view bounds for now + TypeDef(mods, pname, tparams, typeBounds()) + } + if (in.token == VIEWBOUND && (implicitViewBuf ne null)) + implicitViewBuf += atPos(start, in.skipToken()) { makeFunctionTypeTree(List(Ident(pname)), typ()) } param } val params = new ListBuffer[TypeDef] newLineOptWhenFollowedBy(LBRACKET) - if (inToken == LBRACKET) { - inNextToken + if (in.token == LBRACKET) { + in.nextToken() params += typeParam() - while (inToken == COMMA) { - inNextToken + while (in.token == COMMA) { + in.nextToken() params += typeParam() } accept(RBRACKET) @@ -1841,7 +1780,7 @@ self => bound(SUBTYPE, nme.Any)) def bound(tok: Int, default: Name): Tree = - if (inToken == tok) { inNextToken; typ() } + if (in.token == tok) { in.nextToken(); typ() } else rootScalaDot(default.toTypeName) /* -------- DEFS ------------------------------------------- */ @@ -1851,9 +1790,9 @@ self => */ def importClause(): List[Tree] = { accept(IMPORT) - val ts = new ListBuffer[Tree] + importExpr() - while (inToken == COMMA) { - inNextToken; ts += importExpr() + val ts = new ListBuffer[Tree] += importExpr() + while (in.token == COMMA) { + in.nextToken(); ts += importExpr() } ts.toList } @@ -1861,47 +1800,49 @@ self => /** ImportExpr ::= StableId `.' (Id | `_' | ImportSelectors) * XXX: Hook for IDE */ - def importExpr(): Tree = - atPos(inCurrentPos) { - var t: Tree = null - //var pos : ScanPosition = null.asInstanceOf[ScanPosition] - var pos : Int = -1 - if (inToken == THIS) { - t = atPos(inCurrentPos) { This(nme.EMPTY.toTypeName) } - t = atPos(accept(DOT)) { selector(t) } - pos = accept(DOT) + def importExpr(): Tree = { + val start = in.offset + var t: Tree = null + if (in.token == THIS) { + in.nextToken() + t = atPos(start) { This(nme.EMPTY.toTypeName) } + accept(DOT) + t = selector(t) + accept(DOT) + } else { + val id = atPos(start) { Ident(ident()) } + accept(DOT) + if (in.token == THIS) { + in.nextToken() + t = atPos(start) { This(id.name.toTypeName) } + accept(DOT) + t = selector(t) + accept(DOT) } else { - val i = atPos(inCurrentPos) { Ident(ident()) } - pos = accept(DOT) - if (inToken == THIS) { - inNextToken - t = atPos(i.pos) { This(i.name.toTypeName) } - t = atPos(accept(DOT)) { selector(t) } - pos = accept(DOT) - } else { - t = i - } + t = id } - def loop: Tree = - if (inToken == USCORE) { - inNextToken - Import(t, List((nme.WILDCARD, null))) - } else if (inToken == LBRACE) { - Import(t, importSelectors()) - } else { - val identPos = inCurrentPos - val name = ident() // @S: use position of identifier, not dot! - pos = if (name == nme.ERROR) pos else identPos - if (inToken == DOT) { - t = atPos(pos) { Select(t, name) } - pos = accept(DOT) - loop - } else { - Import(t, List((name, name))) + } + def loop(): Tree = + if (in.token == USCORE) { + in.nextToken() + Import(t, List((nme.WILDCARD, null))) + } else if (in.token == LBRACE) { + Import(t, importSelectors()) + } else { + val nameOffset = in.offset + val name = ident() + if (in.token == DOT) { + t = atPos(start, if (name == nme.ERROR) in.offset else nameOffset) { + Select(t, name) } + in.nextToken() + loop() + } else { + Import(t, List((name, name))) } - loop - } + } + atPos(start) { loop() } + } /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' */ @@ -1909,8 +1850,8 @@ self => val names = new ListBuffer[(Name, Name)] accept(LBRACE) var isLast = importSelector(names) - while (!isLast && inToken == COMMA) { - inNextToken + while (!isLast && in.token == COMMA) { + in.nextToken() isLast = importSelector(names) } accept(RBRACE) @@ -1920,15 +1861,15 @@ self => /** ImportSelector ::= Id [`=>' Id | `=>' `_'] */ def importSelector(names: ListBuffer[(Name, Name)]): Boolean = - if (inToken == USCORE) { - inNextToken; names += ((nme.WILDCARD, null)); true + if (in.token == USCORE) { + in.nextToken(); names += ((nme.WILDCARD, null)); true } else { val name = ident() names += (( name, - if (inToken == ARROW) { - inNextToken - if (inToken == USCORE) { inNextToken; nme.WILDCARD } else ident() + if (in.token == ARROW) { + in.nextToken() + if (in.token == USCORE) { in.nextToken(); nme.WILDCARD } else ident() } else { name })) @@ -1948,7 +1889,7 @@ self => def defOrDcl(mods: Modifiers): List[Tree] = { if ((mods hasFlag Flags.LAZY) && in.token != VAL) syntaxError("lazy not allowed here. Only vals can be lazy", false) - inToken match { + in.token match { case VAL => patDefOrDcl(mods) case VAR => @@ -1956,8 +1897,6 @@ self => case DEF => List(funDefOrDcl(mods)) case TYPE => - inNextToken - newLinesOpt() List(typeDefOrDcl(mods)) case _ => List(tmplDef(mods)) @@ -1983,18 +1922,18 @@ self => var newmods = mods val lhsBuf = new ListBuffer[Tree] do { - inNextToken + in.nextToken() val p = pattern2(false) lhsBuf += stripParens(p) - } while (inToken == COMMA) + } while (in.token == COMMA) val lhs = lhsBuf.toList val tp = typedOpt() - val rhs = - if (tp.isEmpty || inToken == EQUALS) { + var rhs = + if (tp.isEmpty || in.token == EQUALS) { accept(EQUALS) if (!tp.isEmpty && newmods.hasFlag(Flags.MUTABLE) && - (lhs.toList forall (_.isInstanceOf[Ident])) && inToken == USCORE) { - inNextToken + (lhs.toList forall (_.isInstanceOf[Ident])) && in.token == USCORE) { + in.nextToken() newmods = newmods | Flags.DEFAULTINIT EmptyTree } else { @@ -2004,26 +1943,16 @@ self => newmods = newmods | Flags.DEFERRED EmptyTree } - var originalUsed = false def mkDefs(p: Tree): List[Tree] = { //Console.println("DEBUG: p = "+p.toString()); // DEBUG val trees = - makePatDef(newmods, - if (tp.isEmpty) - p - else - Typed(p, tp), - if (inIDE && !originalUsed) { - // because duplicates have weaker status than originals - // need an original. - originalUsed = true - rhs - } else rhs.duplicate) map atPos(p.pos) - if (newmods.hasFlag(Flags.DEFERRED)) { + makePatDef(newmods, if (tp.isEmpty) p else Typed(p, tp), rhs) map + atPos(p.pos.start, p.pos.mid) + rhs = rhs.duplicate + if (newmods hasFlag Flags.DEFERRED) { trees match { case List(ValDef(_, _, _, EmptyTree)) => - if (mods.hasFlag(Flags.LAZY)) - syntaxError(p.pos, "lazy values may not be abstract", false) + if (mods.hasFlag(Flags.LAZY)) syntaxError(p.pos, "lazy values may not be abstract", false) case _ => syntaxError(p.pos, "pattern definition may not be abstract", false) } } @@ -2039,14 +1968,14 @@ self => var newmods = mods | Flags.MUTABLE val lhs = new ListBuffer[(Int, Name)] do { - inNextToken - lhs += (inCurrentPos, ident()) - } while (inToken == COMMA) + in.nextToken() + lhs += (in.offset, ident()) + } while (in.token == COMMA) val tp = typedOpt() - val rhs = if (tp.isEmpty || inToken == EQUALS) { + val rhs = if (tp.isEmpty || in.token == EQUALS) { accept(EQUALS) - if (!tp.isEmpty && inToken == USCORE) { - inNextToken + if (!tp.isEmpty && in.token == USCORE) { + in.nextToken() EmptyTree } else { expr() @@ -2072,22 +2001,20 @@ self => * FunSig ::= id [FunTypeParamClause] ParamClauses */ def funDefOrDcl(mods: Modifiers): Tree = { - var pos = inSkipToken // position of `def' - if (inToken == THIS) { - atPos(inCurrentPos) { - inNextToken + val start = in.skipToken() + if (in.token == THIS) { + atPos(start, in.skipToken()) { val vparamss = paramClauses(nme.CONSTRUCTOR, implicitClassViews map (_.duplicate), false) newLineOptWhenFollowedBy(LBRACE) - val rhs = if (inToken == LBRACE) constrBlock(vparamss) + val rhs = if (in.token == LBRACE) constrBlock(vparamss) else { accept(EQUALS); constrExpr(vparamss) } DefDef(mods, nme.CONSTRUCTOR, List(), vparamss, TypeTree(), rhs) } } else { var newmods = mods - val namePos = inCurrentPos + val nameOffset = in.offset val name = ident() - if (name != nme.ERROR) pos = namePos - atPos(pos) { + atPos(start, if (name == nme.ERROR) start else nameOffset) { // implicitViewBuf is for view bounded type parameters of the form // [T <% B]; it contains the equivalent implicit parameter, i.e. (implicit p: T => B) val implicitViewBuf = new ListBuffer[Tree] @@ -2096,25 +2023,26 @@ self => newLineOptWhenFollowedBy(LBRACE) var restype = typedOpt() val rhs = - if (isStatSep || inToken == RBRACE) { + if (isStatSep || in.token == RBRACE) { if (restype.isEmpty) restype = scalaUnitConstr - newmods = newmods | Flags.DEFERRED + newmods |= Flags.DEFERRED EmptyTree - } else if (restype.isEmpty && inToken == LBRACE) { + } else if (restype.isEmpty && in.token == LBRACE) { restype = scalaUnitConstr blockExpr() - } else equalsExpr() + } else { + equalsExpr() + } DefDef(newmods, name, tparams, vparamss, restype, rhs) } } } - /** ConstrExpr ::= SelfInvocation * | ConstrBlock */ def constrExpr(vparamss: List[List[ValDef]]): Tree = - if (inToken == LBRACE) constrBlock(vparamss) + if (in.token == LBRACE) constrBlock(vparamss) else Block(List(selfInvocation(vparamss)), Literal(())) /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} @@ -2123,7 +2051,7 @@ self => atPos(accept(THIS)) { newLineOptWhenFollowedBy(LBRACE) var t = Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) - while (inToken == LPAREN || inToken == LBRACE) { + while (in.token == LPAREN || in.token == LBRACE) { t = Apply(t, argumentExprs()) newLineOptWhenFollowedBy(LBRACE) } @@ -2134,33 +2062,28 @@ self => /** ConstrBlock ::= `{' SelfInvocation {semi BlockStat} `}' */ def constrBlock(vparamss: List[List[ValDef]]): Tree = - atPos(inSkipToken) { + atPos(in.skipToken()) { val statlist = new ListBuffer[Tree] statlist += selfInvocation(vparamss) - val stats = if (isStatSep) { inNextToken; blockStatSeq(statlist) } + val stats = if (isStatSep) { in.nextToken(); blockStatSeq(statlist) } else statlist.toList accept(RBRACE) Block(stats, Literal(())) } - /** TypeDef ::= Id [TypeParamClause] `=' Type - * TypeDcl ::= Id [TypeParamClause] TypeBounds + /** TypeDef ::= type Id [TypeParamClause] `=' Type + * TypeDcl ::= type Id [TypeParamClause] TypeBounds */ - def typeDefOrDcl(mods: Modifiers): Tree = - atPos(inCurrentPos) { + def typeDefOrDcl(mods: Modifiers): Tree = { + val start = in.skipToken() + newLinesOpt() + atPos(start, in.offset) { val name = ident().toTypeName - // @M! a type alias as well as an abstract type may declare type parameters - val tparams = inToken match { - case LBRACKET => - typeParamClauseOpt(name, null) - case _ => - Nil - } - - inToken match { + val tparams = typeParamClauseOpt(name, null) + in.token match { case EQUALS => - inNextToken + in.nextToken() TypeDef(mods, name, tparams, typ()) case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE => TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds()) @@ -2169,6 +2092,7 @@ self => EmptyTree } } + } /** Hook for IDE, for top-level classes/objects */ def topLevelTmplDef: Tree = { @@ -2183,7 +2107,7 @@ self => */ def tmplDef(mods: Modifiers): Tree = { if (mods.hasFlag(Flags.LAZY)) syntaxError("classes cannot be lazy", false) - inToken match { + in.token match { case TRAIT => classDef(mods | Flags.TRAIT | Flags.ABSTRACT) case CLASS => @@ -2205,11 +2129,10 @@ self => * TraitDef ::= Id [TypeParamClause] RequiresTypeOpt TraitTemplateOpt */ def classDef(mods: Modifiers): ClassDef = { - var pos = inSkipToken - var namePos = inCurrentPos + val start = in.skipToken() + val nameOffset = in.offset val name = ident().toTypeName - if (name != nme.ERROR) pos = namePos - atPos(pos) { + atPos(start, if (name == nme.ERROR.toTypeName) start else nameOffset) { val savedViews = implicitClassViews val implicitViewBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, implicitViewBuf) @@ -2222,24 +2145,13 @@ self => val (constrMods, vparamss) = if (mods.hasFlag(Flags.TRAIT)) (Modifiers(Flags.TRAIT), List()) else (accessModifierOpt(), paramClauses(name, implicitClassViews, mods.hasFlag(Flags.CASE))) - val thistpe = requiresTypeOpt() - var mods1 = - if (mods hasFlag Flags.TRAIT) - if (inToken == SUBTYPE) mods | Flags.DEFERRED - else mods - else if (inToken == SUBTYPE) { - syntaxError("classes are not allowed to be virtual", false) - mods - } - else - mods - var template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss) - if (!thistpe.isEmpty) { - if (template.self.isEmpty) { - template = copy.Template( - template, template.parents, makeSelfDef(nme.WILDCARD, thistpe), template.body) - } else syntaxError("`requires' cannot be combined with explicit self type", false) + var mods1 = mods + if (mods hasFlag Flags.TRAIT) { + if (settings.Xexperimental.value && in.token == SUBTYPE) mods1 |= Flags.DEFERRED + } else if (in.token == SUBTYPE) { + syntaxError("classes are not allowed to be virtual", false) } + var template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss) if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE val result = ClassDef(mods1, name, tparams, template) implicitClassViews = savedViews @@ -2250,29 +2162,27 @@ self => /** ObjectDef ::= Id ClassTemplateOpt */ def objectDef(mods: Modifiers): ModuleDef = { - var pos = inSkipToken - var namePos = inCurrentPos - val name = ident().toTermName - if (name != nme.ERROR) pos = namePos - atPos(pos) { - val mods1 = if (inToken == SUBTYPE) mods | Flags.DEFERRED else mods + val start = in.skipToken() + val nameOffset = in.offset + val name = ident() + atPos(start, if (name == nme.ERROR) start else nameOffset) { + val mods1 = if (in.token == SUBTYPE) mods | Flags.DEFERRED else mods val template = templateOpt(mods1, name, NoMods, List()) ModuleDef(mods1, name, template) } } - /** ClassParents ::= AnnotType {`(' [Exprs [`,']] `)'} {with AnnotType} * TraitParents ::= AnnotType {with AnnotType} */ def templateParents(isTrait: Boolean): (List[Tree], List[List[Tree]]) = { - val parents = new ListBuffer[Tree] + annotType(false) + val parents = new ListBuffer[Tree] += annotType(false) val argss = new ListBuffer[List[Tree]] - if (inToken == LPAREN && !isTrait) - do { argss += argumentExprs() } while (inToken == LPAREN) + if (in.token == LPAREN && !isTrait) + do { argss += argumentExprs() } while (in.token == LPAREN) else argss += List() - while (inToken == WITH) { - inNextToken + while (in.token == WITH) { + in.nextToken() parents += annotType(false) } (parents.toList, argss.toList) @@ -2285,21 +2195,21 @@ self => */ def template(isTrait: Boolean): (List[Tree], List[List[Tree]], ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) - if (inToken == LBRACE) { + if (in.token == LBRACE) { // @S: pre template body cannot stub like post body can! val (self, body) = templateBody(true) - if (inToken == WITH && self.isEmpty) { + if (in.token == WITH && self.isEmpty) { val earlyDefs: List[Tree] = body flatMap { case vdef @ ValDef(mods, name, tpt, rhs) if !(mods hasFlag Flags.DEFERRED) => List(copy.ValDef(vdef, mods | Flags.PRESUPER, name, tpt, rhs)) case tdef @ TypeDef(mods, name, tparams, rhs) => List(copy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs)) case stat if !stat.isEmpty => - syntaxError(stat.pos, "only type definitions and concrete field definitions allowed in early object initialization section", false) + syntaxError(stat.pos, "only type definitions and concrete field definitions allowed in early object initialization section", false) List() case _ => List() } - inNextToken + in.nextToken() val (parents, argss) = templateParents(isTrait) val (self1, body1) = templateBodyOpt(isTrait) (parents, argss, self1, earlyDefs ::: body1) @@ -2319,16 +2229,16 @@ self => /** ClassTemplateOpt ::= 'extends' ClassTemplate | [['extends'] TemplateBody] * TraitTemplateOpt ::= TraitExtends TraitTemplate | [['extends'] TemplateBody] | '<:' TemplateBody * TraitExtends ::= 'extends' | `<:' + * @note leaves result unpositioned. */ def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]]): Template = { - val pos = inCurrentPos; val (parents0, argss, self, body) = - if (inToken == EXTENDS || settings.Xexperimental.value && (mods hasFlag Flags.TRAIT) && inToken == SUBTYPE) { - inNextToken + if (in.token == EXTENDS || settings.Xexperimental.value && (mods hasFlag Flags.TRAIT) && in.token == SUBTYPE) { + in.nextToken() template(mods hasFlag Flags.TRAIT) - } else if ((inToken == SUBTYPE) && (mods hasFlag Flags.TRAIT)) { - inNextToken + } else if ((in.token == SUBTYPE) && (mods hasFlag Flags.TRAIT)) { + in.nextToken() template(true) } else { newLineOptWhenFollowedBy(LBRACE) @@ -2341,12 +2251,7 @@ self => if (parents.isEmpty) parents = List(scalaAnyRefConstr) if (mods.hasFlag(Flags.CASE)) parents = parents ::: List(productConstr) - val tree = Template(parents, self, constrMods, vparamss, argss, body) - // @S: if nothing parsed, don't use next position! - // @S: if primary constructor does not always have the same position, then the IDE gets confused. - // @S: since build compiler is used to generate IDE files, don't set position here! - tree - // if (pos == inCurrentPos || inIDE) tree else atPos(pos) {tree} + Template(parents, self, constrMods, vparamss, argss, body) } /* -------- TEMPLATES ------------------------------------------- */ @@ -2362,10 +2267,10 @@ self => } def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) - if (inToken == LBRACE) { + if (in.token == LBRACE) { templateBody(false) } else { - if (inToken == LPAREN) + if (in.token == LPAREN) syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ " may not have parameters", true) (emptyValDef, List()) @@ -2383,18 +2288,39 @@ self => /* -------- STATSEQS ------------------------------------------- */ + /** Create a tree representing a packaging */ + def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef = + atPos(start, pkg.pos.mid) { + pkg match { + case Ident(name) => + PackageDef(name, stats) + case Select(qual, name) => + makePackaging(start, qual, List(PackageDef(name, stats))) + } + } + + /** Create a tree representing a package object, converting + * package object foo { ... } + * to + * package foo { + * object `package` { ... } + * } + */ + def makePackageObject(start: Int, objDef: ModuleDef): PackageDef = objDef match { + case ModuleDef(mods, name, impl) => + makePackaging( + start, atPos(o2p(objDef.pos.start)){ Ident(name) }, List(ModuleDef(mods, nme.PACKAGEkw, impl))) + } + /** Packaging ::= package QualId [nl] `{' TopStatSeq `}' */ - def packaging(pkgPos: Int): Tree = { + def packaging(start: Int): Tree = { val pkg = qualId() - val pos = if (pkg.pos != NoPosition) pkg.pos else i2p(pkgPos) - atPos(pos) { - newLineOptWhenFollowedBy(LBRACE) - accept(LBRACE) - val stats = topStatSeq() - accept(RBRACE) - makePackaging(pkg, stats) - } + newLineOptWhenFollowedBy(LBRACE) + accept(LBRACE) + val stats = topStatSeq() + accept(RBRACE) + makePackaging(start, pkg, stats) } /** TopStatSeq ::= TopStat {semi TopStat} @@ -2406,30 +2332,29 @@ self => */ def topStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree] - while (inToken != RBRACE && inToken != EOF) { - if (inToken == PACKAGE) { - val pkgPos = accept(PACKAGE) + while (in.token != RBRACE && in.token != EOF) { + if (in.token == PACKAGE) { + val start = in.skipToken() stats += { - if (inToken == OBJECT) - atPos(pkgPos) { makePackageObject(objectDef(NoMods)) } - else packaging(pkgPos) - } - } else if (inToken == IMPORT) { + if (in.token == OBJECT) makePackageObject(start, objectDef(NoMods)) + else packaging(start) + } + } else if (in.token == IMPORT) { stats ++= importClause() // XXX: IDE hook this all. - } else if (inToken == CLASS || - inToken == CASECLASS || - inToken == TRAIT || - inToken == OBJECT || - inToken == CASEOBJECT || - inToken == LBRACKET || //todo: remove - inToken == AT || + } else if (in.token == CLASS || + in.token == CASECLASS || + in.token == TRAIT || + in.token == OBJECT || + in.token == CASEOBJECT || + in.token == LBRACKET || //todo: remove + in.token == AT || isModifier) { stats ++ joinComment(List(topLevelTmplDef)) } else if (!isStatSep) { syntaxErrorOrIncomplete("expected class or object definition", true) } - if (inToken != RBRACE && inToken != EOF) acceptStatSep() + if (in.token != RBRACE && in.token != EOF) acceptStatSep() } stats.toList } @@ -2448,36 +2373,36 @@ self => val stats = new ListBuffer[Tree] if (isExprIntro) { val first = expr(InTemplate) // @S: first statement is potentially converted so cannot be stubbed. - if (inToken == ARROW) { + if (in.token == ARROW) { first match { case Typed(tree @ This(name), tpt) if (name == nme.EMPTY.toTypeName) => - self = makeSelfDef(nme.WILDCARD, tpt).setPos(tree.pos) + self = atPos(tree.pos) { makeSelfDef(nme.WILDCARD, tpt) } case _ => convertToParam(first) match { case tree @ ValDef(_, name, tpt, EmptyTree) if (name != nme.ERROR) => - self = makeSelfDef(name, tpt).setPos(tree.pos) + self = atPos(tree.pos) { makeSelfDef(name, tpt) } case _ => } } - inNextToken + in.nextToken() } else { stats += first if (in.token != RBRACE && in.token != EOF/* !isStatSep(in.token)*/) acceptStatSep() } } - while (inToken != RBRACE && inToken != EOF) { - if (inToken == IMPORT) { + while (in.token != RBRACE && in.token != EOF) { + if (in.token == IMPORT) { stats ++= importClause() } else if (isExprIntro) { stats += statement(InTemplate) - } else if (isDefIntro || isModifier || inToken == LBRACKET /*todo: remove */ || inToken == AT) { + } else if (isDefIntro || isModifier || in.token == LBRACKET /*todo: remove */ || in.token == AT) { if (isPre) // @S: avoid caching by calling a different method that does the same thing (except in the IDE) stats ++= joinComment(preNonLocalDefOrDcl) else stats ++= joinComment(nonLocalDefOrDcl) } else if (!isStatSep) { syntaxErrorOrIncomplete("illegal start of definition", true) } - if (inToken != RBRACE && inToken != EOF) acceptStatSep() + if (in.token != RBRACE && in.token != EOF) acceptStatSep() } (self, stats.toList) } @@ -2491,13 +2416,13 @@ self => */ def refineStatSeq(): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] - while (inToken != RBRACE && inToken != EOF) { + while (in.token != RBRACE && in.token != EOF) { if (isDclIntro) { // don't IDE hook stats ++= joinComment(defOrDcl(NoMods)) } else if (!isStatSep) { syntaxErrorOrIncomplete("illegal start of declaration", true) } - if (inToken != RBRACE) acceptStatSep() + if (in.token != RBRACE) acceptStatSep() } stats.toList } @@ -2506,13 +2431,13 @@ self => * Here's an idea how to fill in start and end positions. def localDef : List[Tree] = { atEndPos { - atStartPos(inCurrentPos) { + atStartPos(in.offset) { val annots = annotations(true) val mods = localModifiers() withAnnotations annots if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(mods) else List(tmplDef(mods)) } - } (inCurrentPos) + } (in.offset) } */ @@ -2531,28 +2456,23 @@ self => * | */ def blockStatSeq(stats: ListBuffer[Tree]): List[Tree] = checkNoEscapingPlaceholders { - var keepGoing = true - var hasError = false - while ((inToken != RBRACE) && (inToken != EOF) && (inToken != CASE) && keepGoing) { - var hasError0 = hasError - hasError = false - if (inToken == IMPORT) { + while ((in.token != RBRACE) && (in.token != EOF) && (in.token != CASE)) { + if (in.token == IMPORT) { stats ++= importClause() acceptStatSep() } else if (isExprIntro) { stats += statement(InBlock) - if (inToken != RBRACE && inToken != CASE) acceptStatSep() + if (in.token != RBRACE && in.token != CASE) acceptStatSep() } else if (isDefIntro || isLocalModifier || in.token == AT) { stats ++= localDef - if (inToken == RBRACE || inToken == CASE) { + if (in.token == RBRACE || in.token == CASE) { syntaxError("block must end in result expression, not in definition", false) - stats += Literal(()).setPos(inCurrentPos) + stats += Literal(()).setPos(o2p(in.offset)) } else acceptStatSep() } else if (isStatSep) { - inNextToken + in.nextToken() } else { syntaxErrorOrIncomplete("illegal start of statement", true) - if (hasError0) keepGoing = false else hasError = true } } stats.toList @@ -2561,31 +2481,31 @@ self => /** CompilationUnit ::= [package QualId semi] TopStatSeq */ def compilationUnit(): Tree = checkNoEscapingPlaceholders { - var pos = inCurrentPos; - { - val ts = new ListBuffer[Tree] - // @S: the IDE can insert phantom semi-colons before package during editing - // @S: just eat them (doesn't really change the grammar) - while (inToken == SEMI) inNextToken - if (inToken == PACKAGE) { - pos = inSkipToken - if (in.token == OBJECT) { - ts += makePackageObject(objectDef(NoMods)) - if (inToken != EOF) { - acceptStatSep() - ts ++= topStatSeq() - } - } else { - val pkg = qualId() - newLineOptWhenFollowedBy(LBRACE) - if (inToken == EOF) { - ts += makePackaging(pkg, List()) - } else if (isStatSep) { - inNextToken - ts += makePackaging(pkg, topStatSeq()) - } else { - accept(LBRACE) - ts += makePackaging(pkg, topStatSeq()) + val ts = new ListBuffer[Tree] + + // @S: the IDE can insert phantom semi-colons before package during editing + // @S: just eat them (doesn't really change the grammar) + while (in.token == SEMI) in.nextToken() + val start = in.offset + if (in.token == PACKAGE) { + in.nextToken() + if (in.token == OBJECT) { + ts += makePackageObject(start, objectDef(NoMods)) + if (in.token != EOF) { + acceptStatSep() + ts ++= topStatSeq() + } + } else { + val pkg = qualId() + newLineOptWhenFollowedBy(LBRACE) + if (in.token == EOF) { + ts += makePackaging(start, pkg, List()) + } else if (isStatSep) { + in.nextToken() + ts += makePackaging(start, pkg, topStatSeq()) + } else { + accept(LBRACE) + ts += makePackaging(start, pkg, topStatSeq()) accept(RBRACE) ts ++= topStatSeq() } @@ -2594,14 +2514,12 @@ self => ts ++= topStatSeq() } val stats = ts.toList - val usePos = - if (stats.isEmpty || stats.head.pos == NoPosition) i2p(pos) - else stats.head.pos - atPos(usePos) { stats match { - case List(stat @ PackageDef(_, _)) => stat - case _ => makePackaging(Ident(nme.EMPTY_PACKAGE_NAME), stats) - }} - } + atPos(start) { + stats match { + case List(stat @ PackageDef(_, _)) => stat + case _ => makePackaging(start, atPos(o2p(start)) { Ident(nme.EMPTY_PACKAGE_NAME) }, stats) + } + } } } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 85695b4e85..82dcd74fef 100755 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -51,7 +51,7 @@ trait Scanners { } } - abstract class Scanner extends CharArrayReader1 with TokenData { + abstract class Scanner extends CharArrayReader with TokenData { def flush = { charOffset = offset; nextChar(); this } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index e530c1ce9d..3c67b56e0b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -15,6 +15,7 @@ abstract class TreeBuilder { val global: Global import global._ import posAssigner.atPos; + def freshName(pos : Position, prefix: String): Name def freshName(pos : Position): Name = freshName(pos, "x$") @@ -218,10 +219,10 @@ abstract class TreeBuilder { def makeSyntheticTypeParam(pname: Name, bounds: Tree) = TypeDef(Modifiers(DEFERRED | SYNTHETIC), pname, List(), bounds) - abstract class Enumerator + 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(test: Tree) extends Enumerator + case class Filter(pos: Position, test: Tree) extends Enumerator /** Create tree for for-comprehension <for (enums) do body> or * <for (enums) yield body> where mapName and flatMapName are chosen @@ -302,7 +303,7 @@ abstract class TreeBuilder { atPos(pos) { makeCombination(flatMapName, rhs, pat, makeFor(mapName, flatMapName, rest, body)) } - case ValFrom(pos, pat, rhs) :: Filter(test) :: rest => + case ValFrom(pos, pat, rhs) :: Filter(_, test) :: rest => makeFor(mapName, flatMapName, ValFrom(pos, pat, makeCombination(nme.filter, rhs, pat.duplicate, test)) :: rest, body) @@ -434,19 +435,4 @@ abstract class TreeBuilder { else vparamss ::: List(implicitViews map makeViewParam) } - /** Create a tree representing a packaging */ - def makePackaging(pkg: Tree, stats: List[Tree]): PackageDef = pkg match { - case Ident(name) => - PackageDef(name, stats).setPos(pkg.pos) - case Select(qual, name) => - makePackaging(qual, List(PackageDef(name, stats).setPos(pkg.pos))) - } - - /** Create a tree representing a package object */ - def makePackageObject(objDef: ModuleDef): PackageDef = objDef match { - case ModuleDef(mods, name, impl) => - makePackaging(Ident(name), List(ModuleDef(mods, nme.PACKAGEkw, impl))) - } - - case class Parens(args: List[Tree]) extends Tree } diff --git a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala index 61443ebcdc..1ee41bb676 100755 --- a/src/compiler/scala/tools/nsc/javac/JavaScanners.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaScanners.scala @@ -10,6 +10,7 @@ import SourceFile.{LF, FF, CR, SU} import JavaTokens._ import scala.annotation.switch +// Todo merge these better with Scanners trait JavaScanners { val global : Global import global._ @@ -254,7 +255,7 @@ trait JavaScanners { override var errpos: Int = NoPos def currentPos: Position = g2p(pos - 1) - var in: CharArrayReader = _ + var in: JavaCharArrayReader = _ def dup: JavaScanner = { val dup = clone().asInstanceOf[JavaScanner] @@ -967,7 +968,7 @@ trait JavaScanners { /** ... */ class JavaUnitScanner(unit: CompilationUnit) extends JavaScanner { - in = new CharArrayReader(unit.source.asInstanceOf[BatchSourceFile].content, !settings.nouescape.value, syntaxError) + in = new JavaCharArrayReader(unit.source.asInstanceOf[BatchSourceFile].content, !settings.nouescape.value, syntaxError) init def warning(pos: Int, msg: String) = unit.warning(pos, msg) def error (pos: Int, msg: String) = unit. error(pos, msg) diff --git a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala index a6c10520bb..a6b59cdcae 100644..100755 --- a/src/compiler/scala/tools/nsc/util/CharArrayReader.scala +++ b/src/compiler/scala/tools/nsc/util/CharArrayReader.scala @@ -2,125 +2,89 @@ * Copyright 2005-2009 LAMP/EPFL * @author Martin Odersky */ -// $Id$ +// $Id: NewCharArrayReader.scala 16893 2009-01-13 13:09:22Z cunei $ package scala.tools.nsc.util import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} -class CharArrayReader(buf: RandomAccessSeq[Char], start: Int, /* startline: int, startcol: int, */ - decodeUni: Boolean, error: String => Unit) extends Iterator[Char] with Cloneable { +abstract class CharArrayReader { self => - def this(buf: RandomAccessSeq[Char], decodeUni: Boolean, error: String => Unit) = - this(buf, 0, /* 1, 1, */ decodeUni, error) + val buf: Array[Char] - /** produce a duplicate of this char array reader which starts reading - * at current position, independent of what happens to original reader - */ - def dup: CharArrayReader = clone().asInstanceOf[CharArrayReader] + def decodeUni: Boolean = true - /** layout constant - */ - val tabinc = 8 + /** An error routine to call on bad unicode escapes \\uxxxx. */ + protected def error(offset: Int, msg: String) - /** the line and column position of the current character - */ + /** the last read character */ var ch: Char = _ - var bp = start - var oldBp = -1 - var oldCh: Char = _ - - //private var cline: Int = _ - //private var ccol: Int = _ - def cpos = bp - var isUnicode: Boolean = _ - var lastLineStartPos: Int = 0 - var lineStartPos: Int = 0 - var lastBlankLinePos: Int = 0 - - private var onlyBlankChars = false - //private var nextline = startline - //private var nextcol = startcol - - private def markNewLine() { - lastLineStartPos = lineStartPos - if (onlyBlankChars) lastBlankLinePos = lineStartPos - lineStartPos = bp - onlyBlankChars = true - //nextline += 1 - //nextcol = 1 - } - def hasNext: Boolean = if (bp < buf.length) true - else { - false - } + /** The offset one past the last read character */ + var charOffset: Int = 0 + + /** The start offset of the current line */ + var lineStartOffset: Int = 0 + + /** The start offset of the line before the current one */ + var lastLineStartOffset: Int = 0 - def last: Char = if (bp > start + 2) buf(bp - 2) else ' ' // XML literals + private var lastUnicodeOffset = -1 - def next: Char = { - //cline = nextline - //ccol = nextcol - val buf = this.buf.asInstanceOf[runtime.BoxedCharArray].value - if(!hasNext) { + /** Is last character a unicode escape \\uxxxx? */ + def isUnicodeEscape = charOffset == lastUnicodeOffset + + /** Advance one character */ + final def nextChar() { + if (charOffset >= buf.length) { ch = SU - return SU // there is an endless stream of SU's at the end - } - oldBp = bp - oldCh = ch - ch = buf(bp) - isUnicode = false - bp = bp + 1 - ch match { - case '\t' => - // nextcol = ((nextcol - 1) / tabinc * tabinc) + tabinc + 1; - case CR => - if (bp < buf.size && buf(bp) == LF) { - ch = LF - bp += 1 - } - markNewLine() - case LF | FF => - markNewLine() - case '\\' => - def evenSlashPrefix: Boolean = { - var p = bp - 2 - while (p >= 0 && buf(p) == '\\') p -= 1 - (bp - p) % 2 == 0 - } - def udigit: Int = { - val d = digit2int(buf(bp), 16) - if (d >= 0) { bp += 1; /* nextcol = nextcol + 1 */ } - else error("error in unicode escape"); - d - } - // nextcol += 1 - if (buf(bp) == 'u' && decodeUni && evenSlashPrefix) { - do { - bp += 1 //; nextcol += 1 - } while (buf(bp) == 'u'); - val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit - ch = code.asInstanceOf[Char] - isUnicode = true - } - case _ => - if (ch > ' ') onlyBlankChars = false - // nextcol += 1 + } else { + val c = buf(charOffset) + ch = c + charOffset += 1 + if (c == '\\') potentialUnicode() + else if (c < ' ') potentialLineEnd() +// print("`"+ch+"'") } - ch } - def rewind { - if (oldBp == -1) throw new IllegalArgumentException - bp = oldBp - ch = oldCh - oldBp = -1 - oldCh = 'x' + /** Interpret \\uxxxx escapes */ + private def potentialUnicode() { + def evenSlashPrefix: Boolean = { + var p = charOffset - 2 + while (p >= 0 && buf(p) == '\\') p -= 1 + (charOffset - p) % 2 == 0 + } + def udigit: Int = { + val d = digit2int(buf(charOffset), 16) + if (d >= 0) charOffset += 1 + else error(charOffset, "error in unicode escape") + d + } + if (charOffset < buf.length && buf(charOffset) == 'u' && decodeUni && evenSlashPrefix) { + do charOffset += 1 + while (charOffset < buf.length && buf(charOffset) == 'u') + val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit + lastUnicodeOffset = charOffset + ch = code.toChar + } } - def copy: CharArrayReader = - new CharArrayReader(buf, bp, /* nextcol, nextline, */ decodeUni, error) + /** Handle line ends, replace CR+LF by LF */ + private def potentialLineEnd() { + if (ch == CR) + if (charOffset < buf.length && buf(charOffset) == LF) { + charOffset += 1 + ch = LF + } + if (ch == LF || ch == FF) { + lastLineStartOffset = lineStartOffset + lineStartOffset = charOffset + } + } + /** Convert a character digit to an Int according to given base, + * -1 if no success */ def digit2int(ch: Char, base: Int): Int = { if ('0' <= ch && ch <= '9' && ch < '0' + base) ch - '0' @@ -131,4 +95,13 @@ class CharArrayReader(buf: RandomAccessSeq[Char], start: Int, /* startline: int, else -1 } + + /** A new reader that takes off at the current character position */ + def lookaheadReader = new CharArrayReader { + val buf = self.buf + charOffset = self.charOffset + ch = self.ch + override def decodeUni = self.decodeUni + def error(offset: Int, msg: String) = self.error(offset, msg) + } } diff --git a/src/compiler/scala/tools/nsc/util/CharArrayReader1.scala b/src/compiler/scala/tools/nsc/util/CharArrayReader1.scala deleted file mode 100755 index 6d5843b0ec..0000000000 --- a/src/compiler/scala/tools/nsc/util/CharArrayReader1.scala +++ /dev/null @@ -1,107 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Martin Odersky - */ -// $Id: NewCharArrayReader.scala 16893 2009-01-13 13:09:22Z cunei $ - -package scala.tools.nsc.util - -import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} - -abstract class CharArrayReader1 { self => - - val buf: Array[Char] - - def decodeUni: Boolean = true - - /** An error routine to call on bad unicode escapes \\uxxxx. */ - protected def error(offset: Int, msg: String) - - /** the last read character */ - var ch: Char = _ - - /** The offset one past the last read character */ - var charOffset: Int = 0 - - /** The start offset of the current line */ - var lineStartOffset: Int = 0 - - /** The start offset of the line before the current one */ - var lastLineStartOffset: Int = 0 - - private var lastUnicodeOffset = -1 - - /** Is last character a unicode escape \\uxxxx? */ - def isUnicodeEscape = charOffset == lastUnicodeOffset - - /** Advance one character */ - final def nextChar() { - if (charOffset >= buf.length) { - ch = SU - } else { - val c = buf(charOffset) - ch = c - charOffset += 1 - if (c == '\\') potentialUnicode() - else if (c < ' ') potentialLineEnd() -// print("`"+ch+"'") - } - } - - /** Interpret \\uxxxx escapes */ - private def potentialUnicode() { - def evenSlashPrefix: Boolean = { - var p = charOffset - 2 - while (p >= 0 && buf(p) == '\\') p -= 1 - (charOffset - p) % 2 == 0 - } - def udigit: Int = { - val d = digit2int(buf(charOffset), 16) - if (d >= 0) charOffset += 1 - else error(charOffset, "error in unicode escape") - d - } - if (charOffset < buf.length && buf(charOffset) == 'u' && decodeUni && evenSlashPrefix) { - do charOffset += 1 - while (charOffset < buf.length && buf(charOffset) == 'u') - val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit - lastUnicodeOffset = charOffset - ch = code.toChar - } - } - - /** Handle line ends, replace CR+LF by LF */ - private def potentialLineEnd() { - if (ch == CR) - if (charOffset < buf.length && buf(charOffset) == LF) { - charOffset += 1 - ch = LF - } - if (ch == LF || ch == FF) { - lastLineStartOffset = lineStartOffset - lineStartOffset = charOffset - } - } - - /** Convert a character digit to an Int according to given base, - * -1 if no success */ - def digit2int(ch: Char, base: Int): Int = { - if ('0' <= ch && ch <= '9' && ch < '0' + base) - ch - '0' - else if ('A' <= ch && ch < 'A' + base - 10) - ch - 'A' + 10 - else if ('a' <= ch && ch < 'a' + base - 10) - ch - 'a' + 10 - else - -1 - } - - /** A new reader that takes off at the current character position */ - def lookaheadReader = new CharArrayReader1 { - val buf = self.buf - charOffset = self.charOffset - ch = self.ch - override def decodeUni = self.decodeUni - def error(offset: Int, msg: String) = self.error(offset, msg) - } -} diff --git a/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala new file mode 100755 index 0000000000..175fda193a --- /dev/null +++ b/src/compiler/scala/tools/nsc/util/JavaCharArrayReader.scala @@ -0,0 +1,134 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2009 LAMP/EPFL + * @author Martin Odersky + */ +// $Id: CharArrayReader.scala 17610 2009-04-30 22:38:36Z extempore $ + +package scala.tools.nsc.util + +import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} + +class JavaCharArrayReader(buf: RandomAccessSeq[Char], start: Int, /* startline: int, startcol: int, */ + decodeUni: Boolean, error: String => Unit) extends Iterator[Char] with Cloneable { + + def this(buf: RandomAccessSeq[Char], decodeUni: Boolean, error: String => Unit) = + this(buf, 0, /* 1, 1, */ decodeUni, error) + + /** produce a duplicate of this char array reader which starts reading + * at current position, independent of what happens to original reader + */ + def dup: JavaCharArrayReader = clone().asInstanceOf[JavaCharArrayReader] + + /** layout constant + */ + val tabinc = 8 + + /** the line and column position of the current character + */ + var ch: Char = _ + var bp = start + var oldBp = -1 + var oldCh: Char = _ + + //private var cline: Int = _ + //private var ccol: Int = _ + def cpos = bp + var isUnicode: Boolean = _ + var lastLineStartPos: Int = 0 + var lineStartPos: Int = 0 + var lastBlankLinePos: Int = 0 + + private var onlyBlankChars = false + //private var nextline = startline + //private var nextcol = startcol + + private def markNewLine() { + lastLineStartPos = lineStartPos + if (onlyBlankChars) lastBlankLinePos = lineStartPos + lineStartPos = bp + onlyBlankChars = true + //nextline += 1 + //nextcol = 1 + } + + def hasNext: Boolean = if (bp < buf.length) true + else { + false + } + + def last: Char = if (bp > start + 2) buf(bp - 2) else ' ' // XML literals + + def next: Char = { + //cline = nextline + //ccol = nextcol + val buf = this.buf.asInstanceOf[runtime.BoxedCharArray].value + if(!hasNext) { + ch = SU + return SU // there is an endless stream of SU's at the end + } + oldBp = bp + oldCh = ch + ch = buf(bp) + isUnicode = false + bp = bp + 1 + ch match { + case '\t' => + // nextcol = ((nextcol - 1) / tabinc * tabinc) + tabinc + 1; + case CR => + if (bp < buf.size && buf(bp) == LF) { + ch = LF + bp += 1 + } + markNewLine() + case LF | FF => + markNewLine() + case '\\' => + def evenSlashPrefix: Boolean = { + var p = bp - 2 + while (p >= 0 && buf(p) == '\\') p -= 1 + (bp - p) % 2 == 0 + } + def udigit: Int = { + val d = digit2int(buf(bp), 16) + if (d >= 0) { bp += 1; /* nextcol = nextcol + 1 */ } + else error("error in unicode escape"); + d + } + // nextcol += 1 + if (buf(bp) == 'u' && decodeUni && evenSlashPrefix) { + do { + bp += 1 //; nextcol += 1 + } while (buf(bp) == 'u'); + val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit + ch = code.asInstanceOf[Char] + isUnicode = true + } + case _ => + if (ch > ' ') onlyBlankChars = false + // nextcol += 1 + } + ch + } + + def rewind { + if (oldBp == -1) throw new IllegalArgumentException + bp = oldBp + ch = oldCh + oldBp = -1 + oldCh = 'x' + } + + def copy: JavaCharArrayReader = + new JavaCharArrayReader(buf, bp, /* nextcol, nextline, */ decodeUni, error) + + def digit2int(ch: Char, base: Int): Int = { + if ('0' <= ch && ch <= '9' && ch < '0' + base) + ch - '0' + else if ('A' <= ch && ch < 'A' + base - 10) + ch - 'A' + 10 + else if ('a' <= ch && ch < 'a' + base - 10) + ch - 'a' + 10 + else + -1 + } +} diff --git a/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala b/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala deleted file mode 100644 index 9bec95297f..0000000000 --- a/src/compiler/scala/tools/nsc/util/NewCharArrayReader.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2009 LAMP/EPFL - * @author Martin Odersky - */ -// $Id$ - -package scala.tools.nsc.util - -import scala.tools.nsc.util.SourceFile.{LF, FF, CR, SU} - -class NewCharArrayReader(val buf: RandomAccessSeq[Char], // should not change - decodeUni: Boolean, error: (Int,String) => Unit) extends Iterator[Char] { - private var idx : Int = 0 - private var isUnicode0 = false - def isUnicode = isUnicode0 - - private val bufLength = buf.length - def seek(offset : Int) = { - assert(offset <= bufLength) - idx = offset - } - def offset = idx - def withOffset = new Iterator[(Int,Char)] { - def hasNext = NewCharArrayReader.this.hasNext - def next = (offset, NewCharArrayReader.this.next) - } - override def hasNext = { // could be padded - if (idx == bufLength - 1) buf(idx) != SU - else idx < bufLength - } - override def next : Char = { - isUnicode0 = false - if (!hasNext) return SU - var ch = buf(idx) - idx = idx + 1 - ch match { - case CR if (idx + 1 < length && buf(idx + 1) == LF) => - idx += 1; ch = LF - case LF | FF => - case '\\' => - def evenSlashPrefix: Boolean = { - var p = idx - 2 - while (p >= 0 && buf(p) == '\\') p = p - 1; - (idx - p) % 2 == 0 - } - def udigit: Int = { - val d = digit2int(buf(idx), 16) - if (d >= 0) { idx = idx + 1 } - else if (error != null) error(idx, "error in unicode escape"); - d - } - if (idx < bufLength && buf(idx) == 'u' && decodeUni && evenSlashPrefix) { - do { - idx = idx + 1; // nextcol = nextcol + 1; - } while (idx < bufLength && buf(idx) == 'u'); - val code = udigit << 12 | udigit << 8 | udigit << 4 | udigit - isUnicode0 = true - ch = code.asInstanceOf[Char] - } - case _ => - } - ch - } - def digit2int(ch: Char, base: Int): Int = { - if ('0' <= ch && ch <= '9' && ch < '0' + base) - ch - '0' - else if ('A' <= ch && ch < 'A' + base - 10) - ch - 'A' + 10 - else if ('a' <= ch && ch < 'a' + base - 10) - ch - 'a' + 10 - else - -1 - } -} diff --git a/src/compiler/scala/tools/nsc/util/Position.scala b/src/compiler/scala/tools/nsc/util/Position.scala index f3e76cc3a5..b336e64c62 100644 --- a/src/compiler/scala/tools/nsc/util/Position.scala +++ b/src/compiler/scala/tools/nsc/util/Position.scala @@ -16,6 +16,14 @@ trait Position { def offset: Option[Int] = None def source: Option[SourceFile] = None + def start: Int = mid + def mid: Int = offset.get + def end: Int = mid + + def startOrElse(d: Int) = offset.get//OrElse(d) + def midOrElse(d: Int) = offset.get//OrElse(d) + def endOrElse(d: Int) = offset.get//OrElse(d) + def line: Option[Int] = if (offset.isEmpty || source.isEmpty) None else Some(source.get.offsetToLine(offset.get) + 1) @@ -75,6 +83,7 @@ case class FakePos(msg: String) extends Position { override def toString=msg } +// ??? needed case class LinePosition(source0: SourceFile, line0: Int) extends Position { assert(line0 >= 1) override def offset = None @@ -90,10 +99,15 @@ case class OffsetPosition(source0: SourceFile, offset0: Int) extends Position { case that : OffsetPosition => offset0 == that.offset0 && source0.file == that.source0.file case that => false } - override def hashCode = offset0 + source0.file.hashCode + override def hashCode = offset0 * 37 + source0.file.hashCode } /** new for position ranges */ -class RangePosition(source0: SourceFile, offset0: Int, start: Int, end: Int) -extends OffsetPosition(source0, offset0) +class RangePosition(source0: SourceFile, override val start: Int, override val mid: Int, override val end: Int) +extends OffsetPosition(source0, mid) { + override def startOrElse(d: Int) = start + override def midOrElse(d: Int) = mid + override def endOrElse(d: Int) = end +} + |