Skip to content

Commit

Permalink
Fix: SplitByType macros (#133)
Browse files Browse the repository at this point in the history
  • Loading branch information
HollandDM authored Nov 16, 2024
1 parent 5e20165 commit f19d48b
Show file tree
Hide file tree
Showing 10 changed files with 504 additions and 294 deletions.
89 changes: 43 additions & 46 deletions src/main/scala-3/com/raquo/airstream/split/MacrosUtilities.scala
Original file line number Diff line number Diff line change
@@ -1,73 +1,70 @@
package com.raquo.airstream.split

import scala.quoted.{Expr, Quotes, Type}
import scala.annotation.tailrec
import scala.annotation.compileTimeOnly

private[split] object MacrosUtilities {

def exprOfListToListOfExpr[T: Type](
pfListExpr: Expr[List[T]]
)(
using quotes: Quotes
): List[Expr[T]] = {
import quotes.reflect.*
type CaseAny = Any
type HandlerAny[+O] = Any

pfListExpr match {
case '{ $headExpr :: (${ tailExpr }: List[T]) } =>
headExpr :: exprOfListToListOfExpr(tailExpr)
case '{ Nil } => Nil
case _ =>
report.errorAndAbort(
"Macro expansion failed, please use `handleCase` instead"
)
}
final case class MatchTypeHandler[T] private (private val underlying: Unit) extends AnyVal

object MatchTypeHandler {
@compileTimeOnly("MatchTypeHandler[T] cannot be used at runtime")
def instance[T]: MatchTypeHandler[T] = throw new UnsupportedOperationException("MatchTypeHandler[T] cannot be used at runtime")
}

def listOfExprToExprOfList[T: Type](
pfExprList: List[Expr[T]]
)(
using quotes: Quotes
): Expr[List[T]] = {
import quotes.reflect.*
final case class MatchValueHandler[V] private (private val underlying: Unit) extends AnyVal

pfExprList match
case head :: tail => '{ $head :: ${ listOfExprToExprOfList(tail) } }
case Nil => '{ Nil }
object MatchValueHandler {
@compileTimeOnly("MatchValueHandler[V] cannot be used at runtime")
def instance[V](v: V): MatchValueHandler[V] = throw new UnsupportedOperationException("MatchValueHandler[V] cannot be used at runtime")
}

def innerObservableImpl[I: Type](
iExpr: Expr[I],
caseListExpr: Expr[List[PartialFunction[Any, Any]]]
caseExprSeq: Seq[Expr[CaseAny]]
)(
using quotes: Quotes
): Expr[(Int, Any)] = {
) = {
import quotes.reflect.*

val caseExprList = exprOfListToListOfExpr(caseListExpr)

val allCaseDefLists = caseExprList.reverse.zipWithIndex
.flatMap { case (caseExpr, idx) =>
caseExpr.asTerm match {
case Lambda(_, Match(_, caseDefList)) => {
caseDefList.map { caseDef =>
val idxExpr = Expr.apply(idx)
val newRhsExpr = '{
val res = ${ caseDef.rhs.asExprOf[Any] }; ($idxExpr, res)
}
CaseDef.copy(caseDef)(
caseDef.pattern,
caseDef.guard,
newRhsExpr.asTerm
)
@tailrec
def getCaseDef(
idx: Int,
term: Term
): List[CaseDef] = {
term match {
case Inlined(_, _, inlinedTerm) => getCaseDef(idx, inlinedTerm)
case Lambda(_, Match(_, caseDefList)) => {
caseDefList.map { caseDef =>
val idxExpr = Expr.apply(idx)
val newRhsExpr = '{
val res = ${ caseDef.rhs.asExprOf[Any] }; ($idxExpr, res)
}
}
case _ =>
report.errorAndAbort(
"Macro expansion failed, please use `handleCase` with annonymous partial function"
CaseDef.copy(caseDef)(
caseDef.pattern,
caseDef.guard,
newRhsExpr.asTerm
)
}
}
case _ =>
report.errorAndAbort(
"Macro expansion failed, please use `handleCase` with annonymous partial function"
)
}
}

val allCaseDefLists = caseExprSeq.view
.zipWithIndex
.flatMap { case (caseExpr, idx) =>
getCaseDef(idx, caseExpr.asTerm)
}
.map(_.changeOwner(Symbol.spliceOwner))
.toList

Match(iExpr.asTerm, allCaseDefLists).asExprOf[(Int, Any)]
}
Expand Down
Loading

0 comments on commit f19d48b

Please sign in to comment.