From 1b4fc3f26ea5efbf4784e1eb6d1de38ab1d8b013 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 28 Mar 2011 07:34:04 +0000 Subject: Learned an interesting lesson about having an i... Learned an interesting lesson about having an implicit object with a "def apply(x: Any): List[String]" method imported into power mode. Let's just say this is not advised. This and other rough edges eliminated from power mode, no review. --- .../scala/tools/nsc/interpreter/ILoop.scala | 5 +- .../scala/tools/nsc/interpreter/Power.scala | 157 ++++++++++++++------- 2 files changed, 112 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala index 4541dc165b..d018a5420d 100644 --- a/src/compiler/scala/tools/nsc/interpreter/ILoop.scala +++ b/src/compiler/scala/tools/nsc/interpreter/ILoop.scala @@ -44,7 +44,10 @@ class ILoop(in0: Option[BufferedReader], protected val out: PrintWriter) var settings: Settings = _ var intp: IMain = _ - lazy val power = new Power(this) + lazy val power = { + val g = intp.global + Power[g.type](this, g) + } // TODO // object opt extends AestheticSettings diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala index 0933365d9e..01b2d2328f 100644 --- a/src/compiler/scala/tools/nsc/interpreter/Power.scala +++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala @@ -6,20 +6,56 @@ package scala.tools.nsc package interpreter +import scala.reflect.NameTransformer import scala.collection.{ mutable, immutable } import scala.util.matching.Regex import scala.tools.nsc.util.{ BatchSourceFile } import session.{ History } +trait SharesGlobal[G <: Global] { + val global: G + + // This business gets really old: + // + // found : power.intp.global.Symbol + // required: global.Symbol + // + // Have tried many ways to cast it aside, this is the current winner. + // Todo: figure out a way to abstract over all the type members. + type AnySymbol = Global#Symbol + type AnyType = Global#Type + type AnyName = Global#Name + type AnyTree = Global#Tree + + type Symbol = global.Symbol + type Type = global.Type + type Name = global.Name + type Tree = global.Tree + + implicit def upDependentSymbol(x: AnySymbol): Symbol = x.asInstanceOf[Symbol] + implicit def upDependentType(x: AnyType): Type = x.asInstanceOf[Type] + implicit def upDependentName(x: AnyName): Name = x.asInstanceOf[Name] + implicit def upDependentTree(x: AnyTree): Tree = x.asInstanceOf[Tree] +} + +object Power { + def apply[G <: Global](repl: ILoop, g: G) = + new { final val global: G = g } + with Power[G](repl, repl.intp) // .asInstanceOf[IMain { val global: G }]) + + def apply(intp: IMain) = + new { final val global = intp.global } + with Power[Global](null, intp) +} + /** A class for methods to be injected into the intp in power mode. */ -class Power(repl: ILoop, intp: IMain) { - def this(repl: ILoop) = this(repl, repl.intp) - def this(intp: IMain) = this(null, intp) - - val global: intp.global.type = intp.global - import global._ +abstract class Power[G <: Global]( + val repl: ILoop, + val intp: IMain // { val global: G } +) extends SharesGlobal[G] { import intp.{ beQuietDuring, interpret, parse } + import global.{ opt, definitions, stringToTermName, NoSymbol, NoType, analyzer, CompilationUnit } abstract class SymSlurper { def isKeep(sym: Symbol): Boolean @@ -93,24 +129,22 @@ class Power(repl: ILoop, intp: IMain) { def init = """ |import scala.tools.nsc._ - |val global: intp.global.type = intp.global + |import interpreter.Power + |final val global = repl.power.global + |final val power = repl.power.asInstanceOf[Power[global.type]] + |final val intp = repl.intp |import global._ |import definitions._ |import power.phased - |import power.Implicits._ + |import power.Implicits.{ global => _, _ } """.stripMargin /** Starts up power mode and runs whatever is in init. */ def unleash(): Unit = beQuietDuring { - if (repl != null) { - intp.bind[ILoop]("repl", repl) - intp.bind[History]("history", repl.in.history) - intp.bind("completion", repl.in.completion) - } - - intp.bind[IMain]("intp", intp) - intp.bind[Power]("power", this) + intp.bind[ILoop]("repl", repl) + intp.bind[History]("history", repl.in.history) + intp.bind("completion", repl.in.completion) intp.bind[ISettings]("isettings", intp.isettings) init split '\n' foreach interpret } @@ -122,9 +156,11 @@ class Power(repl: ILoop, intp: IMain) { private def getCompilerClass(name: String) = missingWrap(definitions.getClass(name)) private def getCompilerModule(name: String) = missingWrap(definitions.getModule(name)) - object InternalInfo { + trait LowPriorityInternalInfo { implicit def apply[T: Manifest] : InternalInfo[T] = new InternalInfo[T](None) } + object InternalInfo extends LowPriorityInternalInfo { } + /** Todos... * translate manifest type arguments into applied types * customizable symbol filter (had to hardcode no-spec to reduce noise) @@ -152,11 +188,13 @@ class Power(repl: ILoop, intp: IMain) { def allMembers = tpe.members def bts = info.baseTypeSeq.toList def btsmap = bts map (x => (x, x.decls.toList)) toMap - def pkgName = erasure.getPackage.getName - def pkg = getCompilerModule(pkgName) + def pkgName = Option(erasure.getPackage) map (_.getName) + def pkg = pkgName map getCompilerModule getOrElse NoSymbol def pkgmates = pkg.tpe.members - def pkgslurp = new PackageSlurper(pkgName) slurp() - + def pkgslurp = pkgName match { + case Some(name) => new PackageSlurper(name) slurp() + case _ => Set() + } def ? = this def whoHas(name: String) = bts filter (_.decls.toList exists (_.name.toString == name)) @@ -171,8 +209,24 @@ class Power(repl: ILoop, intp: IMain) { } } - trait PCFormatter extends (Any => List[String]) { - def apply(x: Any): List[String] + trait LowPriorityPrettifier { + implicit object AnyPrettifier extends Prettifier[Any] { + def prettify(x: Any): List[String] = x match { + case x: Name => List(x.decode) + case Tuple2(k, v) => List(prettify(k) ++ Seq("->") ++ prettify(v) mkString " ") + case xs: Traversable[_] => (xs.toList flatMap prettify).sorted.distinct + case x => List("" + x) + } + } + } + object Prettifier extends LowPriorityPrettifier { + def prettify[T](value: T): List[String] = default[T] prettify value + def default[T] = new Prettifier[T] { + def prettify(x: T): List[String] = AnyPrettifier prettify x + } + } + trait Prettifier[T] { + def prettify(x: T): List[String] private var indentLevel = 0 private def spaces = " " * indentLevel @@ -182,12 +236,13 @@ class Power(repl: ILoop, intp: IMain) { finally indentLevel -= 1 } - def show(x: Any): Unit = grep(x, _ => true) - def grep(x: Any, p: String => Boolean): Unit = - apply(x) filter p foreach (x => println(spaces + x)) + def show(x: T): Unit = grep(x, _ => true) + def grep(x: T, p: String => Boolean): Unit = + prettify(x) filter p foreach (x => println(spaces + x)) } - class MultiPrintingConvenience[T](coll: Traversable[T])(implicit fmt: PCFormatter) { - import fmt._ + class MultiPrintingConvenience[T: Prettifier](coll: Traversable[T]) { + val pretty = implicitly[Prettifier[T]] + import pretty._ def freqBy[U](p: T => U) = { val map = coll.toList groupBy p @@ -197,8 +252,8 @@ class Power(repl: ILoop, intp: IMain) { val buf = new mutable.ListBuffer[String] freqBy(p) foreach { case (k, vs) => - buf += "%d: %s".format(vs.size, k) - vs flatMap fmt foreach (buf += " " + _) + buf += "%d: %s".format(vs.size, Prettifier.prettify(k)) + vs flatMap prettify foreach (buf += " " + _) } buf.toList } @@ -215,16 +270,22 @@ class Power(repl: ILoop, intp: IMain) { def #?[U](p: T => U) = this freqByFormatted p } - class PrintingConvenience[T](value: T)(implicit fmt: PCFormatter) { - def > : Unit = >(_ => true) + class PrintingConvenience[T: Prettifier](value: T) { + val pretty = implicitly[Prettifier[T]] + + def > { >(_ => true) } def >(s: String): Unit = >(_ contains s) def >(r: Regex): Unit = >(_ matches r.pattern.toString) - def >(p: String => Boolean): Unit = fmt.grep(value, p) + def >(p: String => Boolean): Unit = pretty.grep(value, p) } protected trait Implicits1 { - implicit def replPrinting[T](x: T)(implicit fmt: PCFormatter) = new PrintingConvenience[T](x) + // fallback + implicit def replPrinting[T](x: T)(implicit pretty: Prettifier[T] = Prettifier.default[T]) = new PrintingConvenience[T](x) } - object Implicits extends Implicits1 { + object Implicits extends Implicits1 with SharesGlobal[G] { + val global = Power.this.global + import global._ + implicit lazy val powerNameOrdering: Ordering[Name] = Ordering[String] on (_.toString) implicit lazy val powerSymbolOrdering: Ordering[Symbol] = Ordering[Name] on (_.name) implicit lazy val powerTypeOrdering: Ordering[Type] = Ordering[Symbol] on (_.typeSymbol) @@ -235,25 +296,23 @@ class Power(repl: ILoop, intp: IMain) { else if (s1 isLess s2) -1 else 1 } - implicit def replCollPrinting[T](xs: Traversable[T])(implicit fmt: PCFormatter) = new MultiPrintingConvenience[T](xs) + implicit def replCollPrinting[T: Prettifier](xs: Traversable[T]): MultiPrintingConvenience[T] = new MultiPrintingConvenience[T](xs) implicit def replInternalInfo[T: Manifest](x: T): InternalInfo[T] = new InternalInfo[T](Some(x)) - implicit object ReplDefaultFormatter extends PCFormatter { - def apply(x: Any): List[String] = x match { - case Tuple2(k, v) => List(apply(k) ++ Seq("->") ++ apply(v) mkString " ") - case xs: Traversable[_] => (xs.toList flatMap apply).sorted.distinct - case x => List("" + x) - } + implicit def replPrettifier[T] : Prettifier[T] = Prettifier.default[T] + implicit def vararsTypeApplication(sym: Symbol) = new { + def apply(targs: Type*) = typeRef(NoPrefix, sym, targs.toList) } + def ?[T: Manifest] = InternalInfo[T] } - object phased extends Phased { - val global: Power.this.global.type = Power.this.global + object phased extends Phased with SharesGlobal[G] { + val global: G = Power.this.global } - def context(code: String) = analyzer.rootContext(unit(code)) - def source(code: String) = new BatchSourceFile("", code) - def unit(code: String) = new CompilationUnit(source(code)) - def trees(code: String): List[Tree] = parse(code) getOrElse Nil - def typeOf(id: String): Type = intp.typeOfExpression(id) getOrElse NoType + def context(code: String) = analyzer.rootContext(unit(code)) + def source(code: String) = new BatchSourceFile("", code) + def unit(code: String) = new CompilationUnit(source(code)) + def trees(code: String) = parse(code) getOrElse Nil + def typeOf(id: String): Type = intp.typeOfExpression(id) getOrElse NoType override def toString = """ |** Power mode status ** -- cgit v1.2.3