1
1
package name .rayrobdod .stringContextParserCombinator
2
2
3
+ import scala .annotation .nowarn
3
4
import scala .quoted .*
5
+ import name .rayrobdod .stringContextParserCombinator .{Unapply => SCUnapply }
4
6
5
7
// scala 2 reads the `'{Some($value}` as an unclosed character literal
6
8
// and ifdef is insufficient to hide that construct from the scala 2 compiler
@@ -13,4 +15,77 @@ object InterpolatorImpl {
13
15
case _ => scala.quoted.quotes.reflect.report.errorAndAbort(s " Do not know how to process this tree " , sc)
14
16
}
15
17
}
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
+ }
16
91
}
0 commit comments