newscanners.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 896 行 · 第 1/2 页
SCALA
896 行
in.scratch append escapeCode(in.offset - 1); true case c => in.scratch.append(c); true }) {} val ret = value(STRINGLIT, in.scratch.toString) in.scratch setLength 0 ret } case '`' => in.scratch setLength 0 while (in.head match { case '`' => in.next; false case CR | LF | FF | SU | EOF => in.error(offset, "unterminated quoted identifier") false case _ => true }) in.scratch append in.next val name = global.newTermName(in.scratch.toString) value(BACKQUOTED_IDENT, (name)) case c if (c == CR | c == LF | c == FF) => var multiple = false in.readWhile{ case d if isNewLine(d) => multiple = multiple || d == c; true case ' ' | '\t' => true // eat the whitespace after newlines. case _ => false } xmlOk = true (if (multiple) NEWLINES else NEWLINE) case c => if (Character.isUnicodeIdentifierStart(c)) { in.scratch.setLength(0) in.scratch append c getIdentRest val name = global.newTermName(in.scratch.toString) in.scratch.setLength(0) val code = name2token(name) value(code, (name)) } else if (isSpecial(c)) { in.scratch.setLength(0) in.scratch append c getOperatorRest val name = global.newTermName(in.scratch.toString) in.scratch.setLength(0) val code = name2token(name) value(code, (name)) } else { in.error(offset, "illegal character: \'" + c + "\'") (ERROR) } } current.length = length } def intVal(offset : Int, token : Int, name0 : RandomAccessSeq[Char], negated: Boolean, base : Int): Long = { if (name0.length == 1 && name0(0) == '0') return 0 var name = name0 if (name.length > 2 && name(0) == '0' && (name(1) match { case 'x'|'X' => true case _ => false })) name = name.drop(2) while (name.last match { case 'l'|'L' => true case _ => false }) name = name.take(name.length - 1) if (token == CHARLIT && !negated) { if (name.length > 0) name(0) else 0 } else { var value: Long = 0 val divider = if (base == 10) 1 else 2 val limit: Long = if (token == LONGLIT) Math.MAX_LONG else Math.MAX_INT var i = 0 val len = name.length while (i < len) { val d = digit2int(name(i), base) if (d < 0) { in.error(offset, "malformed integer number") return 0 } if (value < 0 || limit / (base / divider) < value || limit - (d / divider) < value * (base / divider) && !(negated && limit == value * base - 1 + d)) { in.error(offset, "integer number too large") return 0 } value = value * base + d i += 1 } if (negated) -value else value } } /** convert name, base to double value */ def floatVal(offset : Int, token : Int, name0 : RandomAccessSeq[Char], negated: Boolean): Double = { var name = name0 while (name.last match { case 'f'|'F'|'d'|'D' => true case _ => false }) name = name.take(name.length - 1) val limit: Double = if (token == DOUBLELIT) Math.MAX_DOUBLE else Math.MAX_FLOAT try { val value: Double = java.lang.Double.valueOf(name.mkString).doubleValue() if (value > limit) in.error(offset, "floating point number too large") if (negated) -value else value } catch { case _: NumberFormatException => in.error(offset, "malformed floating point number") 0.0 } } } // utility functions def isSpecial(c : Char) : Boolean = { val chtp = Character.getType(c) chtp == Character.MATH_SYMBOL || chtp == Character.OTHER_SYMBOL } def isDigit(c : Char) : Boolean = digit2int(c, 10) >= 0 def isIdentifierStart(c: Char): Boolean = c match { case 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '$' | '_' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | // scala-mode: need to understand multi-line case patterns 'z' => true case _ => false } def isIdentifierPart(c: Char) : Boolean = c match { case ('A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '$' | '_' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z') => true case '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => true case c if Character.isUnicodeIdentifierPart(c) => true case _ => false } //isIdentifierStart(c) || isDigit(c) || isUnicodeIdentifierPart(c) def isOperatorPart(c : Char) : Boolean = c match { case '~' | '!' | '@' | '#' | '%' | '^' | '*' | '+' | '-' | '<' | '>' | '?' | ':' | '=' | '&' | '|' | '/' | '\\' => true case c if isSpecial(c) => true case _ => false } private def getOperatorRest(implicit in : CoreScannerInput) : Unit = { in.readWhile{ case ('/') if in.startsWith('/','*') || in.startsWith('/','/') => false case ('*') if in.startsWith('*','/') => false case (c) if isOperatorPart(c) => in.scratch append c; true case _ => false } } private def isFraction(c0 : Char, c1 : Char) = isDigit(c0) || (c0 match { case 'd'|'D'|'f'|'F' if !isIdentifierPart(c1) => true case 'e'|'E' if isDigit(c1) => true case _ => false }) private def getFraction(hasWhole : Boolean)(implicit in : CoreScannerInput) : Option[Int] = { val hasDigits = in.readWhile(isDigit) if (!hasDigits && !hasWhole) return None def end(code : Int) : Option[Int] = { if (!hasDigits && isIdentifierPart(in.peek(1))) None else in.next; Some(code) } in.head match { case 'f'|'F' => return end(FLOATLIT) case 'd'|'D' => return end(DOUBLELIT) case 'e'|'E' if { val peek = in.peek(1) peek == '-' || peek == '+' || isDigit(peek) } => in.next // eat the e. var hasDigit = isDigit(in.next) // eat +/-/digit hasDigit = in.readWhile(isDigit) || hasDigit in.readIf{ // eat an optional f or d case 'f'|'F' => FLOATLIT case 'd'|'D' => DOUBLELIT } orElse Some(DOUBLELIT) case _ if hasDigits => Some(DOUBLELIT) case _ => None // we didn't read anything } } private def getNumber(offset : Int, base : Int, prefix : String)(implicit in : CoreScannerInput) : Int = { val hasBody = in.readWhile{ case at if at >= '0' && at <= '9' => true case at if base == 16 && ((at >= 'a' && at <= 'f') || (at >= 'A' && at <= 'F')) => true case _ => false } if (!hasBody) base match { // because Java does this case 16 => in.error(offset, "Invalid hex literal number") return INTLIT case _ => } val code = if (in.head == '.') { in.peek(1) match { case c if isDigit(c) => in.next; getFraction(true).get case 'f'|'F'|'d'|'D' if !isIdentifierPart(in.peek(2)) => in.next; getFraction(true).get case 'e'|'E' if { val peek = in.peek(2) isDigit(peek) || peek == '-' || peek == '+' } => in.next // consume the dot in.next // consume the e in.next // consume the +/-/digit in.readWhile(isDigit) // consume remaining digits in.readIf{ case 'f'|'F' => FLOATLIT case 'd'|'D' => DOUBLELIT } getOrElse DOUBLELIT case c if isIdentifierStart(c) => INTLIT case _ => in.next; DOUBLELIT } } else (in.readIf{ case 'l'|'L' => LONGLIT case 'f'|'F' => FLOATLIT case 'd'|'D' => DOUBLELIT } getOrElse { if (in.head == 'e' || in.head == 'E') { in.next if (in.head == '-' || in.head == '+') in.next in.readWhile(isDigit) in.readIf{ case 'f'|'F' => FLOATLIT case 'd'|'D' => DOUBLELIT } getOrElse DOUBLELIT } else INTLIT }) if (in.readWhile(isIdentifierPart)) in.error(offset, "Invalid literal number") code } def inFirstOfStat(token: Int) = token match { case EOF | /*CASE |*/ CATCH | ELSE | EXTENDS | FINALLY | MATCH | REQUIRES | WITH | YIELD | COMMA | SEMI | NEWLINE | NEWLINES | DOT | USCORE | COLON | EQUALS | ARROW | LARROW | SUBTYPE | VIEWBOUND | SUPERTYPE | HASH | // todo: add LBRACKET RPAREN | RBRACKET | RBRACE => false case _ => true } def inLastOfStat(token: Int) = token match { case CHARLIT | INTLIT | LONGLIT | FLOATLIT | DOUBLELIT | STRINGLIT | SYMBOLLIT | IDENTIFIER | BACKQUOTED_IDENT | THIS | NULL | TRUE | FALSE | RETURN | USCORE | TYPE | XMLSTART | RPAREN | RBRACKET | RBRACE => true case _ => false } def digit(c : Char, radix : Int) = c match { case c if c >= '0' && c <= '7' => c - '0' case c if c >= '8' && c <= '9' && radix >= 10 => c - '0' case c if c >= '8' && c <= '9' && radix == 8 => throw new NumberFormatException("Malformed octal number") case c if c >= 'a' && c <= 'f' && radix == 16 => c - 'a' + 9 case c if c >= 'A' && c <= 'F' && radix == 16 => c - 'A' + 9 } private val simpleEscape : PartialFunction[Char,Char] = { case 'b' => '\b' case 't' => '\t' case 'n' => '\n' case 'f' => '\f' case 'r' => '\r' case '\"' => '\"' case '\'' => '\'' case '\\' => '\\' } def digit2int(ch: Char, base: Int): Int = { if ('0' <= ch && ch <= '9' && ch < '0' + base) ch - '0' else if ('A' <= ch && ch < 'A' + base - 10) ch - 'A' + 10 else if ('a' <= ch && ch < 'a' + base - 10) ch - 'a' + 10 else -1 } object ScannerConfiguration { private var key: Array[Byte] = _ private var maxKey = 0 private var tokenName = new Array[global.Name](128); { var tokenCount = 0 // Enter keywords def enterKeyword(n: global.Name, tokenId: Int) { while (tokenId >= tokenName.length) { val newTokName = new Array[global.Name](tokenName.length * 2) Array.copy(tokenName, 0, newTokName, 0, newTokName.length) tokenName = newTokName } tokenName(tokenId) = n if (n.start > maxKey) maxKey = n.start if (tokenId >= tokenCount) tokenCount = tokenId + 1 } import global.nme enterKeyword(nme.ABSTRACTkw, ABSTRACT) enterKeyword(nme.CASEkw, CASE) enterKeyword(nme.CATCHkw, CATCH) enterKeyword(nme.CLASSkw, CLASS) enterKeyword(nme.DEFkw, DEF) enterKeyword(nme.DOkw, DO) enterKeyword(nme.ELSEkw, ELSE) enterKeyword(nme.EXTENDSkw, EXTENDS) enterKeyword(nme.FALSEkw, FALSE) enterKeyword(nme.FINALkw, FINAL) enterKeyword(nme.FINALLYkw, FINALLY) enterKeyword(nme.FORkw, FOR) enterKeyword(nme.FORSOMEkw, FORSOME) enterKeyword(nme.IFkw, IF) enterKeyword(nme.IMPLICITkw, IMPLICIT) enterKeyword(nme.IMPORTkw, IMPORT) enterKeyword(nme.LAZYkw, LAZY) enterKeyword(nme.MATCHkw, MATCH) enterKeyword(nme.NEWkw, NEW) enterKeyword(nme.NULLkw, NULL) enterKeyword(nme.OBJECTkw, OBJECT) enterKeyword(nme.OVERRIDEkw, OVERRIDE) enterKeyword(nme.PACKAGEkw, PACKAGE) enterKeyword(nme.PRIVATEkw, PRIVATE) enterKeyword(nme.PROTECTEDkw, PROTECTED) enterKeyword(nme.REQUIRESkw, REQUIRES) enterKeyword(nme.RETURNkw, RETURN) enterKeyword(nme.SEALEDkw, SEALED) enterKeyword(nme.SUPERkw, SUPER) enterKeyword(nme.THISkw, THIS) enterKeyword(nme.THROWkw, THROW) enterKeyword(nme.TRAITkw, TRAIT) enterKeyword(nme.TRUEkw, TRUE) enterKeyword(nme.TRYkw, TRY) enterKeyword(nme.TYPEkw, TYPE) enterKeyword(nme.VALkw, VAL) enterKeyword(nme.VARkw, VAR) enterKeyword(nme.WHILEkw, WHILE) enterKeyword(nme.WITHkw, WITH) enterKeyword(nme.YIELDkw, YIELD) enterKeyword(nme.DOTkw, DOT) enterKeyword(nme.USCOREkw, USCORE) enterKeyword(nme.COLONkw, COLON) enterKeyword(nme.EQUALSkw, EQUALS) enterKeyword(nme.ARROWkw, ARROW) enterKeyword(nme.LARROWkw, LARROW) enterKeyword(nme.SUBTYPEkw, SUBTYPE) enterKeyword(nme.VIEWBOUNDkw, VIEWBOUND) enterKeyword(nme.SUPERTYPEkw, SUPERTYPE) enterKeyword(nme.HASHkw, HASH) enterKeyword(nme.ATkw, AT) // Build keyword array key = new Array[Byte](maxKey + 1) for (i <- 0 to maxKey) key(i) = IDENTIFIER for (j <- 0 until tokenCount) if (tokenName(j) ne null) key(tokenName(j).start) = j.asInstanceOf[Byte] }//Token representation ----------------------------------------------------- /** Convert name to token */ def name2token(name: global.Name): Int = if (name.start <= maxKey) key(name.start) else IDENTIFIER def isKeyword(code : Int) = code match { case code if code >= IF && code <= REQUIRES => true case _ => false } /** Returns the string representation of given token. */ def token2string(token: Int): String = token match { case IDENTIFIER | BACKQUOTED_IDENT => "identifier" case CHARLIT => "character literal" case INTLIT => "integer literal" case LONGLIT => "long literal" case FLOATLIT => "float literal" case DOUBLELIT => "double literal" case STRINGLIT => "string literal" case SYMBOLLIT => "symbol literal" case LPAREN => "'('" case RPAREN => "')'" case LBRACE => "'{'" case RBRACE => "'}'" case LBRACKET => "'['" case RBRACKET => "']'" case EOF => "eof" case ERROR => "something" case SEMI => "';'" case NEWLINE => "';'" case NEWLINES => "';'" case COMMA => "','" case CASECLASS => "case class" case CASEOBJECT => "case object" case XMLSTART => "$XMLSTART$<" case COMMENT => "cmnt" case WHITESPACE => "ws" case IGNORE => "ig" case _ => try { "'" + tokenName(token) + "'" } catch { case _: ArrayIndexOutOfBoundsException => "'<" + token + ">'" case _: NullPointerException => "'<(" + token + ")>'" } } } class UnitScanner(unit: CompilationUnit) extends ParserScanner { implicit val in = new DefaultInput(new NewCharArrayReader(unit.source.content, !settings.nouescape.value, error)) { override def error(offset : Int, msg : String) : Unit = UnitScanner.this.error(offset, msg) override def incompleteError(offset : Int, msg : String) = unit.incompleteInputError(new OffsetPosition(unit.source, offset), msg) } init private def error(offset : Int, msg : String) : Unit = unit.error(new OffsetPosition(unit.source,offset), msg) }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?