@@ -9,15 +9,29 @@ object Matcher {
9
9
10
10
private final val debug = false
11
11
12
- /**
12
+ /** Pattern matches an the scrutineeExpr aquainsnt the patternExpr and returns a tuple
13
+ * with the matched holes if successful.
13
14
*
14
- * @param scrutineeExpr
15
- * @param patternExpr
16
- * @param reflection
17
- * @return None if it did not match, Some(tup) if it matched where tup contains Expr[_], Type[_] or Binding[_]
15
+ * Examples:
16
+ * - `Matcher.unapply('{ f(0, myInt) })('{ f(0, myInt) }, _)`
17
+ * will return `Some(())` (where `()` is a tuple of arity 0)
18
+ * - `Matcher.unapply('{ f(0, myInt) })('{ f(patternHole[Int], patternHole[Int]) }, _)`
19
+ * will return `Some(Tuple2('{0}, '{ myInt }))`
20
+ * - `Matcher.unapply('{ f(0, "abc") })('{ f(0, patternHole[Int]) }, _)`
21
+ * will return `None` due to the missmatch of types in the hole
22
+ *
23
+ * Holes:
24
+ * - scala.internal.Quoted.patternHole[T]: hole that matches an expression `x` of type `Expr[U]`
25
+ * if `U <:< T` and returns `x` as part of the match.
26
+ *
27
+ * @param scrutineeExpr `Expr[_]` on which we are pattern matching
28
+ * @param patternExpr `Expr[_]` containing the pattern tree
29
+ * @param reflection instance of the reflection API (implicitly provided by the macro)
30
+ * @return None if it did not match, `Some(tup)` if it matched where `tup` contains `Expr[Ti]``
18
31
*/
19
32
def unapply [Tup <: Tuple ](scrutineeExpr : Expr [_])(implicit patternExpr : Expr [_], reflection : Reflection ): Option [Tup ] = {
20
33
import reflection ._
34
+ // TODO improve performance
21
35
22
36
def treeMatches (scrutinee : Tree , pattern : Tree )(implicit env : Set [(Symbol , Symbol )]): Option [Tuple ] = {
23
37
@@ -38,15 +52,18 @@ object Matcher {
38
52
case (Block (Nil , expr), _) => treeMatches(expr, pattern)
39
53
case (_, Block (Nil , pat)) => treeMatches(scrutinee, pat)
40
54
41
- // Match
55
+ // Match a scala.internal.Quoted.patternHole and return the scrutinee tree
42
56
case (IsTerm (scrutinee), TypeApply (patternHole, tpt :: Nil ))
43
57
if patternHole.symbol == kernel.Definitions_InternalQuoted_patternHole && scrutinee.tpe <:< tpt.tpe =>
44
58
Some (Tuple1 (scrutinee.seal))
45
59
46
- case (Inlined (_, Nil , scr), _) =>
47
- treeMatches(scr, pattern)
48
- case (_, Inlined (_, Nil , pat)) =>
49
- treeMatches(scrutinee, pat)
60
+ // Normalize inline trees
61
+ case (Inlined (_, Nil , scr), _) => treeMatches(scr, pattern)
62
+ case (_, Inlined (_, Nil , pat)) => treeMatches(scrutinee, pat)
63
+
64
+ //
65
+ // Match two equivalent trees
66
+ //
50
67
51
68
case (Literal (constant1), Literal (constant2)) if constant1 == constant2 =>
52
69
Some (())
@@ -150,6 +167,7 @@ object Matcher {
150
167
val finalizerMatch = treeOptMatches(finalizer1, finalizer2)
151
168
foldMatchings(bodyMacth, casesMatch, finalizerMatch)
152
169
170
+ // No Match
153
171
case _ =>
154
172
if (debug)
155
173
println(
@@ -245,7 +263,11 @@ object Matcher {
245
263
treeMatches(scrutineeExpr.unseal, patternExpr.unseal)(Set .empty).asInstanceOf [Option [Tup ]]
246
264
}
247
265
266
+ /** Joins the mattchings into a single matching. If any matching is `None` the result is `None`.
267
+ * Otherwise the result is `Some` of the concatenation of the tupples.
268
+ */
248
269
private def foldMatchings (matchings : Option [Tuple ]* ): Option [Tuple ] = {
270
+ // TODO improve performance
249
271
matchings.foldLeft[Option [Tuple ]](Some (())) {
250
272
case (Some (acc), Some (holes)) => Some (acc ++ holes)
251
273
case (_, _) => None
0 commit comments