All Downloads are FREE. Search and download functionalities are using the official Maven repository.

kyo.debug.Debug.scala Maven / Gradle / Ivy

The newest version!
package kyo.debug

import kyo.*
import kyo.Ansi.*
import kyo.kernel.Effect
import kyo.kernel.Safepoint
import scala.collection.mutable.LinkedHashMap
import scala.language.implicitConversions
import scala.quoted.*

object Debug:

    private inline def maxValueLength = 500

    /** Applies debugging to the given effect, printing the frame and value.
      *
      * @param v
      *   The effect to debug
      * @param frame
      *   The implicit Frame
      * @return
      *   The original effect with debugging applied
      */
    def apply[A, S](v: => A < S)(using frame: Frame): A < S =
        Effect.catching {
            v.map { value =>
                println(frame.render)
                printValue(value)
                value
            }
        } { ex =>
            println(frame.render)
            printValue(ex)
            throw ex
        }
    end apply

    /** Traces the execution of the given effect, printing intermediate values and frames.
      *
      * @param v
      *   The effect to trace
      * @param Frame
      *   The implicit Frame
      * @return
      *   The original effect with tracing applied
      */
    def trace[A, S](v: => A < S)(using Frame): A < S =
        val interceptor = new Safepoint.Interceptor:
            def enter(frame: Frame, value: Any): Boolean =
                printValue(value)
                println(frame.render)
                true
            end enter
            def addFinalizer(f: () => Unit): Unit    = ()
            def removeFinalizer(f: () => Unit): Unit = ()

        Safepoint.propagating(interceptor) {
            Effect.catching {
                v.map { value =>
                    printValue(value)
                    value
                }
            } { ex =>
                printValue(ex)
                throw ex
            }
        }
    end trace

    /** Prints the values of the given parameters along with their code representations.
      *
      * @param params
      *   The parameters to print
      * @param frame
      *   The implicit Frame
      */
    def values(params: Param[?]*)(using frame: Frame): Unit =
        val tuples = LinkedHashMap(params.map(p => (p.code, p.value))*)
        val string = pprint(tuples).render.replaceFirst("LinkedHashMap", "Params")
        println(frame.render)
        println(string)
    end values

    final case class Param[T](code: String, value: T) derives CanEqual

    object Param:

        /** Derives a Param instance from a given value.
          *
          * @param v
          *   The value to derive the Param from
          * @return
          *   A Param instance containing the code representation and value
          */
        implicit inline def derive[T](v: => T): Param[T] =
            ${ paramImpl('v) }

        private def paramImpl[T: Type](v: Expr[T])(using Quotes): Expr[Param[T]] =
            import quotes.reflect.*
            val code = Expr(v.asTerm.pos.sourceCode.get)
            '{ Param($code, $v) }
        end paramImpl

    end Param

    private def printValue(value: Any) =
        println("───────────────────────────────────".dim)
        val rendered = pprint(value).render
        val truncated =
            if rendered.length > maxValueLength then
                rendered.take(maxValueLength) + " ... (truncated)"
            else
                rendered
        println(truncated)
        println("───────────────────────────────────".dim)
    end printValue
end Debug




© 2015 - 2025 Weber Informatics LLC | Privacy Policy