Skip to content

Commit

Permalink
poc
Browse files Browse the repository at this point in the history
  • Loading branch information
arainko committed Dec 20, 2023
1 parent d83d10e commit 51f02e3
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ object Field {
@compileTimeOnly("Field.default is only useable as a field configuration for transformations")
def default[A, B, FieldType](selector: Selector ?=> B => FieldType): Field[A, B] = ???

def useNones[A, B, FieldType](selector: Selector ?=> B => FieldType): Field[A, B] = ???

@compileTimeOnly("Field.allMatching is only useable as a field configuration for transformations")
def allMatching[A, B, DestFieldTpe, ProductTpe](selector: Selector ?=> B => DestFieldTpe, product: ProductTpe): Field[A, B] =
???
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.github.arainko.ducktape

final case class SourceToplevel(level1: SourceLevel1)
final case class SourceLevel1(str: String)

final case class DestToplevel(extra: Option[Int], level1: DestLevel1)
final case class DestLevel1(extra: Option[Int], str: String)

object Playground extends App {
val source = SourceToplevel(SourceLevel1("str"))

val dest =
source
.into[DestToplevel]
.transform(
Field.const(_.extra, Some(1)),
Field.useNones(a => a.level1)
)

println(dest)
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,22 @@ private[ducktape] enum Configuration derives Debug {

private[ducktape] object Configuration {

trait Modifier {
def apply(plan: Plan.Error)(using Quotes): Configuration | plan.type
}

object Modifier {
given Debug[Modifier] = new:
extension (self: Modifier) def show(using Quotes): String = "Modifier(...)"
}

enum At derives Debug {
def path: Path
def target: Target
def span: Span

case Successful(path: Path, target: Target, config: Configuration, span: Span)
case Regional(path: Path, target: Target, modifier: Modifier, span: Span)
case Failed(path: Path, target: Target, message: String, span: Span)
}

Expand Down Expand Up @@ -120,6 +130,18 @@ private[ducktape] object Configuration {
Span.fromPosition(cfg.pos)
) :: Nil

case cfg @ Apply(
TypeApply(Select(IdentOfType('[Field.type]), "useNones"), a :: b :: destFieldTpe :: Nil),
PathSelector(path) :: Nil
) =>
val modifier: Modifier = new:
def apply(plan: Plan.Error)(using Quotes): Configuration | plan.type =
plan.destTpe match {
case tpe @ '[Option[a]] => Configuration.Const('{ None }, tpe)
case _ => plan
}
Configuration.At.Regional(path, Target.Dest, modifier, Span.fromPosition(cfg.pos)) :: Nil

case DeprecatedConfig(configs) => configs

case oopsie =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import scala.quoted.*
private[ducktape] object Logger {

// Logger Config
private[ducktape] transparent inline given level: Level = Level.Off
private[ducktape] transparent inline given level: Level = Level.Info
private val output = Output.StdOut
private def filter(msg: String, meta: Metainformation) = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import io.github.arainko.ducktape.internal.*
import scala.collection.immutable.ListMap
import scala.quoted.*

private[ducktape] type PlanError = Plan.Error

private[ducktape] enum Plan[+E <: PlanError] {
private[ducktape] sealed trait Plan[+E <: Plan.Error] {
import Plan.*

def sourceTpe: Type[?]
Expand All @@ -22,39 +20,41 @@ private[ducktape] enum Plan[+E <: PlanError] {
final def configureAll(configs: List[Configuration.At])(using Quotes): Plan.Reconfigured = PlanConfigurer.run(this, configs)

final def refine: Either[NonEmptyList[Plan.Error], Plan[Nothing]] = PlanRefiner.run(this)
}

case Upcast(
private[ducktape] object Plan {
case class Upcast(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path
) extends Plan[Nothing]

case UserDefined(
case class UserDefined(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
transformer: Expr[Transformer[?, ?]]
) extends Plan[Nothing]

case Derived(
case class Derived(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
transformer: Expr[Transformer.Derived[?, ?]]
) extends Plan[Nothing]

case Configured(
case class Configured(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
config: Configuration
) extends Plan[Nothing]

case BetweenProductFunction(
case class BetweenProductFunction[+E <: Plan.Error](
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
Expand All @@ -63,62 +63,62 @@ private[ducktape] enum Plan[+E <: PlanError] {
function: Function
) extends Plan[E]

case BetweenUnwrappedWrapped(
case class BetweenUnwrappedWrapped(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path
) extends Plan[Nothing]

case BetweenWrappedUnwrapped(
case class BetweenWrappedUnwrapped(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
fieldName: String
) extends Plan[Nothing]

case BetweenSingletons(
case class BetweenSingletons(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
expr: Expr[Any]
) extends Plan[Nothing]

case BetweenProducts(
case class BetweenProducts[+E <: Plan.Error](
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
fieldPlans: Map[String, Plan[E]]
) extends Plan[E]

case BetweenCoproducts(
case class BetweenCoproducts[+E <: Plan.Error](
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
casePlans: Vector[Plan[E]]
) extends Plan[E]

case BetweenOptions(
case class BetweenOptions[+E <: Plan.Error](
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
plan: Plan[E]
) extends Plan[E]

case BetweenNonOptionOption(
case class BetweenNonOptionOption[+E <: Plan.Error](
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
plan: Plan[E]
) extends Plan[E]

case BetweenCollections(
case class BetweenCollections[+E <: Plan.Error](
destCollectionTpe: Type[? <: Iterable[?]],
sourceTpe: Type[?],
destTpe: Type[?],
Expand All @@ -127,17 +127,14 @@ private[ducktape] enum Plan[+E <: PlanError] {
plan: Plan[E]
) extends Plan[E]

case Error(
case class Error(
sourceTpe: Type[?],
destTpe: Type[?],
sourceContext: Path,
destContext: Path,
message: ErrorMessage,
suppressed: Option[Plan.Error]
) extends Plan[Plan.Error]
}

private[ducktape] object Plan {

object Error {
def from(plan: Plan[Plan.Error], message: ErrorMessage, suppressed: Option[Plan.Error]): Plan.Error =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ private[ducktape] object PlanConfigurer {
)
.tap(errors.addOne)

case cfg @ Configuration.At.Regional(path, target, modifier, span) =>
regional(current, modifier)

case cfg @ Configuration.At.Failed(path, target, message, span) =>
Plan.Error.from(current, ErrorMessage.ConfigurationFailed(cfg), None).tap(errors.addOne)
}
Expand All @@ -125,4 +128,51 @@ private[ducktape] object PlanConfigurer {
case other =>
Plan.Error.from(plan, ErrorMessage.InvalidPathSegment(segment, config.target, config.span), None)
}

def regional(
plan: Plan[Plan.Error],
modifier: Configuration.Modifier
)(using Quotes): Plan[Plan.Error] =
plan match {
case plan: Upcast => plan

case plan: UserDefined => plan

case plan: Derived => plan

case plan: Configured => plan

case plan: BetweenProductFunction[Plan.Error] =>
plan.copy(argPlans = plan.argPlans.transform((_, plan) => regional(plan, modifier)))

case plan: BetweenUnwrappedWrapped => plan

case plan: BetweenWrappedUnwrapped => plan

case plan: BetweenSingletons => plan

case plan: BetweenProducts[Plan.Error] =>
plan.copy(fieldPlans = plan.fieldPlans.transform((_, plan) => regional(plan, modifier)))

case plan: BetweenCoproducts[Plan.Error] =>
plan.copy(casePlans = plan.casePlans.map(regional(_, modifier)))

case plan: BetweenOptions[Plan.Error] =>
plan.copy(plan = regional(plan.plan, modifier))

case plan: BetweenNonOptionOption[Plan.Error] =>
plan.copy(plan = regional(plan.plan, modifier))

case plan: BetweenCollections[Plan.Error] =>
plan.copy(plan = regional(plan.plan, modifier))

case plan: Error =>
modifier(plan) match {
case config: Configuration =>
Plan.Configured(plan.sourceTpe, plan.destTpe, plan.sourceContext, plan.destContext, config)
case other: plan.type =>
other
}
}

}
4 changes: 0 additions & 4 deletions tooling/src/main/scala/io/github/arainko/tooling/Debug.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,6 @@ private[ducktape] object Debug {
s"Deferred(...)"
}

given function: Debug[Nothing => Any] with {
extension (self: Nothing => Any) def show(using Quotes): String = s"Function(...)"
}

given expr[A]: Debug[Expr[A]] with {
extension (value: Expr[A]) def show(using Quotes): String = {
import quotes.reflect.*
Expand Down

0 comments on commit 51f02e3

Please sign in to comment.