Skip to content

Commit 96fa6a6

Browse files
committed
Decouple TASTy Reflect printers
1 parent d9a5409 commit 96fa6a6

File tree

7 files changed

+1849
-1851
lines changed

7 files changed

+1849
-1851
lines changed

compiler/src/dotty/tools/dotc/tastyreflect/ReflectionImpl.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ object ReflectionImpl {
1818
val syntaxHighlight =
1919
if (ctx.settings.color.value == "always") SyntaxHighlight.ANSI
2020
else SyntaxHighlight.plain
21-
val printers = new scala.tasty.reflect.Printers(refl)
22-
new printers.SourceCodePrinter(syntaxHighlight).showTree(reflTree)(given reflCtx)
21+
new scala.tasty.reflect.SourceCodePrinter[refl.type](refl)(syntaxHighlight).showTree(reflTree)(given reflCtx)
2322
}
2423
}
2524

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
package scala.tasty
2+
package reflect
3+
4+
class ExtractorsPrinter[R <: Reflection & Singleton](val tasty: R) extends Printer[R] {
5+
import tasty.{_, given}
6+
7+
def showTree(tree: Tree)(given ctx: Context): String =
8+
new Buffer().visitTree(tree).result()
9+
10+
def showTypeOrBounds(tpe: TypeOrBounds)(given ctx: Context): String =
11+
new Buffer().visitType(tpe).result()
12+
13+
def showConstant(const: Constant)(given ctx: Context): String =
14+
new Buffer().visitConstant(const).result()
15+
16+
def showSymbol(symbol: Symbol)(given ctx: Context): String =
17+
new Buffer().visitSymbol(symbol).result()
18+
19+
def showFlags(flags: Flags)(given ctx: Context): String = {
20+
val flagList = List.newBuilder[String]
21+
if (flags.is(Flags.Private)) flagList += "Flags.Private"
22+
if (flags.is(Flags.Protected)) flagList += "Flags.Protected"
23+
if (flags.is(Flags.Abstract)) flagList += "Flags.Abstract"
24+
if (flags.is(Flags.Final)) flagList += "Flags.Final"
25+
if (flags.is(Flags.Sealed)) flagList += "Flags.Sealed"
26+
if (flags.is(Flags.Case)) flagList += "Flags.Case"
27+
if (flags.is(Flags.Implicit)) flagList += "Flags.Implicit"
28+
if (flags.is(Flags.Erased)) flagList += "Flags.Erased"
29+
if (flags.is(Flags.Lazy)) flagList += "Flags.Lazy"
30+
if (flags.is(Flags.Override)) flagList += "Flags.Override"
31+
if (flags.is(Flags.Inline)) flagList += "Flags.Inline"
32+
if (flags.is(Flags.Macro)) flagList += "Flags.Macro"
33+
if (flags.is(Flags.JavaDefined)) flagList += "Flags.JavaDefined"
34+
if (flags.is(Flags.Static)) flagList += "Flags.javaStatic"
35+
if (flags.is(Flags.Object)) flagList += "Flags.Object"
36+
if (flags.is(Flags.Trait)) flagList += "Flags.Trait"
37+
if (flags.is(Flags.Local)) flagList += "Flags.Local"
38+
if (flags.is(Flags.Synthetic)) flagList += "Flags.Synthetic"
39+
if (flags.is(Flags.Artifact)) flagList += "Flags.Artifact"
40+
if (flags.is(Flags.Mutable)) flagList += "Flags.Mutable"
41+
if (flags.is(Flags.FieldAccessor)) flagList += "Flags.FieldAccessor"
42+
if (flags.is(Flags.CaseAcessor)) flagList += "Flags.CaseAcessor"
43+
if (flags.is(Flags.Covariant)) flagList += "Flags.Covariant"
44+
if (flags.is(Flags.Contravariant)) flagList += "Flags.Contravariant"
45+
if (flags.is(Flags.Scala2X)) flagList += "Flags.Scala2X"
46+
if (flags.is(Flags.DefaultParameterized)) flagList += "Flags.DefaultParameterized"
47+
if (flags.is(Flags.StableRealizable)) flagList += "Flags.StableRealizable"
48+
if (flags.is(Flags.Param)) flagList += "Flags.Param"
49+
if (flags.is(Flags.ParamAccessor)) flagList += "Flags.ParamAccessor"
50+
if (flags.is(Flags.Enum)) flagList += "Flags.Enum"
51+
if (flags.is(Flags.ModuleClass)) flagList += "Flags.ModuleClass"
52+
if (flags.is(Flags.PrivateLocal)) flagList += "Flags.PrivateLocal"
53+
if (flags.is(Flags.Package)) flagList += "Flags.Package"
54+
flagList.result().mkString(" | ")
55+
}
56+
57+
private class Buffer(given ctx: Context) { self =>
58+
59+
private val sb: StringBuilder = new StringBuilder
60+
61+
def result(): String = sb.result()
62+
63+
def visitTree(x: Tree): Buffer = x match {
64+
case Ident(name) =>
65+
this += "Ident(\"" += name += "\")"
66+
case Select(qualifier, name) =>
67+
this += "Select(" += qualifier += ", \"" += name += "\")"
68+
case This(qual) =>
69+
this += "This(" += qual += ")"
70+
case Super(qual, mix) =>
71+
this += "Super(" += qual += ", " += mix += ")"
72+
case Apply(fun, args) =>
73+
this += "Apply(" += fun += ", " ++= args += ")"
74+
case TypeApply(fun, args) =>
75+
this += "TypeApply(" += fun += ", " ++= args += ")"
76+
case Literal(const) =>
77+
this += "Literal(" += const += ")"
78+
case New(tpt) =>
79+
this += "New(" += tpt += ")"
80+
case Typed(expr, tpt) =>
81+
this += "Typed(" += expr += ", " += tpt += ")"
82+
case NamedArg(name, arg) =>
83+
this += "NamedArg(\"" += name += "\", " += arg += ")"
84+
case Assign(lhs, rhs) =>
85+
this += "Assign(" += lhs += ", " += rhs += ")"
86+
case Block(stats, expr) =>
87+
this += "Block(" ++= stats += ", " += expr += ")"
88+
case If(cond, thenp, elsep) =>
89+
this += "If(" += cond += ", " += thenp += ", " += elsep += ")"
90+
case Closure(meth, tpt) =>
91+
this += "Closure(" += meth += ", " += tpt += ")"
92+
case Match(selector, cases) =>
93+
this += "Match(" += selector += ", " ++= cases += ")"
94+
case ImpliedMatch(cases) =>
95+
this += "ImpliedMatch(" ++= cases += ")"
96+
case Return(expr) =>
97+
this += "Return(" += expr += ")"
98+
case While(cond, body) =>
99+
this += "While(" += cond += ", " += body += ")"
100+
case Try(block, handlers, finalizer) =>
101+
this += "Try(" += block += ", " ++= handlers += ", " += finalizer += ")"
102+
case Repeated(elems, elemtpt) =>
103+
this += "Repeated(" ++= elems += ", " += elemtpt += ")"
104+
case Inlined(call, bindings, expansion) =>
105+
this += "Inlined("
106+
visitOption(call, visitTree)
107+
this += ", " ++= bindings += ", " += expansion += ")"
108+
case ValDef(name, tpt, rhs) =>
109+
this += "ValDef(\"" += name += "\", " += tpt += ", " += rhs += ")"
110+
case DefDef(name, typeParams, paramss, returnTpt, rhs) =>
111+
this += "DefDef(\"" += name += "\", " ++= typeParams += ", " +++= paramss += ", " += returnTpt += ", " += rhs += ")"
112+
case TypeDef(name, rhs) =>
113+
this += "TypeDef(\"" += name += "\", " += rhs += ")"
114+
case ClassDef(name, constr, parents, derived, self, body) =>
115+
this += "ClassDef(\"" += name += "\", " += constr += ", "
116+
visitList[Tree](parents, visitTree)
117+
this += ", "
118+
visitList[TypeTree](derived, visitTree)
119+
this += ", " += self += ", " ++= body += ")"
120+
case PackageDef(name, owner) =>
121+
this += "PackageDef(\"" += name += "\", " += owner += ")"
122+
case Import(expr, selectors) =>
123+
this += "Import(" += expr += ", " ++= selectors += ")"
124+
case PackageClause(pid, stats) =>
125+
this += "PackageClause(" += pid += ", " ++= stats += ")"
126+
case Inferred() =>
127+
this += "Inferred()"
128+
case TypeIdent(name) =>
129+
this += "TypeIdent(\"" += name += "\")"
130+
case TypeSelect(qualifier, name) =>
131+
this += "TypeSelect(" += qualifier += ", \"" += name += "\")"
132+
case Projection(qualifier, name) =>
133+
this += "Projection(" += qualifier += ", \"" += name += "\")"
134+
case Singleton(ref) =>
135+
this += "Singleton(" += ref += ")"
136+
case Refined(tpt, refinements) =>
137+
this += "Refined(" += tpt += ", " ++= refinements += ")"
138+
case Applied(tpt, args) =>
139+
this += "Applied(" += tpt += ", " ++= args += ")"
140+
case ByName(result) =>
141+
this += "ByName(" += result += ")"
142+
case Annotated(arg, annot) =>
143+
this += "Annotated(" += arg += ", " += annot += ")"
144+
case LambdaTypeTree(tparams, body) =>
145+
this += "LambdaTypeTree(" ++= tparams += ", " += body += ")"
146+
case TypeBind(name, bounds) =>
147+
this += "TypeBind(" += name += ", " += bounds += ")"
148+
case TypeBlock(aliases, tpt) =>
149+
this += "TypeBlock(" ++= aliases += ", " += tpt += ")"
150+
case TypeBoundsTree(lo, hi) =>
151+
this += "TypeBoundsTree(" += lo += ", " += hi += ")"
152+
case WildcardTypeTree() =>
153+
this += s"WildcardTypeTree()"
154+
case MatchTypeTree(bound, selector, cases) =>
155+
this += "MatchTypeTree(" += bound += ", " += selector += ", " ++= cases += ")"
156+
case CaseDef(pat, guard, body) =>
157+
this += "CaseDef(" += pat += ", " += guard += ", " += body += ")"
158+
case TypeCaseDef(pat, body) =>
159+
this += "TypeCaseDef(" += pat += ", " += body += ")"
160+
case Bind(name, body) =>
161+
this += "Bind(\"" += name += "\", " += body += ")"
162+
case Unapply(fun, implicits, patterns) =>
163+
this += "Unapply(" += fun += ", " ++= implicits += ", " ++= patterns += ")"
164+
case Alternatives(patterns) =>
165+
this += "Alternative(" ++= patterns += ")"
166+
}
167+
168+
def visitConstant(x: Constant): Buffer = x match {
169+
case Constant(()) => this += "Constant(())"
170+
case Constant(null) => this += "Constant(null)"
171+
case Constant(value: Boolean) => this += "Constant(" += value += ")"
172+
case Constant(value: Byte) => this += "Constant(" += value += ": Byte)"
173+
case Constant(value: Short) => this += "Constant(" += value += ": Short)"
174+
case Constant(value: Char) => this += "Constant('" += value += "')"
175+
case Constant(value: Int) => this += "Constant(" += value.toString += ")"
176+
case Constant(value: Long) => this += "Constant(" += value += "L)"
177+
case Constant(value: Float) => this += "Constant(" += value += "f)"
178+
case Constant(value: Double) => this += "Constant(" += value += "d)"
179+
case Constant(value: String) => this += "Constant(\"" += value += "\")"
180+
case Constant.ClassTag(value) =>
181+
this += "Constant.ClassTag("
182+
visitType(value) += ")"
183+
}
184+
185+
def visitType(x: TypeOrBounds): Buffer = x match {
186+
case Type.ConstantType(value) =>
187+
this += "Type.ConstantType(" += value += ")"
188+
case Type.TermRef(qual, name) =>
189+
this += "Type.TermRef(" += qual+= ", \"" += name += "\")"
190+
case Type.TypeRef(qual, name) =>
191+
this += "Type.TypeRef(" += qual += ", \"" += name += "\")"
192+
case Type.Refinement(parent, name, info) =>
193+
this += "Type.Refinement(" += parent += ", " += name += ", " += info += ")"
194+
case Type.AppliedType(tycon, args) =>
195+
this += "Type.AppliedType(" += tycon += ", " ++= args += ")"
196+
case Type.AnnotatedType(underlying, annot) =>
197+
this += "Type.AnnotatedType(" += underlying += ", " += annot += ")"
198+
case Type.AndType(left, right) =>
199+
this += "Type.AndType(" += left += ", " += right += ")"
200+
case Type.OrType(left, right) =>
201+
this += "Type.OrType(" += left += ", " += right += ")"
202+
case Type.MatchType(bound, scrutinee, cases) =>
203+
this += "Type.MatchType(" += bound += ", " += scrutinee += ", " ++= cases += ")"
204+
case Type.ByNameType(underlying) =>
205+
this += "Type.ByNameType(" += underlying += ")"
206+
case Type.ParamRef(binder, idx) =>
207+
this += "Type.ParamRef(" += binder += ", " += idx += ")"
208+
case Type.ThisType(tp) =>
209+
this += "Type.ThisType(" += tp += ")"
210+
case Type.SuperType(thistpe, supertpe) =>
211+
this += "Type.SuperType(" += thistpe += ", " += supertpe += ")"
212+
case Type.RecursiveThis(binder) =>
213+
this += "Type.RecursiveThis(" += binder += ")"
214+
case Type.RecursiveType(underlying) =>
215+
this += "Type.RecursiveType(" += underlying += ")"
216+
case Type.MethodType(argNames, argTypes, resType) =>
217+
this += "Type.MethodType(" ++= argNames += ", " ++= argTypes += ", " += resType += ")"
218+
case Type.PolyType(argNames, argBounds, resType) =>
219+
this += "Type.PolyType(" ++= argNames += ", " ++= argBounds += ", " += resType += ")"
220+
case Type.TypeLambda(argNames, argBounds, resType) =>
221+
// resType is not printed to avoid cycles
222+
this += "Type.TypeLambda(" ++= argNames += ", " ++= argBounds += ", _)"
223+
case TypeBounds(lo, hi) =>
224+
this += "TypeBounds(" += lo += ", " += hi += ")"
225+
case NoPrefix() =>
226+
this += "NoPrefix()"
227+
}
228+
229+
def visitId(x: Id): Buffer = {
230+
val Id(name) = x
231+
this += "Id(\"" += name += "\")"
232+
}
233+
234+
def visitSignature(sig: Signature): Buffer = {
235+
val Signature(params, res) = sig
236+
this += "Signature(" ++= params.map(_.toString) += ", " += res += ")"
237+
}
238+
239+
def visitImportSelector(sel: ImportSelector): Buffer = sel match {
240+
case SimpleSelector(id) => this += "SimpleSelector(" += id += ")"
241+
case RenameSelector(id1, id2) => this += "RenameSelector(" += id1 += ", " += id2 += ")"
242+
case OmitSelector(id) => this += "OmitSelector(" += id += ")"
243+
}
244+
245+
def visitSymbol(x: Symbol): Buffer =
246+
if x.isPackageDef then this += "IsPackageDefSymbol(<" += x.fullName += ">)"
247+
else if x.isClassDef then this += "IsClassDefSymbol(<" += x.fullName += ">)"
248+
else if x.isDefDef then this += "IsDefDefSymbol(<" += x.fullName += ">)"
249+
else if x.isValDef then this += "IsValDefSymbol(<" += x.fullName += ">)"
250+
else if x.isTypeDef then this += "IsTypeDefSymbol(<" += x.fullName += ">)"
251+
else { assert(x.isNoSymbol); this += "NoSymbol()" }
252+
253+
def +=(x: Boolean): Buffer = { sb.append(x); this }
254+
def +=(x: Byte): Buffer = { sb.append(x); this }
255+
def +=(x: Short): Buffer = { sb.append(x); this }
256+
def +=(x: Int): Buffer = { sb.append(x); this }
257+
def +=(x: Long): Buffer = { sb.append(x); this }
258+
def +=(x: Float): Buffer = { sb.append(x); this }
259+
def +=(x: Double): Buffer = { sb.append(x); this }
260+
def +=(x: Char): Buffer = { sb.append(x); this }
261+
def +=(x: String): Buffer = { sb.append(x); this }
262+
263+
def ++=(xs: List[String]): Buffer = visitList[String](xs, +=)
264+
265+
private implicit class TreeOps(buff: Buffer) {
266+
def +=(x: Tree): Buffer = { visitTree(x); buff }
267+
def +=(x: Option[Tree]): Buffer = { visitOption(x, visitTree); buff }
268+
def ++=(x: List[Tree]): Buffer = { visitList(x, visitTree); buff }
269+
def +++=(x: List[List[Tree]]): Buffer = { visitList(x, ++=); buff }
270+
}
271+
272+
private implicit class ConstantOps(buff: Buffer) {
273+
def +=(x: Constant): Buffer = { visitConstant(x); buff }
274+
}
275+
276+
private implicit class TypeOps(buff: Buffer) {
277+
def +=(x: TypeOrBounds): Buffer = { visitType(x); buff }
278+
def +=(x: Option[TypeOrBounds]): Buffer = { visitOption(x, visitType); buff }
279+
def ++=(x: List[TypeOrBounds]): Buffer = { visitList(x, visitType); buff }
280+
}
281+
282+
private implicit class IdOps(buff: Buffer) {
283+
def +=(x: Id): Buffer = { visitId(x); buff }
284+
def +=(x: Option[Id]): Buffer = { visitOption(x, visitId); buff }
285+
}
286+
287+
private implicit class SignatureOps(buff: Buffer) {
288+
def +=(x: Option[Signature]): Buffer = { visitOption(x, visitSignature); buff }
289+
}
290+
291+
private implicit class ImportSelectorOps(buff: Buffer) {
292+
def ++=(x: List[ImportSelector]): Buffer = { visitList(x, visitImportSelector); buff }
293+
}
294+
295+
private implicit class SymbolOps(buff: Buffer) {
296+
def +=(x: Symbol): Buffer = { visitSymbol(x); buff }
297+
}
298+
299+
private def visitOption[U](opt: Option[U], visit: U => Buffer): Buffer = opt match {
300+
case Some(x) =>
301+
this += "Some("
302+
visit(x)
303+
this += ")"
304+
case _ =>
305+
this += "None"
306+
}
307+
308+
private def visitList[U](list: List[U], visit: U => Buffer): Buffer = list match {
309+
case x0 :: xs =>
310+
this += "List("
311+
visit(x0)
312+
def visitNext(xs: List[U]): Unit = xs match {
313+
case y :: ys =>
314+
this += ", "
315+
visit(y)
316+
visitNext(ys)
317+
case Nil =>
318+
}
319+
visitNext(xs)
320+
this += ")"
321+
case Nil =>
322+
this += "Nil"
323+
}
324+
}
325+
326+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package scala.tasty
2+
package reflect
3+
4+
trait Printer[R <: Reflection & Singleton] {
5+
6+
/** Instance of reflection interface */
7+
val tasty: R
8+
9+
/** Show a String representation of a tasty.Tree */
10+
def showTree(tree: tasty.Tree)(given ctx: tasty.Context): String
11+
12+
/** Show a String representation of a tasty.TypeOrBounds */
13+
def showTypeOrBounds(tpe: tasty.TypeOrBounds)(given ctx: tasty.Context): String
14+
15+
/** Show a String representation of a tasty.Constant */
16+
def showConstant(const: tasty.Constant)(given ctx: tasty.Context): String
17+
18+
/** Show a String representation of a tasty.Symbol */
19+
def showSymbol(symbol: tasty.Symbol)(given ctx: tasty.Context): String
20+
21+
/** Show a String representation of a tasty.Flags */
22+
def showFlags(flags: tasty.Flags)(given ctx: tasty.Context): String
23+
}

0 commit comments

Comments
 (0)