modelextractor.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 450 行 · 第 1/2 页

SCALA
450
字号
/* NSC -- new Scala compiler * Copyright 2007-2008 LAMP/EPFL * @author  Sean McDirmid */// $Id: ModelExtractor.scala 14416 2008-03-19 01:17:25Z mihaylov $package scala.tools.nsc.docimport scala.collection.jclimport compat.Platform.{EOL => LINE_SEPARATOR}/** This class attempts to reverse engineer source code intent from compiler *  symbol objects. * * @author Sean McDirmid */trait ModelExtractor {  val global: Global  import global._  def settings: doc.Settings   def assert(b: Boolean) {    if (!b) throw new Error  }  def assert(b: Boolean, message: Any) {    if (!b) throw new Error(message.toString)  }  case class Tag(tag: String, option: String, body: String)  case class Comment(body: String, attributes: List[Tag]) {    def decodeAttributes = {      val map = new jcl.LinkedHashMap[String, List[(String, String)]] {        override def default(key: String) = Nil      }      attributes.foreach(a => {        map(a.tag) = map(a.tag) ::: List((a.option, a.body))      });      map    }  }  protected def decode(sym: Symbol) =    if (sym == definitions.ScalaObjectClass || sym == definitions.ObjectClass)       definitions.AnyRefClass    else sym match {      case sym: ModuleClassSymbol => sym.sourceModule      case sym => sym    }  protected def decodeComment(comment0: String): Comment = {    val comment = comment0 // .substring("/**".length, comment0.length - "*/".length)    val tok = new java.util.StringTokenizer(comment, LINE_SEPARATOR)    val buf = new StringBuilder    type AttrDescr = (String, String, StringBuilder)    val attributes = new collection.mutable.ListBuffer[AttrDescr]    var attr: AttrDescr = null    while (tok.hasMoreTokens) {      val s = tok.nextToken.replaceFirst("\\p{Space}?\\*", "")      val mat1 = pat1.matcher(s)      if (mat1.matches) {        attr = (mat1.group(1), null, new StringBuilder(mat1.group(2)))        //if (kind != CONSTRUCTOR)         attributes += attr      } else {        val mat2 = pat2.matcher(s)        if (mat2.matches) {          attr = (mat2.group(1), mat2.group(2), new StringBuilder(mat2.group(3)))          //if (kind != CLASS)           attributes += attr        } else if (attr ne null)          attr._3.append(s + LINE_SEPARATOR)        else          buf.append(s + LINE_SEPARATOR)      }    }    Comment(buf.toString, attributes.toList.map({x => Tag(x._1,x._2,x._3.toString)}))  }  sealed abstract class Entity(val sym: Symbol) {    private[ModelExtractor] def sym0 = sym        override def toString = sym.toString    def comment: Option[String] = global.comments.get(sym)    // comments decoded, now what?    def attributes = sym.attributes    def decodeComment: Option[Comment] = {      val comment0 = this.comment      if (comment0.isEmpty) None      else Some(ModelExtractor.this.decodeComment(comment0.get.trim))    }    protected def accessQualified(core: String, qual: String) = core match {      case "public" => "" // assert(qual == null); "";      case core => core + (if (qual == null) "" else "[" + qual + "]")    }        def flagsString = {      import symtab.Flags      //val isLocal = sym.hasFlag(Flags.LOCAL)      val x =        if (sym hasFlag Flags.PRIVATE) "private"        else if (sym hasFlag Flags.PROTECTED) "protected"        else "public"      var string = accessQualified(x,        if (sym hasFlag Flags.LOCAL) "this"        else if (sym.privateWithin != null && sym.privateWithin != NoSymbol)          sym.privateWithin.nameString        else null      )      def f(flag: Int, str: String) {        if (sym hasFlag flag) string = string + " " + str      }      f(Flags.IMPLICIT, "implicit")      f(Flags.SEALED, "sealed")      f(Flags.OVERRIDE, "override")      f(Flags.CASE, "case")      if (!sym.isTrait) f(Flags.ABSTRACT, "abstract")      if (!sym.isModule) f(Flags.FINAL, "final")      if (!sym.isTrait) f(Flags.DEFERRED, "abstract")      string.trim    }    def listName = name    def name = sym.nameString    def fullName(sep: Char) = sym.fullNameString(sep)    def kind: String    def header { }    def typeParams: List[TypeParam] = Nil    def valueParams: List[List[ValueParam]] = Nil    def resultType: Option[Type] = None    def parents: Iterable[Type] = Nil    def lo: Option[Type] = sym.info match {      case TypeBounds(lo, hi) if decode(lo.typeSymbol) != definitions.AllClass => Some(lo)      case _ => None    }    def hi: Option[Type] = sym.info match {      case TypeBounds(lo, hi) if decode(hi.typeSymbol) != definitions.AnyClass => Some(hi)      case _ => None    }    def variance = {      import symtab.Flags._      if (sym hasFlag COVARIANT) "+"      else if (sym hasFlag CONTRAVARIANT) "-"      else ""    }    def overridden: Iterable[Symbol] = Nil  }  class ValueParam(sym: Symbol) extends Entity(sym) {    override def resultType = Some(sym.tpe)    //def kind = if (sym.isPublic) "val" else "";    def kind = ""  }  class ConstructorParam(sym: Symbol) extends ValueParam(sym) {    override protected def accessQualified(core: String, qual: String) = core match {      case "public" => "val"      case "protected" => super.accessQualified(core,qual) + " val"      case "private" if qual == "this" => ""      case core => super.accessQualified(core, qual)    }  }  def ValueParam(sym: Symbol) = new ValueParam(sym)  class TypeParam(sym: Symbol) extends Entity(sym) {    def kind = ""  }  def TypeParam(sym: Symbol) = new TypeParam(sym)    trait Clazz extends ClassOrObject {    private def csym = sym.asInstanceOf[TypeSymbol]    override def typeParams = csym.typeParams.map(TypeParam)    override def valueParams = {      if (constructorArgs.isEmpty) Nil      else constructorArgs.values.toList :: Nil    }    def isTrait = csym.isTrait    override def kind = if (sym.isTrait) "trait" else "class"  }  trait Object extends ClassOrObject {    override def kind = "object"  }  case class Package(override val sym: Symbol) extends Entity(sym) {    override def kind = "package"    override def name = fullName('.')  }  trait TopLevel extends ClassOrObject  class TopLevelClass (sym: Symbol) extends Entity(sym) with TopLevel with Clazz  class TopLevelObject(sym: Symbol) extends Entity(sym) with TopLevel with Object {    override def attributes = sym.moduleClass.attributes  }  def compare(pathA: List[ClassOrObject], pathB: List[ClassOrObject]): Int = {    var pA = pathA    var pB = pathB    while (true) {      if (pA.isEmpty) return -1      if (pB.isEmpty) return +1      val diff = pA.head.name compare pB.head.name      if (diff != 0) return diff      pA = pA.tail      pB = pB.tail    }    0  }  def isAccessible(sym: Symbol): Boolean = {    import symtab.Flags._    settings.memberaccess.value match {      case "private"   => sym.isPublic || (sym hasFlag PROTECTED) || (sym hasFlag PRIVATE)      case "protected" => sym.isPublic || (sym hasFlag PROTECTED)      case "public"    => sym.isPublic      case _           => false    }  }  trait ClassOrObject extends Entity {    def path: List[ClassOrObject] = this :: Nil    override def listName = path map (_.name) mkString "."    object freshParents extends jcl.LinkedHashSet[Type] {      this addAll sym.tpe.parents

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?