diff options
Diffstat (limited to 'src/dotty/tools/dotc/parsing/Parsers.scala')
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 976 |
1 files changed, 451 insertions, 525 deletions
diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 12a828300..d88d9afab 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -7,6 +7,7 @@ import scala.collection.immutable.BitSet import util.{ SourceFile, FreshNameCreator } import Tokens._ import Scanners._ +import MarkupParsers._ import core._ import Flags._ import Contexts._ @@ -20,44 +21,9 @@ import Types._ import Constants._ import NameOps._ import scala.reflect.internal.Chars._ +import ScriptParsers._ import annotation.switch - -/** <p>Performs the following context-free rewritings:</p> - * <ol> - * <li> - * Places all pattern variables in Bind nodes. In a pattern, for - * identifiers <code>x</code>:<pre> - * x => x @ _ - * x:T => x @ (_ : T)</pre> - * </li> - * <li>Removes pattern definitions (PatDef's) as follows: - * If pattern is a simple (typed) identifier:<pre> - * <b>val</b> x = e ==> <b>val</b> x = e - * <b>val</b> x: T = e ==> <b>val</b> x: T = e</pre> - * - * if there are no variables in pattern<pre> - * <b>val</b> p = e ==> e match (case p => ())</pre> - * - * if there is exactly one variable in pattern<pre> - * <b>val</b> x_1 = e <b>match</b> (case p => (x_1))</pre> - * - * if there is more than one variable in pattern<pre> - * <b>val</b> p = e ==> <b>private synthetic val</b> t$ = e <b>match</b> (case p => (x_1, ..., x_N)) - * <b>val</b> x_1 = t$._1 - * ... - * <b>val</b> x_N = t$._N</pre> - * </li> - * <li> - * Removes function types as follows:<pre> - * (argtpes) => restpe ==> scala.Function_n[argtpes, restpe]</pre> - * </li> - * <li> - * Wraps naked case definitions in a match as follows:<pre> - * { cases } ==> (x => x.match {cases})<span style="font-family:normal;">, except when already argument to match</span></pre> - * </li> - * </ol> - */ object Parsers { import UntypedTrees.{untpd, ugen} @@ -73,147 +39,56 @@ object Parsers { def nonePositive: Boolean = parCounts forall (_ <= 0) } + object Location extends Enumeration { + val InParens, InBlock, ElseWhere = Value + } - class Parser(val source: SourceFile)(implicit ctx: Context) extends DotClass { - -// def this(unit: CompilationUnit) = this(unit, List()) - - val in = new Scanner(source) + object ParamOwner extends Enumeration { + val Class, Type, TypeParam, Def = Value + } - /** The parse starting point depends on whether the source file is self-contained: - * if not, the AST will be supplemented. - */ - def parseStartRule = - if (source.isSelfContained) () => compilationUnit() - else () => scriptBody() + /** The parse starting point depends on whether the source file is self-contained: + * if not, the AST will be supplemented. + */ + def parser(source: SourceFile)(implicit ctx: Context) = + if (source.isSelfContained) new ScriptParser(source) + else new Parser(source) - def sourcePos(off: Int = in.offset): SourcePosition = - source atPos Position(off) + class Parser(val source: SourceFile)(implicit ctx: Context) extends DotClass { - /** the markup parser - lazy val xmlp = new MarkupParser(this, true) + val in = new Scanner(source) - object symbXMLBuilder extends SymbolicXMLBuilder(this, true) { // DEBUG choices - val global: self.global.type = self.global - def freshName(prefix: String): Name = SourceFileParser.this.freshName(prefix) - } - */ val openParens = new ParensCounters - def xmlLiteral() : Tree = ??? // xmlp.xLiteral - def xmlLiteralPattern() : Tree = ??? // xmlp.xLiteralPattern - /** This is the general parse entry point. + * Overridden by ScriptParser */ def parse(): Tree = { - val t = parseStartRule() + val t = compilationUnit() accept(EOF) t } - /** This is the parse entry point for code which is not self-contained, e.g. - * a script which is a series of template statements. They will be - * swaddled in Trees until the AST is equivalent to the one returned - * by compilationUnit(). - */ - def scriptBody(): Tree = unsupported("scriptBody") - /* TODO: reinstantiate - val stmts = templateStatSeq(false)._2 - accept(EOF) - - def mainModuleName = ctx.settings.script.value - - /** If there is only a single object template in the file and it has a - * suitable main method, we will use it rather than building another object - * around it. Since objects are loaded lazily the whole script would have - * been a no-op, so we're not taking much liberty. - */ - def searchForMain(): Option[Tree] = { - /** Have to be fairly liberal about what constitutes a main method since - * nothing has been typed yet - for instance we can't assume the parameter - * type will look exactly like "Array[String]" as it could have been renamed - * via import, etc. - */ - def isMainMethod(t: Tree) = t match { - case DefDef(_, nme.main, Nil, List(_), _, _) => true - case _ => false - } - /** For now we require there only be one top level object. */ - var seenModule = false - val newStmts = stmts collect { - case t @ Import(_, _) => t - case md @ ModuleDef(mods, name, template) - if !seenModule && (template.body exists isMainMethod) => - seenModule = true - /** This slightly hacky situation arises because we have no way to communicate - * back to the scriptrunner what the name of the program is. Even if we were - * willing to take the sketchy route of settings.script.value = progName, that - * does not work when using fsc. And to find out in advance would impose a - * whole additional parse. So instead, if the actual object's name differs from - * what the script is expecting, we transform it to match. - */ - md.derivedModuleDef(mods, mainModuleName.toTermName, template) - case _ => - /** If we see anything but the above, fail. */ - return None - } - Some(makePackaging(0, emptyPkg, newStmts)) - } - - if (mainModuleName == ScriptRunner.defaultScriptMain) - searchForMain() foreach { return _ } - - /** Here we are building an AST representing the following source fiction, - * where <moduleName> is from -Xscript (defaults to "Main") and <stmts> are - * the result of parsing the script file. - * - * object <moduleName> { - * def main(argv: Array[String]): Unit = { - * val args = argv - * new AnyRef { - * <stmts> - * } - * } - * } - */ - import definitions._ - - def emptyPkg = atPos(0, 0, 0) { Ident(nme.EMPTY_PACKAGE_NAME) } - def emptyInit = DefDef( - Modifiers(), - nme.CONSTRUCTOR, - Nil, - List(Nil), - TypeTree(), - Block(List(Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil)), Literal(Constant(()))) - ) - - // def main - def mainParamType = AppliedTypeTree(Ident(tpnme.Array), List(Ident(tpnme.String))) - def mainParameter = List(ValDef(Modifiers(Param), "argv", mainParamType, EmptyTree)) - def mainSetArgv = List(ValDef(Modifiers(), "args", TypeTree(), Ident("argv"))) - def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition) - def mainDef = DefDef(Modifiers(), nme.main, Nil, List(mainParameter), scalaDot(tpnme.Unit), Block(mainSetArgv, mainNew)) - - // object Main - def moduleName = ScriptRunner scriptMain settings - def moduleBody = Template(List(scalaScalaObjectConstr), emptyValDef, List(emptyInit, mainDef)) - def moduleDef = ModuleDef(Modifiers(), moduleName, moduleBody) +/* -------------- TOKEN CLASSES ------------------------------------------- */ - // package <empty> { ... } - makePackaging(0, emptyPkg, List(moduleDef)) - }*/ + def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT + def isIdent(name: Name) = in.token == IDENTIFIER && in.name == name + def isLiteral = literalTokens contains in.token + def isNumericLit = numericLitTokens contains in.token + def isModifier = modifierTokens contains in.token + def isExprIntro = canStartExpressionTokens contains in.token + def isTemplateIntro = templateIntroTokens contains in.token + def isDclIntro = dclIntroTokens contains in.token + def isStatSeqEnd = in.token == RBRACE || in.token == EOF + def mustStartStat = mustStartStatTokens contains in.token - /* --------------- PLACEHOLDERS ------------------------------------------- */ + def isDefIntro(allowedMods: BitSet) = + in.token == AT || (allowedMods contains in.token) || (defIntroTokens contains in.token) - def isWildcard(t: Tree): Boolean = t match { - case Ident(nme.WILDCARD) => true - case Typed(t1, _) => isWildcard(t1) - case Annotated(t1, _) => isWildcard(t1) - case _ => false - } + def isStatSep: Boolean = + in.token == NEWLINE || in.token == NEWLINES || in.token == SEMI - /* ------------- POSITIONS ------------------------------------------- */ +/* ------------- POSITIONS ------------------------------------------- */ def atPos[T <: Positioned](start: Offset, point: Offset, end: Offset)(t: T): T = atPos(Position(start, end, point))(t) @@ -227,30 +102,26 @@ object Parsers { def atPos[T <: Positioned](pos: Position)(t: T): T = if (t.pos.isSourceDerived) t else t.withPos(pos) - def here[T <: Positioned]: T => T = { - val start = in.offset - t => atPos(start, start)(t) - } - def tokenRange = Position(in.offset, in.lastCharOffset) -/* ------------- ERROR HANDLING ------------------------------------------- */ + def sourcePos(off: Int = in.offset): SourcePosition = + source atPos Position(off) - private var inFunReturnType = false - private def fromWithinReturnType[T](body: => T): T = { - val saved = inFunReturnType - try { - inFunReturnType = true - body - } finally inFunReturnType = saved - } +/* ------------- ERROR HANDLING ------------------------------------------- */ - private var lastDefOffset = -1 + /** The offset of the last time when a statement on a new line was definitely + * encountered in the current scope or an outer scope\ + */ + private var lastStatOffset = -1 - def setLastDefOffset() = - if ((mustStartStatTokens contains in.token) && in.isAfterLineEnd) - lastDefOffset = in.offset + def setLastStatOffset() = + if (mustStartStat && in.isAfterLineEnd) + lastStatOffset = in.offset + /** Is offset1 less or equally indented than offset2? + * This is the case if the characters between the preceding end-of-line and offset1 + * are a prefix of the characters between the preceding end-of-line and offset2. + */ def isLeqIndented(offset1: Int, offset2: Int): Boolean = { def lineStart(off: Int): Int = if (off > 0 && source(off) != LF) lineStart(off - 1) @@ -261,7 +132,16 @@ object Parsers { recur(lineStart(offset1), lineStart(offset2)) } - protected def skip(targetToken: Int = EOF) { + /** Skip on error to next safe point. + * Safe points are: + * - Closing braces, provided they match an opening brace before the error point. + * - Closing parens and brackets, provided they match an opening parent or bracket + * before the error point and there are no intervening other kinds of parens. + * - Semicolons and newlines, provided there are no intervening braces. + * - Definite statement starts on new lines, provided they are not more indented + * than the last known statement start before the error point. + */ + protected def skip() { val skippedParens = new ParensCounters while (true) { (in.token: @switch) match { @@ -288,13 +168,11 @@ object Parsers { case LBRACKET=> skippedParens.change(LBRACKET, +1) case _ => + if (mustStartStat && + in.isAfterLineEnd() && + isLeqIndented(in.offset, lastStatOffset)) + return } - if ( (mustStartStatTokens contains in.token) && - in.isAfterLineEnd() && - isLeqIndented(in.offset, lastDefOffset) - || targetToken == in.token && - skippedParens.nonePositive) - return in.nextToken() } } @@ -305,26 +183,38 @@ object Parsers { def deprecationWarning(msg: String, offset: Int = in.offset) = ctx.deprecationWarning(msg, source atPos Position(offset)) - /** whether a non-continuable syntax error has been seen */ + /** The offset where the last syntax error was reported, or if a skip to a + * safepoint occurred afterwards, the offset of the safe point. + */ private var lastErrorOffset : Int = -1 + /** Issue an error at given offset if beyond last error offset + * and update lastErrorOffset. + */ def syntaxError(msg: String, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { syntaxError(msg, Position(offset)) lastErrorOffset = in.offset } + /** Unconditionally issue an error at given position, without + * updating lastErrorOffset. + */ def syntaxError(msg: String, pos: Position): Unit = ctx.error(msg, source atPos pos) + /** Issue an error at current offset taht input is incomplete */ def incompleteInputError(msg: String) = ctx.reporter.incompleteInputError(msg, source atPos Position(in.offset)) + /** If at end of file, issue an incompleteInputError. + * Otherwise issue a syntax error and skip to next safe point. + */ def syntaxErrorOrIncomplete(msg: String) = if (in.token == EOF) incompleteInputError(msg) - else { syntaxError(msg); skip() } + else { syntaxError(msg); skip(); lastErrorOffset = in.offset } - def expectedMsg(token: Int): String = + private def expectedMsg(token: Int): String = showToken(token) + " expected but " + showToken(in.token) + " found." /** Consume one token of the specified type, or @@ -347,33 +237,19 @@ object Parsers { case _ => accept(SEMI) } - def acceptStatSepOpt(altEnd: Token = EOF) = - if (!isStatSeqEnd) acceptStatSep() - - def errorTermTree = here(Literal(Constant(null))) - - /** Check that type parameter is not by name or repeated */ - def checkNotByNameArgs(tpt: Tree) = - if (TreeInfo.isByNameParamType(tpt)) - syntaxError("no by-name parameter type allowed here", tpt.pos) - -/* -------------- TOKEN CLASSES ------------------------------------------- */ - - def isUnaryOp = isIdent && nme.raw.isUnary(in.name) - def isRawStar = isIdent && in.name == nme.raw.STAR - def isRawBar = isIdent && in.name == nme.raw.BAR - def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT - def isIdent(name: Name) = in.token == IDENTIFIER && in.name == name - def isLiteral = literalTokens contains in.token - def isExprIntro = canStartExpressionTokens contains in.token - def isTypeIntro: Boolean = canStartTypeTokens contains in.token - def isStatSeqEnd = in.token == RBRACE || in.token == EOF + def acceptStatSepUnlessAtEnd(altEnd: Token = EOF) = + if (!isStatSeqEnd && in.token != altEnd) acceptStatSep() - def isDefIntro(allowedMods: BitSet) = - in.token == AT || (allowedMods contains in.token) || (defIntroTokens contains in.token) + def errorTermTree = atPos(in.offset) { Literal(Constant(null)) } - def isStatSep: Boolean = - in.token == NEWLINE || in.token == NEWLINES || in.token == SEMI + private var inFunReturnType = false + private def fromWithinReturnType[T](body: => T): T = { + val saved = inFunReturnType + try { + inFunReturnType = true + body + } finally inFunReturnType = saved + } /* ---------- TREE CONSTRUCTION ------------------------------------------- */ @@ -387,13 +263,13 @@ object Parsers { /** Convert tree to formal parameter */ - def convertToParam(tree: Tree, mods: Modifiers = Modifiers()): ValDef = tree match { + def convertToParam(tree: Tree, mods: Modifiers = Modifiers(), expected: String = "formal parameter"): ValDef = tree match { case Ident(name) => Parameter(name.asTermName, TypeTree(), mods) withPos tree.pos case Typed(Ident(name), tpt) if tpt.isType => Parameter(name.asTermName, tpt, mods) withPos tree.pos case _ => - syntaxError("not a legal formal parameter", tree.pos) + syntaxError(s"not a legal $expected", tree.pos) Parameter(nme.ERROR, tree, mods) } @@ -409,13 +285,54 @@ object Parsers { tree } -/* --------- OPERAND/OPERATOR STACK --------------------------------------- */ +/* -------------- XML ---------------------------------------------------- */ + + /** the markup parser */ + lazy val xmlp = new MarkupParser(this, true) - object Location extends Enumeration { - val InParens, InBlock, ElseWhere = Value + object symbXMLBuilder extends SymbolicXMLBuilder(this, true) // DEBUG choices + + def xmlLiteral() : Tree = xmlp.xLiteral + def xmlLiteralPattern() : Tree = xmlp.xLiteralPattern + +/* -------- COMBINATORS -------------------------------------------------------- */ + + def enclosed[T](tok: Token, body: => T): T = { + accept(tok) + openParens.change(tok, 1) + try body + finally { + accept(tok + 1) + openParens.change(tok, -1) + } + } + + def inParens[T](body: => T): T = enclosed(LPAREN, body) + def inBraces[T](body: => T): T = enclosed(LBRACE, body) + def inBrackets[T](body: => T): T = enclosed(LBRACKET, body) + + def inDefScopeBraces[T](body: => T): T = { + val saved = lastStatOffset + try inBraces(body) + finally lastStatOffset = saved + } + + /** part { `separator` part } + */ + def tokenSeparated[T](separator: Int, part: () => T): List[T] = { + val ts = new ListBuffer[T] + while (in.token == separator) { + in.nextToken() + ts += part() + } + ts.toList } - var opstack: List[OpInfo] = Nil + def commaSeparated[T](part: () => T): List[T] = tokenSeparated(COMMA, part) + +/* --------- OPERAND/OPERATOR STACK --------------------------------------- */ + + var opStack: List[OpInfo] = Nil def precedence(operator: Name): Int = if (operator eq nme.ERROR) -1 @@ -436,98 +353,67 @@ object Parsers { } } - def checkSize(kind: String, size: Int, max: Int) { - if (size > max) syntaxError("too many "+kind+", maximum = "+max) - } - def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = if (TreeInfo.isLeftAssoc(op) != leftAssoc) syntaxError( "left- and right-associative operators with same precedence may not be mixed", offset) - def reduceStack(base: List[OpInfo], top0: Tree, prec: Int, leftAssoc: Boolean): Tree = { - var top = top0 - if (opstack != base && precedence(opstack.head.operator) == prec) - checkAssoc(opstack.head.offset, opstack.head.operator, leftAssoc) - while (opstack != base && - (prec < precedence(opstack.head.operator) || - leftAssoc && prec == precedence(opstack.head.operator))) { - val opinfo = opstack.head - opstack = opstack.tail - val opPos = Position(opinfo.offset, opinfo.offset + opinfo.operator.length) - val lPos = opinfo.operand.pos - val start = if (lPos.exists) lPos.start else opPos.start - val rPos = top.pos - val end = if (rPos.exists) rPos.end else opPos.end - top = atPos(start, opinfo.offset, end) { - InfixOp(opinfo.operand, opinfo.operator, top) + def reduceStack(base: List[OpInfo], top: Tree, prec: Int, leftAssoc: Boolean): Tree = { + if (opStack != base && precedence(opStack.head.operator) == prec) + checkAssoc(opStack.head.offset, opStack.head.operator, leftAssoc) + def recur(top: Tree): Tree = { + if (opStack == base) top + else { + val opInfo = opStack.head + val opPrec = precedence(opInfo.operator) + if (prec < opPrec || leftAssoc && prec == opPrec) { + opStack = opStack.tail + recur { + val opPos = Position(opInfo.offset, opInfo.offset + opInfo.operator.length) + atPos(opPos union opInfo.operand.pos union top.pos) { + InfixOp(opInfo.operand, opInfo.operator, top) + } + } + } + else top } } - top + recur(top) } + /** operand { infixop operand} [postfixop], + * respecting rules of associativity and precedence. + * @param notAnOperator a token that does not count as operator. + * @param maybePostfix postfix operators are allowed. + */ def infixOps( - first: Tree, canContinue: Token => Boolean, continue: () => Tree, - noOp: Name = nme.EMPTY, + first: Tree, canStartOperand: Token => Boolean, operand: () => Tree, + notAnOperator: Name = nme.EMPTY, maybePostfix: Boolean = false): Tree = { - val base = opstack + val base = opStack var top = first - while (isIdent && in.name != noOp) { + while (isIdent && in.name != notAnOperator) { val op = in.name top = reduceStack(base, top, precedence(op), TreeInfo.isLeftAssoc(op)) - opstack = OpInfo(top, op, in.offset) :: opstack + opStack = OpInfo(top, op, in.offset) :: opStack ident() - newLineOptWhenFollowing(canContinue) - if (maybePostfix && !canContinue(in.token)) { - val topinfo = opstack.head - opstack = opstack.tail - val od = reduceStack(base, topinfo.operand, 0, true) - return atPos(od.pos.start, topinfo.offset) { - PostfixOp(od, topinfo.operator) + newLineOptWhenFollowing(canStartOperand) + if (maybePostfix && !canStartOperand(in.token)) { + val topInfo = opStack.head + opStack = opStack.tail + val od = reduceStack(base, topInfo.operand, 0, true) + return atPos(od.pos.start, topInfo.offset) { + PostfixOp(od, topInfo.operator) } } - top = continue() + top = operand() } reduceStack(base, top, 0, true) } -/* -------- COMBINATORS -------------------------------------------------------- */ - - def enclosed[T](tok: Token, body: => T): T = { - accept(tok) - openParens.change(tok, 1) - try body - finally { - accept(tok + 1) - openParens.change(tok, -1) - } - } - - def inParens[T](body: => T): T = enclosed(LPAREN, body) - def inBraces[T](body: => T): T = enclosed(LBRACE, body) - def inBrackets[T](body: => T): T = enclosed(LBRACKET, body) - - def inDefScopeBraces[T](body: => T): T = { - val saved = lastDefOffset - try inBraces(body) - finally lastDefOffset = saved - } - - /** part { `sep` part } - * Or if sepFirst is true, { `sep` part } - */ - def tokenSeparated[T](separator: Int, part: () => T): List[T] = { - val ts = new ListBuffer[T] - while (in.token == separator) { - in.nextToken() - ts += part() - } - ts.toList - } - def commaSeparated[T](part: () => T): List[T] = tokenSeparated(COMMA, part) - /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ + /** Accept identifier and return its name as a term name. */ def ident(): TermName = if (isIdent) { val name = in.name @@ -538,10 +424,12 @@ object Parsers { nme.ERROR } + /** Accept identifier and return Ident with its name as a term name. */ def termIdent(): Ident = atPos(in.offset) { makeIdent(in.token, ident()) } + /** Accept identifier and return Ident with its name as a type name. */ def typeIdent(): Ident = atPos(in.offset) { makeIdent(in.token, ident().toTypeName) } @@ -550,6 +438,7 @@ object Parsers { if (tok == BACKQUOTED_IDENT) new BackquotedIdent(name) else Ident(name) + /** IdentOrWildcard ::= id | `_' */ def identOrWildcard(): Name = if (in.token == USCORE) { in.nextToken(); nme.WILDCARD } else ident() @@ -559,15 +448,28 @@ object Parsers { def termIdentOrWildcard(): Ident = if (in.token == USCORE) wildcardIdent() else termIdent() + /** Accept identifier acting as a selector on given tree `t`. */ def selector(t: Tree): Tree = atPos(t.pos.start, in.offset) { Select(t, ident()) } + /** Selectors ::= ident { `.' ident() + * + * Accept `.' separated identifiers acting as a selectors on given tree `t`. + * @param finish An alternative parse in case the next token is not an identifier. + * If the alternative does not apply, its tree argument is returned unchanged. + */ def selectors(t: Tree, finish: Tree => Tree): Tree = { val t1 = finish(t) if (t1 ne t) t1 else dotSelectors(selector(t), finish) } - def dotSelectors(t: Tree, finish: Tree => Tree = id) = + /** Dotelectors ::= { `.' ident() + * + * Accept `.' separated identifiers acting as a selectors on given tree `t`. + * @param finish An alternative parse in case the token following a `.' is not an identifier. + * If the alternative does not apply, its tree argument is returned unchanged. + */ + def dotSelectors(t: Tree, finish: Tree => Tree = id) = if (in.token == DOT) { in.nextToken(); selectors(t, finish) } else t @@ -575,14 +477,18 @@ object Parsers { /** Path ::= StableId * | [Ident `.'] this - * SimpleType ::= Path [`.' type] + * + * @param thisOK If true, [Ident `.'] this is acceptable as the path. + * If false, another selection is required aftre the `this`. + * @param finish An alternative parse in case the token following a `.' is not an identifier. + * If the alternative does not apply, its tree argument is returned unchanged. */ def path(thisOK: Boolean, finish: Tree => Tree = id): Tree = { val start = in.offset def handleThis(name: TypeName) = { in.nextToken() val t = atPos(start) { This(name) } - if (in.token != DOT && !thisOK) syntaxError("'.' expected") + if (!thisOK && in.token != DOT) syntaxError("`.' expected") dotSelectors(t, finish) } def handleSuper(name: TypeName) = { @@ -601,7 +507,8 @@ object Parsers { if (in.token == THIS) handleThis(t.name.toTypeName) else if (in.token == SUPER) handleSuper(t.name.toTypeName) else selectors(t, finish) - } else t + } + else t } } @@ -626,29 +533,33 @@ object Parsers { /** SimpleExpr ::= literal * | symbol * | null - * @note The returned tree does not yet have a position + * @param negOffset The offset of a preceding `-' sign, if any. + * If the literal is not negated, negOffset = in.offset. */ - def literal(isNegated: Boolean = false): Tree = { + def literal(negOffset: Int = in.offset): Tree = { def finish(value: Any): Tree = { - val t = Literal(Constant(value)) + val t = atPos(negOffset) { Literal(Constant(value)) } in.nextToken() t } - if (in.token == SYMBOLLIT) SymbolLit(in.strVal) - else finish(in.token match { - case CHARLIT => in.charVal - case INTLIT => in.intVal(isNegated).toInt - case LONGLIT => in.intVal(isNegated) - case FLOATLIT => in.floatVal(isNegated).toFloat - case DOUBLELIT => in.floatVal(isNegated) - case STRINGLIT => in.strVal - case TRUE => true - case FALSE => false - case NULL => null - case _ => - syntaxErrorOrIncomplete("illegal literal") - null - }) + val isNegated = negOffset < in.offset + atPos(negOffset) { + if (in.token == SYMBOLLIT) SymbolLit(in.strVal) + else finish(in.token match { + case CHARLIT => in.charVal + case INTLIT => in.intVal(isNegated).toInt + case LONGLIT => in.intVal(isNegated) + case FLOATLIT => in.floatVal(isNegated).toFloat + case DOUBLELIT => in.floatVal(isNegated) + case STRINGLIT => in.strVal + case TRUE => true + case FALSE => false + case NULL => null + case _ => + syntaxErrorOrIncomplete("illegal literal") + null + }) + } } /* ------------- NEW LINES ------------------------------------------------- */ @@ -672,10 +583,12 @@ object Parsers { if (in.token == NEWLINE && p(in.next.token)) newLineOpt() } - /* ------------- TYPES ---------------------------------------------------- */ +/* ------------- TYPES ------------------------------------------------------ */ - /** Type ::= FunArgTypes `=>' Type - * | InfixType + /** Type ::= FunArgTypes `=>' Type + * | InfixType + * FunArgTypes ::= InfixType + * | `(' [ FunArgType {`,' FunArgType } ] `)' */ def typ(): Tree = { val start = in.offset @@ -685,18 +598,24 @@ object Parsers { if (in.token == RPAREN) { in.nextToken() atPos(start, accept(ARROW)) { Function(Nil, typ()) } - } else { + } + else { + openParens.change(LPAREN, 1) val ts = commaSeparated(funArgType) + openParens.change(LPAREN, -1) accept(RPAREN) if (in.token == ARROW) atPos(start, in.skipToken()) { Function(ts, typ()) } else { - ts foreach checkNotByNameArgs + for (t <- ts) + if (TreeInfo.isByNameParamType(t)) + syntaxError("no by-name parameter type allowed here", t.pos) val tuple = atPos(start) { ugen.mkTuple(ts) } infixTypeRest(refinedTypeRest(simpleTypeRest(tuple))) } } - } else infixType() + } + else infixType() in.token match { case ARROW => atPos(start, in.skipToken()) { Function(List(t), typ()) } @@ -732,7 +651,7 @@ object Parsers { */ def simpleType(): Tree = simpleTypeRest { if (in.token == LPAREN) - atPos(in.offset) { inParens(ugen.mkTuple(argTypes)) } + atPos(in.offset) { ugen.mkTuple(inParens(argTypes())) } else path(thisOK = false, handleSingletonType) match { case r @ SingletonTypeTree(_) => r case r => convertToTypeId(r) @@ -759,7 +678,7 @@ object Parsers { /** ArgType ::= Type | `_' TypeBounds */ - def argType(): Tree = + val argType = () => if (in.token == USCORE) { val start = in.skipToken() typeBounds().withPos(Position(start, in.offset)) @@ -772,7 +691,7 @@ object Parsers { /** FunArgType ::= ArgType | `=>' ArgType */ - def funArgType(): Tree = + val funArgType = () => if (in.token == ARROW) atPos(in.skipToken()) { PrefixOp(nme.ARROWkw, argType()) } else argType() @@ -784,7 +703,7 @@ object Parsers { val t = argType() if (isIdent(nme.raw.STAR)) { in.nextToken() - atPos(t.pos.start) { PostfixOp(typ(), nme.raw.STAR) } + atPos(t.pos.start) { PostfixOp(t, nme.raw.STAR) } } else t } @@ -842,7 +761,7 @@ object Parsers { def condExpr(altToken: Token): Tree = { if (in.token == LPAREN) { - val t = atPos(in.offset) { inParens(Parens(exprInParens)) } + val t = atPos(in.offset) { Parens(inParens(exprInParens())) } if (in.token == altToken) in.nextToken() t } else { @@ -868,11 +787,9 @@ object Parsers { * | `do' Expr [semi] `while' Expr * | `try' Expr Catches [`finally' Expr] * | `try' Expr [`finally' Expr] - * | `for' (`(' Enumerators `)' | `{' Enumerators `}') - * {nl} [`yield'] Expr - * | `for' Enumerators (`do' Expr | `yield' Expr) * | `throw' Expr * | `return' [Expr] + * | ForExpr * | [SimpleExpr `.'] Id `=' Expr * | SimpleExpr1 ArgumentExprs `=' Expr * | PostfixExpr [Ascription] @@ -883,8 +800,8 @@ object Parsers { * | `:' Annotation {Annotation} * | `:' `_' `*' */ - def exprInParens(): Tree = expr(Location.InParens) - def exprInBlock(): Tree = expr(Location.InBlock) + val exprInParens = () => expr(Location.InParens) + def expr(): Tree = expr(Location.ElseWhere) def expr(location: Location.Value): Tree = { @@ -893,7 +810,7 @@ object Parsers { else t } - def expr1(location: Location.Value): Tree = in.token match { + def expr1(location: Location.Value = Location.ElseWhere): Tree = in.token match { case IF => atPos(in.skipToken()) { val cond = condExpr(THEN) @@ -931,40 +848,12 @@ object Parsers { else EmptyTree() Try(body, catches, finalizer) } - case FOR => - atPos(in.skipToken()) { - var wrappedEnums = true - val enums = - if (in.token == LBRACE) inBraces(enumerators()) - else if (in.token == LPAREN) { - val lparenOffset = in.skipToken() - val pats = patternsOpt() - val pat = - if (in.token == RPAREN) { - wrappedEnums = false - in.nextToken() - atPos(lparenOffset) { ugen.mkTuple(pats) } - } - else if (pats.length == 1) pats.head - else errorTermTree - val res = generatorRest(pat) :: enumeratorsRest() - if (wrappedEnums) accept(RPAREN) - res - } else { - wrappedEnums = false - enumerators() - } - if (in.token == YIELD) ForYield(enums, expr()) - else if (in.token == DO) ForDo(enums, expr()) - else { - if (!wrappedEnums) syntaxErrorOrIncomplete("`yield' or `do' expected") - ForDo(enums, expr()) - } - } case THROW => atPos(in.skipToken()) { Throw(expr()) } case RETURN => atPos(in.skipToken()) { Return(if (isExprIntro) expr() else EmptyTree(), EmptyTree()) } + case FOR => + forExpr() case IMPLICIT => atPos(in.skipToken()) { implicitClosure(in.skipToken(), location) } case _ => @@ -992,16 +881,16 @@ object Parsers { def ascription(t: Tree, location: Location.Value) = atPos(t.pos.start, in.skipToken()) { in.token match { case USCORE => - val uscorePos = in.skipToken() + val uscoreStart = in.skipToken() if (isIdent(nme.raw.STAR)) { in.nextToken() if (in.token != RPAREN) syntaxError("`_*' can be used only for last argument") - Typed(t, atPos(uscorePos) { Ident(tpnme.WILDCARD_STAR) }) + Typed(t, atPos(uscoreStart) { Ident(tpnme.WILDCARD_STAR) }) } else { syntaxErrorOrIncomplete("`*' expected"); t } case AT => - (t /: annotations(skipNewLines = false)) ((t, annot) => Annotated(annot, t)) + (t /: annotations()) ((t, annot) => Annotated(annot, t)) case _ => Typed(t, typeOrInfixType(location)) } @@ -1011,13 +900,14 @@ object Parsers { * BlockResult ::= implicit Id [`:' InfixType] `=>' Block */ def implicitClosure(start: Int, location: Location.Value): Tree = { + val mods = atPos(start) { Modifiers(Implicit) } val id = termIdent() val paramExpr = if (location == Location.InBlock && in.token == COLON) atPos(id.pos.start, in.skipToken()) { Typed(id, infixType()) } else id - val param = convertToParam(paramExpr, Modifiers(Implicit)) + val param = convertToParam(paramExpr, mods) closureRest(start, location, param :: Nil) } @@ -1037,14 +927,14 @@ object Parsers { /** PrefixExpr ::= [`-' | `+' | `~' | `!'] SimpleExpr */ val prefixExpr = () => - if (isIdent && nme.raw.isUnary(in.name)) - atPos(in.offset) { - val name = ident() - if (name == nme.raw.MINUS && (numericLitTokens contains in.token)) - simpleExprRest(literal(isNegated = true), canApply = true) - else - PrefixOp(name, simpleExpr()) - } + if (isIdent && nme.raw.isUnary(in.name)) { + val start = in.offset + val name = ident() + if (name == nme.raw.MINUS && isNumericLit) + simpleExprRest(literal(start), canApply = true) + else + atPos(start) { PrefixOp(name, simpleExpr()) } + } else simpleExpr() /** SimpleExpr ::= new Template @@ -1066,9 +956,9 @@ object Parsers { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => path(thisOK = true) case USCORE => - atPos(in.skipToken()) { Ident(nme.WILDCARD) } + wildcardIdent() case LPAREN => - atPos(in.offset) { inParens(ugen.mkTuple(commaSeparated(exprInParens))) } + atPos(in.offset) { ugen.mkTuple(inParens(exprsInParensOpt())) } case LBRACE => canApply = false blockExpr() @@ -1076,8 +966,7 @@ object Parsers { canApply = false atPos(in.skipToken()) { New(template()) } case _ => - if (literalTokens contains in.token) - atPos(in.offset) { literal() } + if (isLiteral) literal() else { syntaxErrorOrIncomplete("illegal start of simple expression") errorTermTree @@ -1105,38 +994,43 @@ object Parsers { } } + /** ExprsInParens ::= ExprInParens {`,' ExprInParens} + */ + def exprsInParensOpt(): List[Tree] = + if (in.token == RPAREN) Nil else commaSeparated(exprInParens) + /** ArgumentExprs ::= `(' [ExprsInParens] `)' * | `(' [ExprsInParens `,'] PostfixExpr `:' `_' `*' ')' \ * | [nl] BlockExpr */ - def argumentExprs(): List[Tree] = { - def arg() = exprInParens() match { - case a @ Assign(Ident(id), rhs) => a.derivedNamedArg(id, rhs) - case e => e - } - in.token match { - case LBRACE => List(blockExpr()) - case LPAREN => inParens(if (in.token == RPAREN) Nil else commaSeparated(arg)) - case _ => Nil - } + def argumentExprs(): List[Tree] = + if (in.token == LBRACE) blockExpr() :: Nil + else inParens(if (in.token == RPAREN) Nil else commaSeparated(argumentExpr)) + + val argumentExpr = () => exprInParens() match { + case a @ Assign(Ident(id), rhs) => a.derivedNamedArg(id, rhs) + case e => e } /** ArgumentExprss ::= {ArgumentExprs} */ - def argumentExprss(): List[List[Tree]] = { + def argumentExprss(fn: Tree): Tree = { newLineOptWhenFollowedBy(LBRACE) - if (in.token == LPAREN || in.token == LBRACE) argumentExprs() :: argumentExprss() else Nil + if (in.token == LPAREN || in.token == LBRACE) argumentExprss(Apply(fn, argumentExprs())) + else fn } /** BlockExpr ::= `{' (CaseClauses | Block) `}' */ - def blockExpr(): Tree = inDefScopeBraces { - if (in.token == CASE) Match(EmptyTree(), caseClauses()) - else block() + def blockExpr(): Tree = atPos(in.offset) { + inDefScopeBraces { + if (in.token == CASE) Match(EmptyTree(), caseClauses()) + else block() + } } /** Block ::= BlockStatSeq - * @note Return tree does not carry position. + * @note Return tree does not carry source position. */ def block(): Tree = { val stats = blockStatSeq() @@ -1167,7 +1061,7 @@ object Parsers { if (in.token == IF) guard() else { val pat = pattern1() - if (in.token == EQUALS) atPos(pat.pos.start, in.skipToken()) { GenAlias(pat, expr) } + if (in.token == EQUALS) atPos(pat.pos.start, in.skipToken()) { GenAlias(pat, expr()) } else generatorRest(pat) } @@ -1178,10 +1072,52 @@ object Parsers { def generatorRest(pat: Tree) = atPos(pat.pos.start, accept(LARROW)) { GenFrom(pat, expr()) } - /** CaseClauses ::= CaseClause {CaseClause} + /** ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}') + * {nl} [`yield'] Expr + * | `for' Enumerators (`do' Expr | `yield' Expr) + */ + def forExpr(): Tree = atPos(in.skipToken()) { + var wrappedEnums = true + val enums = + if (in.token == LBRACE) inBraces(enumerators()) + else if (in.token == LPAREN) { + val lparenOffset = in.skipToken() + openParens.change(LPAREN, 1) + val pats = patternsOpt() + val pat = + if (in.token == RPAREN || pats.length > 1) { + wrappedEnums = false + accept(RPAREN) + openParens.change(LPAREN, -1) + atPos(lparenOffset) { ugen.mkTuple(pats) } // note: alternatives `|' need to be weeded out by typer. + } + else pats.head + val res = generatorRest(pat) :: enumeratorsRest() + if (wrappedEnums) { + accept(RPAREN) + openParens.change(LPAREN, -1) + } + res + } else { + wrappedEnums = false + enumerators() + } + if (in.token == YIELD) ForYield(enums, expr()) + else if (in.token == DO) ForDo(enums, expr()) + else { + if (!wrappedEnums) syntaxErrorOrIncomplete("`yield' or `do' expected") + ForDo(enums, expr()) + } + } + + /** CaseClauses ::= CaseClause {CaseClause} */ - def caseClauses(): List[CaseDef] = - caseClause() :: (if (in.token == CASE) caseClauses() else Nil) + def caseClauses(): List[CaseDef] = { + val buf = new ListBuffer[CaseDef] + buf += caseClause() + while (in.token == CASE) buf += caseClause() + buf.toList + } /** CaseClause ::= case Pattern [Guard] `=>' Block */ @@ -1194,7 +1130,7 @@ object Parsers { /** Pattern ::= Pattern1 { `|' Pattern1 } */ - def pattern(): Tree = { + val pattern = () => { val pat = pattern1() if (isIdent(nme.raw.BAR)) atPos(pat.pos.start) { Alternative(pat :: patternAlts()) } @@ -1218,7 +1154,7 @@ object Parsers { */ val pattern2 = () => infixPattern() match { case p @ Ident(name) if TreeInfo.isVarPattern(p) && in.token == AT => - atPos(p.pos.start, in.skipToken()) { Bind(name, infixType()) } + atPos(p.pos.start, in.skipToken()) { Bind(name, infixPattern()) } case p => p } @@ -1226,7 +1162,7 @@ object Parsers { /** InfixPattern ::= SimplePattern {Id [nl] SimplePattern} */ def infixPattern(): Tree = - infixOps(simplePattern(), canStartExpressionTokens, simplePattern, noOp = nme.raw.BAR) + infixOps(simplePattern(), canStartExpressionTokens, simplePattern, notAnOperator = nme.raw.BAR) /** SimplePattern ::= PatVar * | Literal @@ -1242,22 +1178,19 @@ object Parsers { val simplePattern = () => in.token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS => path(thisOK = true) match { - case id @ Ident(nme.raw.MINUS) if (numericLitTokens contains in.token) => - atPos(id.pos.start) { literal(isNegated = true) } - case t => - simplePatternRest(t) + case id @ Ident(nme.raw.MINUS) if isNumericLit => literal(id.pos.start) + case t => simplePatternRest(t) } case USCORE => - atPos(in.skipToken()) { Ident(nme.WILDCARD) } + wildcardIdent() case LPAREN => - atPos(in.offset) { inParens(ugen.mkTuple(commaSeparated(pattern))) } + atPos(in.offset) { ugen.mkTuple(inParens(patternsOpt())) } case LBRACE => dotSelectors(blockExpr()) case XMLSTART => xmlLiteralPattern() case _ => - if (literalTokens contains in.token) - atPos(in.offset) { literal() } + if (isLiteral) literal() else { syntaxErrorOrIncomplete("illegal start of simple pattern") errorTermTree @@ -1267,7 +1200,7 @@ object Parsers { def simplePatternRest(t: Tree): Tree = { var p = t if (in.token == LBRACKET) - p = atPos(t.pos.start, in.offset) { TypeApply(convertToTypeId(t), typeArgs()) } + p = atPos(t.pos.start, in.offset) { TypeApply(p, typeArgs()) } if (in.token == LPAREN) p = atPos(t.pos.start, in.offset) { Apply(p, argumentPatterns()) } p @@ -1275,8 +1208,11 @@ object Parsers { /** Patterns ::= Pattern [`,' Pattern] */ + def patterns() = commaSeparated(pattern) + def patternsOpt(): List[Tree] = - if (in.token == RPAREN) Nil else commaSeparated(pattern) + if (in.token == RPAREN) Nil else patterns() + /** ArgumentPatterns ::= `(' [Patterns] `)' * | `(' [Patterns `,'] Pattern2 `:' `_' `*' ') @@ -1286,22 +1222,22 @@ object Parsers { /* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */ - private val flagTokens: Map[Int, FlagSet] = Map( - ABSTRACT -> Abstract, - FINAL -> Final, - IMPLICIT -> Implicit, - LAZY -> Lazy, - OVERRIDE -> Override, - PRIVATE -> Private, - PROTECTED -> Protected, - SEALED -> Sealed - ) + private def flagOfToken(tok: Int): FlagSet = tok match { + case ABSTRACT => Abstract + case FINAL => Final + case IMPLICIT => Implicit + case LAZY => Lazy + case OVERRIDE => Override + case PRIVATE => Private + case PROTECTED => Protected + case SEALED => Sealed + } /** Drop `private' modifier when followed by a qualifier. * Contract `abstract' and `override' to ABSOVERRIDE */ private def normalize(mods: Modifiers): Modifiers = - if ((mods is Private) && mods.privateWithin != tpnme.EMPTY) + if ((mods is Private) && mods.hasPrivateWithin) normalize(mods &~ Private) else if (mods is AbstractAndOverride) normalize(mods &~ (Abstract | Override) | AbsOverride) @@ -1309,7 +1245,7 @@ object Parsers { mods private def addModifier(mods: Modifiers): Modifiers = { - val flag = flagTokens(in.token) + val flag = flagOfToken(in.token) if (mods is flag) syntaxError("repeated modifier") in.nextToken() mods | flag @@ -1319,7 +1255,7 @@ object Parsers { */ def accessQualifierOpt(mods: Modifiers): Modifiers = if (in.token == LBRACKET) { - if (mods.privateWithin != tpnme.EMPTY) + if ((mods is Local) || mods.hasPrivateWithin) syntaxError("duplicate private/protected qualifier") inBrackets { if (in.token == THIS) { in.nextToken(); mods | Local } @@ -1327,7 +1263,8 @@ object Parsers { } } else mods - /** Modifiers ::= {Modifier} + /** {Annotation} {Modifier} + * Modifiers ::= {Modifier} * LocalModifiers ::= {LocalModifier} * AccessModifier ::= (private | protected) [AccessQualifier] * Modifier ::= LocalModifier @@ -1335,13 +1272,14 @@ object Parsers { * | override * LocalModifier ::= abstract | final | sealed | implicit | lazy */ - def modifiers(allowed: BitSet = modifierTokens): Modifiers = normalize { - def loop(mods: Modifiers): Modifiers = - if (allowed contains in.token) { + def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = { + def loop(mods: Modifiers): Modifiers = { + val tok = in.token + if (allowed contains tok) { val mods1 = addModifier(mods) loop { in.token match { - case PRIVATE | PROTECTED => in.nextToken() ; accessQualifierOpt(mods1) + case PRIVATE | PROTECTED => accessQualifierOpt(mods1) case _ => mods1 } } @@ -1351,33 +1289,30 @@ object Parsers { } else { mods } - loop(Modifiers()) + } + normalize(loop(start)) } /** Annotation ::= `@' SimpleType {ArgumentExprs} - * ConstrAnnotation ::= `@' SimpleType ArgumentExprs */ - def annot(forConstructor: Boolean = false) = { + def annot() = { accept(AT) - def args = - if (forConstructor) { - newLineOptWhenFollowedBy(LBRACE) - argumentExprs() :: Nil - } else argumentExprss() - (simpleType() /: args) (Apply(_, _)) + argumentExprss(simpleType()) } - def annotations(skipNewLines: Boolean, forConstructor: Boolean = false): List[Tree] = { + def annotations(skipNewLines: Boolean = false): List[Tree] = { if (skipNewLines) newLineOptWhenFollowedBy(AT) - if (in.token == AT) annot(forConstructor) :: annotations(skipNewLines, forConstructor) + if (in.token == AT) annot() :: annotations(skipNewLines) else Nil } -/* -------- PARAMETERS ------------------------------------------- */ + def annotsAsMods(skipNewLines: Boolean = false): Modifiers = + Modifiers() withAnnotations annotations(skipNewLines) - object ParamOwner extends Enumeration { - val Class, Type, TypeParam, Def = Value - } + def defAnnotsMods(allowed: BitSet): Modifiers = + modifiers(allowed, annotsAsMods(skipNewLines = true)) + + /* -------- PARAMETERS ------------------------------------------- */ /** ClsTypeParamClause::= `[' ClsTypeParam {`,' ClsTypeParam} `]' * ClsTypeParam ::= {Annotation} [{Modifier} type] [`+' | `-'] @@ -1395,21 +1330,22 @@ object Parsers { def typeParamClause(ownerKind: ParamOwner.Value): List[TypeDef] = inBrackets { def typeParam(): TypeDef = { val isConcreteOwner = ownerKind == ParamOwner.Class || ownerKind == ParamOwner.Def - val start = in.offset - val annots = annotations(skipNewLines = false) - var mods = - if (ownerKind == ParamOwner.Class) { - val mods1 = modifiers() withAnnotations annots - atPos(start, in.offset) { + val modStart = in.offset + var mods = annotsAsMods() + if (ownerKind == ParamOwner.Class) { + mods = modifiers(start = mods) + mods = + atPos(modStart, in.offset) { if (in.token == TYPE) { in.nextToken() - mods1 | TypeParam + mods | TypeParam } else { - if (mods1.flags != EmptyFlags) syntaxError("`type' expected") - mods1 | TypeParam | PrivateLocal + if (mods.hasFlags) syntaxError("`type' expected") + mods | TypeParam | PrivateLocal } } - } else atPos(start) { Modifiers(TypeParam) withAnnotations annots } + } + else mods = atPos(modStart) (mods | TypeParam) if (ownerKind != ParamOwner.Def) { if (isIdent(nme.raw.PLUS)) mods |= Covariant else if (isIdent(nme.raw.MINUS)) mods |= Contravariant @@ -1443,26 +1379,27 @@ object Parsers { */ def paramClauses(owner: Name): List[List[ValDef]] = { var implicitFlag = EmptyFlags + var implicitOffset = -1 // use once def param(): ValDef = { - val start = in.offset - val annots = annotations(skipNewLines = false) - val mods = - if (owner.isTypeName) { - val mods1 = modifiers() withAnnotations annots - if (mods1 is Lazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead") - atPos(start, in.offset) { + val modStart = in.offset + var mods = annotsAsMods() + if (owner.isTypeName) { + mods = modifiers(start = mods) + mods = + atPos(modStart, in.offset) { if (in.token == VAL) { in.nextToken() - mods1 | Param + mods | Param } else if (in.token == VAR) { in.nextToken() - mods1 | Param | Mutable + mods | Param | Mutable } else { - if (mods1.flags != EmptyFlags) syntaxError("`val' or `var' expected") - mods1 | Param | PrivateLocal + if (mods.hasFlags) syntaxError("`val' or `var' expected") + mods | Param | PrivateLocal } } - } else atPos(start) { Modifiers(Param) withAnnotations annots } + } + else mods = atPos(modStart) { mods | Param } atPos(tokenRange) { val name = ident() val tpt = @@ -1481,6 +1418,10 @@ object Parsers { val default = if (in.token == EQUALS) { in.nextToken(); expr() } else EmptyTree() + if (implicitOffset >= 0) { + mods = mods.withPos(mods.pos.withStart(implicitOffset)) + implicitOffset = -1 + } ValDef(mods | implicitFlag, name, tpt, default) } } @@ -1488,7 +1429,7 @@ object Parsers { if (in.token == RPAREN) Nil else { if (in.token == IMPLICIT) { - in.nextToken() + implicitOffset = in.skipToken() implicitFlag = Implicit } commaSeparated(param) @@ -1512,7 +1453,6 @@ object Parsers { /* -------- DEFS ------------------------------------------- */ - /** Import ::= import ImportExpr {`,' ImportExpr} */ def importClause(): List[Tree] = { @@ -1527,10 +1467,10 @@ object Parsers { /** ImportExpr ::= StableId `.' (Id | `_' | ImportSelectors) */ - def importExpr(): Tree = path(thisOK = false, handleImport) match { - case sel @ Select(qual, name) => sel.derivedImport(qual, Ident(name) :: Nil) + val importExpr = () => path(thisOK = false, handleImport) match { case imp: Import => imp - case _ => accept(DOT); EmptyTree() + case sel @ Select(qual, name) => sel.derivedImport(qual, Ident(name) :: Nil) + case t => accept(DOT); Import(t, Ident(nme.WILDCARD) :: Nil) } val handleImport = { tree: Tree => @@ -1546,10 +1486,11 @@ object Parsers { else { val sel = importSelector() sel :: { - if (!isWildcard(sel) && in.token == COMMA) { + if (!TreeInfo.isWildcardArg(sel) && in.token == COMMA) { in.nextToken() importSelectors() - } else Nil + } + else Nil } } @@ -1582,18 +1523,13 @@ object Parsers { case VAR => patDefOrDcl(posMods(start, mods | Mutable)) case DEF => - funDefOrDcl(posMods(start, mods)) + defDefOrDcl(posMods(start, mods)) case TYPE => typeDefOrDcl(posMods(start, mods)) case _ => tmplDef(start, mods) } - def defAnnotsMods(allowed: BitSet): Modifiers = { - val annots = annotations(skipNewLines = true) - modifiers(allowed) withAnnotations annots - } - /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr * VarDef ::= PatDef | Id {`,' Id} `:' Type `=' `_' * ValDcl ::= Id {`,' Id} `:' Type @@ -1624,7 +1560,7 @@ object Parsers { * DefDcl ::= DefSig [`:' Type] * DefSig ::= id [DefTypeParamClause] ParamClauses */ - def funDefOrDcl(mods: Modifiers): Tree = atPos(tokenRange) { + def defDefOrDcl(mods: Modifiers): Tree = atPos(tokenRange) { if (in.token == THIS) { val vparamss = paramClauses(nme.CONSTRUCTOR) newLineOptWhenFollowedBy(LBRACE) @@ -1640,8 +1576,8 @@ object Parsers { val name = ident() val tparams = typeParamClauseOpt(ParamOwner.Def) val vparamss = paramClauses(name) - newLineOptWhenFollowedBy(LBRACE) var restype = fromWithinReturnType(typedOpt()) + newLineOptWhenFollowedBy(LBRACE) val rhs = if (isStatSep || in.token == RBRACE) EmptyTree() else if (restype.isEmpty && in.token == LBRACE) { @@ -1666,8 +1602,7 @@ object Parsers { def selfInvocation(): Tree = atPos(accept(THIS)) { newLineOptWhenFollowedBy(LBRACE) - var t = Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) - (t /: argumentExprss())(Apply(_, _)) + argumentExprss(Apply(Ident(nme.CONSTRUCTOR), argumentExprs())) } /** ConstrBlock ::= `{' SelfInvocation {semi BlockStat} `}' @@ -1694,7 +1629,7 @@ object Parsers { case EQUALS => in.nextToken() TypeDef(mods, name, tparams, typ()) - case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE => + case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | EOF => TypeDef(mods, name, tparams, typeBounds()) case _ => syntaxErrorOrIncomplete("`=', `>:', or `<:' expected") @@ -1703,14 +1638,6 @@ object Parsers { } } - /** Hook for IDE, for top-level classes/objects - def topLevelTmplDef: Tree = { - val annots = annotations(true) - val pos = caseAwareTokenOffset - val mods = modifiers() withAnnotations annots - tmplDef(pos, mods) - }*/ - /** TmplDef ::= ([`case'] `class' | `trait') ClassDef * | [`case'] `object' ObjectDef */ @@ -1730,24 +1657,28 @@ object Parsers { EmptyTree() } - /** ClassDef ::= Id [ClsTypeParamClause] {ConstrAnnotation} - [AccessModifier] ClsParamClauses TemplateOpt + /** ClassDef ::= Id [ClsTypeParamClause] + * [ConstrMods] ClsParamClauses TemplateOpt */ def classDef(mods: Modifiers): ClassDef = atPos(tokenRange) { val name = ident().toTypeName val tparams = typeParamClauseOpt(ParamOwner.Class) - val constr = atPos(in.offset) { - val constrMods = atPos(in.offset) { - val constrAnnots = annotations(skipNewLines = false, forConstructor = true) - modifiers(accessModifierTokens) withAnnotations constrAnnots - } - val vparamss = paramClauses(name) - ugen.constructor(constrMods, vparamss) - } + val cmods = constrModsOpt() + val vparamss = paramClauses(name) + val constr = ugen.constructor(cmods, vparamss) val templ = templateOpt(constr) ClassDef(mods, name, tparams, templ) } + /** ConstrMods ::= AccessModifier + * | Annotation {Annotation} (AccessModifier | `this') + */ + def constrModsOpt(): Modifiers = { + val mods = modifiers(accessModifierTokens, annotsAsMods()) + if (mods.hasAnnotations && !mods.hasFlags) accept(THIS) + mods + } + /** ObjectDef ::= Id TemplateOpt */ def objectDef(mods: Modifiers): ModuleDef = { @@ -1761,9 +1692,8 @@ object Parsers { /** ConstrApp ::= RefinedType {ArgumentExprs} */ - def constrApp() = - (refinedType() /: argumentExprss()) (Apply(_, _)) - + val constrApp = () => + argumentExprss(refinedType()) /** Template ::= ConstrApps [TemplateBody] | TemplateBody * ConstrApps ::= ConstrApp {`with' ConstrApp} @@ -1826,22 +1756,22 @@ object Parsers { def topStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree] while (!isStatSeqEnd) { - setLastDefOffset() + setLastStatOffset() if (in.token == PACKAGE) { val start = in.skipToken() - if (in.token == OBJECT) stats += objectDef(atPos(start) { Modifiers(Package) }) + if (in.token == OBJECT) stats += objectDef(atPos(start, in.offset) { Modifiers(Package) }) else stats += packaging(start) } else if (in.token == IMPORT) stats ++= importClause() - else if (in.token == AT || (templateIntroTokens contains in.token) || (modifierTokens contains in.token)) + else if (in.token == AT || isTemplateIntro || isModifier) stats += tmplDef(in.offset, defAnnotsMods(modifierTokens)) else if (!isStatSep) { syntaxErrorOrIncomplete("expected class or object definition") - if (mustStartStatTokens contains in.token) // do parse all definitions even if they are probably local (i.e. a "}" has been forgotten) + if (mustStartStat) // do parse all definitions even if they are probably local (i.e. a "}" has been forgotten) defOrDcl(in.offset, defAnnotsMods(modifierTokens)) } - acceptStatSepOpt() + acceptStatSepUnlessAtEnd() } stats.toList } @@ -1858,38 +1788,35 @@ object Parsers { var self: ValDef = EmptyValDef() val stats = new ListBuffer[Tree] if (isExprIntro) { - val first = expr1(Location.ElseWhere) // @S: first statement is potentially converted so cannot be stubbed. + val first = expr1() if (in.token == ARROW) { first match { case Typed(tree @ This(tpnme.EMPTY), tpt) => self = ugen.selfDef(nme.WILDCARD, tpt).withPos(first.pos) case _ => - convertToParam(first) match { - case tree @ ValDef(_, name, tpt, _) if (name != nme.ERROR) => - self = ugen.selfDef(name, tpt).withPos(first.pos) - case _ => - } + val ValDef(_, name, tpt, _) = convertToParam(first, expected = "self type clause") + self = ugen.selfDef(name, tpt).withPos(first.pos) } in.nextToken() } else { stats += first - acceptStatSepOpt() + acceptStatSepUnlessAtEnd() } } var exitOnError = false while (!isStatSeqEnd && !exitOnError) { - setLastDefOffset() + setLastStatOffset() if (in.token == IMPORT) stats ++= importClause() else if (isExprIntro) - stats += expr() + stats += expr1() else if (isDefIntro(modifierTokens)) defOrDcl(in.offset, defAnnotsMods(modifierTokens)) else if (!isStatSep) { - exitOnError = mustStartStatTokens contains in.token + exitOnError = mustStartStat syntaxErrorOrIncomplete("illegal start of definition") } - acceptStatSepOpt() + acceptStatSepUnlessAtEnd() } (self, if (stats.isEmpty) List(EmptyTree()) else stats.toList) } @@ -1902,7 +1829,7 @@ object Parsers { def refineStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree] while (!isStatSeqEnd) { - if (dclIntroTokens contains in.token) { + if (isDclIntro) { stats += defOrDcl(in.offset, Modifiers()) } else if (!isStatSep) { syntaxErrorOrIncomplete( @@ -1910,7 +1837,7 @@ object Parsers { (if (inFunReturnType) " (possible cause: missing `=' in front of current method body)" else "")) } - if (in.token != RBRACE) acceptStatSep() + acceptStatSepUnlessAtEnd() } stats.toList } @@ -1929,7 +1856,7 @@ object Parsers { val stats = new ListBuffer[Tree] var exitOnError = false while (!isStatSeqEnd && in.token != CASE && !exitOnError) { - setLastDefOffset() + setLastStatOffset() if (in.token == IMPORT) { stats ++= importClause() } @@ -1950,11 +1877,11 @@ object Parsers { stats += localDef(in.offset, EmptyFlags) } else if (!isStatSep && (in.token != CASE)) { - exitOnError = mustStartStatTokens contains in.token - val addendum = if (modifierTokens contains in.token) " (no modifiers allowed here)" else "" - syntaxErrorOrIncomplete("illegal start of statement"+addendum) + exitOnError = mustStartStat + val addendum = if (isModifier) " (no modifiers allowed here)" else "" + syntaxErrorOrIncomplete("illegal start of statement" + addendum) } - acceptStatSepOpt(CASE) + acceptStatSepUnlessAtEnd(CASE) } stats.toList } @@ -1969,7 +1896,7 @@ object Parsers { if (in.token == PACKAGE) { in.nextToken() if (in.token == OBJECT) { - ts += objectDef(atPos(start) { Modifiers(Package) }) + ts += objectDef(atPos(start, in.offset) { Modifiers(Package) }) if (in.token != EOF) { acceptStatSep() ts ++= topStatSeq() @@ -1981,7 +1908,7 @@ object Parsers { ts += makePackaging(start, pkg, List()) else if (in.token == LBRACE) { ts += inDefScopeBraces(makePackaging(start, pkg, topStatSeq())) - acceptStatSepOpt() + acceptStatSepUnlessAtEnd() ts ++= topStatSeq() } else { @@ -2024,5 +1951,4 @@ object Parsers { override def templateBody() = skipBraces((EmptyValDef(), List(EmptyTree()))) } - } |