summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/interpreter/Power.scala
blob: ac8f08ec80482e4fb87e5976cc5ff4c5419b6b34 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/* NSC -- new Scala compiler
 * Copyright 2005-2011 LAMP/EPFL
 * @author  Paul Phillips
 */

package scala.tools.nsc
package interpreter

import scala.collection.{ mutable, immutable }
import mutable.{ HashMap }
import scala.tools.nsc.util.{ NoPosition, BatchSourceFile }

/** A class for methods to be injected into the repl in power mode.
 */
class Power(repl: Interpreter) {
  val global: repl.compiler.type = repl.compiler

  import global._
  import definitions.{ getMember, getModule, getClass => getCompilerClass }
  import repl.{ beQuietDuring, interpret, parse }

  object phased extends Phased {
    val global: Power.this.global.type = Power.this.global
  }

  class ReplSnippet[T](val path: String, initial: T) {
    var code: String = ""
    var value: T = initial

    def set(code: String) = interpret(path + ".value = " + code)
    def get: T = value
    override def toString = "repl." + path + ".value = \"" + code + "\""
  }

  object vars {
    private def create[T](name: String, initial: T): ReplSnippet[T] =
      new ReplSnippet[T]("power.vars." + name, initial)

    val symfilter = create("symfilter", (s: Symbol) => true)
  }

  def banner = """
    |** Power User mode enabled - BEEP BOOP      **
    |** scala.tools.nsc._ has been imported      **
    |** New vals! Try repl, global, power        **
    |** New cmds! :help to discover them         **
    |** New defs! Type power.<tab> to reveal     **
  """.stripMargin.trim

  def init = """
    |import scala.tools.nsc._
    |val global: repl.compiler.type = repl.compiler
    |import global._
    |import definitions._
    |import power.{ phased, show, clazz, module }
  """.stripMargin

  /** Starts up power mode and runs whatever is in init.
   */
  def unleash(): Unit = {
    def f = {
      repl.bind[Interpreter]("repl", repl)
      repl.bind[Power]("power", this)
      init split '\n' foreach interpret
    }
    if (isReplDebug) f
    else beQuietDuring { f }
  }

  object show {
    private def defStrings(sym: Symbol, p: Symbol => Boolean) =
      phased(sym.info.members filter p map (_.defString))

    private def display(sym: Symbol, p: Symbol => Boolean) =
      defStrings(sym, p) foreach println

    def methods[T: Manifest] = display(clazz[T], _.isMethod)
    def apply[T: Manifest] = display(clazz[T], vars.symfilter.get)
  }

  abstract class NameBased[T <: Name] {
    def mkName(s: String): T
    def mkSymbol(s: String): Symbol

    def apply[T: Manifest]                 = mkSymbol(manifest[T].erasure.getName)
    def tpe[T: Manifest]                   = apply[T].tpe
    def members[T: Manifest]               = tpe[T].members
    def member[T: Manifest](name: Name)    = getMember(apply[T], name)
    def vmember[T: Manifest](name: String) = member[T](newTermName(name))
    def tmember[T: Manifest](name: String) = member[T](newTypeName(name))
  }
  private def missingWrap(op: => Symbol): Symbol =
    try op
    catch { case _: MissingRequirementError => NoSymbol }

  object clazz extends NameBased[TypeName] {
    def mkName(s: String) = newTypeName(s)
    def mkSymbol(s: String): Symbol = missingWrap(getCompilerClass(s))
  }
  object module extends NameBased[TermName] {
    def mkName(s: String) = newTermName(s)
    def mkSymbol(s: String): Symbol = missingWrap(getModule(s))
  }

  def mkContext(code: String = "") = analyzer.rootContext(mkUnit(code))
  def mkAlias(name: String, what: String) = interpret("type %s = %s".format(name, what))
  def mkSourceFile(code: String) = new BatchSourceFile("<console>", code)
  def mkUnit(code: String) = new CompilationUnit(mkSourceFile(code))

  def mkTree(code: String): Tree = mkTrees(code).headOption getOrElse EmptyTree
  def mkTrees(code: String): List[Tree] = parse(code) getOrElse Nil
  def mkTypedTrees(code: String*): List[Tree] = {
    class TyperRun extends Run {
      override def stopPhase(name: String) = name == "superaccessors"
    }

    reporter.reset
    val run = new TyperRun
    run compileSources (code.toList.zipWithIndex map {
      case (s, i) => new BatchSourceFile("<console %d>".format(i), s)
    })
    run.units.toList map (_.body)
  }
  def mkTypedTree(code: String) = mkTypedTrees(code).head
  def mkType(id: String): Type = repl.stringToCompilerType(id)

  override def toString = """
    |** Power mode status **
    |Default phase: %s
    |Names: %s
    |Identifiers: %s
  """.stripMargin.format(
      phased.get,
      repl.allreferencedNames mkString " ",
      repl.unqualifiedIds mkString " "
    )
}