Skip to content

Commit

Permalink
finishing touches
Browse files Browse the repository at this point in the history
  • Loading branch information
arainko committed Nov 11, 2022
1 parent 7f32828 commit 64fe78d
Show file tree
Hide file tree
Showing 11 changed files with 63 additions and 57 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ If this project interests you, please drop a 🌟 - these things are worthless b

### Installation
```scala
libraryDependencies += "io.github.arainko" %% "ducktape" % "0.1.0-RC2"
libraryDependencies += "io.github.arainko" %% "ducktape" % "0.1.0"
```

### Examples
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ lazy val ducktape =
project
.in(file("ducktape"))
.settings(
scalacOptions ++= List("-Xcheck-macros", "-no-indent", "-old-syntax", "-Xfatal-warnings", "-explain"),
scalacOptions ++= List("-Xcheck-macros", "-no-indent", "-old-syntax", "-Xfatal-warnings"),
libraryDependencies += "org.scalameta" %% "munit" % "1.0.0-M6" % Test
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ object Transformer {
def transform(from: Source): Dest = f(from)
}
}

given [Source, Dest >: Source]: Identity[Source, Dest] = Identity[Source, Dest]

inline given forProducts[Source, Dest](using Mirror.ProductOf[Source], Mirror.ProductOf[Dest]): ForProduct[Source, Dest] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import io.github.arainko.ducktape.*

import scala.quoted.*

object DebugMacros {
private[ducktape] object DebugMacros {
inline def structure[A](inline value: A) = ${ structureMacro('value) }

def structureMacro[A: Type](value: Expr[A])(using Quotes) = {
Expand All @@ -23,27 +23,4 @@ object DebugMacros {
report.info(struct)
value
}

inline def matchTest[A](inline expr: A) = ${ matchTestMacro('expr) }

def matchTestMacro[A](expr: Expr[A])(using Quotes) = {
import quotes.reflect.*

object StripNoisyNodes extends TreeMap {
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match {
case Inlined(_, Nil, term) => transformTerm(term)(owner)
case other => super.transformTerm(other)(owner)
}
}

val stripped = StripNoisyNodes.transformTerm(expr.asTerm)(Symbol.spliceOwner)

stripped match {
case Block(_, Typed(Apply(_, Lambda(param :: Nil, body) :: Nil), _)) =>
// report.info(param.show)
report.info(body.show(using Printer.TreeStructure))
stripped.asExpr
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package io.github.arainko.ducktape.internal.macros

import scala.quoted.*
import io.github.arainko.ducktape.internal.modules.*

import scala.quoted.*

private[ducktape] class NormalizationMacros(using val quotes: Quotes) extends Module, NormalizationModule

private[ducktape] object NormalizationMacros {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ private[ducktape] class ProductTransformerMacros(using val quotes: Quotes)
sourceValue
).map(field => field.name -> field).toMap

val callsInOrder = Fields.dest.value.map { (field) =>
val callsInOrder = Fields.dest.value.map { field =>
transformedFields
.get(field.name)
.getOrElse(configuredFields(field.name))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package io.github.arainko.ducktape.internal.modules
import io.github.arainko.ducktape.*

import scala.quoted.*
import scala.reflect.TypeTest

private[ducktape] trait NormalizationModule { self: Module =>
import quotes.reflect.*
Expand All @@ -30,7 +29,7 @@ private[ducktape] trait NormalizationModule { self: Module =>
case other => other
}

// Match on all the possibilieties of method invocations (that is, named args 'field = ...' and normal param passing).
// Match on all the possibilieties of method invocations (that is, named args 'field = ...' and normalterms).
private def transformTransformerInvocation(term: Term): Term =
term match {
case Untyped(TransformerInvocation(transformerLambda, appliedTo)) =>
Expand Down Expand Up @@ -58,7 +57,15 @@ private[ducktape] trait NormalizationModule { self: Module =>

}

class Replacer(transformerLambda: TransformerLambda, appliedTo: Term) extends TreeMap {
/**
* Replaces all instances of 'param' of the given TransformerLamba with `appliedTo`. Eg.:
*
* val name = (((param: String) => new Name(param)): Transformer.ToAnyVal[String, Name]).transform("appliedTo")
*
* After replacing this piece of code will look like this:
* val name = new Name("appliedTo")
*/
final class Replacer(transformerLambda: TransformerLambda, appliedTo: Term) extends TreeMap {
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match {
// by checking symbols we know if the term refers to the TransformerLambda parameter so we can replace it
Expand All @@ -68,14 +75,6 @@ private[ducktape] trait NormalizationModule { self: Module =>
}
}

object StripNoisyNodes extends TreeMap {
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match {
case Inlined(_, Nil, term) => transformTerm(term)(owner)
case other => super.transformTerm(other)(owner)
}
}

enum TransformerLambda {
def param: ValDef

Expand All @@ -87,26 +86,43 @@ private[ducktape] trait NormalizationModule { self: Module =>
object TransformerLambda {

/**
* Matches a SAM Transformer creation eg.:
* Matches a .make Transformer.ForProduct creation eg.:
*
* ((p: Person) => new Person2(p.int, p.str)): Transformer[Person, Person2]
* Transformer.ForProduct.make((p: Person) => new Person2(p.int, p.str))
*
* @return the parameter ('p'), a call to eg. a method ('new Person2')
* and the args of that call ('p.int', 'p.str')
*/
def fromForProduct(expr: Expr[Transformer.ForProduct[?, ?]]): Option[TransformerLambda.ForProduct] =
def fromForProduct(expr: Expr[Transformer.ForProduct[?, ?]]): Option[TransformerLambda.ForProduct] =
PartialFunction.condOpt(expr.asTerm) {
case MakeTransformer(param, Untyped(Apply(method, methodArgs))) =>
TransformerLambda.ForProduct(param, method, methodArgs)
}


/**
* Matches a .make Transformer.ToAnyVal creation eg.:
*
* final case class Name(value: String) extends AnyVal
*
* Transformer.ToAnyVal.make((str: String) => new Name(str))
*
* @return the parameter ('str'), the constructor call ('new Name') and the singular arg ('str').
*/
def fromToAnyVal(expr: Expr[Transformer.ToAnyVal[?, ?]]): Option[TransformerLambda.ToAnyVal] =
PartialFunction.condOpt(expr.asTerm) {
case MakeTransformer(param, Untyped(Apply(Untyped(constructorCall), List(arg)))) =>
TransformerLambda.ToAnyVal(param, constructorCall, arg)
}

/**
* Matches a .make Transformer.FromAnyVal creation eg.:
*
* final case class Name(value: String) extends AnyVal
*
* Transformer.FromAnyVal.make((name: Name) => name.value)
*
* @return the parameter ('name'), and the field name ('value' from the expression 'name.value')
*/
def fromFromAnyVal(expr: Expr[Transformer.FromAnyVal[?, ?]]): Option[TransformerLambda.FromAnyVal] =
PartialFunction.condOpt(expr.asTerm) {
case MakeTransformer(param, Untyped(Select(Untyped(_: Ident), fieldName))) =>
Expand All @@ -127,6 +143,20 @@ private[ducktape] trait NormalizationModule { self: Module =>
}
}

/**
* Strips all Inlined nodes that don't introduce any new vals into the scope.
*/
object StripNoisyNodes extends TreeMap {
override def transformTerm(tree: Term)(owner: Symbol): Term =
tree match {
case Inlined(_, Nil, term) => transformTerm(term)(owner)
case other => super.transformTerm(other)(owner)
}
}

/**
* Recursively unpacks Typed nodes
*/
object Untyped {
def unapply(term: Term)(using Quotes): Some[Term] =
term match {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.github.arainko.ducktapetest.builder

import io.github.arainko.ducktape.*
import io.github.arainko.ducktape.internal.macros.DebugMacros
import io.github.arainko.ducktapetest.DucktapeSuite

import scala.deriving.Mirror
import io.github.arainko.ducktape.internal.macros.DebugMacros

class AppliedBuilderSuite extends DucktapeSuite {
import AppliedBuilderSuite.*
Expand All @@ -15,10 +15,10 @@ class AppliedBuilderSuite extends DucktapeSuite {
val expected = TestClassWithAdditionalList(1, "str", List("const"))

val actual =
testClass
.into[TestClassWithAdditionalList]
.transform(Field.const(_.additionalArg, List("const")))
testClass
.into[TestClassWithAdditionalList]
.transform(Field.const(_.additionalArg, List("const")))

assertEquals(actual, expected)
}

Expand Down Expand Up @@ -86,7 +86,6 @@ class AppliedBuilderSuite extends DucktapeSuite {
Field.computed(_.additionalArg, _.str + "-computed")
)


assertEquals(actual, expected)
}

Expand All @@ -101,7 +100,6 @@ class AppliedBuilderSuite extends DucktapeSuite {
Case.const[MoreCases.Case5.type](LessCases.Case3)
)


assertEquals(actual, expected)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package io.github.arainko.ducktapetest.builder
import io.github.arainko.ducktape.*
import io.github.arainko.ducktape.builder.AppliedViaBuilder
import io.github.arainko.ducktape.function.FunctionArguments
import io.github.arainko.ducktape.internal.macros.DebugMacros
import io.github.arainko.ducktapetest.DucktapeSuite
import io.github.arainko.ducktapetest.builder.AppliedViaBuilderSuite.*
import io.github.arainko.ducktape.internal.macros.DebugMacros

class AppliedViaBuilderSuite extends DucktapeSuite {
private val testClass = TestClass("str", 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.arainko.ducktapetest.derivation

import io.github.arainko.ducktape.Transformer.ForProduct
import io.github.arainko.ducktape.*
import io.github.arainko.ducktape.internal.macros.*
import io.github.arainko.ducktapetest.DucktapeSuite
Expand All @@ -8,7 +9,6 @@ import munit.FunSuite

import scala.compiletime.testing.*
import scala.deriving.Mirror
import io.github.arainko.ducktape.Transformer.ForProduct

object DerivedTransformerSuite {
// If these are declared inside their tests the compiler crashes 🤔
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.github.arainko.ducktapetest.derivation

import io.github.arainko.ducktape.*
import io.github.arainko.ducktape.internal.macros.DebugMacros
import io.github.arainko.ducktapetest.DucktapeSuite
import munit.FunSuite

import scala.compiletime.testing.*
import io.github.arainko.ducktape.internal.macros.DebugMacros

final case class Input(int: Int, string: String, list: List[Int], option: Option[Int])

Expand Down Expand Up @@ -33,7 +33,7 @@ class ViaSuite extends DucktapeSuite {
val value = Input(1, "a", List(1, 2, 3), Some(4))
val expected = Transformed(1, "a", List(1, 2, 3), Some(4))
val actual = value.via(method)

assertEquals(actual, expected)
}

Expand All @@ -52,14 +52,14 @@ class ViaSuite extends DucktapeSuite {
TransformedWithSubtransformations[A](int, string, list, option)

val value = Input(1, "a", List(1, 2, 3), Some(4))

val expected = TransformedWithSubtransformations(
WrappedInt(1),
WrappedString("a"),
List(WrappedInt(1), WrappedInt(2), WrappedInt(3)),
Some(WrappedInt(4))
)

val actual = value.via(method[WrappedInt])

assertEquals(actual, expected)
Expand Down

0 comments on commit 64fe78d

Please sign in to comment.