/
Symbol.scala
120 lines (98 loc) · 3.59 KB
/
Symbol.scala
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
package slick.ast
import slick.util.ConstArray
import scala.collection.mutable.HashMap
import scala.reflect.ClassTag
import scala.util.DynamicVariable
/** A symbol which can be used in the AST. It can be either a TypeSymbol or a TermSymbol. */
sealed trait Symbol {
def name: String
override def toString = SymbolNamer(this)
}
/** The symbol of a nominal type */
trait TypeSymbol extends Symbol
/** A symbol representing a variable */
trait TermSymbol extends Symbol
/** A named symbol which refers to an (aliased or unaliased) field. */
case class FieldSymbol(name: String)(val options: Seq[ColumnOption[_]], val tpe: Type) extends TermSymbol {
def findColumnOption[T <: ColumnOption[_]](implicit ct: ClassTag[T]): Option[T] =
options.find(ct.runtimeClass.isInstance _).asInstanceOf[Option[T]]
}
/** An element of a ProductNode (using a 1-based index) */
case class ElementSymbol(idx: Int) extends TermSymbol {
def name = "_" + idx
}
/** A TypeSymbol which uniquely identifies a table type */
trait TableIdentitySymbol extends TypeSymbol
/** Default implementation of TableIdentitySymbol */
case class SimpleTableIdentitySymbol(constituents: AnyRef*) extends TableIdentitySymbol {
def name = constituents.mkString("@(", ".", ")")
}
/** An anonymous symbol defined in the AST. */
class AnonTypeSymbol extends TypeSymbol {
def name = "$@"+System.identityHashCode(this)
}
/** An anonymous TableIdentitySymbol. */
class AnonTableIdentitySymbol extends AnonTypeSymbol with TableIdentitySymbol {
override def toString = "@"+SymbolNamer(this)+""
}
/** An anonymous symbol defined in the AST. */
class AnonSymbol extends TermSymbol {
def name = "@"+System.identityHashCode(this)
}
/** A Node which introduces a NominalType. */
trait TypeGenerator {
def identity: TypeSymbol
}
/** A Node which introduces Symbols. */
trait DefNode extends Node {
def generators: ConstArray[(TermSymbol, Node)]
protected[this] def rebuildWithSymbols(gen: ConstArray[TermSymbol]): Node
final def mapScopedChildren(f: (Option[TermSymbol], Node) => Node): Self with DefNode = {
val gens = generators
val ch = children
val all = ch.zipWithIndex.map[(Option[TermSymbol], Node)] { case (ch, idx) =>
val o = if(idx < gens.length) Some(gens(idx)._1) else None
(o, ch)
}
val mapped = all.map(f.tupled)
if(ch.zip(mapped).force.exists { case (n1, n2) => n1 ne n2 }) rebuild(mapped).asInstanceOf[Self with DefNode]
else this
}
final def mapSymbols(f: TermSymbol => TermSymbol): Node = {
val s = generators.map(_._1)
val s2 = s.endoMap(f)
if(s2 eq s) this else rebuildWithSymbols(s2)
}
}
/** Provides names for symbols */
class SymbolNamer(treeSymbolPrefix: String, typeSymbolPrefix: String, parent: Option[SymbolNamer] = None) {
private var curSymbolId = 1
private val map = new HashMap[Symbol, String]
def create(prefix: String) = {
curSymbolId += 1
prefix + curSymbolId
}
def get(s: Symbol): Option[String] =
map.get(s) orElse parent.flatMap(_.get(s))
def apply(s: Symbol): String = get(s).getOrElse(s match {
case a: AnonSymbol =>
val n = create(treeSymbolPrefix)
update(a, n)
n
case a: AnonTypeSymbol =>
val n = create(typeSymbolPrefix)
update(a, n)
n
case s => namedSymbolName(s)
})
def namedSymbolName(s: Symbol) = s.name
def update(s: Symbol, n: String): Unit = map += s -> n
def use[T](f: => T): T = SymbolNamer.dyn.withValue(this)(f)
}
object SymbolNamer {
private val dyn = new DynamicVariable[SymbolNamer](null)
def apply(s: Symbol): String = {
val n = dyn.value
if(n eq null) s.name else n(s)
}
}