8000 keep paths inside structures instead of plans by arainko · Pull Request #110 · arainko/ducktape · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ private[ducktape] object Configuration {
val substituteWithDefaults = new ErrorModifier:
def apply(parent: Plan[Plan.Error] | None.type, plan: Plan.Error)(using Quotes): Configuration | plan.type =
PartialFunction
.condOpt(parent -> plan.destContext.segments.lastOption) {
case (Plan.BetweenProducts(_, dest, _, _, _), Some(Path.Segment.Field(_, fieldName))) =>
.condOpt(parent -> plan.destPath.segments.lastOption) {
case (Plan.BetweenProducts(_, dest, _), Some(Path.Segment.Field(_, fieldName))) =>
import quotes.reflect.*

dest.defaults
Expand Down Expand Up @@ -228,7 +228,7 @@ private[ducktape] object Configuration {
) = {

Structure
.fromTypeRepr(fieldSourceTpe)
.fromTypeRepr(fieldSourceTpe, Path.empty(fieldSourceTpe.asType))
.narrow[Structure.Product]
.map { sourceStruct =>
val modifier = new FieldModifier:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ private[ducktape] sealed trait Plan[+E <: Plan.Error] {

def dest: Structure

def sourceContext: Path
final def sourcePath: Path = source.path

def destContext: Path
final def destPath: Path = dest.path

final def narrow[A <: Plan[Plan.Error]](using tt: TypeTest[Plan[Plan.Error], A]): Option[A] = tt.unapply(this)

Expand All @@ -29,111 +29,82 @@ private[ducktape] sealed trait Plan[+E <: Plan.Error] {
private[ducktape] object Plan {
case class Upcast(
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path
dest: Structure
) extends Plan[Nothing]

case class UserDefined(
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
transformer: Expr[Transformer[?, ?]]
) extends Plan[Nothing]

case class Derived(
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
transformer: Expr[Transformer.Derived[?, ?]]
) extends Plan[Nothing]

case class Configured(
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
config: Configuration
) extends Plan[Nothing]

case class BetweenProductFunction[+E <: Plan.Error](
source: Structure.Product,
dest: Structure.Function,
sourceContext: Path,
destContext: Path,
argPlans: ListMap[String, Plan[E]]
) extends Plan[E]

case class BetweenUnwrappedWrapped(
source: Structure,
dest: Structure.ValueClass,
sourceContext: Path,
destContext: Path
dest: Structure.ValueClass
) extends Plan[Nothing]

case class BetweenWrappedUnwrapped(
source: Structure.ValueClass,
dest: Structure,
sourceContext: Path,
destContext: Path,
fieldName: String
) extends Plan[Nothing]

case class BetweenSingletons(
source: Structure.Singleton,
dest: Structure.Singleton,
sourceContext: Path,
destContext: Path
dest: Structure.Singleton
) extends Plan[Nothing]

case class BetweenProducts[+E <: Plan.Error](
source: Structure.Product,
dest: Structure.Product,
sourceContext: Path,
destContext: Path,
fieldPlans: Map[String, Plan[E]]
) extends Plan[E]

case class BetweenCoproducts[+E <: Plan.Error](
source: Structure.Coproduct,
dest: Structure.Coproduct,
sourceContext: Path,
destContext: Path,
casePlans: Vector[Plan[E]]
) extends Plan[E]

case class BetweenOptions[+E <: Plan.Error](
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
source: Structure.Optional,
dest: Structure.Optional,
plan: Plan[E]
) extends Plan[E]

case class BetweenNonOptionOption[+E <: Plan.Error](
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
dest: Structure.Optional,
plan: Plan[E]
) extends Plan[E]

case class BetweenCollections[+E <: Plan.Error](
destCollectionTpe: Type[? <: Iterable[?]],
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
source: Structure.Collection,
dest: Structure.Collection,
plan: Plan[E]
) extends Plan[E]

case class Error(
source: Structure,
dest: Structure,
sourceContext: Path,
destContext: Path,
message: ErrorMessage,
suppressed: Option[Plan.Error]
) extends Plan[Plan.Error]
Expand All @@ -143,8 +114,6 @@ private[ducktape] object Plan {
Plan.Error(
plan.source,
plan.dest,
plan.sourceContext,
plan.destContext,
message,
suppressed
)
Expand All @@ -155,8 +124,6 @@ private[ducktape] object Plan {
Plan.Configured(
plan.source,
plan.dest,
plan.sourceContext,
plan.destContext,
conf
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ private[ducktape] object PlanConfigurer {
segments match {
case (segment @ Path.Segment.Field(_, fieldName)) :: tail =>
current match {
case plan @ BetweenProducts(sourceTpe, destTpe, sourceContext, destContext, fieldPlans) =>
case plan @ BetweenProducts(sourceTpe, destTpe, fieldPlans) =>
val fieldPlan =
fieldPlans
.get(fieldName)
Expand All @@ -31,7 +31,7 @@ private[ducktape] object PlanConfigurer {

plan.copy(fieldPlans = fieldPlans.updated(fieldName, fieldPlan))

case plan @ BetweenProductFunction(sourceTpe, destTpe, sourceContext, destContext, argPlans) =>
case plan @ BetweenProductFunction(sourceTpe, destTpe, argPlans) =>
val argPlan =
argPlans
.get(fieldName)
Expand All @@ -49,7 +49,7 @@ private[ducktape] object PlanConfigurer {
case plan: BetweenNonOptionOption[Plan.Error] if config.side.isSource =>
plan.copy(plan = recurse(plan.plan, segments, plan))

case plan @ BetweenCoproducts(sourceTpe, destTpe, sourceContext, destContext, casePlans) =>
case plan @ BetweenCoproducts(sourceTpe, destTpe, casePlans) =>
def sideTpe(plan: Plan[Plan.Error]) = if (config.side.isSource) plan.source.tpe.repr else plan.dest.tpe.repr

casePlans.zipWithIndex
Expand All @@ -62,13 +62,13 @@ private[ducktape] object PlanConfigurer {

case (segment @ Path.Segment.Element(tpe)) :: tail =>
current match {
case p @ BetweenCollections(_, _, _, _, _, plan) =>
case p @ BetweenCollections(_, _, plan) =>
p.copy(plan = recurse(plan, tail, p))

case p @ BetweenOptions(_, _, _, _, plan) =>
case p @ BetweenOptions(_, _, plan) =>
p.copy(plan = recurse(plan, tail, p))

case p @ BetweenNonOptionOption(_, _, _, _, plan) =>
case p @ BetweenNonOptionOption(_, _, plan) =>
p.copy(plan = recurse(plan, tail, p))

case other => invalidPathSegment(config, other, segment)
Expand Down Expand Up @@ -242,12 +242,12 @@ private[ducktape] object PlanConfigurer {
config: Configuration
)(using quotes: Quotes, errors: Accumulator[Plan.Error], successes: Accumulator[(Path, Side)]) = {
def isReplaceableBy(update: Configuration)(using Quotes) =
update.tpe.repr <:< currentPlan.destContext.currentTpe.repr
update.tpe.repr <:< currentPlan.destPath.currentTpe.repr

if isReplaceableBy(config) then
Accumulator.append {
if instruction.side == Side.Dest then currentPlan.destContext -> instruction.side
else currentPlan.sourceContext -> instruction.side
if instruction.side == Side.Dest then currentPlan.destPath -> instruction.side
else currentPlan.sourcePath -> instruction.side
}
Plan.Configured.from(currentPlan, config)
else
Expand All @@ -256,7 +256,7 @@ private[ducktape] object PlanConfigurer {
currentPlan,
ErrorMessage.InvalidConfiguration(
config.tpe,
currentPlan.destContext.currentTpe,
currentPlan.destPath.currentTpe,
instruction.side,
instruction.span
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ private[ducktape] object PlanInterpreter {
import quotes.reflect.*

plan match {
case Plan.Upcast(_, _, _, _) => value
case Plan.Upcast(_, _) => value

case Plan.Configured(_, _, _, _, config) =>
case Plan.Configured(_, _, config) =>
config match {
case Configuration.Const(value, _) =>
value
Expand All @@ -29,7 +29,7 @@ private[ducktape] object PlanInterpreter {
source.accessFieldByName(name).asExpr
}

case Plan.BetweenProducts(sourceTpe, destTpe, _, _, fieldPlans) =>
case Plan.BetweenProducts(sourceTpe, destTpe, fieldPlans) =>
val args = fieldPlans.map {
case (fieldName, p: Plan.Configured) =>
NamedArg(fieldName, recurse(p, value).asTerm)
Expand All @@ -39,7 +39,7 @@ private[ducktape] object PlanInterpreter {
}
Constructor(destTpe.tpe.repr).appliedToArgs(args.toList).asExpr

case Plan.BetweenCoproducts(sourceTpe, destTpe, _, _, casePlans) =>
case Plan.BetweenCoproducts(sourceTpe, destTpe, casePlans) =>
val branches = casePlans.map { plan =>
(plan.source.tpe -> plan.dest.tpe) match {
case '[src] -> '[dest] =>
Expand All @@ -49,7 +49,7 @@ private[ducktape] object PlanInterpreter {
}.toList
ifStatement(branches).asExpr

case Plan.BetweenProductFunction(sourceTpe, destTpe, _, _, argPlans) =>
case Plan.BetweenProductFunction(sourceTpe, destTpe, argPlans) =>
val args = argPlans.map {
case (fieldName, p: Plan.Configured) =>
recurse(p, value).asTerm
Expand All @@ -59,24 +59,24 @@ private[ducktape] object PlanInterpreter {
}
destTpe.function.appliedTo(args.toList)

case Plan.BetweenOptions(sourceTpe, destTpe, _, _, plan) =>
(sourceTpe.tpe -> destTpe.tpe) match {
case Plan.BetweenOptions(sourceTpe, destTpe, plan) =>
(sourceTpe.paramStruct.tpe -> destTpe.paramStruct.tpe) match {
case '[src] -> '[dest] =>
val optionValue = value.asExprOf[Option[src]]
def transformation(value: Expr[src])(using Quotes): Expr[dest] = recurse(plan, value).asExprOf[dest]
'{ $optionValue.map(src => ${ transformation('src) }) }
}

case Plan.BetweenNonOptionOption(sourceTpe, destTpe, _, _, plan) =>
(sourceTpe.tpe -> destTpe.tpe) match {
case Plan.BetweenNonOptionOption(sourceTpe, destTpe, plan) =>
(sourceTpe.tpe -> destTpe.paramStruct.tpe) match {
case '[src] -> '[dest] =>
val sourceValue = value.asExprOf[src]
def transformation(value: Expr[src])(using Quotes): Expr[dest] = recurse(plan, value).asExprOf[dest]
'{ Some(${ transformation(sourceValue) }) }
}

case Plan.BetweenCollections(destCollectionTpe, sourceTpe, destTpe, _, _, plan) =>
(destCollectionTpe, sourceTpe.tpe, destTpe.tpe) match {
case Plan.BetweenCollections(source, dest, plan) =>
(dest.tpe, source.paramStruct.tpe, dest.paramStruct.tpe) match {
case ('[destCollTpe], '[srcElem], '[destElem]) =>
val sourceValue = value.asExprOf[Iterable[srcElem]]
// TODO: Make it nicer, move this into Planner since we cannot be sure that a facotry exists
Expand All @@ -85,22 +85,22 @@ private[ducktape] object PlanInterpreter {
'{ $sourceValue.map(src => ${ transformation('src) }).to($factory) }
}

case Plan.BetweenSingletons(sourceTpe, destTpe, _, _) => destTpe.value
case Plan.BetweenSingletons(sourceTpe, destTpe) => destTpe.value

case Plan.BetweenWrappedUnwrapped(sourceTpe, destTpe, _, _, fieldName) =>
case Plan.BetweenWrappedUnwrapped(sourceTpe, destTpe, fieldName) =>
value.accessFieldByName(fieldName).asExpr

case Plan.BetweenUnwrappedWrapped(sourceTpe, destTpe, _, _) =>
case Plan.BetweenUnwrappedWrapped(sourceTpe, destTpe) =>
Constructor(destTpe.tpe.repr).appliedTo(value.asTerm).asExpr

case Plan.UserDefined(source, dest, _, _, transformer) =>
case Plan.UserDefined(source, dest, transformer) =>
transformer match {
case '{ $t: Transformer[src, dest] } =>
val sourceValue = value.asExprOf[src]
'{ $t.transform($sourceValue) }
}

case Plan.Derived(source, dest, _, _, transformer) =>
case Plan.Derived(source, dest, transformer) =>
transformer match {
case '{ $t: Transformer.Derived[src, dest] } =>
val sourceValue = value.asExprOf[src]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ private[ducktape] object PlanRefiner {
case head :: next =>
head match {
case plan: Plan.Upcast => recurse(next, errors)
case Plan.BetweenProducts(_, _, _, _, fieldPlans) =>
case Plan.BetweenProducts(_, _, fieldPlans) =>
recurse(fieldPlans.values.toList ::: next, errors)
case Plan.BetweenCoproducts(_, _, _, _, casePlans) =>
case Plan.BetweenCoproducts(_, _, casePlans) =>
recurse(casePlans.toList ::: next, errors)
case Plan.BetweenProductFunction(_, _, _, _, argPlans) =>
case Plan.BetweenProductFunction(_, _, argPlans) =>
recurse(argPlans.values.toList ::: next, errors)
case Plan.BetweenOptions(_, _, _, _, plan) => recurse(plan :: next, errors)
case Plan.BetweenNonOptionOption(_, _, _, _, plan) => recurse(plan :: next, errors)
case Plan.BetweenCollections(_, _, _, _, _, plan) => recurse(plan :: next, errors)
case plan: Plan.BetweenSingletons => recurse(next, errors)
case plan: Plan.UserDefined => recurse(next, errors)
case plan: Plan.Derived => recurse(next, errors)
case plan: Plan.Configured => recurse(next, errors)
case plan: Plan.BetweenWrappedUnwrapped => recurse(next, errors)
case plan: Plan.BetweenUnwrappedWrapped => recurse(next, errors)
case error: Plan.Error => recurse(next, error :: errors)
case Plan.BetweenOptions(_, _, plan) => recurse(plan :: next, errors)
case Plan.BetweenNonOptionOption(_, _, plan) => recurse(plan :: next, errors)
case Plan.BetweenCollections(_, _, plan) => recurse(plan :: next, errors)
case plan: Plan.BetweenSingletons => recurse(next, errors)
case plan: Plan.UserDefined => recurse(next, errors)
case plan: Plan.Derived => recurse(next, errors)
case plan: Plan.Configured => recurse(next, errors)
case plan: Plan.BetweenWrappedUnwrapped => recurse(next, errors)
case plan: Plan.BetweenUnwrappedWrapped => recurse(next, errors)
case error: Plan.Error => recurse(next, error :: errors)
}
case Nil => errors
}
Expand Down
Loading
0