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