You need to:
- resolve the implicit and place the found value in
Expr
- you can expand a macro inside an inline def
(just like vampyre macros from Scala 2), but NOT when you are constructing expressions with '{}
, then you have to have all implicits resolved
- return
Expr[Either[Throwable, T]]
- when creating a body of a Scala 3 macro, the whole returned value has to be an Expr
, otherwise you cannot unquote it within ${}
(it might work as a value returned from an helper which would turn it into Expr
, but ${}
accepts only single call to something defined in top level scope)
- separate the body of
Expr => Expr
macro definition from its expansion - you cannot write "just" inline def something[T: Type](a: Expr[T])(using Quotes): Expr[T] = ...
- body of a macro is a (non-inline) def
taking Type
s and Expr
s and Quotes
and returning a single Expr
. inline def
has to unquote a single Expr
with ${}
... or just be a normal def which would be copy-pasted into the call site and resolved there. But then it unquotes no Expr
s
So it's either:
// Quotes API requires separate inline def sth = ${ sthImpl }
// and def sthImpl[T: Type](a: Expr[...])(using Quotes): Expr[...]
inline def parseJson[T](x: String)(using r: Reader[T]): Either[Throwable, T] =
${ parseJsonImpl[T]('x)('r) }
// Since it builds a complete TASTy, it cannot "defer" implicit
// resolution to callsite. It either already gets value to put
// into using, or has to import quotes.*, quotes.reflect.* and
// then use Expr.summon[T].getOrElse(...)
def parseJsonImpl[T:Type](
x: Expr[String]
)(
reader: Expr[Reader[T]]
)(using Quotes): Expr[Either[String, T]] = '{
try
Right(read[T]($x)(using $reader))
catch
case e: Throwable => Left(s"Deserialization error: ${e.getMessage}")
}
or
// inline def NOT using quotation API - NO Quotes, NO '{}
inline def parseJson[T: Reader](x: String): Either[String, T] = {
try
// Here, you can use something like a "vampyre macros" and
// let the compiler expand macros at the call site
Right(read[T](x))
catch
case e: Throwable => Left(s"Deserialization error: ${e.getMessage}")
}