~ubuntu-branches/debian/sid/scala/sid

« back to all changes in this revision

Viewing changes to src/compiler/scala/reflect/reify/utils/SymbolTables.scala

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg, Mehdi Dogguy, Lucas Satabin, Frank S. Thomas, Emmanuel Bourg
  • Date: 2015-06-05 23:52:59 UTC
  • mfrom: (1.2.11)
  • Revision ID: package-import@ubuntu.com-20150605235259-wk00vgk83dh8o19g
Tags: 2.10.5-1
* Team upload.

[ Mehdi Dogguy ]
* New upstream release (Closes: #744278).

[ Lucas Satabin ]
* Update patches
* Update the clean target
* Update paths of elements to install
* Update watch file

[ Frank S. Thomas ]
* Remove myself from Uploaders.

[ Emmanuel Bourg ]
* The package has been adopted by the Java Team (Closes: #754935)
* Patched the build to avoid downloading libraries from the Internet
* Replaced the minified JavaScript files with unobfuscated ones
* No longer build scala-partest.jar until diffutils is packaged or replaced
* debian/watch: Fixed the versions matched (x.y.z instead of x.y.z..z)
* debian/rules:
  - Added the missing get-orig-source target (Closes: #724704)
  - Improved the clean target
* debian/control:
  - Build depend on scala (>= 2.10) and bnd
  - Use canonical URLs for the Vcs-* fields
  - Standards-Version updated to 3.9.6 (no changes)
* Switch to debhelper level 9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package scala.reflect.reify
 
2
package utils
 
3
 
 
4
import scala.collection._
 
5
import scala.compat.Platform.EOL
 
6
 
 
7
trait SymbolTables {
 
8
  self: Utils =>
 
9
 
 
10
  import global._
 
11
  import definitions._
 
12
  import Flag._
 
13
 
 
14
  class SymbolTable private[SymbolTable] (
 
15
    private[SymbolTable] val symtab: immutable.ListMap[Symbol, Tree] = immutable.ListMap[Symbol, Tree](),
 
16
    private[SymbolTable] val aliases: List[(Symbol, TermName)] = List[(Symbol, TermName)](),
 
17
    private[SymbolTable] val original: Option[List[Tree]] = None) {
 
18
 
 
19
    def syms: List[Symbol] = symtab.keys.toList
 
20
    def isConcrete: Boolean = symtab.values forall (sym => !FreeTypeDef.unapply(sym).isDefined)
 
21
 
 
22
//    def aliases: Map[Symbol, List[TermName]] = aliases.distinct groupBy (_._1) mapValues (_ map (_._2))
 
23
 
 
24
    def symDef(sym: Symbol): Tree =
 
25
      symtab.getOrElse(sym, EmptyTree)
 
26
 
 
27
    def symName(sym: Symbol): TermName =
 
28
      symtab.get(sym) match {
 
29
        case Some(FreeDef(_, name, _, _, _)) => name
 
30
        case Some(SymDef(_, name, _, _)) => name
 
31
        case None => nme.EMPTY
 
32
      }
 
33
 
 
34
    def symAliases(sym: Symbol): List[TermName] =
 
35
      symName(sym) match {
 
36
        case name if name.isEmpty => Nil
 
37
        case _ => (aliases.distinct groupBy (_._1) mapValues (_ map (_._2)))(sym)
 
38
      }
 
39
 
 
40
    def symBinding(sym: Symbol): Tree =
 
41
      symtab.get(sym) match {
 
42
        case Some(FreeDef(_, _, binding, _, _)) => binding
 
43
        case Some(SymDef(_, _, _, _)) => throw new UnsupportedOperationException(s"${symtab(sym)} is a symdef, hence it doesn't have a binding")
 
44
        case None => EmptyTree
 
45
      }
 
46
 
 
47
    def symRef(sym: Symbol): Tree =
 
48
      symtab.get(sym) match {
 
49
        case Some(FreeDef(_, name, binding, _, _)) => Ident(name) updateAttachment binding
 
50
        case Some(SymDef(_, name, _, _)) => Ident(name) updateAttachment ReifyBindingAttachment(Ident(sym))
 
51
        case None => EmptyTree
 
52
      }
 
53
 
 
54
    def +(sym: Symbol, name: TermName, reification: Tree): SymbolTable = add(sym, name, reification)
 
55
    def +(symDef: Tree): SymbolTable = add(symDef)
 
56
    def ++(symDefs: TraversableOnce[Tree]): SymbolTable = (this /: symDefs)((symtab, symDef) => symtab.add(symDef))
 
57
    def ++(symtab: SymbolTable): SymbolTable = { val updated = this ++ symtab.symtab.values; new SymbolTable(updated.symtab, updated.aliases ++ symtab.aliases) }
 
58
    def -(sym: Symbol): SymbolTable = remove(sym)
 
59
    def -(name: TermName): SymbolTable = remove(name)
 
60
    def -(symDef: Tree): SymbolTable = remove(reifyBinding(symDef).symbol)
 
61
    def --(syms: GenTraversableOnce[Symbol]): SymbolTable = (this /: syms)((symtab, sym) => symtab.remove(sym))
 
62
    def --(names: Iterable[TermName]): SymbolTable = (this /: names)((symtab, name) => symtab.remove(name))
 
63
    def --(symDefs: TraversableOnce[Tree]): SymbolTable = this -- (symDefs map (reifyBinding(_)))
 
64
    def --(symtab: SymbolTable): SymbolTable = { val updated = this -- symtab.symtab.values; new SymbolTable(updated.symtab, updated.aliases diff symtab.aliases) }
 
65
    def filterSyms(p: Symbol => Boolean): SymbolTable = this -- (syms filterNot p)
 
66
    def filterAliases(p: (Symbol, TermName) => Boolean): SymbolTable = this -- (aliases filterNot (tuple => p(tuple._1, tuple._2)) map (_._2))
 
67
 
 
68
    private def add(symDef: Tree): SymbolTable = {
 
69
      val sym = reifyBinding(symDef).symbol
 
70
      assert(sym != NoSymbol, showRaw(symDef))
 
71
      val name = symDef match {
 
72
        case FreeDef(_, name, _, _, _) => name
 
73
        case SymDef(_, name, _, _) => name
 
74
      }
 
75
      val newSymtab = if (!(symtab contains sym)) symtab + (sym -> symDef) else symtab
 
76
      val newAliases = aliases :+ (sym -> name)
 
77
      new SymbolTable(newSymtab, newAliases)
 
78
    }
 
79
 
 
80
    private def add(sym: Symbol, name0: TermName, reification: Tree): SymbolTable = {
 
81
      def freshName(name0: TermName): TermName = {
 
82
        var name = name0.toString
 
83
        name = name.replace(".type", "$type")
 
84
        name = name.replace(" ", "$")
 
85
        val fresh = typer.context.unit.fresh
 
86
        newTermName(fresh.newName(name))
 
87
      }
 
88
      val bindingAttachment = reification.attachments.get[ReifyBindingAttachment].get
 
89
      add(ValDef(NoMods, freshName(name0), TypeTree(), reification) updateAttachment bindingAttachment)
 
90
    }
 
91
 
 
92
    private def add(sym: Symbol, name: TermName): SymbolTable = {
 
93
      if (!(syms contains sym)) error("cannot add an alias to a symbol not in the symbol table")
 
94
      add(sym, name, EmptyTree)
 
95
    }
 
96
 
 
97
    private def remove(sym: Symbol): SymbolTable = {
 
98
      val newSymtab = symtab - sym
 
99
      val newAliases = aliases filter (_._1 != sym)
 
100
      new SymbolTable(newSymtab, newAliases)
 
101
    }
 
102
 
 
103
    private def remove(name: TermName): SymbolTable = {
 
104
      var newSymtab = symtab
 
105
      val newAliases = aliases filter (_._2 != name)
 
106
      newSymtab = newSymtab filter { case ((sym, _)) => newAliases exists (_._1 == sym) }
 
107
      newSymtab = newSymtab map { case ((sym, tree)) =>
 
108
        val ValDef(mods, primaryName, tpt, rhs) = tree
 
109
        val tree1 =
 
110
          if (!(newAliases contains (sym, primaryName))) {
 
111
            val primaryName1 = newAliases.find(_._1 == sym).get._2
 
112
            ValDef(mods, primaryName1, tpt, rhs).copyAttrs(tree)
 
113
          } else tree
 
114
        (sym, tree1)
 
115
      }
 
116
      new SymbolTable(newSymtab, newAliases)
 
117
    }
 
118
 
 
119
    private val cache = mutable.Map[SymbolTable, List[Tree]]()
 
120
    def encode: List[Tree] = cache.getOrElseUpdate(this, SymbolTable.encode(this)) map (_.duplicate)
 
121
 
 
122
    override def toString = {
 
123
      val symtabString = symtab.keys.map(symName(_)).mkString(", ")
 
124
      val trueAliases = aliases.distinct.filter(entry => symName(entry._1) != entry._2)
 
125
      val aliasesString = trueAliases.map(entry => s"${symName(entry._1)} -> ${entry._2}").mkString(", ")
 
126
      s"""symtab = [$symtabString], aliases = [$aliasesString]${if (original.isDefined) ", has original" else ""}"""
 
127
    }
 
128
 
 
129
    def debugString: String = {
 
130
      val buf = new StringBuilder
 
131
      buf.append("symbol table = " + (if (syms.length == 0) "<empty>" else "")).append(EOL)
 
132
      syms foreach (sym => buf.append(symDef(sym)).append(EOL))
 
133
      buf.delete(buf.length - EOL.length, buf.length)
 
134
      buf.toString
 
135
    }
 
136
  }
 
137
 
 
138
  object SymbolTable {
 
139
    def apply(): SymbolTable =
 
140
      new SymbolTable()
 
141
 
 
142
    def apply(encoded: List[Tree]): SymbolTable = {
 
143
      var result = new SymbolTable(original = Some(encoded))
 
144
      encoded foreach (entry => (entry.attachments.get[ReifyBindingAttachment], entry.attachments.get[ReifyAliasAttachment]) match {
 
145
        case (Some(ReifyBindingAttachment(_)), _) => result += entry
 
146
        case (_, Some(ReifyAliasAttachment(sym, alias))) => result = new SymbolTable(result.symtab, result.aliases :+ (sym, alias))
 
147
        case _ => // do nothing, this is boilerplate that can easily be recreated by subsequent `result.encode`
 
148
      })
 
149
      result
 
150
    }
 
151
 
 
152
    private[SymbolTable] def encode(symtab0: SymbolTable): List[Tree] = {
 
153
      if (symtab0.original.isDefined) return symtab0.original.get.map(_.duplicate)
 
154
      else assert(hasReifier, "encoding a symbol table requires a reifier")
 
155
      // during `encode` we might need to do some reifications
 
156
      // these reifications might lead to changes in `reifier.symtab`
 
157
      // reifier is mutable, symtab is immutable. this is a tough friendship
 
158
      val backup = reifier.state.backup
 
159
      reifier.state.symtab = symtab0.asInstanceOf[reifier.SymbolTable]
 
160
      def currtab = reifier.symtab.asInstanceOf[SymbolTable]
 
161
      try {
 
162
        val cumulativeSymtab = mutable.ArrayBuffer[Tree](symtab0.symtab.values.toList: _*)
 
163
        val cumulativeAliases = mutable.ArrayBuffer[(Symbol, TermName)](symtab0.aliases: _*)
 
164
 
 
165
        def fillInSymbol(sym: Symbol): Tree = {
 
166
          if (reifyDebug) println("Filling in: %s (%s)".format(sym, sym.accurateKindString))
 
167
          val isFreeTerm = FreeTermDef.unapply(currtab.symDef(sym)).isDefined
 
168
          // SI-6204 don't reify signatures for incomplete symbols, because this might lead to cyclic reference errors
 
169
          val signature =
 
170
            if (sym.isInitialized) {
 
171
              if (sym.isCapturedVariable) capturedVariableType(sym)
 
172
              else if (isFreeTerm) sym.tpe
 
173
              else sym.info
 
174
            } else NoType
 
175
          val rset = reifier.mirrorBuildCall(nme.setTypeSignature, currtab.symRef(sym), reifier.reify(signature))
 
176
          // `Symbol.annotations` doesn't initialize the symbol, so we don't need to do anything special here
 
177
          // also since we call `sym.info` a few lines above, by now the symbol will be initialized (if possible)
 
178
          // so the annotations will be filled in and will be waiting to be reified (unless symbol initialization is prohibited as described above)
 
179
          if (sym.annotations.isEmpty) rset
 
180
          else reifier.mirrorBuildCall(nme.setAnnotations, rset, reifier.mkList(sym.annotations map reifier.reifyAnnotationInfo))
 
181
        }
 
182
 
 
183
        // `fillInSymbol` might add symbols to `symtab`, that's why this is done iteratively
 
184
        var progress = 0
 
185
        while (progress < cumulativeSymtab.length) {
 
186
          val sym = reifyBinding(cumulativeSymtab(progress)).symbol
 
187
          if (sym != NoSymbol) {
 
188
            val symtabProgress = currtab.symtab.size
 
189
            val aliasesProgress = currtab.aliases.length
 
190
            val fillIn = fillInSymbol(sym)
 
191
            cumulativeSymtab ++= currtab.symtab.values drop symtabProgress
 
192
            cumulativeAliases ++= currtab.aliases drop aliasesProgress
 
193
            cumulativeSymtab += fillIn
 
194
          }
 
195
          progress += 1
 
196
        }
 
197
 
 
198
        val withAliases = cumulativeSymtab flatMap (entry => {
 
199
          val result = mutable.ListBuffer[Tree]()
 
200
          result += entry
 
201
          val sym = reifyBinding(entry).symbol
 
202
          if (sym != NoSymbol)
 
203
            result ++= cumulativeAliases.distinct filter (alias => alias._1 == sym && alias._2 != currtab.symName(sym)) map (alias => {
 
204
              val canonicalName = currtab.symName(sym)
 
205
              val aliasName = alias._2
 
206
              ValDef(NoMods, aliasName, TypeTree(), Ident(canonicalName)) updateAttachment ReifyAliasAttachment(sym, aliasName)
 
207
            })
 
208
          result.toList
 
209
        })
 
210
 
 
211
        withAliases.toList
 
212
      } finally {
 
213
        reifier.state.restore(backup)
 
214
      }
 
215
    }
 
216
  }
 
217
}
 
 
b'\\ No newline at end of file'