parsers.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 1,932 行 · 第 1/5 页
SCALA
1,932 行
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Martin Odersky */// $Id: Parsers.scala 14561 2008-04-09 09:57:10Z odersky $//todo: allow infix type patternspackage scala.tools.nsc.ast.parserimport scala.tools.nsc.util.{ListBuffer, Position, OffsetPosition, NoPosition, BatchSourceFile}import symtab.Flagsimport Tokens._//todo verify when stableId's should be just plain qualified type ids/** <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> */trait Parsers extends NewScanners with MarkupParsers { val global : Global import global._ private val glob: global.type = global import global.posAssigner.atPos case class OpInfo(operand: Tree, operator: Name, pos: Int) /** ... * * @author Sean McDirmid */ class UnitParser(val unit: global.CompilationUnit) extends Parser { val in = new UnitScanner(unit) def freshName(pos : Position, prefix : String) = unit.fresh.newName(pos, prefix) implicit def i2p(offset : Int) : Position = new OffsetPosition(unit.source,offset) def warning(pos : Int, msg : String) : Unit = unit.warning(pos, msg) def incompleteInputError(msg: String) : Unit = unit.incompleteInputError(unit.source.asInstanceOf[BatchSourceFile].content.length - 1, msg) def deprecationWarning(pos : Int, msg : String) : Unit = unit.deprecationWarning(pos, msg) def syntaxError(pos: Int, msg: String) : Unit = unit.error(pos, msg) /** the markup parser */ def xmlp = { if (xmlp0 == null) xmlp0 = new MarkupParser(this, true) xmlp0 } object symbXMLBuilder extends SymbolicXMLBuilder(treeBuilder, this, true) { // DEBUG choices val global: Parsers.this.global.type = Parsers.this.global def freshName(prefix: String): Name = UnitParser.this.freshName(NoPosition, prefix) } private var xmlp0: MarkupParser = null def xmlLiteral : Tree = xmlp.xLiteral def xmlLiteralPattern : Tree = xmlp.xLiteralPattern } // parser constants, here so they don't pollute parser debug listing private object ParserConfiguration { final val Local = 0 final val InBlock = 1 final val InTemplate = 2 final val MINUS: Name = "-" final val PLUS : Name = "+" final val BANG : Name = "!" final val TILDE: Name = "~" final val AMP : Name = "&" final val SLASH: Name = "/" final val STAR : Name = "*" final val BAR : Name = "|" final val OPT : Name = "?" final val LT : Name = "<" } abstract class Parser { ParserConfiguration.hashCode import ParserConfiguration._ val in: ParserScanner //val unit : CompilationUnit //import in.ScanPosition protected def freshName(pos : Position, prefix: String): Name protected def posToReport: Int = in.currentPos protected implicit def i2p(offset : Int) : Position private implicit def p2i(pos : Position) = pos.offset.get private def inToken = in.token private def inSkipToken = in.skipToken private def inNextToken = in.nextToken private def inCurrentPos = in.currentPos private def inNextTokenCode : Int = in.nextTokenCode private def inName = in.name private def charVal = in.charVal private def intVal(isNegated : Boolean) = in.intVal(isNegated).asInstanceOf[Int] private def longVal(isNegated : Boolean) = in.intVal(isNegated) private def floatVal(isNegated : Boolean) = in.floatVal(isNegated).asInstanceOf[Float] private def doubleVal(isNegated : Boolean) = in.floatVal(isNegated) private def stringVal = in.stringVal /** whether a non-continuable syntax error has been seen */ //private var syntaxErrorSeen = false private var lastErrorPos : Int = -1 object treeBuilder extends TreeBuilder { val global: Parsers.this.global.type = Parsers.this.global def freshName(pos : Position, prefix: String): Name = Parser.this.freshName(pos, prefix) } import treeBuilder._ /** The implicit view parameters of the surrounding class */ var implicitClassViews: List[Tree] = Nil /** this is the general parse method */ def parse(): Tree = { val t = compilationUnit() accept(EOF) t }/////////// 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]) { t = ExistentialTypeTree(t, placeholderTypes.reverse) placeholderTypes = List() } placeholderTypes = placeholderTypes ::: savedPlaceholderTypes t }/////// ERROR HANDLING ////////////////////////////////////////////////////// protected def skip() { var nparens = 0 var nbraces = 0 while (true) { inToken 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 _ => } inNextToken } } def warning(pos : Int, msg : String) : Unit def incompleteInputError(msg: String) : Unit def deprecationWarning(pos : Int, msg : String) : Unit def syntaxError(pos: Int, msg: String) : Unit def syntaxError(msg: String, skipIt: Boolean) { syntaxError(inCurrentPos, msg, skipIt) } def syntaxError(pos: Int, msg: String, skipIt: Boolean) { if (pos > lastErrorPos) { syntaxError(pos, msg) // no more errors on this token. lastErrorPos = inCurrentPos } if (skipIt) skip() } def warning(msg: String) : Unit = warning(inCurrentPos, msg) def syntaxErrorOrIncomplete(msg: String, skipIt: Boolean) { val inToken = this.inToken if (inToken == EOF) incompleteInputError(msg) else syntaxError(inCurrentPos, msg, skipIt) } // unused. def mismatch(expected: Int, found: Int) { val posToReport = this.posToReport val msg = ScannerConfiguration.token2string(expected) + " expected but " + ScannerConfiguration.token2string(found) + " found." if (found == EOF) incompleteInputError(msg) else syntaxError(posToReport, msg, true) } /** Consume one token of the specified type, or * signal an error if it is not there. */ def accept(token: Int): Int = { val pos = inCurrentPos if (inToken != token) { val posToReport = //if (inCurrentPos.line(unit.source).get(0) > in.lastPos.line(unit.source).get(0)) // in.lastPos //else inCurrentPos val msg = ScannerConfiguration.token2string(token) + " expected but " + ScannerConfiguration.token2string(inToken) + " found." if (inToken == EOF) incompleteInputError(msg) else syntaxError(posToReport, msg, true) } if (inToken == token) inNextToken pos } def surround[T](open : Int, close : Int)(f : => T, orElse : T) : T = { val wasOpened = inToken == open accept(open) if (wasOpened) { val ret = f accept(close) ret } else orElse } /** semi = nl {nl} | `;' * nl = `\n' // where allowed */ def acceptStatSep() : Boolean = { if (inToken == NEWLINE || inToken == NEWLINES) { inNextToken; true } else { val ret = inToken == SEMI accept(SEMI) ret } } def errorTypeTree = TypeTree().setType(ErrorType).setPos((inCurrentPos)) def errorTermTree = Literal(Constant(null)).setPos((inCurrentPos)) def errorPatternTree = Ident(nme.WILDCARD).setPos((inCurrentPos))/////// TOKEN CLASSES ////////////////////////////////////////////////////// def isModifier: Boolean = inToken match { case ABSTRACT | FINAL | SEALED | PRIVATE | PROTECTED | OVERRIDE | IMPLICIT | LAZY => true case _ => false } def isLocalModifier: Boolean = inToken match { case ABSTRACT | FINAL | SEALED | IMPLICIT | LAZY => true case _ => false } def isDefIntro: Boolean = inToken match { case VAL | VAR | DEF | TYPE | OBJECT | CASEOBJECT | CLASS | CASECLASS | TRAIT => true case _ => false } def isDclIntro: Boolean = inToken match { case VAL | VAR | DEF | TYPE => true case _ => false } def isIdent = inToken == IDENTIFIER || inToken == BACKQUOTED_IDENT def isExprIntroToken(token: Int): Boolean = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | TRUE | FALSE | NULL | IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | IF | FOR | NEW | USCORE | TRY | WHILE | DO | RETURN | THROW | LPAREN | LBRACE | XMLSTART => true case _ => false } def isExprIntro: Boolean = isExprIntroToken(inToken) def isTypeIntroToken(token: Int): Boolean = token match { case IDENTIFIER | BACKQUOTED_IDENT | THIS | SUPER | USCORE | LPAREN | AT => true case _ => false } def isTypeIntro: Boolean = isTypeIntroToken(inToken) def isStatSep(token: Int): Boolean = token == NEWLINE || token == NEWLINES || token == SEMI def isStatSep: Boolean = isStatSep(inToken)/////// COMMENT AND ATTRIBUTE COLLECTION ////////////////////////////////////// /** Join the comment associated with a definition */ def joinComment(trees: => List[Tree]): List[Tree] = { val buf = in.flushDoc if ((buf ne null) && buf.length > 0) trees map (t => DocDef(buf, t) setPos t.pos) else trees }/////// TREE CONSTRUCTION //////////////////////////////////////////////////// /** Convert tree to formal parameter list */ def convertToParams(tree: Tree): List[ValDef] = tree match { case Parens(ts) => ts map convertToParam case _ => List(convertToParam(tree))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?