def mregex(c: Context)(t: c.Expr[String]): c.Expr[Regex] = try {
// test regex
t.eval.r
c.reify(t.eval.r)
} catch {
case e: java.util.regex.PatternSyntaxException =>
c.error(c.enclosingPosition, e.getMessage())
throw e
}
--
Johannes
-----------------------------------------------
Johannes Rudolph
http://virtual-void.net
>
> My question is how to use variable in macro implementation?
I think you are confusing stages here: The reg variable contains here
the value of evaluating the expression at macro expansion time. What
you are then trying to do when using `reify` is to transfer this value
to runtime which isn't possible per se. In the example which works you
are doing something else: You are generating code which at runtime
generates the regular expression.
An additional note: The important thing you have to always remember
when dealing with macros is that you are really mainly operating on
expression trees, not on runtime values. So, if you splice (using
`.eval` inside of `reify`) you have to splice in trees not values.
Incidentally: I think the surprising thing here is that evaluating
expression trees (using `.eval` outside of `reify`) at macro expansion
time works for some expressions. Eugene, is there some effort to
improve error messages in cases this fails? For example, calling the
example macro from this thread with `MacroRegex.build("abc"*3)`
results in a
[error] /home/johannes/git/self/scala-days/src/test/scala/MacroTest.scala:2:
exception during macro expansion:
[error] scala.tools.nsc.ToolBoxes$ToolBox$ToolBoxError: reflective
toolbox has failed: cannot operate on trees that are already typed
[error] at scala.tools.nsc.ToolBoxes$ToolBox.runExpr(ToolBoxes.scala:50)
[error] at scala.reflect.api.Exprs$Expr.eval(Exprs.scala:15)
at compilation of user code which may be confusing. Probably it's the
responsibility of the macro to catch those problems, are there any
helpers to do that effectively?
So, I don't have a recent Scala here to try, but wouldn't this work?
val regExpr = reify(text.eval.r)
try regExpr.eval catch { ... }
regExpr
> catch {
> case e: java.util.regex.PatternSyntaxException =>
> c.error(c.enclosingPosition, e.getMessage())
> }
> c.reify(reg)
> }
> }
>
> The aim is to get regexp syntax error at compile time.
> But i get this cryptic error:
> " error: macro expansion contains free term variable reg defined by
> buildImp in regex.scala:10:9. have you forgot to use eval when
> splicing this variable into a reifee? if you have troubles tracking
> free term variables, consider using -Xlog-free-terms "
>
> I remove the reg variable and get a correct code.
>
> object MacroRegex {
> def build(text: String): Regex = macro buildImp
> def buildImp(c: Context)(text: c.Expr[String]): c.Expr[Regex] = {
> try { text.eval.r }
> catch {
> case e: java.util.regex.PatternSyntaxException =>
> c.error(c.enclosingPosition, e.getMessage())
> }
> c.reify(text.eval.r)
> }
> }
>
>
> My question is how to use variable in macro implementation?
> (i use scala 2.10-snapshot)
>
> Thanks you.
--
Daniel C. Sobral
I travel to the future all the time.
This is the same as just `e`. Apart from that you can include
deserialization into the macro as well:
object RegMacro {
def go(regex: String): Regex = macro goImpl
def goImpl(c: Context)(regex: c.Expr[String]): c.Expr[Regex] = {
val r = new Reg(regex.eval, List().toSeq)
val a = r.write
import c.mirror._
val e = Expr[Array[Byte]](ArrayValue(TypeTree(ByteTpe),
a.toList.map(e => Literal(Constant(e)))))
c.reify(Reg.read(e.eval))