semantictokens.scala
来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 719 行 · 第 1/2 页
SCALA
719 行
/* NSC -- new Scala compiler * Copyright 2005-2007 LAMP/EPFL * @author Martin Odersky */// $Id: SemanticTokens.scala 14241 2008-03-03 14:53:47Z washburn $package scala.tools.nsc.modelsimport java.lang.Character.isJavaIdentifierPartimport java.lang.Threadimport scala.collection.mutable.{HashMap, HashSet}import scala.tools.nsc.Globalimport scala.tools.nsc.symtab.{Flags, Names}import scala.tools.nsc.symtab.Flags.DEFERREDimport scala.tools.nsc.util.{BatchSourceFile, NameTransformer, NoPosition, Position, SourceFile}class SemanticTokens(val compiler: Global) { import compiler._ object walker extends symtab.SymbolWalker { lazy val global : compiler.type = compiler } abstract class Kind {} object OBJECT extends Kind object CLASS extends Kind object TRAIT extends Kind object DEF extends Kind object VAL extends Kind object VAR extends Kind object ARG extends Kind object TPARAM extends Kind type AnyClass = Class[_] // static constants here abstract class Token { def length: Int def prev: HasNext def next: HasPrev } def eatKeyword(source: BatchSourceFile, pos: Int, keywords: List[String]) : Int = { if (keywords.isEmpty) pos else if (pos == source.length) -1 else if (source.beginsWith(pos, " ")) eatKeywords(source, pos + 1) else if (source.beginsWith(pos, keywords.head + " ")) eatKeywords(source, pos + keywords.head.length + 1) else eatKeyword(source, pos, keywords.tail) } def eatKeywords(source: BatchSourceFile, pos: Int): Int = { val keywords = "package" :: "val" :: "var" :: "def" :: "class" :: "trait" :: "override" :: "case" :: "object" :: "sealed" :: "private" :: "protected" :: Nil if (pos != -1) eatKeyword(source, pos, keywords) else pos } trait HasNext extends Token { var next0: HasPrev = _ def next = next0 } trait HasPrev extends Token { var prev0: HasNext = _ def prev = prev0 } abstract class Actual extends HasNext with HasPrev { def convertToGap: (Int, Actual) = { val nextGap = next.isInstanceOf[Gap] val prevGap = prev.isInstanceOf[Gap] if (prevGap) { val ret = prev.length val gap = prev.asInstanceOf[Gap] gap.setLength(gap.length + length) if (nextGap) { gap.setLength(gap.length + next.length) gap.next0 = next.next next.next.prev0 = gap } else { gap.next0 = next next.prev0 = gap } (ret, gap) } else if (nextGap) { val gap = next.asInstanceOf[Gap] gap.setLength(gap.length + length) gap.prev0 = prev prev.next0 = gap (0, gap) } else { prev.next0 = next next.prev0 = prev val gap = new Gap(prev) gap.setLength(length) (0, gap) } } def insert(prev1: HasNext) { next0 = prev1.next prev0 = prev1 prev0.next0 = this next0.prev0 = this } } // Actual final class Gap extends Actual { def this(prev1: HasNext) = { this() insert(prev1) } override def toString() = "gap-" + length var length0: Int = -1 def length: Int = length0 def setLength(length1: Int) = length0 = length1 // already gap override def convertToGap: (Int,Actual) = (0, this) } def Process(unit: CompilationUnit) = new Process(unit) class Process(val unit: CompilationUnit) { private var doLog = true def source = unit.source def dbg(tree : Tree) = { def treePos : Position = if (tree ne null) tree.pos else NoPosition; ( "TREE=" + tree + (if (tree ne null) (" CLASS=" + tree.getClass()) else "") + " SYM=" + tree.symbol + " POS=" + treePos.dbgString )} val symbols = new HashMap[Symbol, Info] class Info(val symbol: Symbol) { var defined : Def = _ val uses = new HashSet[Use] symbols.update(symbol, this) } def info(symbol: Symbol): Info = if (symbols.contains(symbol)) symbols(symbol) else new Info(symbol) abstract class Semantic(val symbol: Symbol) extends Actual { val name = NameTransformer.decode(symbol.name.toString).trim() assert(symbol != NoSymbol) def myOuter = Process.this def tpe: Type = symbol.tpe def length = name.length() def info: Info = if (symbols.contains(symbol)) symbols(symbol) else new Info(symbol) def kind = { val term0 = symbol if (false) null else if (term0.isVariable) VAR else if (term0.isValueParameter) ARG else if (term0.isMethod) DEF else if (term0.isClass) CLASS else if (term0.isModule) OBJECT else if (term0.isValue) VAL else if (term0.isTypeParameter) TPARAM else if (term0.isType ) TPARAM else { // Console.err.println("UNRECOGNIZED SYMBOL: " + term0 + " " + name); null } } } class Def(symbol0: Symbol) extends Semantic(symbol0) { info.defined = this override def toString() = "def-" + name + "-" + symbol.getClass() } class Use(symbol0: Symbol, tpe0: Type) extends Semantic(symbol0) { info.uses += this override def tpe : Type = if (tpe0 ne null) tpe0 else super.tpe; override def toString() = "use-" + name + "-" + symbol.getClass(); } val list = new TokenList //build(unit.body) val map = new scala.collection.jcl.LinkedHashMap[Int,Symbol] map.clear // populate the map. class visitor extends walker.Visitor { def contains(pos : Position) = map.contains(pos.offset.get) def apply(pos : Position) = map(pos.offset.get) def update(pos : Position, sym : Symbol) : Unit = if (pos.offset.isDefined) { val offset = pos.offset.get map(offset) = sym val isDef = pos.offset == sym.pos.offset list.put(offset, (if (isDef) new Def(sym) else new Use(sym, NoType))); } } walker.walk(unit.body, new visitor)(offset => unit.source.identifier(offset, compiler)) // ok start building.... def build[T <: Tree](trees : List[T]) : Unit = for (val tree : T <- trees) build(tree) def build(tree0: Tree) : Unit = try { /* if (tree0.pos != NoPosition) */ tree0 match { case tree: ImplDef => val pos = eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get) if (pos == -1) { } else buildDef(tree.symbol, eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get)); tree match { case cdef: ClassDef => build(cdef.tparams) case _ => ; } build(tree.impl.parents) build(tree.impl.body) case tree: ValOrDefDef => if (!tree.symbol.hasFlag(Flags.ACCESSOR) || tree.symbol.hasFlag(DEFERRED)) { // MO: I added !tree.symbol.hasFlag(DEFERRED) in a refactoring where // getters now can be abstract whereas before they could not. // Adding the condition thus keeps the old behavior. // todo: review whether this is correct, or whether abstract getters should be included. { val pos : Int = if (tree.name.toString().equals("<init>")) -1 else eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.get); if (false) Console.err.println("VALDEF: tree=" + tree + " sym=" + tree.symbol + " pos0=" + tree.symbol.pos + " alias=" + tree.symbol.alias + " pos1=" + pos + " pos2=" + tree.pos.dbgString + " " + tree.symbol.hasFlag(Flags.SYNTHETIC)); if (pos != -1 && !tree.hasFlag(Flags.SYNTHETIC)) buildDef(tree.symbol, pos); } if (tree.isInstanceOf[DefDef]) { val ddef = tree.asInstanceOf[DefDef]; build(ddef.tparams); for (val l0 <- ddef.vparamss; val arg <- l0) { val pos0 : Int = if (!unit.source.beginsWith(arg.pos.offset.get, "val ")) arg.pos.offset.get; else unit.source.skipWhitespace(arg.pos.offset.get + ("val ").length()); buildDef(arg.symbol, pos0); build(arg.tpt); } } try { //TPT=scala.Iterator[DocGenerator.this.compiler0.CompilationUnit] 260 class scala.tools.nsc.ast.Trees$TypeTree scala.Iterator[DocGenerator.this.compiler0.CompilationUnit] class scala.tools.nsc.symtab.Types$$anon$5 if ((tree.tpt eq null) || (tree.tpt.tpe eq null)) { //Console.err.println("BAD: " + tree.tpt + " in " + tree); } else { //Console.err.println("TPT=" + tree.tpt + " " + tree.tpt.pos + " " + tree.tpt.getClass() + " " + tree.tpt.tpe + " " + tree.tpt.tpe.getClass() + " " + tree.tpt.tpe.getClass().getSuperclass()); build(tree.tpt); } } catch { case e: Error => Console.err.println("VALDEF: " + tree + " " + tree.tpt + " " + tree.pos + " " + tree.tpt.pos); throw e; } //Console.err.println("RHS: " + tree.rhs + " " + tree.rhs.getClass() + " " + tree.rhs.getClass().getSuperclass()); build(tree.rhs); } case tree: PackageDef => //Console.err.println("PACKAGE: " + tree.name); if (false) { val pos = eatKeywords(unit.source.asInstanceOf[BatchSourceFile], tree.pos.offset.getOrElse(-1)) if (pos != -1) buildDef(tree.symbol, pos) } build(tree.stats) case tree: Function => for (val arg <- tree.vparams) if (arg.pos != NoPosition) { val name = arg.name.toString().trim() val pos: Int = if (unit.source.beginsWith(arg.pos.offset.getOrElse(-1), "val ")) unit.source.skipWhitespace(arg.pos.offset.getOrElse(-1) + ("val ").length()) else if (unit.source.asInstanceOf[BatchSourceFile].content(arg.pos.offset.get) == ':') { var posx : Int = arg.pos.offset.get while (unit.source.asInstanceOf[BatchSourceFile].content(posx - 1).isWhitespace) posx = posx - 1 posx - name.length() } else arg.pos.offset.get buildDef(arg.symbol, pos) build(arg.tpt) } build(tree.body) case tree : TypeTree => val treex = tree val tree1 = if (tree.original ne null) tree.original else tree def classes(clazz: AnyClass): List[AnyClass] = if (clazz eq null) Nil else clazz :: classes(clazz.getSuperclass()) if (tree.original eq null) { if (false) Console.err.println("NO_ORIGINAL: " + tree + " " + tree.tpe + " " + classes(tree.tpe.getClass())); } if (tree.tpe ne null) buildT(tree1, tree.tpe); def buildT( tree : Tree, tpe : Type) : Unit = if (tree.pos != NoPosition) tpe match { case tpe0 : TypeRef => tree match { case apt : AppliedTypeTree => buildUse(tpe.typeSymbol, apt.tpt.pos.offset.getOrElse(-1), tpe0); //Console.err.println("APT: " + treex + " vs. " + treex.original); //Console.err.println("APT: " + treex.pos + " vs. " + treex.original.pos + " " + unit.source.dbg(treex.original.pos)); //Console.err.println("APT: " + apt.tpt + " sym0=" + apt.tpt.symbol + " sym1=" + tpe0.sym + " apt.args=" + apt.args + " tpe0.args=" + tpe0.args); buildTs (apt.args, tpe0.args); case ident : Ident => buildUse(tpe0.sym, ident.pos.offset.getOrElse(-1), tpe0); case select : Select => if (select.symbol == NoSymbol) try { // build(select); buildUse(tpe0.typeSymbol, selectPos(select), tpe0); //Console.err.println("QUALIFIER: " + select.qualifier + " " + unit.source.dbg(select.qualifier.pos) + " " + tpe0.prefix + " " + tpe0.prefix.getClass() + " " + tpe0.prefix.getClass().getSuperclass() +" " + tpe0.prefix.widen + " " + tpe0.prefix.toLongString); buildT(select.qualifier, tpe0.prefix); } catch { case e : Error => Console.err.println("BUILD_SELECT: " + select + " @ " + tpe0 + " " + (select.pos).dbgString); throw e; } case tpt : TypeTree => if (tpt.symbol ne null) { Console.err.println("SYM0 " + tpt.symbol + " " + (tpt.pos).dbgString); buildUse(tpt.symbol, tpt.pos.offset.getOrElse(-1), tpe0); } else if (tpe0.typeSymbol ne null) { //Console.err.println("TYPE_SYM1 " + tpe0.symbol + " " + unit.source.dbg(tpt.pos)); buildUse(tpe0.typeSymbol, tpt.pos.offset.getOrElse(-1), tpe0); } else { Console.err.println("UNKNOWN TPT0: " + (tpt.pos).dbgString + " tpt=" + tpt + " " + tpt.symbol + " tpe0="+ tpe0 + " " + tpe0.typeSymbol + " tpe0.args=" + tpe0.args); } case sft : SelectFromTypeTree => build(sft.qualifier); // XXX: broken if (false) Console.err.println("SFTT: " + sft + " sym=" + sft.symbol + " selector=" + sft.selector + " qual=" + sft.qualifier + " qual.sym=" + sft.qualifier.symbol + " qual.pos=" + (sft.qualifier.pos).dbgString + " symbol=" + sft.symbol + " type=" + tpe0 + " type.sym=" + tpe0.typeSymbol); case _ => Console.err.println("UNKNOWN TPT2: " + tree + " vs. " + tpe0 + " " + tree.getClass() + " " + (tree.pos).dbgString); } case tpe0 : MethodType => tree match { case tpt: TypeTree => if (tpt.original ne null) buildT(tpt.original, tpe); else { Console.err.println("UNKNOWN TPT3: " + tree + " vs. " + tpe0 + " " + (tree.pos).dbgString); } case ident : Ident => buildT(ident, tpe0.resultType); case select : Select => buildT(select, tpe0.resultType); case _ => Console.err.println("UNKNOWN TPE: " + tree + " vs. " + tpe0 + " " + tree.getClass()); }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?