Skip to content

Commit

Permalink
support scalajs
Browse files Browse the repository at this point in the history
  • Loading branch information
kitlangton committed Feb 19, 2024
1 parent 6636bb2 commit de80f51
Show file tree
Hide file tree
Showing 28 changed files with 595 additions and 245 deletions.
21 changes: 11 additions & 10 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,35 @@ inThisBuild(

Global / onChangedBuildSource := ReloadOnSourceChanges

lazy val root = (project in file("."))
lazy val root = (crossProject(JSPlatform, JVMPlatform) in file("."))
.settings(
name := "quotidian"
name := "root"
)
.aggregate(core)
.dependsOn(core)

lazy val core = (project in file("modules/core"))
lazy val core = (crossProject(JSPlatform, JVMPlatform) in file("modules/core"))
.settings(
name := "quotidian",
libraryDependencies ++= Seq(
"dev.zio" %% "zio-test" % "2.0.9" % Test,
"dev.zio" %% "zio-test-sbt" % "2.0.9" % Test,
"dev.zio" %% "zio-test" % "2.1-RC1" % Test,
"dev.zio" %% "zio-test-sbt" % "2.1-RC1" % Test,
"com.lihaoyi" %% "pprint" % "0.8.1"
),
scalacOptions ++= Seq(
"-deprecation",
"-explain",
"-Xcheck-macros"
// "-Ycheck:all"
)
)
.enablePlugins(ScalaJSPlugin)

lazy val examples = (project in file("examples"))
lazy val examples = (crossProject(JSPlatform, JVMPlatform) in file("examples"))
.settings(
name := "quotidian-examples",
libraryDependencies ++= Seq(
"dev.zio" %% "zio-test" % "2.0.9" % Test,
"dev.zio" %% "zio-test-sbt" % "2.0.9" % Test
"dev.zio" %% "zio-test" % "2.1-RC1" % Test,
"dev.zio" %% "zio-test-sbt" % "2.1-RC1" % Test
)
)
.dependsOn(core)
.enablePlugins(ScalaJSPlugin)
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package quotidian.examples.show

import quotidian.MacroMirror
import quotidian.MacroMirror.{Product, Sum}
import quotidian.syntax.*
import scala.deriving.*

import scala.quoted.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ object Debug:
val showTypeRepr = typeRepr.show
val prettyTypeRepr = pprint(typeRepr).toString
val showExpr = expr.show
val prettyTerm = pprint(expr.asTerm.underlyingArgument).toString
val symbol = typeRepr.typeSymbol
val info = SymbolInfo.fromSymbol(symbol)

val prettyTerm = pprint(expr.asTerm.underlyingArgument).toString
val symbol = typeRepr.typeSymbol
val info = SymbolInfo.fromSymbol(symbol)
val message =
s"""${"EXPR".blue.underlined}
|$showExpr
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package quotidian

import quotidian.syntax.{*, given}
import scala.quoted.*
import scala.compiletime.*
import quotidian.syntax.*

import scala.deriving.Mirror

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package quotidian

import quotidian.syntax.*
import quotidian.syntax.{*, given}

import scala.compiletime.*
import scala.deriving.Mirror
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
package quotidian

import quotidian.syntax.{*, given}
import scala.quoted.*
import scala.deriving.Mirror
import quotidian.syntax.*

class MirrorElem[Q <: Quotes, M, A](using val quotes: Q, val asType: Type[A])(
trait Method[Q <: Quotes, Parent]:
val quotes: Q
def name: String
def symbol: quotes.reflect.Symbol
end Method

class MirrorElem[Q <: Quotes, M, A](using
val quotes: Q,
val asType: Type[A]
)(
val label: String,
val typeRepr: quotes.reflect.TypeRepr,
val symbol: quotes.reflect.Symbol
Expand All @@ -14,20 +23,25 @@ class MirrorElem[Q <: Quotes, M, A](using val quotes: Q, val asType: Type[A])(
def get(parent: Expr[M]): Expr[A] =
dereference(parent.asTerm).asExprOf[A]

def dereference(parent: quotes.reflect.Term): quotes.reflect.Term =
def dereference(parent: Term): Term =
parent.selectUnique(label)

def ==(that: MirrorElem[?, ?, ?]) = symbol == that.symbol

def summon[F[_]: Type]: Expr[F[A]] =
val repr = quotes.reflect.TypeRepr.of[F[A]]
val repr = TypeRepr.of[F[A]]
Expr
.summon[F[A]]
.getOrElse(quotes.reflect.report.errorAndAbort(s"Cannot summon ${repr.show}"))
.getOrElse(report.errorAndAbort(s"Cannot summon ${repr.show}"))

def summonAsAny[F[_]: Type]: Expr[F[Any]] =
summon[F].cast[F[Any]]

def valueOfConstant: Option[A] =
Type.valueOfConstant[A]

end MirrorElem

sealed trait MacroMirror[Q <: Quotes, A]:
val quotes: Q
val tpe: Type[A]
Expand All @@ -53,7 +67,10 @@ sealed trait MacroMirror[Q <: Quotes, A]:
}

def summonAll[F[_]: Type]: List[Expr[F[Any]]] =
elems.map(_.summon[F]).asInstanceOf[List[Expr[F[Any]]]]
elems.map(_.summonAsAny[F])

def summonAllArray[F[_]: Type](using Quotes): Expr[Array[F[Any]]] =
Expr.ofArray[F[Any]](summonAll[F]*)

/** Returns an Expr[Array[F[_]]], first trying to summon an instance of `F[_]`
* for each element type, and then falling back to deriving an instance of
Expand All @@ -66,8 +83,8 @@ sealed trait MacroMirror[Q <: Quotes, A]:
)(using Quotes): Expr[Array[F[Any]]] =
Expr.ofArray[F[Any]](
elemTypes.map { case '[t] =>
val fallback = deriveFallback()(using Type.of[t])
'{ ${ Expr.summon[F[t]].getOrElse(fallback) }.asInstanceOf[F[Any]] }
val instance = Expr.summon[F[t]].getOrElse(deriveFallback())
'{ $instance.asInstanceOf[F[Any]] }
}*
)

Expand All @@ -85,6 +102,8 @@ sealed trait MacroMirror[Q <: Quotes, A]:
| elemTypes = ${elemTypeReprs.map(_.show)}
|)""".stripMargin

end MacroMirror

object MacroMirror:

abstract class Sum[Q <: Quotes, A](using
Expand All @@ -103,6 +122,7 @@ object MacroMirror:
elemTypeReprs.indexWhere(repr =:= _) match
case -1 => report.errorAndAbort(s"Type $repr is not a member of $monoType")
case n => n
end Sum

abstract class Product[Q <: Quotes, A](using
override val quotes: Q,
Expand All @@ -116,6 +136,20 @@ object MacroMirror:
.call("apply", monoType.typeArgs, args.toList)
.asExprOf[A]

def constructExpr(args: Expr[Array[Any]]): Expr[A] =
val terms = elems.zipWithIndex.map((elem, i) => //
elem.asType match
case '[t] =>
'{ $args(${ Expr(i) }).asInstanceOf[t] }.asTerm,
)
construct(terms)

def toArrayExpr(a: Expr[A]): Expr[Array[Any]] =
val terms = elems.map(_.dereference(a.asTerm).asExpr.cast[Any])
Expr.ofArray[Any](terms*)

end Product

abstract class Singleton[Q <: Quotes, A](using
override val quotes: Q,
override val tpe: Type[A]
Expand All @@ -127,6 +161,7 @@ object MacroMirror:

def expr: Expr[A] =
Ref(monoType.termSymbol).asExprOf[A]
end Singleton

def summon[A: Type](using quotes: Quotes): Option[MacroMirror[quotes.type, A]] =
import quotes.reflect.*
Expand All @@ -142,10 +177,10 @@ object MacroMirror:
}
} =>
new MacroMirror.Singleton[quotes.type, A]:
val label = Type.valueOfConstant[label].get.asInstanceOf[String]
val monoType = TypeRepr.of[monoType]
val elemLabels = TypeRepr.of[elemLabels].tupleToList.map(_.valueAs[String])
val elemTypeReprs = TypeRepr.of[elemTypes].tupleToList
val label: String = Type.valueAs[label, String]
val monoType: TypeRepr = TypeRepr.of[monoType]
val elemLabels: List[String] = TypeRepr.of[elemLabels].tupleToList.map(_.valueAs[String])
val elemTypeReprs: List[TypeRepr] = TypeRepr.of[elemTypes].tupleToList

case '{
$m: Mirror.ProductOf[A] {
Expand All @@ -156,7 +191,7 @@ object MacroMirror:
}
} =>
new MacroMirror.Product[quotes.type, A]:
val label = Type.valueOfConstant[label].get.asInstanceOf[String]
val label = Type.valueAs[label, String]
val monoType = TypeRepr.of[monoType]
val elemLabels = TypeRepr.of[elemLabels].tupleToList.map(_.valueAs[String])
val elemTypeReprs = TypeRepr.of[elemTypes].tupleToList
Expand All @@ -170,7 +205,7 @@ object MacroMirror:
}
} =>
new Sum[quotes.type, A]:
val label = Type.valueOfConstant[label].get.asInstanceOf[String]
val label = Type.valueAs[label, String]
val monoType = TypeRepr.of[monoType]
val elemLabels = TypeRepr.of[elemLabels].tupleToList.map(_.valueAs[String])
val elemTypeReprs = TypeRepr.of[elemTypes].tupleToList
Expand Down
Loading

0 comments on commit de80f51

Please sign in to comment.