Skip to content

Commit 6fb7970

Browse files
Merge pull request #4630 from dotty-staging/add-while-to-tasty-relect
Add While and DoWhile extractors Tasty reflect
2 parents 89010f2 + d143026 commit 6fb7970

File tree

4 files changed

+68
-53
lines changed

4 files changed

+68
-53
lines changed

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

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,9 +374,31 @@ class TastyImpl(val rootContext: Contexts.Context) extends scala.tasty.Tasty { s
374374
}
375375

376376
object Block extends BlockExtractor {
377-
def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = x match {
378-
case x: tpd.Block @unchecked => Some((x.stats, x.expr))
379-
case _ => None
377+
def unapply(x: Term)(implicit ctx: Context): Option[(List[Statement], Term)] = normalizedLoops(x) match {
378+
case Trees.Block(_, expr) if expr.symbol.is(Flags.Label) => None // while or doWhile loops
379+
case Trees.Block(stats, expr) => Some((stats, expr))
380+
case _ => None
381+
}
382+
/** Normilizes non Blocks.
383+
* i) Put `while` and `doWhile` loops in thier own blocks: `{ def while$() = ...; while$() }`
384+
*/
385+
private def normalizedLoops(tree: tpd.Tree)(implicit ctx: Context): tpd.Tree = tree match {
386+
case block: tpd.Block if block.stats.size > 1 =>
387+
def normalizeInnerLoops(stats: List[tpd.Tree]): List[tpd.Tree] = stats match {
388+
case (x: tpd.DefDef) :: y :: xs if y.symbol.is(Flags.Label) =>
389+
tpd.Block(x :: Nil, y) :: normalizeInnerLoops(xs)
390+
case x :: xs => x :: normalizeInnerLoops(xs)
391+
case Nil => Nil
392+
}
393+
if (block.expr.symbol.is(Flags.Label)) {
394+
val stats1 = normalizeInnerLoops(block.stats.init)
395+
val normalLoop = tpd.Block(block.stats.last :: Nil, block.expr)
396+
tpd.Block(stats1, normalLoop)
397+
} else {
398+
val stats1 = normalizeInnerLoops(block.stats)
399+
tpd.cpy.Block(block)(stats1, block.expr)
400+
}
401+
case _ => tree
380402
}
381403
}
382404

@@ -441,6 +463,28 @@ class TastyImpl(val rootContext: Contexts.Context) extends scala.tasty.Tasty { s
441463
}
442464
}
443465

466+
object While extends WhileExtractor {
467+
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match {
468+
case Trees.Block((ddef: tpd.DefDef) :: Nil, expr) if expr.symbol.is(Flags.Label) && expr.symbol.name == nme.WHILE_PREFIX =>
469+
val Trees.If(cond, Trees.Block(bodyStats, _), _) = ddef.rhs
470+
Some((cond, loopBody(bodyStats)))
471+
case _ => None
472+
}
473+
}
474+
475+
object DoWhile extends DoWhileExtractor {
476+
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)] = x match {
477+
case Trees.Block((ddef: tpd.DefDef) :: Nil, expr) if expr.symbol.is(Flags.Label) && expr.symbol.name == nme.DO_WHILE_PREFIX =>
478+
val Trees.Block(bodyStats, Trees.If(cond, _, _)) = ddef.rhs
479+
Some((loopBody(bodyStats), cond))
480+
case _ => None
481+
}
482+
}
483+
484+
private def loopBody(stats: List[tpd.Tree])(implicit ctx: Context): tpd.Tree = stats match {
485+
case body :: Nil => body
486+
case stats => tpd.Block(stats.init, stats.last)
487+
}
444488
}
445489

446490
// ----- CaseDef --------------------------------------------------

library/src/scala/tasty/Tasty.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,17 @@ abstract class Tasty { tasty =>
339339
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Int, Type)]
340340
}
341341

342+
val While: WhileExtractor
343+
abstract class WhileExtractor {
344+
/** Extractor for while loops. Matches `while (<cond>) <body>` and returns (<cond>, <body>) */
345+
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)]
346+
}
347+
348+
val DoWhile: DoWhileExtractor
349+
abstract class DoWhileExtractor {
350+
/** Extractor for do while loops. Matches `do <body> while (<cond>)` and returns (<body>, <cond>) */
351+
def unapply(x: Term)(implicit ctx: Context): Option[(Term, Term)]
352+
}
342353
}
343354

344355
// ----- CaseDef --------------------------------------------------

library/src/scala/tasty/util/ShowSourceCode.scala

Lines changed: 8 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -204,33 +204,15 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
204204
this
205205
}
206206

207-
case While(cond, stats) =>
207+
case Term.While(cond, body) =>
208208
this += "while ("
209209
printTree(cond)
210210
this += ") "
211-
stats match {
212-
case stat :: Nil =>
213-
printTree(stat)
214-
case stats =>
215-
this += "{"
216-
indented {
217-
printStats(stats.init, stats.last)
218-
}
219-
this += lineBreak() += "}"
220-
}
211+
printTree(body)
221212

222-
case DoWhile(stats, cond) =>
213+
case Term.DoWhile(body, cond) =>
223214
this += "do "
224-
stats match {
225-
case stat :: Nil =>
226-
printTree(stat)
227-
case stats =>
228-
this += "{"
229-
indented {
230-
printStats(stats.init, stats.last)
231-
}
232-
this += lineBreak() += "}"
233-
}
215+
printTree(body)
234216
this += " while ("
235217
printTree(cond)
236218
this += ")"
@@ -361,14 +343,11 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
361343
printTree(rhs)
362344

363345
case Term.Block(stats0, expr) =>
364-
def shouldNotBePrinted(tree: Tree): Boolean = tree match {
365-
case Term.Apply(Term.Ident("while$" | "doWhile$"), _) => true
366-
case tree @ ValDef(_, _, _) => tree.flags.isObject
367-
case _ => false
346+
val stats = stats0.filter {
347+
case tree @ ValDef(_, _, _) => !tree.flags.isObject
348+
case _ => true
368349
}
369350

370-
val stats = stats0.filterNot(shouldNotBePrinted)
371-
372351
expr match {
373352
case Term.Lambda(_, _) =>
374353
// Decompile lambda from { def annon$(...) = ...; closure(annon$, ...)}
@@ -380,11 +359,8 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
380359
this += ")"
381360
case _ =>
382361
this += "{"
383-
val (stats1, expr1) =
384-
if (shouldNotBePrinted(expr)) (stats.init, stats.last)
385-
else (stats, expr)
386362
indented {
387-
printStats(stats1, expr1)
363+
printStats(stats, expr)
388364
}
389365
this += lineBreak() += "}"
390366
}
@@ -452,7 +428,6 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
452428
def printSeparator(next: Tree): Unit = {
453429
// Avoid accidental application of opening `{` on next line with a double break
454430
next match {
455-
case Term.Block(DefDef("while$" | "doWhile$", _, _, _, _) :: Nil, _) => this += lineBreak()
456431
case Term.Block(_, _) => this += doubleLineBreak()
457432
case Term.Inlined(_, _, _) => this += doubleLineBreak()
458433
case Term.Select(qual, _, _) => printSeparator(qual)
@@ -1092,7 +1067,6 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
10921067
private def escapedString(str: String): String = str flatMap escapedChar
10931068
}
10941069

1095-
10961070
private object SpecialOp {
10971071
def unapply(arg: Term)(implicit ctx: Context): Option[(String, List[Term])] = arg match {
10981072
case arg@Term.Apply(fn, args) =>
@@ -1105,22 +1079,6 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
11051079
}
11061080
}
11071081

1108-
private object While {
1109-
def unapply(arg: Tree)(implicit ctx: Context): Option[(Term, List[Statement])] = arg match {
1110-
case DefDef("while$", _, _, _, Some(Term.If(cond, Term.Block(bodyStats, _), _))) => Some((cond, bodyStats))
1111-
case Term.Block(List(tree), _) => unapply(tree)
1112-
case _ => None
1113-
}
1114-
}
1115-
1116-
private object DoWhile {
1117-
def unapply(arg: Tree)(implicit ctx: Context): Option[(List[Statement], Term)] = arg match {
1118-
case DefDef("doWhile$", _, _, _, Some(Term.Block(body, Term.If(cond, _, _)))) => Some((body, cond))
1119-
case Term.Block(List(tree), _) => unapply(tree)
1120-
case _ => None
1121-
}
1122-
}
1123-
11241082
private object Annotation {
11251083
def unapply(arg: Tree)(implicit ctx: Context): Option[(TypeTree, List[Term])] = arg match {
11261084
case Term.New(annot) => Some((annot, Nil))

tests/pos/tasty/definitions.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ object definitions {
8585
case Return(expr: Term)
8686
case Repeated(args: List[Term])
8787
case SelectOuter(from: Term, levels: Int, target: Type) // can be generated by inlining
88+
case While(cond: Term, body: Term)
89+
case DoWhile(body: Term, cond: Term)
8890
}
8991

9092
/** Trees denoting types */

0 commit comments

Comments
 (0)