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
|
package scala.reflect
package macros
/**
* <span class="badge badge-red" style="float: right;">EXPERIMENTAL</span>
*
* A slice of [[scala.reflect.macros.Context the Scala macros context]] that
* exposes functions to introduce synthetic definitions.
*
* @define TOPLEVEL_TREE Top-level tree is a tree that represents a non-inner class or object in one of the currently compiled source files.
* Note that top-level isn't equivalent to [[scala.reflect.api.Symbols#SymbolApi.isStatic]],
* because static also embraces definitions nested in static objects
*
* @define INTRODUCE_TOP_LEVEL Allowed definitions include classes (represented by `ClassDef` trees), traits (represented
* by `ClassDef` trees having the `TRAIT` flag set in `mods`) and objects (represented by `ModuleDef` trees).
*
* The definitions are put into the package with a prototype provided in `packagePrototype`.
* Supported prototypes are (see [[PackageSpec]] for more details):
* * Strings and names representing a fully-qualified name of the package
* * Trees that can work as package ids
* * Package or package class symbols
*
* Typical value for a package prototype is a fully-qualified name in a string.
* For example, to generate a class available at `foo.bar.Test`, call this method as follows:
*
* introduceTopLevel("foo.bar", ClassDef(<mods>, TypeName("Test"), <tparams>, <template>))
*
* It is possible to add definitions to the empty package by using `nme.EMPTY_PACKAGE_NAME.toString`, but
* that's not recommended, since such definitions cannot be seen from outside the empty package.
*
* Only the multi-parameter overload of this method can be used to introduce companions.
* If companions are introduced by two different calls, then they will be put into different virtual files, and `scalac`
* will show an error about companions being defined in different files. By the way, this also means that there's currently no way
* to define a companion for an existing class or module
*/
trait Synthetics {
self: Context =>
import universe._
/** Looks up a top-level definition tree with a given fully-qualified name
* (term name for modules, type name for classes). $TOPLEVEL_TREE.
* If such a tree does not exist, returns `EmptyTree`.
*/
def topLevelDef(name: Name): Tree
/** Returns a reference to a top-level definition tree with a given fully-qualified name
* (term name for modules, type name for classes). $TOPLEVEL_TREE.
* If such a tree does not exist, returns `EmptyTree`.
*/
def topLevelRef(name: Name): Tree
/** Adds a top-level definition to the compiler's symbol table. $INTRODUCE_TOP_LEVEL.
*
* Returns a fully-qualified reference to the introduced definition.
*/
def introduceTopLevel[T: PackageSpec](packagePrototype: T, definition: ImplDef): RefTree
/** Adds a list of top-level definitions to the compiler's symbol table. $INTRODUCE_TOP_LEVEL.
*
* Returns a list of fully-qualified references to the introduced definitions.
*/
def introduceTopLevel[T: PackageSpec](packagePrototype: T, definitions: ImplDef*): List[RefTree]
/** A factory which can create a package def from a prototype and a list of declarations.
*/
trait PackageSpec[T] { def mkPackageDef(prototype: T, stats: List[Tree]): PackageDef }
/** Hosts supported package specs.
*/
object PackageSpec {
/** Package def can be created from a fully-qualified name and a list of definitions.
* The name is converted into an Ident or a chain of Selects.
*/
implicit val stringIsPackageSpec = new PackageSpec[String] {
def mkPackageDef(prototype: String, stats: List[Tree]): PackageDef = self.mkPackageDef(prototype, stats)
}
/** Package def can be created from a fully-qualified term name and a list of definitions.
* The name is converted into an Ident or a chain of Selects.
*/
implicit val termNameIsPackageSpec = new PackageSpec[TermName] {
def mkPackageDef(prototype: TermName, stats: List[Tree]): PackageDef = self.mkPackageDef(prototype, stats)
}
/** Package def can be created from a package id tree and a list of definitions.
* If the tree is not a valid package id, i.e. is not a term-name ident or a chain of term-name selects,
* then the produced PackageDef will fail compilation at some point in the future.
*/
implicit val refTreeIsPackageSpec = new PackageSpec[RefTree] {
def mkPackageDef(prototype: RefTree, stats: List[Tree]): PackageDef = self.mkPackageDef(prototype, stats)
}
/** Package def can be created from a package/package class symbol and a list of definitions.
* If the provided symbol is not a package symbol or a package class symbol, package construction will throw an exception.
*/
implicit val SymbolIsPackageSpec = new PackageSpec[Symbol] {
def mkPackageDef(prototype: Symbol, stats: List[Tree]): PackageDef = self.mkPackageDef(prototype, stats)
}
}
protected def mkPackageDef(name: String, stats: List[Tree]): PackageDef
protected def mkPackageDef(name: TermName, stats: List[Tree]): PackageDef
protected def mkPackageDef(tree: RefTree, stats: List[Tree]): PackageDef
protected def mkPackageDef(sym: Symbol, stats: List[Tree]): PackageDef
}
|