alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (Parsers.scala)

This example Scala source code file (Parsers.scala) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Scala tags/keywords

boolean, boolean, emptytree, int, int, list, list, lparen, modifiers, nil, string, t, tree, tree

The Scala Parsers.scala source code

/* NSC -- new Scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Martin Odersky
 */

//todo: allow infix type patterns
//todo verify when stableId's should be just plain qualified type ids

package scala.tools.nsc
package ast.parser

import scala.collection.mutable.ListBuffer
import util.{ SourceFile, OffsetPosition, FreshNameCreator }
import scala.reflect.generic.{ ModifierFlags => Flags }
import Tokens._
import util.Chars.{ isScalaLetter }

/** Historical note: JavaParsers started life as a direct copy of Parsers
 *  but at a time when that Parsers had been replaced by a different one.
 *  Later it was dropped and the original Parsers reinstated, leaving us with
 *  massive duplication between Parsers and JavaParsers.
 *
 *  This trait and the similar one for Scanners/JavaScanners represents
 *  the beginnings of a campaign against this latest incursion by Cutty
 *  McPastington and his army of very similar soldiers.
 */
trait ParsersCommon extends ScannersCommon {
  val global : Global
  import global._
  
  trait ParserCommon {
    val in: ScannerCommon
    def freshName(prefix: String): Name
    def freshTermName(prefix: String): TermName
    def freshTypeName(prefix: String): TypeName
    def deprecationWarning(off: Int, msg: String): Unit
    def accept(token: Int): Int

    /** Methods inParensOrError and similar take a second argument which, should
     *  the next token not be the expected opener (e.g. LPAREN) will be returned
     *  instead of the contents of the groupers.  However in all cases accept(LPAREN)
     *  will be called, so a parse error will still result.  If the grouping is
     *  optional, in.token should be tested before calling these methods.
     */
    def inParens[T](body: => T): T = {
      accept(LPAREN)
      val ret = body
      accept(RPAREN)
      ret
    }
    def inParensOrError[T](body: => T, alt: T): T = 
      if (in.token == LPAREN) inParens(body)
      else { accept(LPAREN) ; alt }
    def inParensOrUnit[T](body: => Tree): Tree = inParensOrError(body, Literal(()))
    def inParensOrNil[T](body: => List[T]): List[T] = inParensOrError(body, Nil)

    def inBraces[T](body: => T): T = {
      accept(LBRACE)
      val ret = body
      accept(RBRACE)
      ret
    }
    def inBracesOrError[T](body: => T, alt: T): T =
      if (in.token == LBRACE) inBraces(body)
      else { accept(LBRACE) ; alt }
    def inBracesOrNil[T](body: => List[T]): List[T] = inBracesOrError(body, Nil)
    def inBracesOrUnit[T](body: => Tree): Tree = inBracesOrError(body, Literal(()))
    
    def inBrackets[T](body: => T): T = {
      accept(LBRACKET)
      val ret = body
      accept(RBRACKET)
      ret
    }
    
    /** Creates an actual Parens node (only used during parsing.)
     */
    def makeParens(body: => List[Tree]): Parens =
      Parens(inParens(if (in.token == RPAREN) Nil else body))
  }
}

/** <p>Performs the following context-free rewritings:

* <ol> * <li> * Places all pattern variables in Bind nodes. In a pattern, for * identifiers <code>x:
 *                 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 x = e     ==>  val x = e
 *        <b>val x: T = e  ==>  val x: T = e
* * if there are no variables in pattern<pre> * <b>val p = e ==> e match (case p => ())
* * if there is exactly one variable in pattern<pre> * <b>val x_1 = e match (case p => (x_1)) * * if there is more than one variable in pattern<pre> * <b>val p = e ==> private synthetic val t$ = e match (case p => (x_1, ..., x_N)) * <b>val x_1 = t$._1 * ... * <b>val x_N = t$._N * </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 * </li> * </ol> */ trait Parsers extends Scanners with MarkupParsers with ParsersCommon { self => val global: Global import global._ private val glob: global.type = global case class OpInfo(operand: Tree, operator: Name, offset: Offset) class SourceFileParser(val source: SourceFile) extends Parser { /** 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() def newScanner = new SourceFileScanner(source) val in = newScanner in.init() private val globalFresh = new FreshNameCreator.Default def freshName(prefix: String): Name = freshTermName(prefix) def freshTermName(prefix: String): TermName = newTermName(globalFresh.newName(prefix)) def freshTypeName(prefix: String): TypeName = newTypeName(globalFresh.newName(prefix)) def o2p(offset: Int): Position = new OffsetPosition(source, offset) def r2p(start: Int, mid: Int, end: Int): Position = rangePos(source, start, mid, end) // suppress warnings; silent abort on errors def warning(offset: Int, msg: String) {} def deprecationWarning(offset: Int, msg: String) {} def syntaxError(offset: Int, msg: String): Unit = throw new MalformedInput(offset, msg) def incompleteInputError(msg: String): Unit = throw new MalformedInput(source.content.length - 1, msg) /** the markup parser */ lazy val xmlp = new MarkupParser(this, true) object symbXMLBuilder extends SymbolicXMLBuilder(this, true) { // DEBUG choices val global: self.global.type = self.global def freshName(prefix: String): Name = SourceFileParser.this.freshName(prefix) } def xmlLiteral : Tree = xmlp.xLiteral def xmlLiteralPattern : Tree = xmlp.xLiteralPattern } class OutlineParser(source: SourceFile) extends SourceFileParser(source) { def skipBraces[T](body: T): T = { accept(LBRACE) var openBraces = 1 while (in.token != EOF && openBraces > 0) { if (in.token == XMLSTART) xmlLiteral() else { if (in.token == LBRACE) openBraces += 1 else if (in.token == RBRACE) openBraces -= 1 in.nextToken() } } body } override def blockExpr(): Tree = skipBraces(EmptyTree) override def templateBody(isPre: Boolean) = skipBraces(emptyValDef, List(EmptyTree)) } class UnitParser(val unit: global.CompilationUnit, patches: List[BracePatch]) extends SourceFileParser(unit.source) { def this(unit: global.CompilationUnit) = this(unit, List()) override def newScanner = new UnitScanner(unit, patches) override def freshTermName(prefix: String): TermName = unit.freshTermName(prefix) override def freshTypeName(prefix: String): TypeName = unit.freshTypeName(prefix) override def warning(offset: Int, msg: String) { unit.warning(o2p(offset), msg) } override def deprecationWarning(offset: Int, msg: String) { unit.deprecationWarning(o2p(offset), msg) } private var smartParsing = false private def withSmartParsing[T](body: => T): T = { val saved = smartParsing try { smartParsing = true body } finally smartParsing = saved // false } val syntaxErrors = new ListBuffer[(Int, String)] def showSyntaxErrors() = for ((offset, msg) <- syntaxErrors) unit.error(o2p(offset), msg) override def syntaxError(offset: Int, msg: String) { if (smartParsing) syntaxErrors += ((offset, msg)) else unit.error(o2p(offset), msg) } override def incompleteInputError(msg: String) { val offset = source.content.length - 1 if (smartParsing) syntaxErrors += ((offset, msg)) else unit.incompleteInputError(o2p(offset), msg) } /** parse unit. If there are inbalanced braces, * try to correct them and reparse. */ def smartParse(): Tree = withSmartParsing { val firstTry = parse() if (syntaxErrors.isEmpty) firstTry else in.healBraces() match { case Nil => showSyntaxErrors() ; firstTry case patches => new UnitParser(unit, patches).parse() } } } final val Local = 0 final val InBlock = 1 final val InTemplate = 2 import nme.raw abstract class Parser extends ParserCommon { val in: Scanner def freshName(prefix: String): Name def freshTermName(prefix: String): TermName def freshTypeName(prefix: String): TypeName def o2p(offset: Int): Position def r2p(start: Int, mid: Int, end: Int): Position /** whether a non-continuable syntax error has been seen */ private var lastErrorOffset : Int = -1 object treeBuilder extends TreeBuilder { val global: self.global.type = self.global def freshName(prefix: String): Name = freshTermName(prefix) def freshTermName(prefix: String): TermName = Parser.this.freshTermName(prefix) def freshTypeName(prefix: String): TypeName = Parser.this.freshTypeName(prefix) def o2p(offset: Int) = Parser.this.o2p(offset) def r2p(start: Int, point: Int, end: Int) = Parser.this.r2p(start, point, end) } import treeBuilder.{global => _, _} /** The types of the context bounds of type parameters of the surrounding class */ private var classContextBounds: List[Tree] = Nil private def savingClassContextBounds[T](op: => T): T = { val saved = classContextBounds try op finally classContextBounds = saved } /** Are we inside the Scala package? Set for files that start with package scala */ private var inScalaPackage = false private var currentPackage = "" def resetPackage() { inScalaPackage = false currentPackage = "" } private lazy val anyValNames: Set[Name] = tpnme.ScalaValueNames.toSet + tpnme.AnyVal private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array private def isAnyValType(name: Name) = inScalaRootPackage && anyValNames(name) def parseStartRule: () => Tree /** This is the general parse entry point. */ def parse(): Tree = { val t = parseStartRule() 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 = { val stmts = templateStatSeq(false)._2 accept(EOF) def mainModuleName = 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 && (md 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. */ if (name.toString == mainModuleName) md else treeCopy.ModuleDef(md, mods, mainModuleName, 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 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( NoMods, 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(Flags.PARAM), "argv", mainParamType, EmptyTree)) def mainSetArgv = List(ValDef(NoMods, "args", TypeTree(), Ident("argv"))) def mainNew = makeNew(Nil, emptyValDef, stmts, List(Nil), NoPosition, NoPosition) def mainDef = DefDef(NoMods, 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(NoMods, moduleName, moduleBody) // package <empty> { ... } makePackaging(0, emptyPkg, List(moduleDef)) } /* --------------- PLACEHOLDERS ------------------------------------------- */ /** The implicit parameters introduced by `_' in the current expression. * Parameters appear in reverse order */ var placeholderParams: List[ValDef] = Nil /** The placeholderTypes introduced by `_' in the current type. * Parameters appear in reverse order */ var placeholderTypes: List[TypeDef] = Nil def checkNoEscapingPlaceholders[T](op: => T): T = { val savedPlaceholderParams = placeholderParams val savedPlaceholderTypes = placeholderTypes placeholderParams = List() placeholderTypes = List() val res = op placeholderParams match { case vd :: _ => syntaxError(vd.pos, "unbound placeholder parameter", false) placeholderParams = List() case _ => } placeholderTypes match { case td :: _ => syntaxError(td.pos, "unbound wildcard type", false) placeholderTypes = List() case _ => } placeholderParams = savedPlaceholderParams placeholderTypes = savedPlaceholderTypes res } def placeholderTypeBoundary(op: => Tree): Tree = { val savedPlaceholderTypes = placeholderTypes placeholderTypes = List() var t = op if (!placeholderTypes.isEmpty && t.isInstanceOf[AppliedTypeTree]) { val expos = t.pos ensureNonOverlapping(t, placeholderTypes) t = atPos(expos) { 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 ------------------------------------------- */ var assumedClosingParens = collection.mutable.Map(RPAREN -> 0, RBRACKET -> 0, RBRACE -> 0) private var inFunReturnType = false private def fromWithinReturnType[T](body: => T): T = { val saved = inFunReturnType try { inFunReturnType = true body } finally inFunReturnType = saved } protected def skip(targetToken: Int) { var nparens = 0 var nbraces = 0 while (true) { in.token match { case EOF => return case SEMI => if (nparens == 0 && nbraces == 0) return case NEWLINE => if (nparens == 0 && nbraces == 0) return case NEWLINES => if (nparens == 0 && nbraces == 0) return case RPAREN => nparens -= 1 case RBRACE => if (nbraces == 0) return nbraces -= 1 case LPAREN => nparens += 1 case LBRACE => nbraces += 1 case _ => } if (targetToken == in.token && nparens == 0 && nbraces == 0) return in.nextToken() } } def warning(offset: Int, msg: String): Unit def incompleteInputError(msg: String): Unit private def syntaxError(pos: Position, msg: String, skipIt: Boolean) { syntaxError(pos pointOrElse in.offset, msg, skipIt) } def syntaxError(offset: Int, msg: String): Unit def syntaxError(msg: String, skipIt: Boolean) { syntaxError(in.offset, msg, skipIt) } def syntaxError(offset: Int, msg: String, skipIt: Boolean) { if (offset > lastErrorOffset) { syntaxError(offset, msg) // no more errors on this token. lastErrorOffset = in.offset } if (skipIt) skip(UNDEF) } def warning(msg: String) { warning(in.offset, msg) } def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) { if (in.token == EOF) incompleteInputError(msg) else syntaxError(in.offset, msg, skipIt) } def expectedMsg(token: Int): String = token2string(token) + " expected but " +token2string(in.token) + " found." /** Consume one token of the specified type, or * signal an error if it is not there. */ def accept(token: Int): Int = { val offset = in.offset if (in.token != token) { syntaxErrorOrIncomplete(expectedMsg(token), false) if ((token == RPAREN || token == RBRACE || token == RBRACKET)) if (in.parenBalance(token) + assumedClosingParens(token) < 0) assumedClosingParens(token) += 1 else skip(token) else skip(UNDEF) } if (in.token == token) in.nextToken() offset } /** semi = nl {nl} | `;' * nl = `\n' // where allowed */ def acceptStatSep(): Unit = in.token match { case NEWLINE | NEWLINES => in.nextToken() case _ => accept(SEMI) } def acceptStatSepOpt() = if (!isStatSeqEnd) acceptStatSep() 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 or repeated */ def checkNotByNameOrVarargs(tpt: Tree) = { if (treeInfo isByNameParamType tpt) syntaxError(tpt.pos, "no by-name parameter type allowed here", false) else if (treeInfo isRepeatedParamType tpt) syntaxError(tpt.pos, "no * parameter type allowed here", false) } /** 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 = in.token match { case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT | LAZY => true case _ => false } def isLocalModifier: Boolean = in.token match { case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY => true case _ => false } def isTemplateIntro: Boolean = in.token match { case OBJECT | CASEOBJECT | CLASS | CASECLASS | TRAIT => true case _ => false } def isDclIntro: Boolean = in.token match { case VAL | VAR | DEF | TYPE => true case _ => false } def isDefIntro = isTemplateIntro || isDclIntro def isNumericLit: Boolean = in.token match { case INTLIT | LONGLIT | FLOATLIT | DOUBLELIT => true case _ => false } def isUnaryOp = isIdent && raw.isUnary(in.name) def isRawStar = isIdent && in.name == raw.STAR def isRawBar = isIdent && in.name == raw.BAR def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT def isLiteralToken(token: Int) = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => true case _ => false } def isLiteral = isLiteralToken(in.token) def isExprIntroToken(token: Int): Boolean = isLiteralToken(token) || (token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | DO | RETURN | THROW | LPAREN | LBRACE | XMLSTART => true case _ => false }) def isExprIntro: Boolean = isExprIntroToken(in.token) def isTypeIntroToken(token: Int): Boolean = token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | USCORE | LPAREN | AT => true case _ => false } def isTypeIntro: Boolean = isTypeIntroToken(in.token) def isStatSeqEnd = in.token == RBRACE || in.token == EOF def isStatSep(token: Int): Boolean = token == NEWLINE || token == NEWLINES || token == SEMI def isStatSep: Boolean = isStatSep(in.token) /* --------- COMMENT AND ATTRIBUTE COLLECTION ----------------------------- */ /** Join the comment associated with a definition */ def joinComment(trees: => List[Tree]): List[Tree] = { val doc = in.flushDoc if ((doc ne null) && doc.raw.length > 0) { val joined = trees map { t => DocDef(doc, t) setPos { if (t.pos.isDefined) { val pos = doc.pos.withEnd(t.pos.endOrPoint) if (t.pos.isOpaqueRange) pos else pos.makeTransparent } else { t.pos } } } joined.find(_.pos.isOpaqueRange) foreach { main => val mains = List(main) joined foreach { t => if (t ne main) ensureNonOverlapping(t, mains) } } joined } else trees } /* ---------- TREE CONSTRUCTION ------------------------------------------- */ def atPos[T <: Tree](offset: Int)(t: T): T = global.atPos(r2p(offset, offset, in.lastOffset max offset))(t) def atPos[T <: Tree](start: Int, point: Int)(t: T): T = global.atPos(r2p(start, point, in.lastOffset max start))(t) def atPos[T <: Tree](start: Int, point: Int, end: Int)(t: T): T = global.atPos(r2p(start, point, end))(t) def atPos[T <: Tree](pos: Position)(t: T): T = global.atPos(pos)(t) /** Convert tree to formal parameter list */ def convertToParams(tree: Tree): List[ValDef] = tree match { case Parens(ts) => ts map convertToParam case _ => List(convertToParam(tree)) } /** 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) makeParam(name, TypeTree() setPos o2p(tree.pos.endOrPoint)) case Typed(Ident(name), tpe) if tpe.isType => // get the ident! removeAsPlaceholder(name) makeParam(name, tpe) case _ => syntaxError(tree.pos, "not a legal formal parameter", false) makeParam(nme.ERROR, errorTypeTree setPos o2p(tree.pos.endOrPoint)) } } /** Convert (qual)ident to type identifier */ def convertToTypeId(tree: Tree): Tree = atPos(tree.pos) { convertToTypeName(tree) getOrElse { syntaxError(tree.pos, "identifier expected", false) errorTypeTree } } /** part { `sep` part } * Or if sepFirst is true, { `sep` part } */ def tokenSeparated[T](separator: Int, sepFirst: Boolean, part: => T): List[T] = { val ts = new ListBuffer[T] if (!sepFirst) ts += part while (in.token == separator) { in.nextToken() ts += part } ts.toList } def commaSeparated[T](part: => T): List[T] = tokenSeparated(COMMA, false, part) def caseSeparated[T](part: => T): List[T] = tokenSeparated(CASE, true, part) def readAnnots[T](part: => T): List[T] = tokenSeparated(AT, true, part) /* --------- 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 = if (operator eq nme.ERROR) -1 else { val firstCh = operator(0) if (isScalaLetter(firstCh)) 1 else if (nme.isOpAssignmentName(operator)) 0 else firstCh match { case '|' => 2 case '^' => 3 case '&' => 4 case '=' | '!' => 5 case '<' | '>' => 6 case ':' => 7 case '+' | '-' => 8 case '*' | '/' | '%' => 9 case _ => 10 } } def checkSize(kind: String, size: Int, max: Int) { if (size > max) syntaxError("too many "+kind+", maximum = "+max, false) } def checkAssoc(offset: Int, op: Name, leftAssoc: Boolean) = if (treeInfo.isLeftAssoc(op) != leftAssoc) syntaxError( 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.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 = r2p(opinfo.offset, opinfo.offset, opinfo.offset+opinfo.operator.length) val lPos = opinfo.operand.pos val start = if (lPos.isDefined) lPos.startOrPoint else opPos.startOrPoint val rPos = top.pos val end = if (rPos.isDefined) rPos.endOrPoint else opPos.endOrPoint top = atPos(start, opinfo.offset, end) { makeBinop(isExpr, opinfo.operand, opinfo.operator, top, opPos) } } top } /* -------- IDENTIFIERS AND LITERALS ------------------------------------------- */ /** Methods which implicitly propagate the context in which they were * called: either in a pattern context or not. Formerly, this was * threaded through numerous methods as boolean isPattern. */ trait PatternContextSensitive { /** ArgType ::= Type */ def argType(): Tree def functionArgType(): Tree private def tupleInfixType(start: Int) = { in.nextToken() if (in.token == RPAREN) { in.nextToken() atPos(start, accept(ARROW)) { makeFunctionTypeTree(Nil, typ()) } } else { val ts = functionTypes() accept(RPAREN) if (in.token == ARROW) atPos(start, in.skipToken()) { makeFunctionTypeTree(ts, typ()) } else { ts foreach checkNotByNameOrVarargs val tuple = atPos(start) { makeTupleType(ts, true) } infixTypeRest( compoundTypeRest( annotTypeRest( simpleTypeRest( tuple))), InfixMode.FirstOp ) } } } private def makeExistentialTypeTree(t: Tree) = { val whereClauses = refinement() whereClauses foreach checkLegalExistential ExistentialTypeTree(t, whereClauses) } /** Type ::= InfixType `=>' Type * | `(' [`=>' Type] `)' `=>' Type * | InfixType [ExistentialClause] * ExistentialClause ::= forSome `{' ExistentialDcl {semi ExistentialDcl}} `}' * ExistentialDcl ::= type TypeDcl | val ValDcl */ def typ(): Tree = placeholderTypeBoundary { val start = in.offset val t = if (in.token == LPAREN) tupleInfixType(start) else infixType(InfixMode.FirstOp) in.token match { case ARROW => atPos(start, in.skipToken()) { makeFunctionTypeTree(List(t), typ()) } case FORSOME => atPos(start, in.skipToken()) { makeExistentialTypeTree(t) } case _ => t } } /** TypeArgs ::= `[' ArgType {`,' ArgType} `]' */ def typeArgs(): List[Tree] = inBrackets(types()) /** AnnotType ::= SimpleType {Annotation} */ def annotType(): Tree = placeholderTypeBoundary { annotTypeRest(simpleType()) } /** SimpleType ::= SimpleType TypeArgs * | SimpleType `#' Id * | StableId * | Path `.' type * | `(' Types `)' * | WildcardType */ def simpleType(): Tree = { val start = in.offset simpleTypeRest(in.token match { case LPAREN => atPos(start)(makeTupleType(inParens(types()), true)) case USCORE => wildcardType(in.skipToken()) case _ => path(false, true) match { case r @ SingletonTypeTree(_) => r case r => convertToTypeId(r) } }) } private def typeProjection(t: Tree): Tree = { val hashOffset = in.skipToken() val nameOffset = in.offset val name = identForType(false) val point = if (name == tpnme.ERROR) hashOffset else nameOffset atPos(t.pos.startOrPoint, point)(SelectFromTypeTree(t, name)) } def simpleTypeRest(t: Tree): Tree = in.token match { case HASH => simpleTypeRest(typeProjection(t)) case LBRACKET => simpleTypeRest(atPos(t.pos.startOrPoint)(AppliedTypeTree(t, typeArgs()))) case _ => t } /** CompoundType ::= AnnotType {with AnnotType} [Refinement] * | Refinement */ def compoundType(): Tree = compoundTypeRest( if (in.token == LBRACE) atPos(o2p(in.offset))(scalaAnyRefConstr) else annotType() ) def compoundTypeRest(t: Tree): Tree = { var ts = new ListBuffer[Tree] += t while (in.token == WITH) { in.nextToken() ts += annotType() } newLineOptWhenFollowedBy(LBRACE) atPos(t.pos.startOrPoint) { 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 // refinement from no refinement at all. See bug #284. for (Ident(name) <- ts) name.toString match { case "Unit" | "scala.Unit" => warning("Detected apparent refinement of Unit; are you missing an '=' sign?") case _ => } CompoundTypeTree(Template(ts.toList, emptyValDef, refinement())) } else makeIntersectionTypeTree(ts.toList) } } def infixTypeRest(t: Tree, 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 = identForType() val tycon = atPos(opOffset) { Ident(op) } newLineOptWhenFollowing(isTypeIntroToken) def mkOp(t1: Tree) = atPos(t.pos.startOrPoint, opOffset) { AppliedTypeTree(tycon, List(t, t1)) } if (leftAssoc) infixTypeRest(mkOp(compoundType()), InfixMode.LeftOp) else mkOp(infixType(InfixMode.RightOp)) } else t } /** InfixType ::= CompoundType {id [nl] CompoundType} */ def infixType(mode: InfixMode.Value): Tree = placeholderTypeBoundary { infixTypeRest(compoundType(), mode) } /** Types ::= Type {`,' Type} */ def types(): List[Tree] = commaSeparated(argType()) def functionTypes(): List[Tree] = commaSeparated(functionArgType()) } /** Assumed (provisionally) to be TermNames. */ def ident(skipIt: Boolean): Name = if (isIdent) { val name = in.name.encode in.nextToken() name } else { syntaxErrorOrIncomplete(expectedMsg(IDENTIFIER), skipIt) nme.ERROR } def ident(): Name = ident(true) /** For when it's known already to be a type name. */ def identForType(): TypeName = ident().toTypeName def identForType(skipIt: Boolean): TypeName = ident(skipIt).toTypeName def selector(t: Tree): Tree = { val point = in.offset //assert(t.pos.isDefined, t) if (t != EmptyTree) Select(t, ident(false)) setPos r2p(t.pos.startOrPoint, point, in.lastOffset) else errorTermTree // has already been reported } /** Path ::= StableId * | [Ident `.'] this * AnnotType ::= Path [`.' type] */ def path(thisOK: Boolean, typeOK: Boolean): Tree = { val start = in.offset var t: Tree = null if (in.token == THIS) { in.nextToken() t = atPos(start) { This(tpnme.EMPTY) } if (!thisOK || in.token == DOT) { t = selectors(t, typeOK, accept(DOT)) } } else if (in.token == SUPER) { in.nextToken() t = atPos(start) { Super(This(tpnme.EMPTY), mixinQualifierOpt()) } accept(DOT) t = selector(t) if (in.token == DOT) t = selectors(t, typeOK, in.skipToken()) } else { val tok = in.token val name = ident() t = atPos(start) { if (tok == BACKQUOTED_IDENT) new BackQuotedIdent(name) else Ident(name) } 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 (in.token == SUPER) { in.nextToken() t = atPos(start) { Super(This(name.toTypeName), mixinQualifierOpt()) } accept(DOT) t = selector(t) if (in.token == DOT) t = selectors(t, typeOK, in.skipToken()) } else { t = selectors(t, typeOK, dotOffset) } } } t } def selectors(t: Tree, typeOK: Boolean, dotOffset: Int): Tree = if (typeOK && in.token == TYPE) { in.nextToken() atPos(t.pos.startOrPoint, dotOffset) { SingletonTypeTree(t) } } else { val t1 = selector(t) if (in.token == DOT) { selectors(t1, typeOK, in.skipToken()) } else t1 } /** MixinQualifier ::= `[' Id `]' */ def mixinQualifierOpt(): TypeName = if (in.token == LBRACKET) inBrackets(identForType()) else tpnme.EMPTY /** StableId ::= Id * | Path `.' Id * | [id '.'] super [`[' id `]']`.' id */ def stableId(): Tree = path(false, false) /** QualId ::= Id {`.' Id} */ def qualId(): Tree = { val start = in.offset val id = atPos(start) { Ident(ident()) } if (in.token == DOT) { selectors(id, false, in.skipToken()) } else id } /** Calls qualId() and manages some package state. */ private def pkgQualId() = { if (in.token == IDENTIFIER && in.name.encode == nme.scala_) inScalaPackage = true val pkg = qualId() newLineOptWhenFollowedBy(LBRACE) if (currentPackage == "") currentPackage = pkg.toString else currentPackage = currentPackage + "." + pkg pkg } /** SimpleExpr ::= literal * | symbol * | null * @note The returned tree does not yet have a position */ def literal(isNegated: Boolean): Tree = { def finish(value: Any): Tree = { val t = Literal(Constant(value)) in.nextToken() t } if (in.token == SYMBOLLIT) Apply(scalaDot(nme.Symbol), List(finish(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", true) null }) } /* ------------- NEW LINES ------------------------------------------------- */ def newLineOpt() { if (in.token == NEWLINE) in.nextToken() } def newLinesOpt() { if (in.token == NEWLINE || in.token == NEWLINES) in.nextToken() } def newLineOptWhenFollowedBy(token: Int) { // note: next is defined here because current == NEWLINE if (in.token == NEWLINE && in.next.token == token) newLineOpt() } def newLineOptWhenFollowing(p: Int => Boolean) { // note: next is defined here because current == NEWLINE if (in.token == NEWLINE && p(in.next.token)) newLineOpt() } /* ------------- TYPES ---------------------------------------------------- */ /** TypedOpt ::= [`:' Type] */ def typedOpt(): Tree = if (in.token == COLON) { in.nextToken(); typ() } else TypeTree() def typeOrInfixType(location: Int): Tree = if (location == Local) typ() else startInfixType() def annotTypeRest(t: Tree): Tree = (t /: annotations(false)) (makeAnnotated) /** WildcardType ::= `_' TypeBounds */ def wildcardType(start: Int) = { val pname = freshTypeName("_$") val t = atPos(start) { Ident(pname) } val bounds = typeBounds() val param = atPos(t.pos union bounds.pos) { makeSyntheticTypeParam(pname, bounds) } placeholderTypes = param :: placeholderTypes t } /* ----------- EXPRESSIONS ------------------------------------------------ */ /** EqualsExpr ::= `=' Expr */ def equalsExpr(): Tree = { accept(EQUALS) expr() } 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 | [`implicit'] Id | `_') `=>' Expr * | Expr1 * ResultExpr ::= (Bindings | Id `:' CompoundType) `=>' Block * | Expr1 * Expr1 ::= if `(' Expr `)' {nl} Expr [[semi] else Expr] * | try (`{' Block `}' | Expr) [catch `{' CaseClauses `}'] [finally Expr] * | while `(' Expr `)' {nl} Expr * | do Expr [semi] while `(' Expr `)' * | for (`(' Enumerators `)' | '{' Enumerators '}') {nl} [yield] Expr * | throw Expr * | return [Expr] * | [SimpleExpr `.'] Id `=' Expr * | SimpleExpr1 ArgumentExprs `=' Expr * | PostfixExpr Ascription * | PostfixExpr match `{' CaseClauses `}' * Bindings ::= `(' [Binding {`,' Binding}] `)' * Binding ::= (Id | `_') [`:' Type] * Ascription ::= `:' CompoundType * | `:' Annotation {Annotation} * | `:' `_' `*' */ def expr(): Tree = expr(Local) def expr(location: Int): Tree = { var savedPlaceholderParams = placeholderParams placeholderParams = List() 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 (in.token == ELSE) { in.nextToken(); expr() } else Literal(()) If(cond, thenp, elsep) } case TRY => atPos(in.skipToken()) { val body = in.token match { case LBRACE => inBracesOrUnit(block()) case LPAREN => inParensOrUnit(expr()) case _ => expr() } def catchFromExpr() = List(makeCatchFromExpr(expr())) val catches: List[CaseDef] = if (in.token != CATCH) Nil else { in.nextToken() if (in.token != LBRACE) catchFromExpr() else inBracesOrNil { if (in.token == CASE) caseClauses() else catchFromExpr() } } val finalizer = in.token match { case FINALLY => in.nextToken() ; expr() case _ => EmptyTree } Try(body, catches, finalizer) } case WHILE => val start = in.offset atPos(in.skipToken()) { val lname: Name = freshTermName(nme.WHILE_PREFIX) val cond = condExpr() newLinesOpt() val body = expr() makeWhile(lname, cond, body) } case DO => val start = in.offset atPos(in.skipToken()) { val lname: Name = freshTermName(nme.DO_WHILE_PREFIX) val body = expr() if (isStatSep) in.nextToken() accept(WHILE) val cond = condExpr() makeDoWhile(lname, body, cond) } case FOR => atPos(in.skipToken()) { val enums = if (in.token == LBRACE) inBracesOrNil(enumerators()) else inParensOrNil(enumerators()) newLinesOpt() if (in.token == YIELD) { in.nextToken() makeForYield(enums, expr()) } else { makeFor(enums, expr()) } } case RETURN => atPos(in.skipToken()) { Return(if (isExprIntro) expr() else Literal(())) } case THROW => atPos(in.skipToken()) { Throw(expr()) } case IMPLICIT => implicitClosure(in.skipToken(), location) case _ => var t = postfixExpr() if (in.token == EQUALS) { t match { case Ident(_) | Select(_, _) | Apply(_, _) => t = atPos(t.pos.startOrPoint, in.skipToken()) { makeAssign(t, expr()) } case _ => } } 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.startOrPoint, colonPos) { Typed(t, atPos(uscorePos) { Ident(tpnme.WILDCARD_STAR) }) } } else { syntaxErrorOrIncomplete("`*' expected", true) } } else if (in.token == AT) { t = (t /: annotations(false)) (makeAnnotated) } else { t = atPos(t.pos.startOrPoint, colonPos) { val tpt = typeOrInfixType(location) if (isWildcard(t)) (placeholderParams: @unchecked) match { case (vd @ ValDef(mods, name, _, _)) :: rest => placeholderParams = treeCopy.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) } } } else if (in.token == MATCH) { t = atPos(t.pos.startOrPoint, in.skipToken()) { /** For debugging pattern matcher transition issues */ if (settings.Ypmatnaive.value) makeSequencedMatch(stripParens(t), inBracesOrNil(caseClauses())) else Match(stripParens(t), inBracesOrNil(caseClauses())) } } // 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.startOrPoint, in.skipToken()) { Function(convertToParams(t), if (location != InBlock) expr() else block()) } } stripParens(t) } /** Expr ::= implicit Id => Expr */ def implicitClosure(start: Int, location: Int): Tree = { val param0 = convertToParam { atPos(in.offset) { var paramexpr: Tree = Ident(ident()) if (in.token == COLON) { in.nextToken() paramexpr = Typed(paramexpr, typeOrInfixType(location)) } paramexpr } } val param = treeCopy.ValDef(param0, param0.mods | Flags.IMPLICIT, param0.name, param0.tpt, param0.rhs) atPos(start, in.offset) { accept(ARROW) Function(List(param), if (location != InBlock) expr() else block()) } } /** PostfixExpr ::= InfixExpr [Id [nl]] * InfixExpr ::= PrefixExpr * | InfixExpr Id [nl] InfixExpr */ def postfixExpr(): Tree = { val base = opstack var top = prefixExpr() while (isIdent) { top = reduceStack(true, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) val op = in.name opstack = OpInfo(top, op, in.offset) :: opstack ident() newLineOptWhenFollowing(isExprIntroToken) if (isExprIntro) { val next = prefixExpr() if (next == EmptyTree) return reduceStack(true, base, top, 0, true) top = next } else { val topinfo = opstack.head opstack = opstack.tail val od = stripParens(reduceStack(true, base, topinfo.operand, 0, true)) return atPos(od.pos.startOrPoint, topinfo.offset) { Select(od, topinfo.operator.encode) } } } reduceStack(true, base, top, 0, true) } /** PrefixExpr ::= [`-' | `+' | `~' | `!' | `&'] SimpleExpr */ def prefixExpr(): Tree = { if (isUnaryOp) { atPos(in.offset) { val name: Name = "unary_" + ident() if (in.name == raw.MINUS && isNumericLit) simpleExprRest(atPos(in.offset)(literal(true)), true) else Select(stripParens(simpleExpr()), name) } } else simpleExpr() } def xmlLiteral(): Tree /* SimpleExpr ::= new (ClassTemplate | TemplateBody) * | BlockExpr * | SimpleExpr1 [`_'] * SimpleExpr1 ::= literal * | xLiteral * | Path * | `(' [Exprs] `)' * | SimpleExpr `.' Id * | SimpleExpr TypeArgs * | SimpleExpr1 ArgumentExprs */ def simpleExpr(): Tree = { var canApply = true val t = if (isLiteral) atPos(in.offset)(literal(false)) else in.token match { case XMLSTART => xmlLiteral() case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER => path(true, false) case USCORE => val start = in.offset val pname = freshName("x$") in.nextToken() val id = atPos(start) (Ident(pname)) val param = atPos(id.pos.focus){ makeSyntheticParam(pname) } placeholderParams = param :: placeholderParams id case LPAREN => atPos(in.offset)(makeParens(commaSeparated(expr))) case LBRACE => canApply = false blockExpr() case NEW => canApply = false val nstart = in.skipToken() val npos = r2p(nstart, nstart, in.lastOffset) val tstart = in.offset val (parents, argss, self, stats) = template(false) val cpos = r2p(tstart, tstart, in.lastOffset max tstart) makeNew(parents, self, stats, argss, npos, cpos) case _ => syntaxErrorOrIncomplete("illegal start of simple expression", true) errorTermTree } simpleExprRest(t, canApply) } def simpleExprRest(t: Tree, canApply: Boolean): Tree = { if (canApply) newLineOptWhenFollowedBy(LBRACE) in.token match { case DOT => in.nextToken() simpleExprRest(selector(stripParens(t)), true) case LBRACKET => val t1 = stripParens(t) t1 match { case Ident(_) | Select(_, _) => val tapp = atPos(t1.pos.startOrPoint, in.offset) { TypeApply(t1, exprTypeArgs()) } simpleExprRest(tapp, true) case _ => t1 } case LPAREN | LBRACE if (canApply) => val app = atPos(t.pos.startOrPoint, in.offset) { // look for anonymous function application like (f _)(x) and // translate to (f _).apply(x), bug #460 val sel = t match { case Parens(List(Typed(_, _: Function))) => Select(stripParens(t), nme.apply) case _ => stripParens(t) } Apply(sel, argumentExprs()) } simpleExprRest(app, true) case USCORE => atPos(t.pos.startOrPoint, in.skipToken()) { Typed(stripParens(t), Function(Nil, EmptyTree)) } case _ => t } } /** ArgumentExprs ::= `(' [Exprs] `)' * | [nl] BlockExpr */ def argumentExprs(): List[Tree] = { def args(): List[Tree] = commaSeparated { val maybeNamed = isIdent expr() match { case a @ Assign(id, rhs) if maybeNamed => atPos(a.pos) { AssignOrNamedArg(id, rhs) } case e => e } } in.token match { case LBRACE => List(blockExpr()) case LPAREN => inParens(if (in.token == RPAREN) Nil else args()) case _ => Nil } } /** A succession of argument lists. */ def multipleArgumentExprs(): List[List[Tree]] = { if (in.token != LPAREN) Nil else argumentExprs() :: multipleArgumentExprs() } /** BlockExpr ::= `{' (CaseClauses | Block) `}' */ def blockExpr(): Tree = atPos(in.offset) { inBraces { if (in.token == CASE) Match(EmptyTree, caseClauses()) else block() } } /** Block ::= BlockStatSeq * @note Return tree does not carry position. */ def block(): Tree = makeBlock(blockStatSeq()) /** CaseClauses ::= CaseClause {CaseClause} * CaseClause ::= case Pattern [Guard] `=>' Block */ def caseClauses(): List[CaseDef] = { val cases = caseSeparated { atPos(in.offset)(makeCaseDef(pattern(), guard(), caseBlock())) } if (cases.isEmpty) // trigger error if there are no cases accept(CASE) cases } // IDE HOOK (so we can memoize case blocks) // needed? def caseBlock(): Tree = atPos(accept(ARROW))(block()) /** Guard ::= if PostfixExpr */ def guard(): Tree = if (in.token == IF) { in.nextToken(); stripParens(postfixExpr()) } else EmptyTree /** Enumerators ::= Generator {semi Enumerator} * Enumerator ::= Generator * | Guard * | val Pattern1 `=' Expr */ def enumerators(): List[Enumerator] = { val newStyle = in.token != VAL 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) { in.nextToken() if (newStyle) { if (in.token == IF) enums += makeFilter(in.offset, guard()) else generator(enums, true) } else { if (in.token == VAL) generator(enums, true) else enums += makeFilter(in.offset, expr()) } } enums.toList } /** Generator ::= Pattern1 (`<-' | '=') Expr [Guard] */ def generator(enums: ListBuffer[Enumerator], eqOK: Boolean) { val start = in.offset if (in.token == VAL) in.nextToken() val pat = noSeq.pattern1() val point = in.offset val tok = in.token if (tok == EQUALS && eqOK) in.nextToken() else accept(LARROW) val rhs = expr() enums += makeGenerator(r2p(start, point, in.lastOffset max start), pat, tok == EQUALS, rhs) // why max above? IDE stress tests have shown that lastOffset could be less than start, // I guess this happens if instead if a for-expression we sit on a closing paren. while (in.token == IF) enums += makeFilter(in.offset, guard()) } def makeFilter(start: Int, tree: Tree) = Filter(r2p(start, tree.pos.point, tree.pos.endOrPoint), tree) /* -------- PATTERNS ------------------------------------------- */ /** Methods which implicitly propagate whether the initial call took * place in a context where sequences are allowed. Formerly, this * was threaded through methods as boolean seqOK. */ trait SeqContextSensitive extends PatternContextSensitive { /** Returns Some(tree) if it finds a star and prematurely ends parsing. * This is an artifact of old implementation which has proven difficult * to cleanly extract. */ def interceptStarPattern(top: Tree): Option[Tree] def functionArgType(): Tree = argType() def argType(): Tree = { val start = in.offset in.token match { case USCORE => in.nextToken() if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start) else atPos(start) { Bind(tpnme.WILDCARD, EmptyTree) } case IDENTIFIER if treeInfo.isVariableName(in.name) => atPos(start) { Bind(identForType(), EmptyTree) } case _ => typ() } } /** Patterns ::= Pattern { `,' Pattern } * SeqPatterns ::= SeqPattern { `,' SeqPattern } */ def patterns(): List[Tree] = commaSeparated(pattern()) /** Pattern ::= Pattern1 { `|' Pattern1 } * SeqPattern ::= SeqPattern1 { `|' SeqPattern1 } */ def pattern(): Tree = { val start = in.offset def loop(): List[Tree] = pattern1() :: { if (isRawBar) { in.nextToken() ; loop() } else Nil } loop() match { case pat :: Nil => pat case xs => atPos(start)(makeAlternative(xs)) } } /** Pattern1 ::= varid `:' TypePat * | `_' `:' TypePat * | Pattern2 * SeqPattern1 ::= varid `:' TypePat * | `_' `:' TypePat * | [SeqPattern2] */ def pattern1(): Tree = pattern2() match { case p @ Ident(name) if treeInfo.isVarPattern(p) && in.token == COLON => atPos(p.pos.startOrPoint, in.skipToken()) { Typed(p, compoundType()) } case p => p } /* Pattern2 ::= varid [ @ Pattern3 ] * | Pattern3 * SeqPattern2 ::= varid [ @ SeqPattern3 ] * | SeqPattern3 */ def pattern2(): Tree = { val p = pattern3() if (in.token != AT) p else p match { case Ident(nme.WILDCARD) => in.nextToken() pattern3() case Ident(name) if treeInfo.isVarPattern(p) => in.nextToken() atPos(p.pos.startOrPoint) { Bind(name, pattern3()) } case _ => p } } /* Pattern3 ::= SimplePattern * | SimplePattern {Id [nl] SimplePattern} * SeqPattern3 ::= SeqSimplePattern [ '*' | '?' | '+' ] * | SeqSimplePattern {Id [nl] SeqSimplePattern} */ def pattern3(): Tree = { val base = opstack var top = simplePattern() interceptStarPattern(top) foreach { x => return x } while (isIdent && in.name != raw.BAR) { top = reduceStack( false, base, top, precedence(in.name), treeInfo.isLeftAssoc(in.name)) val op = in.name opstack = OpInfo(top, op, in.offset) :: opstack ident() top = simplePattern() } stripParens(reduceStack(false, base, top, 0, true)) } /** SimplePattern ::= varid * | `_' * | literal * | XmlPattern * | StableId [TypeArgs] [`(' [SeqPatterns] `)'] * | `(' [Patterns] `)' * SimpleSeqPattern ::= varid * | `_' * | literal * | XmlPattern * | `<' xLiteralPattern * | StableId [TypeArgs] [`(' [SeqPatterns] `)'] * | `(' [SeqPatterns] `)' * * XXX: Hook for IDE */ def simplePattern(): 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(nme.MINUS) => return atPos(start) { literal(true) } case _ => } case _ => } val typeAppliedTree = in.token match { case LBRACKET => atPos(start, in.offset)(TypeApply(convertToTypeId(t), typeArgs())) case _ => t } in.token match { case LPAREN => atPos(start, in.offset)(Apply(typeAppliedTree, argumentPatterns())) case _ => typeAppliedTree } case USCORE => in.nextToken() atPos(start, start) { Ident(nme.WILDCARD) } case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL => atPos(start) { literal(false) } case LPAREN => atPos(start)(makeParens(noSeq.patterns())) case XMLSTART => xmlLiteralPattern() case _ => syntaxErrorOrIncomplete("illegal start of simple pattern", true) errorPatternTree } } } /** The implementation of the context sensitive methods for parsing * outside of patterns. */ object outPattern extends PatternContextSensitive { def argType(): Tree = typ() def functionArgType(): Tree = paramType(useStartAsPosition = true) } /** The implementation for parsing inside of patterns at points where * sequences are allowed. */ object seqOK extends SeqContextSensitive { // See ticket #3189 for the motivation for the null check. // TODO: dredge out the remnants of regexp patterns. // ... and now this is back the way it was because it caused #3480. def interceptStarPattern(top: Tree): Option[Tree] = if (isRawStar) Some(atPos(top.pos.startOrPoint, in.skipToken())(Star(stripParens(top)))) else None } /** The implementation for parsing inside of patterns at points where * sequences are disallowed. */ object noSeq extends SeqContextSensitive { def interceptStarPattern(top: Tree) = None } /** These are default entry points into the pattern context sensitive methods: * they are all initiated from non-pattern context. */ def typ(): Tree = outPattern.typ() def startInfixType() = outPattern.infixType(InfixMode.FirstOp) def startAnnotType() = outPattern.annotType() def exprTypeArgs() = outPattern.typeArgs() def exprSimpleType() = outPattern.simpleType() /** Default entry points into some pattern contexts. */ def pattern(): Tree = noSeq.pattern() def patterns(): List[Tree] = noSeq.patterns() def seqPatterns(): List[Tree] = seqOK.patterns() // Also called from xml parser def argumentPatterns(): List[Tree] = inParens { if (in.token == RPAREN) Nil else seqPatterns() } def xmlLiteralPattern(): Tree /* -------- MODIFIERS and ANNOTATIONS ------------------------------------------- */ /** Drop `private' modifier when followed by a qualifier. * Contract `abstract' and `override' to ABSOVERRIDE */ private def normalize(mods: Modifiers): Modifiers = if (mods.isPrivate && mods.hasAccessBoundary) normalize(mods &~ Flags.PRIVATE) else if (mods hasAllFlags (Flags.ABSTRACT | Flags.OVERRIDE)) normalize(mods &~ (Flags.ABSTRACT | Flags.OVERRIDE) | Flags.ABSOVERRIDE) else mods private def addMod(mods: Modifiers, mod: Long, pos: Position): Modifiers = { if (mods hasFlag mod) syntaxError(in.offset, "repeated modifier", false) in.nextToken() (mods | mod) withPosition (mod, pos) } private def tokenRange(token: TokenData) = r2p(token.offset, token.offset, token.offset + token.name.length - 1) /** AccessQualifier ::= "[" (Id | this) "]" */ def accessQualifierOpt(mods: Modifiers): Modifiers = { var result = mods if (in.token == LBRACKET) { in.nextToken() if (mods.hasAccessBoundary) syntaxError("duplicate private/protected qualifier", false) result = if (in.token == THIS) { in.nextToken(); mods | Flags.LOCAL } else Modifiers(mods.flags, identForType()) accept(RBRACKET) } result } private val flagTokens: Map[Int, Long] = Map( ABSTRACT -> Flags.ABSTRACT, FINAL -> Flags.FINAL, IMPLICIT -> Flags.IMPLICIT, LAZY -> Flags.LAZY, OVERRIDE -> Flags.OVERRIDE, PRIVATE -> Flags.PRIVATE, PROTECTED -> Flags.PROTECTED, SEALED -> Flags.SEALED ) /** AccessModifier ::= (private | protected) [AccessQualifier] */ def accessModifierOpt(): Modifiers = normalize { in.token match { case m @ (PRIVATE | PROTECTED) => in.nextToken() ; accessQualifierOpt(Modifiers(flagTokens(m))) case _ => NoMods } } /** Modifiers ::= {Modifier} * Modifier ::= LocalModifier * | AccessModifier * | override */ def modifiers(): Modifiers = normalize { def loop(mods: Modifiers): Modifiers = in.token match { case PRIVATE | PROTECTED => loop(accessQualifierOpt(addMod(mods, flagTokens(in.token), tokenRange(in)))) case ABSTRACT | FINAL | SEALED | OVERRIDE | IMPLICIT | LAZY => loop(addMod(mods, flagTokens(in.token), tokenRange(in))) case NEWLINE => in.nextToken() loop(mods) case _ => mods } loop(NoMods) } /** LocalModifiers ::= {LocalModifier} * LocalModifier ::= abstract | final | sealed | implicit | lazy */ def localModifiers(): Modifiers = { def loop(mods: Modifiers): Modifiers = if (isLocalModifier) loop(addMod(mods, flagTokens(in.token), tokenRange(in))) else mods loop(NoMods) } /** Annotations ::= {`@' SimpleType {ArgumentExprs}} * ConsrAnnotations ::= {`@' SimpleType ArgumentExprs} */ def annotations(skipNewLines: Boolean): List[Tree] = readAnnots { val t = annotationExpr() if (skipNewLines) newLineOpt() t } def constructorAnnotations(): List[Tree] = readAnnots { atPos(in.offset)(New(exprSimpleType(), List(argumentExprs()))) } def annotationExpr(): Tree = atPos(in.offset) { val t = exprSimpleType() if (in.token == LPAREN) New(t, multipleArgumentExprs()) else New(t, List(Nil)) } /* -------- PARAMETERS ------------------------------------------- */ /** ParamClauses ::= {ParamClause} [[nl] `(' implicit Params `)'] * ParamClause ::= [nl] `(' [Params] ')' * Params ::= Param {`,' Param} * Param ::= {Annotation} Id [`:' ParamType] [`=' Expr] * ClassParamClauses ::= {ClassParamClause} [[nl] `(' implicit ClassParams `)'] * ClassParamClause ::= [nl] `(' [ClassParams] ')' * ClassParams ::= ClassParam {`,' ClassParam} * ClassParam ::= {Annotation} [{Modifier} (`val' | `var')] Id [`:' ParamType] [`=' Expr] */ def paramClauses(owner: Name, contextBounds: List[Tree], ofCaseClass: Boolean): List[List[ValDef]] = { var implicitmod = 0 var caseParam = ofCaseClass def param(): ValDef = { val start = in.offset val annots = annotations(false) var mods = Modifiers(Flags.PARAM) if (owner.isTypeName) { mods = modifiers() | Flags.PARAMACCESSOR if (mods.isLazy) syntaxError("lazy modifier not allowed here. Use call-by-name parameters instead", false) in.token match { case v @ (VAL | VAR) => mods = mods withPosition (in.token, tokenRange(in)) if (v == VAR) mods |= Flags.MUTABLE in.nextToken() case _ => if (mods.flags != Flags.PARAMACCESSOR) accept(VAL) if (!caseParam) mods |= Flags.PRIVATE | Flags.LOCAL } if (caseParam) mods |= Flags.CASEACCESSOR } val nameOffset = in.offset val name = ident() var bynamemod = 0 val tpt = if (settings.YmethodInfer.value && !owner.isTypeName && in.token != COLON) { TypeTree() } else { // XX-METHOD-INFER accept(COLON) if (in.token == ARROW) { if (owner.isTypeName && !mods.hasLocalFlag) syntaxError( in.offset, (if (mods.isMutable) "`var'" else "`val'") + " parameters may not be call-by-name", false) else if (implicitmod != 0) syntaxError( in.offset, "implicit parameters may not be call-by-name", false) else bynamemod = Flags.BYNAMEPARAM } paramType() } val default = if (in.token == EQUALS) { in.nextToken() mods |= Flags.DEFAULTPARAM expr() } else EmptyTree atPos(start, if (name == nme.ERROR) start else nameOffset) { ValDef((mods | implicitmod | bynamemod) withAnnotations annots, name, tpt, default) } } def paramClause(): List[ValDef] = { if (in.token == RPAREN) return Nil if (in.token == IMPLICIT) { if (contextBounds.nonEmpty) syntaxError("cannot have both implicit parameters and context bounds `: ...' or view bounds `<% ...' on type parameters", false) in.nextToken() implicitmod = Flags.IMPLICIT } commaSeparated(param()) } val vds = new ListBuffer[List[ValDef]] val start = in.offset newLineOptWhenFollowedBy(LPAREN) if (ofCaseClass && in.token != LPAREN) deprecationWarning(in.lastOffset, "case classes without a parameter list have been deprecated;\n"+ "use either case objects or case classes with `()' as parameter list.") while (implicitmod == 0 && in.token == LPAREN) { in.nextToken() vds += paramClause() accept(RPAREN) caseParam = false newLineOptWhenFollowedBy(LPAREN) } val result = vds.toList if (owner == nme.CONSTRUCTOR && (result.isEmpty || (result.head take 1 exists (_.mods.isImplicit)))) { in.token match { case LBRACKET => syntaxError(in.offset, "no type parameters allowed here", false) case EOF => incompleteInputError("auxiliary constructor needs non-implicit parameter list") case _ => syntaxError(start, "auxiliary constructor needs non-implicit parameter list", false) } } addEvidenceParams(owner, result, contextBounds) } /** ParamType ::= Type | `=>' Type | Type `*' */ def paramType(): Tree = paramType(useStartAsPosition = false) def paramType(useStartAsPosition: Boolean): Tree = { val start = in.offset in.token match { case ARROW => in.nextToken() atPos(start)(byNameApplication(typ())) case _ => val t = typ() if (isRawStar) { in.nextToken() if (useStartAsPosition) atPos(start)(repeatedApplication(t)) else atPos(t.pos.startOrPoint, t.pos.point)(repeatedApplication(t)) } else t } } /** TypeParamClauseOpt ::= [TypeParamClause] * TypeParamClause ::= `[' VariantTypeParam {`,' VariantTypeParam} `]'] * VariantTypeParam ::= {Annotation} [`+' | `-'] TypeParam * FunTypeParamClauseOpt ::= [FunTypeParamClause] * FunTypeParamClause ::= `[' TypeParam {`,' TypeParam} `]'] * TypeParam ::= Id TypeParamClauseOpt TypeBounds {<% Type} {":" Type} */ def typeParamClauseOpt(owner: Name, contextBoundBuf: ListBuffer[Tree]): List[TypeDef] = { def typeParam(ms: Modifiers): TypeDef = { var mods = ms | Flags.PARAM val start = in.offset if (owner.isTypeName && isIdent) { if (in.name == raw.PLUS) { in.nextToken() mods |= Flags.COVARIANT } else if (in.name == raw.MINUS) { in.nextToken() mods |= Flags.CONTRAVARIANT } } val nameOffset = in.offset // TODO AM: freshName(o2p(in.skipToken()), "_$$"), will need to update test suite val pname: TypeName = wildcardOrIdent().toTypeName val param = atPos(start, nameOffset) { val tparams = typeParamClauseOpt(pname, null) // @M TODO null --> no higher-order context bounds for now TypeDef(mods, pname, tparams, typeBounds()) } if (contextBoundBuf ne null) { while (in.token == VIEWBOUND) { contextBoundBuf += atPos(in.skipToken()) { makeFunctionTypeTree(List(Ident(pname)), typ()) } } while (in.token == COLON) { contextBoundBuf += atPos(in.skipToken()) { AppliedTypeTree(typ(), List(Ident(pname))) } } } param } newLineOptWhenFollowedBy(LBRACKET) if (in.token == LBRACKET) inBrackets(commaSeparated(typeParam(NoMods withAnnotations annotations(true)))) else Nil } /** TypeBounds ::= [`>:' Type] [`<:' Type] */ def typeBounds(): TypeBoundsTree = { val t = TypeBoundsTree( bound(SUPERTYPE, tpnme.Nothing), bound(SUBTYPE, tpnme.Any) ) t setPos wrappingPos(List(t.hi, t.lo)) } def bound(tok: Int, default: TypeName): Tree = if (in.token == tok) { in.nextToken(); typ() } else atPos(o2p(in.lastOffset)) { rootScalaDot(default) } /* -------- DEFS ------------------------------------------- */ /** Import ::= import ImportExpr {`,' ImportExpr} */ def importClause(): List[Tree] = { val offset = accept(IMPORT) commaSeparated(importExpr()) match { case Nil => Nil case t :: rest => // The first import should start at the position of the keyword. t.setPos(t.pos.withStart(offset)) t :: rest } } /** ImportExpr ::= StableId `.' (Id | `_' | ImportSelectors) */ def importExpr(): Tree = { val start = in.offset def thisDotted(name: TypeName) = { in.nextToken() val t = atPos(start)(This(name)) accept(DOT) val result = selector(t) accept(DOT) result } /** Walks down import foo.bar.baz.{ ... } until it ends at a * an underscore, a left brace, or an undotted identifier. */ def loop(expr: Tree): Tree = { expr setPos expr.pos.makeTransparent val selectors: List[ImportSelector] = in.token match { case USCORE => List(importSelector()) // import foo.bar._; case LBRACE => importSelectors() // import foo.bar.{ x, y, z } case _ => val nameOffset = in.offset val name = ident() if (in.token == DOT) { // import foo.bar.ident.<unknown> and so create a select node and recurse. val t = atPos(start, if (name == nme.ERROR) in.offset else nameOffset)(Select(expr, name)) in.nextToken() return loop(t) } // import foo.bar.Baz; else List(makeImportSelector(name, nameOffset)) } // reaching here means we're done walking. atPos(start)(Import(expr, selectors)) } loop(in.token match { case THIS => thisDotted(tpnme.EMPTY) case _ => val id = atPos(start)(Ident(ident())) accept(DOT) if (in.token == THIS) thisDotted(id.name.toTypeName) else id }) } /** ImportSelectors ::= `{' {ImportSelector `,'} (ImportSelector | `_') `}' */ def importSelectors(): List[ImportSelector] = { val selectors = inBracesOrNil(commaSeparated(importSelector())) selectors.init foreach { case ImportSelector(nme.WILDCARD, pos, _, _) => syntaxError(pos, "Wildcard import must be in last position") case _ => () } selectors } def wildcardOrIdent() = { if (in.token == USCORE) { in.nextToken() ; nme.WILDCARD } else ident() } /** ImportSelector ::= Id [`=>' Id | `=>' `_'] */ def importSelector(): ImportSelector = { val start = in.offset val name = wildcardOrIdent() var renameOffset = -1 val rename = in.token match { case ARROW => in.nextToken() renameOffset = in.offset wildcardOrIdent() case _ if name == nme.WILDCARD => null case _ => renameOffset = start name } ImportSelector(name, start, rename, renameOffset) } /** Def ::= val PatDef * | var PatDef * | def FunDef * | type [nl] TypeDef * | TmplDef * Dcl ::= val PatDcl * | var PatDcl * | def FunDcl * | type [nl] TypeDcl */ def defOrDcl(pos: Int, mods: Modifiers): List[Tree] = { if (mods.isLazy && in.token != VAL) syntaxError("lazy not allowed here. Only vals can be lazy", false) in.token match { case VAL => patDefOrDcl(pos, mods withPosition(VAL, tokenRange(in))) case VAR => patDefOrDcl(pos, (mods | Flags.MUTABLE) withPosition (VAR, tokenRange(in))) case DEF => List(funDefOrDcl(pos, mods withPosition(DEF, tokenRange(in)))) case TYPE => List(typeDefOrDcl(pos, mods withPosition(TYPE, tokenRange(in)))) case _ => List(tmplDef(pos, mods)) } } private def caseAwareTokenOffset = if (in.token == CASECLASS || in.token == CASEOBJECT) in.prev.offset else in.offset def nonLocalDefOrDcl : List[Tree] = { val annots = annotations(true) defOrDcl(caseAwareTokenOffset, modifiers() withAnnotations annots) } /** PatDef ::= Pattern2 {`,' Pattern2} [`:' Type] `=' Expr * ValDcl ::= Id {`,' Id} `:' Type * VarDef ::= PatDef | Id {`,' Id} `:' Type `=' `_' */ def patDefOrDcl(pos : Int, mods: Modifiers): List[Tree] = { var newmods = mods in.nextToken() val lhs = commaSeparated(stripParens(noSeq.pattern2())) val tp = typedOpt() val rhs = if (tp.isEmpty || in.token == EQUALS) { accept(EQUALS) if (!tp.isEmpty && newmods.isMutable && (lhs.toList forall (_.isInstanceOf[Ident])) && in.token == USCORE) { in.nextToken() newmods = newmods | Flags.DEFAULTINIT EmptyTree } else { expr() } } else { newmods = newmods | Flags.DEFERRED EmptyTree } def mkDefs(p: Tree, tp: Tree, rhs: Tree): List[Tree] = { //Console.println("DEBUG: p = "+p.toString()); // DEBUG val trees = makePatDef(newmods, if (tp.isEmpty) p else Typed(p, tp) setPos (p.pos union tp.pos), rhs) if (newmods.isDeferred) { trees match { case List(ValDef(_, _, _, EmptyTree)) => if (mods.isLazy) syntaxError(p.pos, "lazy values may not be abstract", false) case _ => syntaxError(p.pos, "pattern definition may not be abstract", false) } } trees } val trees = (lhs.toList.init flatMap (mkDefs(_, tp.duplicate, rhs.duplicate))) ::: mkDefs(lhs.last, tp, rhs) val hd = trees.head hd setPos hd.pos.withStart(pos) ensureNonOverlapping(hd, trees.tail) trees } /** VarDef ::= PatDef * | Id {`,' Id} `:' Type `=' `_' * VarDcl ::= Id {`,' Id} `:' Type def varDefOrDcl(mods: Modifiers): List[Tree] = { var newmods = mods | Flags.MUTABLE val lhs = new ListBuffer[(Int, Name)] do { in.nextToken() lhs += (in.offset, ident()) } while (in.token == COMMA) val tp = typedOpt() val rhs = if (tp.isEmpty || in.token == EQUALS) { accept(EQUALS) if (!tp.isEmpty && in.token == USCORE) { in.nextToken() EmptyTree } else { expr() } } else { newmods = newmods | Flags.DEFERRED EmptyTree } } */ /** FunDef ::= FunSig `:' Type `=' Expr * | FunSig [nl] `{' Block `}' * | this ParamClause ParamClauses (`=' ConstrExpr | [nl] ConstrBlock) * FunDcl ::= FunSig [`:' Type] * FunSig ::= id [FunTypeParamClause] ParamClauses */ def funDefOrDcl(start : Int, mods: Modifiers): Tree = { in.nextToken if (in.token == THIS) { atPos(start, in.skipToken()) { val vparamss = paramClauses(nme.CONSTRUCTOR, classContextBounds map (_.duplicate), false) newLineOptWhenFollowedBy(LBRACE) val rhs = in.token match { case LBRACE => atPos(in.offset) { constrBlock(vparamss) } case _ => accept(EQUALS) ; atPos(in.offset) { constrExpr(vparamss) } } DefDef(mods, nme.CONSTRUCTOR, List(), vparamss, TypeTree(), rhs) } } else { var newmods = mods val nameOffset = in.offset val name = ident() val result = atPos(start, if (name == nme.ERROR) start else nameOffset) { // contextBoundBuf is for context bounded type parameters of the form // [T : B] or [T : => B]; it contains the equivalent implicit parameter type, // i.e. (B[T] or T => B) val contextBoundBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, contextBoundBuf) val vparamss = paramClauses(name, contextBoundBuf.toList, false) newLineOptWhenFollowedBy(LBRACE) var restype = fromWithinReturnType(typedOpt()) val rhs = if (isStatSep || in.token == RBRACE) { if (restype.isEmpty) restype = scalaUnitConstr newmods |= Flags.DEFERRED EmptyTree } else if (restype.isEmpty && in.token == LBRACE) { restype = scalaUnitConstr blockExpr() } else { equalsExpr() } DefDef(newmods, name, tparams, vparamss, restype, rhs) } signalParseProgress(result.pos) result } } /** ConstrExpr ::= SelfInvocation * | ConstrBlock */ def constrExpr(vparamss: List[List[ValDef]]): Tree = if (in.token == LBRACE) constrBlock(vparamss) else Block(List(selfInvocation(vparamss)), Literal(())) /** SelfInvocation ::= this ArgumentExprs {ArgumentExprs} */ def selfInvocation(vparamss: List[List[ValDef]]): Tree = atPos(accept(THIS)) { newLineOptWhenFollowedBy(LBRACE) var t = Apply(Ident(nme.CONSTRUCTOR), argumentExprs()) newLineOptWhenFollowedBy(LBRACE) while (in.token == LPAREN || in.token == LBRACE) { t = Apply(t, argumentExprs()) newLineOptWhenFollowedBy(LBRACE) } if (classContextBounds.isEmpty) t else Apply(t, vparamss.last.map(vp => Ident(vp.name))) } /** ConstrBlock ::= `{' SelfInvocation {semi BlockStat} `}' */ def constrBlock(vparamss: List[List[ValDef]]): Tree = atPos(in.skipToken()) { val stats = selfInvocation(vparamss) :: { if (isStatSep) { in.nextToken(); blockStatSeq() } else Nil } accept(RBRACE) Block(stats, Literal(())) } /** TypeDef ::= type Id [TypeParamClause] `=' Type * TypeDcl ::= type Id [TypeParamClause] TypeBounds */ def typeDefOrDcl(start: Int, mods: Modifiers): Tree = { in.nextToken() newLinesOpt() atPos(start, in.offset) { val name = identForType() // @M! a type alias as well as an abstract type may declare type parameters val tparams = typeParamClauseOpt(name, null) in.token match { case EQUALS => in.nextToken() TypeDef(mods, name, tparams, typ()) case SUPERTYPE | SUBTYPE | SEMI | NEWLINE | NEWLINES | COMMA | RBRACE => TypeDef(mods | Flags.DEFERRED, name, tparams, typeBounds()) case _ => syntaxErrorOrIncomplete("`=', `>:', or `<:' expected", true) EmptyTree } } } /** 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 ClassDef * | [case] object ObjectDef * | [override] trait TraitDef */ def tmplDef(pos: Int, mods: Modifiers): Tree = { if (mods.isLazy) syntaxError("classes cannot be lazy", false) in.token match { case TRAIT => classDef(pos, (mods | Flags.TRAIT | Flags.ABSTRACT) withPosition (Flags.TRAIT, tokenRange(in))) case CLASS => classDef(pos, mods) case CASECLASS => classDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'class', thus take prev*/))) case OBJECT => objectDef(pos, mods) case CASEOBJECT => objectDef(pos, (mods | Flags.CASE) withPosition (Flags.CASE, tokenRange(in.prev /*scanner skips on 'case' to 'object', thus take prev*/))) case _ => syntaxErrorOrIncomplete("expected start of definition", true) EmptyTree } } /** ClassDef ::= Id [TypeParamClause] {Annotation} [AccessModifier] ClassParamClauses RequiresTypeOpt ClassTemplateOpt * TraitDef ::= Id [TypeParamClause] RequiresTypeOpt TraitTemplateOpt */ def classDef(start: Int, mods: Modifiers): ClassDef = { in.nextToken val nameOffset = in.offset val name = identForType() def isTrait = mods.hasTraitFlag atPos(start, if (name == tpnme.ERROR) start else nameOffset) { savingClassContextBounds { val contextBoundBuf = new ListBuffer[Tree] val tparams = typeParamClauseOpt(name, contextBoundBuf) classContextBounds = contextBoundBuf.toList val tstart = in.offset :: classContextBounds.map(_.pos.startOrPoint) min; if (!classContextBounds.isEmpty && isTrait) { syntaxError("traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'", false) classContextBounds = List() } val constrAnnots = constructorAnnotations() val (constrMods, vparamss) = if (isTrait) (Modifiers(Flags.TRAIT), List()) else (accessModifierOpt(), paramClauses(name, classContextBounds, mods.isCase)) var mods1 = mods if (isTrait) { if (settings.YvirtClasses && in.token == SUBTYPE) mods1 |= Flags.DEFERRED } else if (in.token == SUBTYPE) { syntaxError("classes are not allowed to be virtual", false) } val template = templateOpt(mods1, name, constrMods withAnnotations constrAnnots, vparamss, tstart) if (isInterface(mods1, template.body)) mods1 |= Flags.INTERFACE val result = ClassDef(mods1, name, tparams, template) // Context bounds generate implicit parameters (part of the template) with types // from tparams: we need to ensure these don't overlap if (!classContextBounds.isEmpty) ensureNonOverlapping(template, tparams) result } } } /** ObjectDef ::= Id ClassTemplateOpt */ def objectDef(start: Int, mods: Modifiers): ModuleDef = { in.nextToken val nameOffset = in.offset val name = ident() val tstart = in.offset 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, Nil, tstart) 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] += startAnnotType() val argss = if (in.token == LPAREN && !isTrait) multipleArgumentExprs() else List(Nil) while (in.token == WITH) { in.nextToken() parents += startAnnotType() } (parents.toList, argss) } /** ClassTemplate ::= [EarlyDefs with] ClassParents [TemplateBody] * TraitTemplate ::= [EarlyDefs with] TraitParents [TemplateBody] * EarlyDefs ::= `{' [EarlyDef {semi EarlyDef}] `}' * EarlyDef ::= Annotations Modifiers PatDef */ def template(isTrait: Boolean): (List[Tree], List[List[Tree]], ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { // @S: pre template body cannot stub like post body can! val (self, body) = templateBody(true) if (in.token == WITH && self.isEmpty) { val earlyDefs: List[Tree] = body flatMap { case vdef @ ValDef(mods, name, tpt, rhs) if !mods.isDeferred => List(treeCopy.ValDef(vdef, mods | Flags.PRESUPER, name, tpt, rhs)) case tdef @ TypeDef(mods, name, tparams, rhs) => List(treeCopy.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) List() case _ => List() } in.nextToken() val (parents, argss) = templateParents(isTrait) val (self1, body1) = templateBodyOpt(isTrait) (parents, argss, self1, earlyDefs ::: body1) } else { (List(), List(List()), self, body) } } else { val (parents, argss) = templateParents(isTrait) val (self, body) = templateBodyOpt(isTrait) (parents, argss, self, body) } } def isInterface(mods: Modifiers, body: List[Tree]): Boolean = mods.hasTraitFlag && (body forall treeInfo.isInterfaceMember) /** ClassTemplateOpt ::= 'extends' ClassTemplate | [['extends'] TemplateBody] * TraitTemplateOpt ::= TraitExtends TraitTemplate | [['extends'] TemplateBody] | '<:' TemplateBody * TraitExtends ::= 'extends' | `<:' */ def templateOpt(mods: Modifiers, name: Name, constrMods: Modifiers, vparamss: List[List[ValDef]], tstart: Int): Template = { val (parents0, argss, self, body) = ( if (in.token == EXTENDS || in.token == SUBTYPE && mods.hasTraitFlag) { in.nextToken() template(mods.hasTraitFlag) } else { newLineOptWhenFollowedBy(LBRACE) val (self, body) = templateBodyOpt(false) (List(), List(List()), self, body) } ) val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { if (isAnyValType(name)) { val parent = if (name == tpnme.AnyVal) tpnme.Any else tpnme.AnyVal Template(List(scalaDot(parent)), self, body) } else { val parents = ( if (!isInterface(mods, body) && !isScalaArray(name)) parents0 :+ scalaScalaObjectConstr else if (parents0.isEmpty) List(scalaAnyRefConstr) else parents0 ) ++ ( if (mods.isCase) List(productConstr, serializableConstr) else Nil ) Template(parents, self, constrMods, vparamss, argss, body, o2p(tstart)) } } } /* -------- TEMPLATES ------------------------------------------- */ /** TemplateBody ::= [nl] `{' TemplateStatSeq `}' * @param isPre specifies whether in early initializer (true) or not (false) */ def templateBody(isPre: Boolean) = inBraces(templateStatSeq(isPre)) match { case (self, Nil) => (self, List(EmptyTree)) case result => result } def templateBodyOpt(traitParentSeen: Boolean): (ValDef, List[Tree]) = { newLineOptWhenFollowedBy(LBRACE) if (in.token == LBRACE) { templateBody(false) } else { if (in.token == LPAREN) syntaxError((if (traitParentSeen) "parents of traits" else "traits or objects")+ " may not have parameters", true) (emptyValDef, List()) } } /** Refinement ::= [nl] `{' RefineStat {semi RefineStat} `}' */ def refinement(): List[Tree] = inBraces(refineStatSeq()) /* -------- STATSEQS ------------------------------------------- */ /** Create a tree representing a packaging */ def makePackaging(start: Int, pkg: Tree, stats: List[Tree]): PackageDef = pkg match { case x: RefTree => atPos(start, pkg.pos.point)(PackageDef(x, stats)) } /* pkg match { case id @ Ident(_) => PackageDef(id, stats) case Select(qual, name) => // drop this to flatten packages makePackaging(start, qual, List(PackageDef(Ident(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.startOrPoint)){ Ident(name) }, List(ModuleDef(mods, nme.PACKAGEkw, impl))) } /** Packaging ::= package QualId [nl] `{' TopStatSeq `}' */ def packaging(start: Int): Tree = { val pkg = pkgQualId() val stats = inBracesOrNil(topStatSeq()) makePackaging(start, pkg, stats) } /** TopStatSeq ::= TopStat {semi TopStat} * TopStat ::= Annotations Modifiers TmplDef * | Packaging * | package object objectDef * | Import * | */ def topStatSeq(): List[Tree] = { val stats = new ListBuffer[Tree] while (!isStatSeqEnd) { stats ++= (in.token match { case PACKAGE => val start = in.skipToken() if (in.token == OBJECT) joinComment(List(makePackageObject(start, objectDef(in.offset, NoMods)))) else { in.flushDoc List(packaging(start)) } case IMPORT => in.flushDoc importClause() case x if x == AT || isTemplateIntro || isModifier => joinComment(List(topLevelTmplDef)) case _ => if (!isStatSep) syntaxErrorOrIncomplete("expected class or object definition", true) Nil }) acceptStatSepOpt() } stats.toList } /** TemplateStatSeq ::= [id [`:' Type] `=>'] TemplateStat {semi TemplateStat} * TemplateStat ::= Import * | Annotations Modifiers Def * | Annotations Modifiers Dcl * | Expr1 * | super ArgumentExprs {ArgumentExprs} * | * @param isPre specifies whether in early initializer (true) or not (false) */ def templateStatSeq(isPre : Boolean): (ValDef, List[Tree]) = checkNoEscapingPlaceholders { var self: ValDef = emptyValDef val stats = new ListBuffer[Tree] if (isExprIntro) { in.flushDoc val first = expr(InTemplate) // @S: first statement is potentially converted so cannot be stubbed. if (in.token == ARROW) { first match { case Typed(tree @ This(tpnme.EMPTY), tpt) => self = atPos(tree.pos union tpt.pos) { makeSelfDef(nme.WILDCARD, tpt) } case _ => convertToParam(first) match { case tree @ ValDef(_, name, tpt, EmptyTree) if (name != nme.ERROR) => self = atPos(tree.pos union tpt.pos) { makeSelfDef(name, tpt) } case _ => } } in.nextToken() } else { stats += first acceptStatSepOpt() } } while (!isStatSeqEnd) { if (in.token == IMPORT) { in.flushDoc stats ++= importClause() } else if (isExprIntro) { in.flushDoc stats += statement(InTemplate) } else if (isDefIntro || isModifier || in.token == AT) { stats ++= joinComment(nonLocalDefOrDcl) } else if (!isStatSep) { syntaxErrorOrIncomplete("illegal start of definition", true) } acceptStatSepOpt() } (self, stats.toList) } /** RefineStatSeq ::= RefineStat {semi RefineStat} * RefineStat ::= Dcl * | type TypeDef * | */ def refineStatSeq(): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] while (!isStatSeqEnd) { if (isDclIntro) { // don't IDE hook stats ++= joinComment(defOrDcl(in.offset, NoMods)) } else if (!isStatSep) { syntaxErrorOrIncomplete( "illegal start of declaration"+ (if (inFunReturnType) " (possible cause: missing `=' in front of current method body)" else ""), true) } if (in.token != RBRACE) acceptStatSep() } stats.toList } /** overridable IDE hook for local definitions of blockStatSeq * Here's an idea how to fill in start and end positions. def localDef : List[Tree] = { atEndPos { 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)) } } (in.offset) } */ def localDef(implicitMod: Int): List[Tree] = { val annots = annotations(true) val pos = in.offset val mods = (localModifiers() | implicitMod) withAnnotations annots val defs = if (!(mods hasFlag ~(Flags.IMPLICIT | Flags.LAZY))) defOrDcl(pos, mods) else List(tmplDef(pos, mods)) in.token match { case RBRACE | CASE => defs :+ (Literal(()) setPos o2p(in.offset)) case _ => defs } } /** BlockStatSeq ::= { BlockStat semi } [ResultExpr] * BlockStat ::= Import * | Annotations [implicit] [lazy] Def * | Annotations LocalModifiers TmplDef * | Expr1 * | */ def blockStatSeq(): List[Tree] = checkNoEscapingPlaceholders { val stats = new ListBuffer[Tree] while (!isStatSeqEnd && in.token != CASE) { if (in.token == IMPORT) { stats ++= importClause() acceptStatSep() } else if (isExprIntro) { stats += statement(InBlock) if (in.token != RBRACE && in.token != CASE) acceptStatSep() } else if (isDefIntro || isLocalModifier || in.token == AT) { if (in.token == IMPLICIT) { val start = in.skipToken() if (isIdent) stats += implicitClosure(start, InBlock) else stats ++= localDef(Flags.IMPLICIT) } else { stats ++= localDef(0) } acceptStatSepOpt() } else if (isStatSep) { in.nextToken() } else { val addendum = if (isModifier) " (no modifiers allowed here)" else "" syntaxErrorOrIncomplete("illegal start of statement" + addendum, true) } } stats.toList } /** CompilationUnit ::= {package QualId semi} TopStatSeq */ def compilationUnit(): Tree = checkNoEscapingPlaceholders { def topstats(): List[Tree] = { val ts = new ListBuffer[Tree] while (in.token == SEMI) in.nextToken() val start = in.offset if (in.token == PACKAGE) { in.nextToken() if (in.token == OBJECT) { ts ++= joinComment(List(makePackageObject(start, objectDef(in.offset, NoMods)))) if (in.token != EOF) { acceptStatSep() ts ++= topStatSeq() } } else { in.flushDoc val pkg = pkgQualId() if (in.token == EOF) { ts += makePackaging(start, pkg, List()) } else if (isStatSep) { in.nextToken() ts += makePackaging(start, pkg, topstats()) } else { ts += inBraces(makePackaging(start, pkg, topStatSeq())) acceptStatSepOpt() ts ++= topStatSeq() } } } else { ts ++= topStatSeq() } ts.toList } resetPackage() topstats() match { case List(stat @ PackageDef(_, _)) => stat case stats => val start = if (stats forall (_ == EmptyTree)) 0 else { val wpos = wrappingPos(stats) if (wpos.isDefined) wpos.startOrPoint else 0 } makePackaging(start, atPos(start, start, start) { Ident(nme.EMPTY_PACKAGE_NAME) }, stats) } } } }

Other Scala examples (source code examples)

Here is a short list of links related to this Scala Parsers.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.