0

Can you please explain why the two usages of Scala quasiquote below give different output between result1 and result2? Is it possible to reproduce result3 using quasiquote? i.e parse a string content and evaluate it?

import scala.tools.reflect.ToolBox
import scala.reflect.runtime.universe._

val miniSrc = "val lst = (1 to 5).toList ; val sum = lst.foldLeft(0)(_ + _); sum"

val tree1 = q"$miniSrc"
//tree1: reflect.runtime.universe.Tree = "val lst = (1 to 5).toList ; val sum = lst.foldLeft(0)(_ + _); sum"

val tree2 = q"val lst = (1 to 5).toList ; val sum = lst.foldLeft(0)(_ + _); sum"
//tree2: reflect.runtime.universe.Tree =
//{
//  val lst = 1.to(5).toList;
//  val sum = lst.foldLeft(0)(((x$1, x$2) => x$1.$plus(x$2)));
//  sum
//}

val tb = scala.reflect.runtime.currentMirror.mkToolBox()
val result1 = tb.eval(tree1)
//result1: Any = val lst = (1 to 5).toList ; val sum = lst.foldLeft(0)(_ + _); sum

val result2 = tb.eval(tree2)
//result2: Any = 15

val result3 = tb.eval(tb.parse(miniSrc))
//result3: Any = 15
Polymerase
  • 6,311
  • 11
  • 47
  • 65

1 Answers1

3

Can you please explain why the two usages of Scala quasiquote below give different output between result1 and result2?

miniSrc is a literal String and not a Tree. q"{$miniSrc}" lifts miniSrc, a literal String into another Tree. Lifting does not parse arbitrary code into a Tree, it simply splices together trees or other types into trees. tree1 is therefore a Tree that contains a literal String.

This example ought to illustrate well enough why lifting a literal string into a tree shouldn't involve any parsing:

scala> val miniSrc = "abc"
miniSrc: String = abc

scala> val tree1 = q"$miniSrc"
tree1: reflect.runtime.universe.Tree = "abc"

tree2 is inherently different because you are creating the Tree directly with the quasiquotes interpolator. Therefore, result1 is just a literal string, but result2 is the result of some executed code within tree2.

Is it possible to reproduce result3 using quasiquotes? i.e parse a string content and evaluate it?

No, that's what parsing is for. If you want to lift arbitrary code as a string literal into quasiquotes, you must parse it into a Tree first. Otherwise, it will just be a literal.

scala> val tree1 = q"${tb.parse(miniSrc)}"
tree1: tb.u.Tree =
{
  val lst = 1.to(5).toList;
  val sum = lst.foldLeft(0)(((x$1, x$2) => x$1.$plus(x$2)));
  sum
}

Not that when working with macros, you can parse using the macro's Context. That is, c.parse (instead of using ToolBox).

Michael Zajac
  • 55,144
  • 7
  • 113
  • 138