Skip to content

Commit

Permalink
First draft of the @tostring annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
hamzaremmal committed Oct 15, 2024
1 parent aa719af commit 994c995
Showing 1 changed file with 41 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/main/scala/steps/annotation/toString.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package steps.annotation

import scala.annotation.{experimental, MacroAnnotation}
import scala.quoted.*

@experimental
final class toString extends MacroAnnotation:
override def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] =
import quotes.reflect.*
val toStringSym = Symbol.requiredMethod("java.lang.Object.toString")
tree match
case _: ClassDef if toStringSym.overridingSymbol(tree.symbol).exists =>
report.warning(s"@toString is not necessary since hashcode is defined in ${tree.symbol}")
List(tree)
case ClassDef(className, ctr, parents, self, body) =>
val cls = tree.symbol

val fields = body.collect {
case vdef: ValDef if vdef.symbol.flags.is(Flags.ParamAccessor) =>
Select(This(cls), vdef.symbol).asExpr
}

val toStringOverrideSym = Symbol.newMethod(cls, "toString", toStringSym.info, Flags.Override, Symbol.noSymbol)

def toStringOverrideDefBody(argss: List[List[Tree]]): Option[Term] =
given Quotes = toStringOverrideSym.asQuotes
Some(toStringExpr(className, fields).asTerm)

val toStringDef = DefDef(toStringOverrideSym, toStringOverrideDefBody)
List(ClassDef.copy(tree)(className, ctr, parents, self, toStringDef :: body))
case _ =>
report.errorAndAbort("@toString is only supported in class/object/trait")
end transform

private def toStringExpr(className: String, thisFields: List[Expr[Any]])(using Quotes): Expr[String] =
val fieldsSeq = Expr.ofSeq(thisFields)
val prefix = Expr(className + "(")
'{ $fieldsSeq.mkString($prefix, ", ", ")") }
end toStringExpr

end toString

0 comments on commit 994c995

Please sign in to comment.