/
MacroCompatScala2.scala
95 lines (88 loc) · 2.68 KB
/
MacroCompatScala2.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
package munit.internal
import munit.Clue
import munit.Location
import scala.reflect.macros.blackbox.Context
import scala.reflect.macros.TypecheckException
import scala.reflect.macros.ParseException
object MacroCompatScala2 {
def locationImpl(c: Context): c.Tree = {
import c.universe._
val line = Literal(Constant(c.enclosingPosition.line))
val path = Literal(Constant(c.enclosingPosition.source.path))
New(c.mirror.staticClass(classOf[Location].getName()), path, line)
}
def clueImpl(c: Context)(value: c.Tree): c.Tree = {
import c.universe._
val text: String =
if (value.pos != null && value.pos.isRange) {
val chars = value.pos.source.content
val start = value.pos.start
val end = value.pos.end
if (
end > start &&
start >= 0 && start < chars.length &&
end >= 0 && end < chars.length
) {
new String(chars, start, end - start)
} else {
""
}
} else {
""
}
def simplifyType(tpe: Type): Type = tpe match {
case TypeRef(ThisType(pre), sym, args) if pre == sym.owner =>
simplifyType(c.internal.typeRef(NoPrefix, sym, args))
case t =>
// uncomment to debug:
// Printers.log(t)(Location.empty)
t.widen
}
val source = Literal(Constant(text))
val valueType = Literal(Constant(simplifyType(value.tpe).toString()))
New(
c.internal.typeRef(
NoPrefix,
c.mirror.staticClass(classOf[Clue[_]].getName()),
List(value.tpe.widen)
),
source,
value,
valueType
)
}
def compileErrorsImpl(c: Context)(code: c.Tree): c.Tree = {
import c.universe._
val toParse: String = code match {
case Literal(Constant(literal: String)) => literal
case _ =>
c.abort(
code.pos,
"cannot compile dynamic expressions, only constant literals.\n" +
"To fix this problem, pass in a string literal in double quotes \"...\""
)
}
def formatError(message: String, pos: scala.reflect.api.Position): String =
new StringBuilder()
.append("error:")
.append(if (message.contains('\n')) "\n" else " ")
.append(message)
.append("\n")
.append(pos.lineContent)
.append("\n")
.append(" " * (pos.column - 1))
.append("^")
.toString()
val message: String =
try {
c.typecheck(c.parse(s"{\n$toParse\n}"))
""
} catch {
case e: ParseException =>
formatError(e.getMessage(), e.pos)
case e: TypecheckException =>
formatError(e.getMessage(), e.pos)
}
Literal(Constant(message))
}
}