Hi, I am trying to identify a while(true){block_of_code} in a sythax tree using a quasiquote.
Using the quasiquote q"while ($expr) $expr"
from the quasiquote patterns page recognises other while loops but not while(true) loops.
How can I do this with a quasiquote?
The same quasiquote q"while (true) $expr"
should work
def test(t: Tree) = t match {
case q"while (true) $expr" => println(s"expr=$expr")
case _ => println("default")
}
test(q"while (true) i=1") //expr=i = 1
test(q"while (false) i=1") //default
test(q"while (x == x) i=1") //default
1 Like
Hmm, that doesn’t seem to work from within a compiler plugin while analysing source code line by line. Admittedly I am parsing each line as a Trees#Tree rather than just a Tree but the matching of other while statements works fine.
The quasiquote q"while ($expr) $expr"
picks up only while loops without true/false as the condition by the way, rather than picking up all of them.
A while
loop is represented as a LabelDef
and an If
block. I think there’s a compiler phase that transforms if (true) x else y
expressions to x
. If your plugin runs after that phase I guess it doesn’t recognize that LabelDef
as a while loop anymore cause the If
block is gone.
If that’s the case you could match on LabelDef(_, _, rhs)
and check that rhs
is not an If
tree. I haven’t tested any of this though.
3 Likes
Here’s what I do in my scala-fortify plugin. It’s a late-phase compiler plugin, so as Jasper indicates, it must handle already-transformed trees. As a result, I don’t use quasiquote-based matching at all.
My plugin is closed-source, but here’s the relevant snippet of code:
// while(true) / do while(true)
case LabelDef(
TermName(name),
List(),
block @ Block(statements, Apply(Ident(TermName(name2)), List())))
if (name.startsWith("while$") || name.startsWith("doWhile$")) && name2 == name =>
You might look at Scala.js, which is also a late-phase plugin but is open-source. I bet it has a similar match in it. (It’s even possible I cribbed my version from Scala.js…)
2 Likes