11package name .rayrobdod .stringContextParserCombinator
22
3+ import scala .annotation .nowarn
34import scala .quoted .*
5+ import name .rayrobdod .stringContextParserCombinator .{Unapply => SCUnapply }
46
57// scala 2 reads the `'{Some($value}` as an unclosed character literal
68// and ifdef is insufficient to hide that construct from the scala 2 compiler
@@ -13,4 +15,77 @@ object InterpolatorImpl {
1315 case _ => scala.quoted.quotes.reflect.report.errorAndAbort(s " Do not know how to process this tree " , sc)
1416 }
1517 }
18+
19+ def unapplyExprToExpr [UnexprA ](expr : UnapplyExpr [quoted.Expr , quoted.Type , quoted.Expr [UnexprA ]])(using Type [UnexprA ], Quotes ): Expr [SCUnapply [UnexprA ]] = {
20+ val conditionFn : quoted.Expr [UnexprA ] => quoted.Expr [Boolean ] = expr.condition
21+
22+ expr.parts match {
23+ case Nil =>
24+ ' {((a: UnexprA ) => $ {conditionFn(' a )}): Unapply .Zero [UnexprA ]}
25+ case (part : UnapplyExpr .Part [quoted.Expr , quoted.Type , quoted.Expr [UnexprA ], z]) :: Nil =>
26+ @ nowarn(" msg=unused local definition" ) given quoted .Type [z] = part.typ
27+ ' {((a: UnexprA ) => Option .when[z]($ {conditionFn(' a )})($ {part.value(' a )})): Unapply .Fixed [UnexprA , z]}
28+ case _ =>
29+ import quotes .reflect ._
30+ val unexpraTypeTree = TypeTree .of[UnexprA ]
31+
32+ val tupleTypeConstructorSymbol = defn.TupleClass (expr.parts.size)
33+ val tupleTypeConstructorTree = TypeIdent (tupleTypeConstructorSymbol)
34+ val tupleTypeTree = Applied (tupleTypeConstructorTree, expr.parts.map(part => TypeTree .of(using part.typ)))
35+ val optionTupleTypeTree = Applied (TypeIdent (defn.OptionClass ), List (tupleTypeTree))
36+
37+ val tupleModule = tupleTypeConstructorSymbol.companionModule
38+ val tupleConstructorTree = Ref (tupleModule)
39+
40+ val unapplyTypeConstructorTree = TypeIdent (Symbol .requiredClass(" name.rayrobdod.stringContextParserCombinator.Unapply.Fixed" ))
41+
42+ val anonfunType = MethodType (
43+ List (" a" ))(
44+ {(_:MethodType ) => List (unexpraTypeTree.tpe)},
45+ {(_:MethodType ) => optionTupleTypeTree.tpe},
46+ )
47+ val anonfunSymbol = Symbol .newMethod(
48+ Symbol .spliceOwner,
49+ " $anonfun" ,
50+ anonfunType
51+ )
52+
53+ Block (
54+ List (
55+ DefDef (
56+ anonfunSymbol,
57+ {paramss =>
58+ val param = paramss(0 )(0 ).asExprOf[UnexprA ]
59+ val condition = conditionFn(param).asTerm
60+ val optionModule = defn.OptionClass .companionModule
61+
62+ val partsTuple = {
63+ val typeArgs = expr.parts.map(part => TypeTree .of(using part.typ))
64+ val valueArgs = expr.parts.map(part => part.value(param).asTerm)
65+
66+ tupleConstructorTree
67+ .select(tupleModule.methodMember(" apply" )(0 ))
68+ .appliedToTypeTrees(typeArgs)
69+ .appliedToArgs(valueArgs)
70+ }
71+
72+ Option (
73+ Ref (optionModule)
74+ .select(optionModule.methodMember(" when" )(0 ))
75+ .appliedToType(tupleTypeTree.tpe)
76+ .appliedToArgss(
77+ List (List (condition), List (partsTuple))
78+ )
79+ )
80+ }
81+ ),
82+ ),
83+ Closure (
84+ Ref (anonfunSymbol),
85+ Option (AppliedType (unapplyTypeConstructorTree.tpe, List (unexpraTypeTree.tpe, tupleTypeTree.tpe)))
86+ )
87+ )
88+ .asExprOf[SCUnapply [UnexprA ]]
89+ }
90+ }
1691}
0 commit comments