Readren
Readren

Reputation: 1270

How to ge the `Expr` of a regular class's field declared in its primary constructor with scala 3.5.1 macros?

This is probably a very easy question to answer. And maybe also easy to find the answer. However, I couldn't find it after several hours. The documentation for the Scala API scala.quoted.Quotes.reflectModule is not very helpful.

I need to know how on earth to get the value of a field declared in the primary constructor of a regular class (not a case class) using metaprogramming with Scala 3.5.1.

Specifically, I need to implement the select function below. Preferably with splices and quotes.

I've included the toStrImpl method below as a usage example just to provide context and purpose for the matter. It generates the toString implementation of regular clases.



    /** Given the expression `productExpr` that gets an instance of
     * a regular class `A`, and the symbol of a parameter of `A`'s
     * primary-constructor, obtain the expression that gets the value
     * of said parameter. */
    def select[A: Type](using quotes: Quotes)(productExpr: Expr[A], elemSymbol: quotes.reflect.Symbol): Expr[Any] =
        ??? // TODO implement

    def toStrImpl[A: Type](product: Expr[A])(using quotes: Quotes): Expr[String] = {
        import quotes.reflect.*

        val productSymbol = TypeRepr.of[T].typeSymbol
        val primaryConstructor = productSymbol.primaryConstructor
        val productTerm = productExpr.asTerm
        var stringBuilderExpr = '{ new StringBuilder(${ Expr[String](productSymbol.name) }) }

        for {
            paramsList <- primaryConstructor.paramSymss
            if paramsList.forall(_.isTerm) // skips type parameters
        } do {
            stringBuilderExpr = '{ $stringBuilderExpr.append('(') }
            var isFirst = true
            for param <- paramsList do {
                if isFirst then isFirst = false else stringBuilderExpr = '{ $stringBuilderExpr.append(", ") }
                val argValueExpr: Expr[Any] = select(product, param)
                
                stringBuilderExpr = '{ $stringBuilderExpr.append(${ Expr(paramName) }).append('=').append($argValueExpr.toString) }
            }
            stringBuilderExpr = '{ $stringBuilderExpr.append(')') }
        }
        '{ $stringBuilderExpr.toString }
    }

Upvotes: 0

Views: 41

Answers (1)

Readren
Readren

Reputation: 1270

This is a response but does not use slices and quotes:

def select[A: Type](using quotes: Quotes)(productExpr: Expr[A], elemSymbol: quotes.reflect.Symbol): Expr[Any] =
    Select.unique(productExpr.asTerm, elemSymbol.name).asExpr

Upvotes: 0

Related Questions