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 + -
显示快捷键?