8000 Selectable arg selectors by arainko · Pull Request #15 · arainko/ducktape · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
8000

Selectable arg selectors #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 25, 2022
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
10 changes: 10 additions & 0 deletions .scalafix.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
rules = [
OrganizeImports
]

OrganizeImports {
coalesceToWildcardImportThreshold = 3
groupedImports = AggressiveMerge

removeUnused = false
}
6 changes: 3 additions & 3 deletions 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-RC1"
libraryDependencies += "io.github.arainko" %% "ducktape" % "0.1.0-RC2"
```

### Examples
Expand Down Expand Up @@ -322,13 +322,13 @@ val definedViaTransformer =
Transformer
.defineVia[TestClass](method)
.build(Arg.const(_.additionalArg, List("const")))
// definedViaTransformer: Transformer[TestClass, TestClassWithAdditionalList] = repl.MdocSession$MdocApp6$$Lambda$8962/0x0000000802e7e040@61870c88
// definedViaTransformer: Transformer[TestClass, TestClassWithAdditionalList] = repl.MdocSession$MdocApp6$$Lambda$41195/0x000000010897d840@6ee2238f

val definedTransformer =
Transformer
.define[TestClass, TestClassWithAdditionalList]
.build(Field.const(_.additionalArg, List("const")))
// definedTransformer: Transformer[TestClass, TestClassWithAdditionalList] = repl.MdocSession$MdocApp6$$Lambda$8963/0x0000000802e7e440@2f13a6ac
// definedTransformer: Transformer[TestClass, TestClassWithAdditionalList] = repl.MdocSession$MdocApp6$$Lambda$41196/0x000000010897dc40@3eb47bb1

val transformedVia = definedViaTransformer.transform(testClass)
// transformedVia: TestClassWithAdditionalList = TestClassWithAdditionalList(
Expand Down
5 changes: 3 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ ThisBuild / developers := List(
url("https://github.com/arainko")
)
)
ThisBuild / scalaVersion := "3.1.3"
ThisBuild / scalaVersion := "3.2.0"
ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.6.0"

name := "ducktape"
sonatypeRepository := "https://s01.oss.sonatype.org/service/local"
Expand All @@ -29,7 +30,7 @@ lazy val ducktape =
project
.in(file("ducktape"))
.settings(
scalacOptions ++= List("-Xcheck-macros", "-no-indent", "-old-syntax"),
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
@@ -1,38 +1,43 @@
package io.github.arainko.ducktape

import io.github.arainko.ducktape.function.FunctionArguments
import scala.deriving.Mirror
import scala.annotation.implicitNotFound
import io.github.arainko.ducktape.internal.NotQuotedException

opaque type ArgBuilderConfig[Source, Dest, NamedArgs <: Tuple] = Unit
import scala.annotation.{ compileTimeOnly, implicitNotFound }
import scala.deriving.Mirror

object ArgBuilderConfig {
private[ducktape] def instance[Source, Dest, NamedArgs <: Tuple]: ArgBuilderConfig[Source, Dest, NamedArgs] = ()
}
opaque type ArgBuilderConfig[Source, Dest, ArgSelector <: FunctionArguments] = Unit

object Arg {
def const[Source, Dest, ArgType, ActualType, NamedArgs <: Tuple](
selector: FunctionArguments[NamedArgs] => ArgType,

@compileTimeOnly("'Arg.const' needs to be e 5D39 rased from the AST with a macro.")
def const[Source, Dest, ArgType, ActualType, ArgSelector <: FunctionArguments](
selector: ArgSelector => ArgType,
const: ActualType
)(using
@implicitNotFound("Arg.const is only supported for product types but ${Source} is not a product type.")
ev: Mirror.ProductOf[Source]
): ArgBuilderConfig[Source, Dest, NamedArgs] = ArgBuilderConfig.instance
ev1: Mirror.ProductOf[Source],
ev2: ActualType <:< ArgType
): ArgBuilderConfig[Source, Dest, ArgSelector] = throw NotQuotedException("Arg.const")

def computed[Source, Dest, ArgType, ActualType, NamedArgs <: Tuple](
selector: FunctionArguments[NamedArgs] => ArgType,
@compileTimeOnly("'Arg.computed' needs to be erased from the AST with a macro.")
def computed[Source, Dest, ArgType, ActualType, ArgSelector <: FunctionArguments](
selector: ArgSelector => ArgType,
f: Source => ActualType
)(using
@implicitNotFound("Arg.computed is only supported for product types but ${Source} is not a product type.")
ev: Mirror.ProductOf[Source]
): ArgBuilderConfig[Source, Dest, NamedArgs] = ArgBuilderConfig.instance
ev1: Mirror.ProductOf[Source],
ev2: ActualType <:< ArgType
): ArgBuilderConfig[Source, Dest, ArgSelector] = throw NotQuotedException("Arg.computed")

def renamed[Source, Dest, ArgType, FieldType, NamedArgs <: Tuple](
destSelector: FunctionArguments[NamedArgs] => ArgType,
@compileTimeOnly("'Arg.renamed' needs to be erased from the AST with a macro.")
def renamed[Source, Dest, ArgType, FieldType, ArgSelector <: FunctionArguments](
destSelector: ArgSelector => ArgType,
sourceSelector: Source => FieldType
)(using
@implicitNotFound("Arg.renamed is only supported for product types but ${Source} is not a product type.")
ev: Mirror.ProductOf[Source]
): ArgBuilderConfig[Source, Dest, NamedArgs] = ArgBuilderConfig.instance
ev1: Mirror.ProductOf[Source],
ev2: FieldType <:< ArgType
): ArgBuilderConfig[Source, Dest, ArgSelector] = throw NotQuotedException("Arg.renamed")

}
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
package io.github.arainko.ducktape

import io.github.arainko.ducktape.internal.NotQuotedException

import scala.annotation.{ compileTimeOnly, implicitNotFound }
import scala.deriving.Mirror
import scala.util.NotGiven
import scala.annotation.implicitNotFound

opaque type BuilderConfig[Source, Dest] = Unit

object BuilderConfig {
private[ducktape] def instance[Source, Dest]: BuilderConfig[Source, Dest] = ()
}

object Field {

@compileTimeOnly("'Field.const' needs to be erased from the AST with a macro.")
def const[Source, Dest, FieldType, ActualType](selector: Dest => FieldType, value: ActualType)(using
ev1: ActualType <:< FieldType,
@implicitNotFound("Field.const is supported for product types only, but ${Source} is not a product type.")
ev2: Mirror.ProductOf[Source],
@implicitNotFound("Field.const is supported for product types only, but ${Dest} is not a product type.")
ev3: Mirror.ProductOf[Dest]
): BuilderConfig[Source, Dest] = BuilderConfig.instance
): BuilderConfig[Source, Dest] = throw NotQuotedException("Field.const")

@compileTimeOnly("'Field.computed' needs to be erased from the AST with a macro.")
def computed[Source, Dest, FieldType, ActualType](selector: Dest => FieldType, f: Source => ActualType)(using
ev1: ActualType <:< FieldType,
@implicitNotFound("Field.computed is supported for product types only, but ${Source} is not a product type.")
ev2: Mirror.ProductOf[Source],
@implicitNotFound("Field.computed is supported for product types only, but ${Dest} is not a product type.")
ev3: Mirror.ProductOf[Dest]
): BuilderConfig[Source, Dest] = BuilderConfig.instance
): BuilderConfig[Source, Dest] = throw NotQuotedException("Field.computed")

@compileTimeOnly("'Field.renamed' needs to be erased from the AST with a macro.")
def renamed[Source, Dest, SourceFieldType, DestFieldType](
destSelector: Dest => DestFieldType,
sourceSelector: Source => SourceFieldType
Expand All @@ -36,43 +38,47 @@ object Field {
ev2: Mirror.ProductOf[Source],
@implicitNotFound("Field.renamed is supported for product types only, but ${Dest} is not a product type.")
ev3: Mirror.ProductOf[Dest]
): BuilderConfig[Source, Dest] = BuilderConfig.instance
): BuilderConfig[Source, Dest] = throw NotQuotedException("Field.renamed")
}

//TODO: Slap a @compileTimeOnly on all things here
object Case {
def const[SourceSubtype]: Case.Const[SourceSubtype] = Const.instance

def computed[SourceSubtype]: Case.Computed[SourceSubtype] = Computed.instance
@compileTimeOnly("'Case.const' needs to be erased from the AST with a macro.")
def const[SourceSubtype]: Case.Const[SourceSubtype] = throw NotQuotedException("Case.const")

@compileTimeOnly("'Case.computed' needs to be erased from the AST with a macro.")
def computed[SourceSubtype]: Case.Computed[SourceSubtype] = throw NotQuotedException("Case.computed")

opaque type Computed[SourceSubtype] = Unit

object Computed {
private[ducktape] def instance[SourceSubtype]: Computed[SourceSubtype] = ()

extension [SourceSubtype](inst: Computed[SourceSubtype]) {

@compileTimeOnly("'Case.computed' needs to be erased from the AST with a macro.")
def apply[Source, Dest](f: SourceSubtype => Dest)(using
@implicitNotFound("Case.computed is only supported for coproducts but ${Source} is not a coproduct.")
ev1: Mirror.SumOf[Source],
ev2: SourceSubtype <:< Source,
@implicitNotFound("Case.computed is only supported for subtypes of ${Source}.")
ev3: NotGiven[SourceSubtype =:= Source]
): BuilderConfig[Source, Dest] = BuilderConfig.instance
): BuilderConfig[Source, Dest] = throw NotQuotedException("Case.computed")
}
}

opaque type Const[SourceSubtype] = Unit

object Const {
private[ducktape] def instance[SourceSubtype]: Const[SourceSubtype] = ()

extension [SourceSubtype](inst: Const[SourceSubtype]) {

@compileTimeOnly("'Case.const' needs to be erased from the AST with a macro.")
def apply[Source, Dest](const: Dest)(using
@implicitNotFound("Case.computed is only supported for coproducts but ${Source} is not a coproduct.")
ev1: Mirror.SumOf[Source],
ev2: SourceSubtype <:< Source,
@implicitNotFound("Case.instance is only supported for subtypes of ${Source}.")
ev3: NotGiven[SourceSubtype =:= Source]
): BuilderConfig[Source, Dest] = BuilderConfig.instance
): BuilderConfig[Source, Dest] = throw NotQuotedException("Case.const")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ package io.github.arainko.ducktape
import io.github.arainko.ducktape.builder.*
import io.github.arainko.ducktape.internal.macros.*

import scala.collection.BuildFrom
import scala.collection.Factory
import scala.collection.{ BuildFrom, Factory }
import scala.compiletime.*
import scala.deriving.Mirror

Expand All @@ -20,12 +19,12 @@ object Transformer {

def defineVia[A]: DefinitionViaBuilder.PartiallyApplied[A] = DefinitionViaBuilder.create[A]

sealed trait Identity[Source] extends Transformer[Source, Source]

given [Source]: Identity[Source] = new {
final class Identity[Source] private[Transformer] extends Transformer[Source, Source] {
def transform(from: Source): Source = from
}

given [Source]: Identity[Source] = Identity[Source]

inline given forProducts[Source, Dest](using Mirror.ProductOf[Source], Mirror.ProductOf[Dest]): Transformer[Source, Dest] =
from => ProductTransformerMacros.transform(from)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
package io.github.arainko.ducktape.builder

import io.github.arainko.ducktape.*
import io.github.arainko.ducktape.function.*
import io.github.arainko.ducktape.internal.macros.*
import scala.deriving.Mirror
import io.github.arainko.ducktape.function.FunctionMirror
import io.github.arainko.ducktape.function.NamedArgument

import scala.compiletime.*
import scala.deriving.Mirror

sealed abstract class AppliedViaBuilder[Source, Dest, Func, NamedArguments <: Tuple](source: Source, function: Func) {
final class AppliedViaBuilder[Source, Dest, Func, ArgSelector <: FunctionArguments] private (
source: Source,
function: Func
) {

inline def transform(
inline config: ArgBuilderConfig[Source, Dest, NamedArguments]*
inline config: ArgBuilderConfig[Source, Dest, ArgSelector]*
)(using Source: Mirror.ProductOf[Source]): Dest =
ProductTransformerMacros.viaConfigured[Source, Dest, Func, NamedArguments](source, function, config*)
ProductTransformerMacros.viaConfigured[Source, Dest, Func, ArgSelector](source, function, config*)
}

object AppliedViaBuilder {
private def instance[Source, Dest, Func, ArgSelector <: FunctionArguments](
source: Source,
function: Func
) = AppliedViaBuilder[Source, Dest, Func, ArgSelector](source, function)

transparent inline def create[Source, Func](source: Source, inline func: Func)(using Func: FunctionMirror[Func]) = {
val builder = new AppliedViaBuilder[Source, Func.Return, Func, Nothing](source, func) {}
FunctionMacros.namedArguments(func, builder)
val builder = instance[Source, Func.Return, Func, Nothing](source, func)
FunctionMacros.namedArguments(func, instance[Source, Func.Return, Func, Nothing](source, func))
}
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
package io.github.arainko.ducktape.builder

import io.github.arainko.ducktape.*
import io.github.arainko.ducktape.function.*
import io.github.arainko.ducktape.internal.macros.*

import scala.deriving.*
import io.github.arainko.ducktape.function.FunctionMirror

sealed abstract class DefinitionViaBuilder[Source, Dest, Func, NamedArguments <: Tuple](function: Func) {
final class DefinitionViaBuilder[Source, Dest, Func, ArgSelector <: FunctionArguments] private (function: Func) {

inline def build(
inline config: ArgBuilderConfig[Source, Dest, NamedArguments]*
inline config: ArgBuilderConfig[Source, Dest, ArgSelector]*
)(using Mirror.ProductOf[Source]): Transformer[Source, Dest] = from =>
ProductTransformerMacros.viaConfigured[Source, Dest, Func, NamedArguments](from, function, config*)
ProductTransformerMacros.viaConfigured[Source, Dest, Func, ArgSelector](from, function, config*)
}

object DefinitionViaBuilder {
private def instance[Source, Dest, Func, ArgSelector <: FunctionArguments](function: Func) =
DefinitionViaBuilder[Source, Dest, Func, ArgSelector](function)

def create[Source]: PartiallyApplied[Source] = ()

opaque type PartiallyApplied[Source] = Unit

object PartiallyApplied {
extension [Source](partial: PartiallyApplied[Source]) {
transparent inline def apply[Func](inline func: Func)(using Func: FunctionMirror[Func]) = {
val builder = new DefinitionViaBuilder[Source, Func.Return, Func, Nothing](func) {}
val builder = instance[Source, Func.Return, Func, Nothing](func)
FunctionMacros.namedArguments(func, builder)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package io.github.arainko.ducktape.function

import scala.annotation.implicitNotFound
import scala.language.dynamics
import scala.util.NotGiven

sealed trait FunctionArguments[NamedArgs <: Tuple] extends Dynamic {
def selectDynamic(value: String): NamedArgument.FindByName[value.type, NamedArgs]
sealed trait FunctionArguments extends Selectable {
def selectDynamic(value: String): Nothing
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.arainko.ducktape.function

import io.github.arainko.ducktape.internal.macros.*

import scala.annotation.implicitNotFound

@implicitNotFound("FunctionMirrors are only available for function types, but got ${F}")
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.github.arainko.ducktape.internal

private[ducktape] final class NotQuotedException(name: String)
extends Exception(
s"""
|'$name' was not lifted away from the AST with a macro but also skirted past the compiler into the runtime.
|This is not good.
|Please file an issue on the 'ducktape' repository.""".stripMargin
)
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.github.arainko.ducktape.internal.macros

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

import scala.deriving.*
import scala.quoted.*

private[ducktape] class CoproductTransformerMacros(using val quotes: Quotes)
extends Module,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.github.arainko.ducktape.internal.macros

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

object DebugMacros {
import scala.quoted.*

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

def structureMacro[A: Type](value: Expr[A])(using Quotes) = {
Expand All @@ -17,11 +18,8 @@ object DebugMacros {

def codeCompiletimeMacro[A: Type](value: Expr[A])(using Quotes) = {
import quotes.reflect.*

val struct = Printer.TreeShortCode.show(value.asTerm)

report.info(struct)

value
}
}
Loading
0