Skip to content

Commit f7b4cca

Browse files
Move macro-related stuff to separate file
1 parent 24df4f5 commit f7b4cca

File tree

2 files changed

+199
-164
lines changed

2 files changed

+199
-164
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
package sourcecode
2+
3+
import language.experimental.macros
4+
5+
trait NameMacros {
6+
implicit def generate: Name = macro Macros.nameImpl
7+
}
8+
9+
trait NameMachineMacros {
10+
implicit def generate: Name.Machine = macro Macros.nameMachineImpl
11+
}
12+
13+
trait FullNameMacros {
14+
implicit def generate: FullName = macro Macros.fullNameImpl
15+
}
16+
17+
trait FullNameMachineMacros {
18+
implicit def generate: FullName.Machine = macro Macros.fullNameMachineImpl
19+
}
20+
21+
trait FileMacros {
22+
implicit def generate: sourcecode.File = macro Macros.fileImpl
23+
}
24+
25+
trait LineMacros {
26+
implicit def generate: sourcecode.Line = macro Macros.lineImpl
27+
}
28+
29+
trait EnclosingMacros {
30+
implicit def generate: Enclosing = macro Macros.enclosingImpl
31+
}
32+
33+
trait EnclosingMachineMacros {
34+
implicit def generate: Enclosing.Machine = macro Macros.enclosingMachineImpl
35+
}
36+
37+
trait PkgMacros {
38+
implicit def generate: Pkg = macro Macros.pkgImpl
39+
}
40+
41+
trait TextMacros {
42+
implicit def generate[T](v: T): Text[T] = macro Macros.text[T]
43+
def apply[T](v: T): Text[T] = macro Macros.text[T]
44+
}
45+
46+
trait ArgsMacros {
47+
implicit def generate: Args = macro Macros.argsImpl
48+
}
49+
50+
object Util{
51+
def isSynthetic(c: Compat.Context)(s: c.Symbol) = isSyntheticName(getName(c)(s))
52+
def isSyntheticName(name: String) = {
53+
name == "<init>" || (name.startsWith("<local ") && name.endsWith(">"))
54+
}
55+
def getName(c: Compat.Context)(s: c.Symbol) = s.name.decoded.toString.trim
56+
}
57+
58+
object Macros {
59+
60+
def nameImpl(c: Compat.Context): c.Expr[Name] = {
61+
import c.universe._
62+
var owner = Compat.enclosingOwner(c)
63+
while(Util.isSynthetic(c)(owner)) owner = owner.owner
64+
val simpleName = Util.getName(c)(owner)
65+
c.Expr[sourcecode.Name](q"""${c.prefix}($simpleName)""")
66+
}
67+
68+
def nameMachineImpl(c: Compat.Context): c.Expr[Name.Machine] = {
69+
import c.universe._
70+
val owner = Compat.enclosingOwner(c)
71+
val simpleName = Util.getName(c)(owner)
72+
c.Expr[Name.Machine](q"""${c.prefix}($simpleName)""")
73+
}
74+
75+
def fullNameImpl(c: Compat.Context): c.Expr[FullName] = {
76+
import c.universe._
77+
val owner = Compat.enclosingOwner(c)
78+
val fullName =
79+
owner.fullName.trim
80+
.split("\\.", -1)
81+
.filterNot(Util.isSyntheticName)
82+
.mkString(".")
83+
c.Expr[sourcecode.FullName](q"""${c.prefix}($fullName)""")
84+
}
85+
86+
def fullNameMachineImpl(c: Compat.Context): c.Expr[FullName.Machine] = {
87+
import c.universe._
88+
val owner = Compat.enclosingOwner(c)
89+
val fullName = owner.fullName.trim
90+
c.Expr[FullName.Machine](q"""${c.prefix}($fullName)""")
91+
}
92+
93+
def fileImpl(c: Compat.Context): c.Expr[sourcecode.File] = {
94+
import c.universe._
95+
val file = c.enclosingPosition.source.path
96+
c.Expr[sourcecode.File](q"""${c.prefix}($file)""")
97+
}
98+
99+
def lineImpl(c: Compat.Context): c.Expr[sourcecode.Line] = {
100+
import c.universe._
101+
val line = c.enclosingPosition.line
102+
c.Expr[sourcecode.Line](q"""${c.prefix}($line)""")
103+
}
104+
105+
def enclosingImpl(c: Compat.Context): c.Expr[Enclosing] = enclosing[Enclosing](c)(
106+
!Util.isSynthetic(c)(_)
107+
)
108+
109+
def enclosingMachineImpl(c: Compat.Context): c.Expr[Enclosing.Machine] =
110+
enclosing[Enclosing.Machine](c)(_ => true)
111+
112+
def pkgImpl(c: Compat.Context): c.Expr[Pkg] = enclosing[Pkg](c)(_.isPackage)
113+
114+
def argsImpl(c: Compat.Context): c.Expr[Args] = {
115+
import c.universe._
116+
val param = Compat.enclosingParamList(c)
117+
val texts = param.map(_.map(p => c.Expr[Text[_]](q"""sourcecode.Text($p, ${p.name.toString})""")))
118+
val textSeqs = texts.map(s => c.Expr(q"""Seq(..$s)"""))
119+
c.Expr[Args](q"""Seq(..$textSeqs)""")
120+
}
121+
122+
123+
def text[T: c.WeakTypeTag](c: Compat.Context)(v: c.Expr[T]): c.Expr[sourcecode.Text[T]] = {
124+
import c.universe._
125+
val fileContent = new String(v.tree.pos.source.content)
126+
val start = v.tree.collect {
127+
case treeVal => treeVal.pos match {
128+
case NoPosition Int.MaxValue
129+
case p p.startOrPoint
130+
}
131+
}.min
132+
val g = c.asInstanceOf[reflect.macros.runtime.Context].global
133+
val parser = g.newUnitParser(fileContent.drop(start))
134+
parser.expr()
135+
val end = parser.in.lastOffset
136+
val txt = fileContent.slice(start, start + end)
137+
val tree = q"""${c.prefix}(${v.tree}, $txt)"""
138+
c.Expr[sourcecode.Text[T]](tree)
139+
}
140+
sealed trait Chunk
141+
object Chunk{
142+
case class Pkg(name: String) extends Chunk
143+
case class Obj(name: String) extends Chunk
144+
case class Cls(name: String) extends Chunk
145+
case class Trt(name: String) extends Chunk
146+
case class Val(name: String) extends Chunk
147+
case class Var(name: String) extends Chunk
148+
case class Lzy(name: String) extends Chunk
149+
case class Def(name: String) extends Chunk
150+
151+
}
152+
153+
def enclosing[T](c: Compat.Context)(filter: c.Symbol => Boolean): c.Expr[T] = {
154+
155+
import c.universe._
156+
var current = Compat.enclosingOwner(c)
157+
var path = List.empty[Chunk]
158+
while(current != NoSymbol && current.toString != "package <root>"){
159+
if (filter(current)) {
160+
161+
val chunk = current match {
162+
case x if x.isPackage => Chunk.Pkg
163+
case x if x.isModuleClass => Chunk.Obj
164+
case x if x.isClass && x.asClass.isTrait => Chunk.Trt
165+
case x if x.isClass => Chunk.Cls
166+
case x if x.isMethod => Chunk.Def
167+
case x if x.isTerm && x.asTerm.isVar => Chunk.Var
168+
case x if x.isTerm && x.asTerm.isLazy => Chunk.Lzy
169+
case x if x.isTerm && x.asTerm.isVal => Chunk.Val
170+
}
171+
172+
path = chunk(Util.getName(c)(current)) :: path
173+
}
174+
current = current.owner
175+
}
176+
val renderedPath = path.map{
177+
case Chunk.Pkg(s) => s + "."
178+
case Chunk.Obj(s) => s + "."
179+
case Chunk.Cls(s) => s + "#"
180+
case Chunk.Trt(s) => s + "#"
181+
case Chunk.Val(s) => s + " "
182+
case Chunk.Var(s) => s + " "
183+
case Chunk.Lzy(s) => s + " "
184+
case Chunk.Def(s) => s + " "
185+
}.mkString.dropRight(1)
186+
c.Expr[T](q"""${c.prefix}($renderedPath)""")
187+
}
188+
}
Lines changed: 11 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
package sourcecode
22

3-
import language.experimental.macros
43

5-
6-
object Util{
7-
def isSynthetic(c: Compat.Context)(s: c.Symbol) = isSyntheticName(getName(c)(s))
8-
def isSyntheticName(name: String) = {
9-
name == "<init>" || (name.startsWith("<local ") && name.endsWith(">"))
10-
}
11-
def getName(c: Compat.Context)(s: c.Symbol) = s.name.decoded.toString.trim
12-
}
134
abstract class SourceValue[T]{
145
def value: T
156
}
@@ -18,176 +9,32 @@ abstract class SourceCompanion[T, V <: SourceValue[T]](build: T => V){
189
implicit def wrap(s: T): V = build(s)
1910
}
2011
case class Name(value: String) extends SourceValue[String]
21-
object Name extends SourceCompanion[String, Name](new Name(_)){
22-
implicit def generate: Name = macro impl
23-
24-
def impl(c: Compat.Context): c.Expr[Name] = {
25-
import c.universe._
26-
var owner = Compat.enclosingOwner(c)
27-
while(Util.isSynthetic(c)(owner)) owner = owner.owner
28-
val simpleName = Util.getName(c)(owner)
29-
c.Expr[sourcecode.Name](q"""${c.prefix}($simpleName)""")
30-
}
12+
object Name extends SourceCompanion[String, Name](new Name(_)) with NameMacros {
3113
case class Machine(value: String) extends SourceValue[String]
32-
object Machine extends SourceCompanion[String, Machine](new Machine(_)){
33-
implicit def generate: Machine = macro impl
34-
def impl(c: Compat.Context): c.Expr[Machine] = {
35-
import c.universe._
36-
val owner = Compat.enclosingOwner(c)
37-
val simpleName = Util.getName(c)(owner)
38-
c.Expr[Machine](q"""${c.prefix}($simpleName)""")
39-
}
40-
}
14+
object Machine extends SourceCompanion[String, Machine](new Machine(_)) with NameMachineMacros
4115
}
4216
case class FullName(value: String) extends SourceValue[String]
43-
object FullName extends SourceCompanion[String, FullName](new FullName(_)){
44-
implicit def generate: FullName = macro impl
45-
46-
def impl(c: Compat.Context): c.Expr[FullName] = {
47-
import c.universe._
48-
val owner = Compat.enclosingOwner(c)
49-
val fullName =
50-
owner.fullName.trim
51-
.split("\\.", -1)
52-
.filterNot(Util.isSyntheticName)
53-
.mkString(".")
54-
c.Expr[sourcecode.FullName](q"""${c.prefix}($fullName)""")
55-
}
17+
object FullName extends SourceCompanion[String, FullName](new FullName(_)) with FullNameMacros {
5618
case class Machine(value: String) extends SourceValue[String]
57-
object Machine extends SourceCompanion[String, Machine](new Machine(_)){
58-
implicit def generate: Machine = macro impl
59-
60-
def impl(c: Compat.Context): c.Expr[Machine] = {
61-
import c.universe._
62-
val owner = Compat.enclosingOwner(c)
63-
val fullName = owner.fullName.trim
64-
c.Expr[Machine](q"""${c.prefix}($fullName)""")
65-
}
66-
}
19+
object Machine extends SourceCompanion[String, Machine](new Machine(_)) with FullNameMachineMacros
6720
}
6821
case class File(value: String) extends SourceValue[String]
69-
object File extends SourceCompanion[String, File](new File(_)){
70-
implicit def generate: sourcecode.File = macro impl
71-
72-
def impl(c: Compat.Context): c.Expr[sourcecode.File] = {
73-
import c.universe._
74-
val file = c.enclosingPosition.source.path
75-
c.Expr[sourcecode.File](q"""${c.prefix}($file)""")
76-
}
77-
}
22+
object File extends SourceCompanion[String, File](new File(_)) with FileMacros
7823
case class Line(value: Int) extends SourceValue[Int]
79-
object Line extends SourceCompanion[Int, Line](new Line(_)){
80-
implicit def generate: sourcecode.Line = macro impl
81-
def impl(c: Compat.Context): c.Expr[sourcecode.Line] = {
82-
import c.universe._
83-
val line = c.enclosingPosition.line
84-
c.Expr[sourcecode.Line](q"""${c.prefix}($line)""")
85-
}
86-
}
24+
object Line extends SourceCompanion[Int, Line](new Line(_)) with LineMacros
8725
case class Enclosing(value: String) extends SourceValue[String]
8826

89-
object Enclosing extends SourceCompanion[String, Enclosing](new Enclosing(_)){
90-
implicit def generate: Enclosing = macro impl
91-
def impl(c: Compat.Context): c.Expr[Enclosing] = Impls.enclosing[Enclosing](c)(
92-
!Util.isSynthetic(c)(_)
93-
)
27+
object Enclosing extends SourceCompanion[String, Enclosing](new Enclosing(_)) with EnclosingMacros {
9428
case class Machine(value: String) extends SourceValue[String]
95-
object Machine extends SourceCompanion[String, Machine](new Machine(_)){
96-
implicit def generate: Machine = macro impl
97-
def impl(c: Compat.Context): c.Expr[Machine] = Impls.enclosing[Machine](c)(_ => true)
98-
}
29+
object Machine extends SourceCompanion[String, Machine](new Machine(_)) with EnclosingMachineMacros
9930
}
10031

10132

10233
case class Pkg(value: String) extends SourceValue[String]
103-
object Pkg extends SourceCompanion[String, Pkg](new Pkg(_)){
104-
implicit def generate: Pkg = macro impl
105-
def impl(c: Compat.Context): c.Expr[Pkg] = Impls.enclosing[Pkg](c)(_.isPackage)
106-
}
34+
object Pkg extends SourceCompanion[String, Pkg](new Pkg(_)) with PkgMacros
10735

10836
case class Text[T](value: T, source: String)
109-
object Text{
110-
implicit def generate[T](v: T): Text[T] = macro Impls.text[T]
111-
def apply[T](v: T): Text[T] = macro Impls.text[T]
112-
113-
}
37+
object Text extends TextMacros
11438

11539
case class Args(value: Seq[Seq[Text[_]]]) extends SourceValue[Seq[Seq[Text[_]]]]
116-
object Args extends SourceCompanion[Seq[Seq[Text[_]]], Args](new Args(_)) {
117-
implicit def generate: Args = macro impl
118-
def impl(c: Compat.Context): c.Expr[Args] = {
119-
import c.universe._
120-
val param = Compat.enclosingParamList(c)
121-
val texts = param.map(_.map(p => c.Expr[Text[_]](q"""sourcecode.Text($p, ${p.name.toString})""")))
122-
val textSeqs = texts.map(s => c.Expr(q"""Seq(..$s)"""))
123-
c.Expr[Args](q"""Seq(..$textSeqs)""")
124-
}
125-
}
126-
127-
object Impls{
128-
def text[T: c.WeakTypeTag](c: Compat.Context)(v: c.Expr[T]): c.Expr[sourcecode.Text[T]] = {
129-
import c.universe._
130-
val fileContent = new String(v.tree.pos.source.content)
131-
val start = v.tree.collect {
132-
case treeVal => treeVal.pos match {
133-
case NoPosition Int.MaxValue
134-
case p p.startOrPoint
135-
}
136-
}.min
137-
val g = c.asInstanceOf[reflect.macros.runtime.Context].global
138-
val parser = g.newUnitParser(fileContent.drop(start))
139-
parser.expr()
140-
val end = parser.in.lastOffset
141-
val txt = fileContent.slice(start, start + end)
142-
val tree = q"""${c.prefix}(${v.tree}, $txt)"""
143-
c.Expr[sourcecode.Text[T]](tree)
144-
}
145-
sealed trait Chunk
146-
object Chunk{
147-
case class Pkg(name: String) extends Chunk
148-
case class Obj(name: String) extends Chunk
149-
case class Cls(name: String) extends Chunk
150-
case class Trt(name: String) extends Chunk
151-
case class Val(name: String) extends Chunk
152-
case class Var(name: String) extends Chunk
153-
case class Lzy(name: String) extends Chunk
154-
case class Def(name: String) extends Chunk
155-
156-
}
157-
158-
def enclosing[T](c: Compat.Context)(filter: c.Symbol => Boolean): c.Expr[T] = {
159-
160-
import c.universe._
161-
var current = Compat.enclosingOwner(c)
162-
var path = List.empty[Chunk]
163-
while(current != NoSymbol && current.toString != "package <root>"){
164-
if (filter(current)) {
165-
166-
val chunk = current match {
167-
case x if x.isPackage => Chunk.Pkg
168-
case x if x.isModuleClass => Chunk.Obj
169-
case x if x.isClass && x.asClass.isTrait => Chunk.Trt
170-
case x if x.isClass => Chunk.Cls
171-
case x if x.isMethod => Chunk.Def
172-
case x if x.isTerm && x.asTerm.isVar => Chunk.Var
173-
case x if x.isTerm && x.asTerm.isLazy => Chunk.Lzy
174-
case x if x.isTerm && x.asTerm.isVal => Chunk.Val
175-
}
176-
177-
path = chunk(Util.getName(c)(current)) :: path
178-
}
179-
current = current.owner
180-
}
181-
val renderedPath = path.map{
182-
case Chunk.Pkg(s) => s + "."
183-
case Chunk.Obj(s) => s + "."
184-
case Chunk.Cls(s) => s + "#"
185-
case Chunk.Trt(s) => s + "#"
186-
case Chunk.Val(s) => s + " "
187-
case Chunk.Var(s) => s + " "
188-
case Chunk.Lzy(s) => s + " "
189-
case Chunk.Def(s) => s + " "
190-
}.mkString.dropRight(1)
191-
c.Expr[T](q"""${c.prefix}($renderedPath)""")
192-
}
193-
}
40+
object Args extends SourceCompanion[Seq[Seq[Text[_]]], Args](new Args(_)) with ArgsMacros

0 commit comments

Comments
 (0)