@@ -32,6 +32,7 @@ object Matcher {
32
32
*/
33
33
def unapply [Tup <: Tuple ](scrutineeExpr : Expr [_])(implicit patternExpr : Expr [_], reflection : Reflection ): Option [Tup ] = {
34
34
import reflection .{Bind => BindPattern , _ }
35
+ import Matching ._
35
36
36
37
type Env = Set [(Symbol , Symbol )]
37
38
@@ -45,7 +46,7 @@ object Matcher {
45
46
* @param `the[Env]` Set of tuples containing pairs of symbols (s, p) where s defines a symbol in `scrutinee` which corresponds to symbol p in `pattern`.
46
47
* @return `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
47
48
*/
48
- def treeMatches (scrutinee : Tree , pattern : Tree ) given Env : Option [ Tuple ] = {
49
+ def (scrutinee : Tree ) =#= ( pattern : Tree ) given Env : Matching = {
49
50
50
51
/** Check that both are `val` or both are `lazy val` or both are `var` **/
51
52
def checkValFlags (): Boolean = {
@@ -56,7 +57,7 @@ object Matcher {
56
57
}
57
58
58
59
def bindingMatch (sym : Symbol ) =
59
- Some ( Tuple1 ( new Bind (sym.name, sym) ))
60
+ matched( new Bind (sym.name, sym))
60
61
61
62
def hasBindTypeAnnotation (tpt : TypeTree ): Boolean = tpt match {
62
63
case Annotated (tpt2, Apply (Select (New (TypeIdent (" patternBindHole" )), " <init>" ), Nil )) => true
@@ -67,9 +68,9 @@ object Matcher {
67
68
def hasBindAnnotation (sym : Symbol ) =
68
69
sym.annots.exists { case Apply (Select (New (TypeIdent (" patternBindHole" ))," <init>" ),List ()) => true ; case _ => true }
69
70
70
- def treesMatch (scrutinees : List [Tree ], patterns : List [Tree ]): Option [ Tuple ] =
71
- if (scrutinees.size != patterns.size) None
72
- else foldMatchings(scrutinees.zip(patterns).map(treeMatches ): _* )
71
+ def treesMatch (scrutinees : List [Tree ], patterns : List [Tree ]): Matching =
72
+ if (scrutinees.size != patterns.size) notMatched
73
+ else foldMatchings(scrutinees.zip(patterns).map((s, p) => s =#= p ): _* )
73
74
74
75
/** Normalieze the tree */
75
76
def normalize (tree : Tree ): Tree = tree match {
@@ -85,126 +86,128 @@ object Matcher {
85
86
if patternHole.symbol == kernel.Definitions_InternalQuoted_patternHole &&
86
87
s.tpe <:< tpt.tpe &&
87
88
tpt2.tpe.derivesFrom(definitions.RepeatedParamClass ) =>
88
- Some ( Tuple1 ( scrutinee.seal) )
89
+ matched( scrutinee.seal)
89
90
90
91
// Match a scala.internal.Quoted.patternHole and return the scrutinee tree
91
92
case (IsTerm (scrutinee), TypeApply (patternHole, tpt :: Nil ))
92
93
if patternHole.symbol == kernel.Definitions_InternalQuoted_patternHole &&
93
94
scrutinee.tpe <:< tpt.tpe =>
94
- Some ( Tuple1 ( scrutinee.seal) )
95
+ matched( scrutinee.seal)
95
96
96
97
//
97
98
// Match two equivalent trees
98
99
//
99
100
100
101
case (Literal (constant1), Literal (constant2)) if constant1 == constant2 =>
101
- Some (())
102
+ matched
102
103
103
104
case (Typed (expr1, tpt1), Typed (expr2, tpt2)) =>
104
- foldMatchings(treeMatches( expr1, expr2), treeMatches( tpt1, tpt2))
105
+ expr1 =#= expr2 && tpt1 =#= tpt2
105
106
106
107
case (Ident (_), Ident (_)) if scrutinee.symbol == pattern.symbol || the[Env ].apply((scrutinee.symbol, pattern.symbol)) =>
107
- Some (())
108
+ matched
108
109
109
110
case (Select (qual1, _), Select (qual2, _)) if scrutinee.symbol == pattern.symbol =>
110
- treeMatches( qual1, qual2)
111
+ qual1 =#= qual2
111
112
112
113
case (IsRef (_), IsRef (_)) if scrutinee.symbol == pattern.symbol =>
113
- Some (())
114
+ matched
114
115
115
116
case (Apply (fn1, args1), Apply (fn2, args2)) if fn1.symbol == fn2.symbol =>
116
- foldMatchings(treeMatches( fn1, fn2), treesMatch(args1, args2) )
117
+ fn1 =#= fn2 && treesMatch(args1, args2)
117
118
118
119
case (TypeApply (fn1, args1), TypeApply (fn2, args2)) if fn1.symbol == fn2.symbol =>
119
- foldMatchings(treeMatches( fn1, fn2), treesMatch(args1, args2) )
120
+ fn1 =#= fn2 && treesMatch(args1, args2)
120
121
121
122
case (Block (stats1, expr1), Block (stats2, expr2)) =>
122
- foldMatchings( treesMatch(stats1, stats2), treeMatches( expr1, expr2))
123
+ treesMatch(stats1, stats2) && expr1 =#= expr2
123
124
124
125
case (If (cond1, thenp1, elsep1), If (cond2, thenp2, elsep2)) =>
125
- foldMatchings(treeMatches( cond1, cond2), treeMatches( thenp1, thenp2), treeMatches( elsep1, elsep2))
126
+ cond1 =#= cond2 && thenp1 =#= thenp2 && elsep1 =#= elsep2
126
127
127
128
case (Assign (lhs1, rhs1), Assign (lhs2, rhs2)) =>
128
129
val lhsMatch =
129
- if (treeMatches (lhs1, lhs2).isDefined) Some (())
130
- else None
131
- foldMatchings( lhsMatch, treeMatches( rhs1, rhs2))
130
+ if ((lhs1 =#= lhs2).isMatch) matched
131
+ else notMatched
132
+ lhsMatch && rhs1 =#= rhs2
132
133
133
134
case (While (cond1, body1), While (cond2, body2)) =>
134
- foldMatchings(treeMatches( cond1, cond2), treeMatches( body1, body2))
135
+ cond1 =#= cond2 && body1 =#= body2
135
136
136
137
case (NamedArg (name1, expr1), NamedArg (name2, expr2)) if name1 == name2 =>
137
- treeMatches( expr1, expr2)
138
+ expr1 =#= expr2
138
139
139
140
case (New (tpt1), New (tpt2)) =>
140
- treeMatches( tpt1, tpt2)
141
+ tpt1 =#= tpt2
141
142
142
143
case (This (_), This (_)) if scrutinee.symbol == pattern.symbol =>
143
- Some (())
144
+ matched
144
145
145
146
case (Super (qual1, mix1), Super (qual2, mix2)) if mix1 == mix2 =>
146
- treeMatches( qual1, qual2)
147
+ qual1 =#= qual2
147
148
148
149
case (Repeated (elems1, _), Repeated (elems2, _)) if elems1.size == elems2.size =>
149
150
treesMatch(elems1, elems2)
150
151
151
152
case (IsTypeTree (scrutinee @ TypeIdent (_)), IsTypeTree (pattern @ TypeIdent (_))) if scrutinee.symbol == pattern.symbol =>
152
- Some (())
153
+ matched
153
154
154
155
case (IsInferred (scrutinee), IsInferred (pattern)) if scrutinee.tpe <:< pattern.tpe =>
155
- Some (())
156
+ matched
156
157
157
158
case (Applied (tycon1, args1), Applied (tycon2, args2)) =>
158
- foldMatchings(treeMatches( tycon1, tycon2), treesMatch(args1, args2) )
159
+ tycon1 =#= tycon2 && treesMatch(args1, args2)
159
160
160
161
case (ValDef (_, tpt1, rhs1), ValDef (_, tpt2, rhs2)) if checkValFlags() =>
161
162
val bindMatch =
162
163
if (hasBindAnnotation(pattern.symbol) || hasBindTypeAnnotation(tpt2)) bindingMatch(scrutinee.symbol)
163
- else Some (())
164
- val returnTptMatch = treeMatches( tpt1, tpt2)
164
+ else matched
165
+ val returnTptMatch = tpt1 =#= tpt2
165
166
val rhsEnv = the[Env ] + (scrutinee.symbol -> pattern.symbol)
166
167
val rhsMatchings = treeOptMatches(rhs1, rhs2) given rhsEnv
167
- foldMatchings( bindMatch, returnTptMatch, rhsMatchings)
168
+ bindMatch && returnTptMatch && rhsMatchings
168
169
169
170
case (DefDef (_, typeParams1, paramss1, tpt1, Some (rhs1)), DefDef (_, typeParams2, paramss2, tpt2, Some (rhs2))) =>
170
171
val typeParmasMatch = treesMatch(typeParams1, typeParams2)
171
172
val paramssMatch =
172
- if (paramss1.size != paramss2.size) None
173
+ if (paramss1.size != paramss2.size) notMatched
173
174
else foldMatchings(paramss1.zip(paramss2).map { (params1, params2) => treesMatch(params1, params2) }: _* )
174
175
val bindMatch =
175
176
if (hasBindAnnotation(pattern.symbol)) bindingMatch(scrutinee.symbol)
176
- else Some (())
177
- val tptMatch = treeMatches( tpt1, tpt2)
177
+ else matched
178
+ val tptMatch = tpt1 =#= tpt2
178
179
val rhsEnv =
179
180
the[Env ] + (scrutinee.symbol -> pattern.symbol) ++
180
181
typeParams1.zip(typeParams2).map((tparam1, tparam2) => tparam1.symbol -> tparam2.symbol) ++
181
182
paramss1.flatten.zip(paramss2.flatten).map((param1, param2) => param1.symbol -> param2.symbol)
182
- val rhsMatch = treeMatches (rhs1, rhs2) given rhsEnv
183
+ val rhsMatch = (rhs1 =#= rhs2) given rhsEnv
183
184
184
- foldMatchings( bindMatch, typeParmasMatch, paramssMatch, tptMatch, rhsMatch)
185
+ bindMatch && typeParmasMatch && paramssMatch && tptMatch && rhsMatch
185
186
186
187
case (Lambda (_, tpt1), Lambda (_, tpt2)) =>
187
188
// TODO match tpt1 with tpt2?
188
- Some (())
189
+ matched
189
190
190
191
case (Match (scru1, cases1), Match (scru2, cases2)) =>
191
- val scrutineeMacth = treeMatches( scru1, scru2)
192
+ val scrutineeMacth = scru1 =#= scru2
192
193
val casesMatch =
193
- if (cases1.size != cases2.size) None
194
+ if (cases1.size != cases2.size) notMatched
194
195
else foldMatchings(cases1.zip(cases2).map(caseMatches): _* )
195
- foldMatchings( scrutineeMacth, casesMatch)
196
+ scrutineeMacth && casesMatch
196
197
197
198
case (Try (body1, cases1, finalizer1), Try (body2, cases2, finalizer2)) =>
198
- val bodyMacth = treeMatches( body1, body2)
199
+ val bodyMacth = body1 =#= body2
199
200
val casesMatch =
200
- if (cases1.size != cases2.size) None
201
+ if (cases1.size != cases2.size) notMatched
201
202
else foldMatchings(cases1.zip(cases2).map(caseMatches): _* )
202
203
val finalizerMatch = treeOptMatches(finalizer1, finalizer2)
203
- foldMatchings( bodyMacth, casesMatch, finalizerMatch)
204
+ bodyMacth && casesMatch && finalizerMatch
204
205
205
206
// Ignore type annotations
206
- case (Annotated (tpt, _), _) => treeMatches(tpt, pattern)
207
- case (_, Annotated (tpt, _)) => treeMatches(scrutinee, tpt)
207
+ case (Annotated (tpt, _), _) =>
208
+ tpt =#= pattern
209
+ case (_, Annotated (tpt, _)) =>
210
+ scrutinee =#= tpt
208
211
209
212
// No Match
210
213
case _ =>
@@ -225,26 +228,26 @@ object Matcher {
225
228
|
226
229
|
227
230
| """ .stripMargin)
228
- None
231
+ notMatched
229
232
}
230
233
}
231
234
232
- def treeOptMatches (scrutinee : Option [Tree ], pattern : Option [Tree ]) given Env : Option [ Tuple ] = {
235
+ def treeOptMatches (scrutinee : Option [Tree ], pattern : Option [Tree ]) given Env : Matching = {
233
236
(scrutinee, pattern) match {
234
- case (Some (x), Some (y)) => treeMatches(x, y)
235
- case (None , None ) => Some (())
236
- case _ => None
237
+ case (Some (x), Some (y)) => x =#= y
238
+ case (None , None ) => matched
239
+ case _ => notMatched
237
240
}
238
241
}
239
242
240
- def caseMatches (scrutinee : CaseDef , pattern : CaseDef ) given Env : Option [ Tuple ] = {
241
- val (caseEnv, patternMatch) = patternMatches( scrutinee.pattern, pattern.pattern)
243
+ def caseMatches (scrutinee : CaseDef , pattern : CaseDef ) given Env : Matching = {
244
+ val (caseEnv, patternMatch) = scrutinee.pattern =%= pattern.pattern
242
245
243
246
{
244
247
implied for Env = caseEnv
245
248
val guardMatch = treeOptMatches(scrutinee.guard, pattern.guard)
246
- val rhsMatch = treeMatches( scrutinee.rhs, pattern.rhs)
247
- foldMatchings( patternMatch, guardMatch, rhsMatch)
249
+ val rhsMatch = scrutinee.rhs =#= pattern.rhs
250
+ patternMatch && guardMatch && rhsMatch
248
251
}
249
252
}
250
253
@@ -258,34 +261,34 @@ object Matcher {
258
261
* @return The new environment containing the bindings defined in this pattern tuppled with
259
262
* `None` if it did not match or `Some(tup: Tuple)` if it matched where `tup` contains the contents of the holes.
260
263
*/
261
- def patternMatches (scrutinee : Pattern , pattern : Pattern ) given Env : (Env , Option [ Tuple ] ) = (scrutinee, pattern) match {
264
+ def (scrutinee : Pattern ) =%= ( pattern : Pattern ) given Env : (Env , Matching ) = (scrutinee, pattern) match {
262
265
case (Pattern .Value (v1), Pattern .Unapply (TypeApply (Select (patternHole @ Ident (" patternHole" ), " unapply" ), List (tpt)), Nil , Nil ))
263
266
if patternHole.symbol.owner.fullName == " scala.runtime.quoted.Matcher$" =>
264
- (the[Env ], Some ( Tuple1 ( v1.seal) ))
267
+ (the[Env ], matched( v1.seal))
265
268
266
269
case (Pattern .Value (v1), Pattern .Value (v2)) =>
267
- (the[Env ], treeMatches(v1, v2) )
270
+ (the[Env ], v1 =#= v2 )
268
271
269
272
case (Pattern .Bind (name1, body1), Pattern .Bind (name2, body2)) =>
270
273
val bindEnv = the[Env ] + (scrutinee.symbol -> pattern.symbol)
271
- patternMatches (body1, body2) given bindEnv
274
+ (body1 =%= body2) given bindEnv
272
275
273
276
case (Pattern .Unapply (fun1, implicits1, patterns1), Pattern .Unapply (fun2, implicits2, patterns2)) =>
274
- val funMatch = treeMatches( fun1, fun2)
277
+ val funMatch = fun1 =#= fun2
275
278
val implicitsMatch =
276
- if (implicits1.size != implicits2.size) None
277
- else foldMatchings(implicits1.zip(implicits2).map(treeMatches ): _* )
279
+ if (implicits1.size != implicits2.size) notMatched
280
+ else foldMatchings(implicits1.zip(implicits2).map((i1, i2) => i1 =#= i2 ): _* )
278
281
val (patEnv, patternsMatch) = foldPatterns(patterns1, patterns2)
279
- (patEnv, foldMatchings( funMatch, implicitsMatch, patternsMatch) )
282
+ (patEnv, funMatch && implicitsMatch && patternsMatch)
280
283
281
284
case (Pattern .Alternatives (patterns1), Pattern .Alternatives (patterns2)) =>
282
285
foldPatterns(patterns1, patterns2)
283
286
284
287
case (Pattern .TypeTest (tpt1), Pattern .TypeTest (tpt2)) =>
285
- (the[Env ], treeMatches( tpt1, tpt2) )
288
+ (the[Env ], tpt1 =#= tpt2)
286
289
287
290
case (Pattern .WildcardPattern (), Pattern .WildcardPattern ()) =>
288
- (the[Env ], Some (()) )
291
+ (the[Env ], matched )
289
292
290
293
case _ =>
291
294
if (debug)
@@ -305,30 +308,56 @@ object Matcher {
305
308
|
306
309
|
307
310
| """ .stripMargin)
308
- (the[Env ], None )
311
+ (the[Env ], notMatched )
309
312
}
310
313
311
- def foldPatterns (patterns1 : List [Pattern ], patterns2 : List [Pattern ]) given Env : (Env , Option [ Tuple ] ) = {
312
- if (patterns1.size != patterns2.size) (the[Env ], None )
313
- else patterns1.zip(patterns2).foldLeft((the[Env ], Option [ Tuple ](()) )) { (acc, x) =>
314
- val (env, res) = patternMatches (x._1, x._2) given acc ._1
315
- (env, foldMatchings( acc._2, res) )
314
+ def foldPatterns (patterns1 : List [Pattern ], patterns2 : List [Pattern ]) given Env : (Env , Matching ) = {
315
+ if (patterns1.size != patterns2.size) (the[Env ], notMatched )
316
+ else patterns1.zip(patterns2).foldLeft((the[Env ], matched )) { (acc, x) =>
317
+ val (env, res) = (x._1 =%= x._2) given acc ._1
318
+ (env, acc._2 && res)
316
319
}
317
320
}
318
321
319
322
implied for Env = Set .empty
320
- treeMatches (scrutineeExpr.unseal, patternExpr.unseal).asInstanceOf [Option [Tup ]]
323
+ (scrutineeExpr.unseal =#= patternExpr.unseal).asOptionOfTuple .asInstanceOf [Option [Tup ]]
321
324
}
322
325
323
- /** Joins the mattchings into a single matching. If any matching is `None` the result is `None`.
324
- * Otherwise the result is `Some` of the concatenation of the tupples.
325
- */
326
- private def foldMatchings (matchings : Option [Tuple ]* ): Option [Tuple ] = {
327
- // TODO improve performance
328
- matchings.foldLeft[Option [Tuple ]](Some (())) {
329
- case (Some (acc), Some (holes)) => Some (acc ++ holes)
330
- case (_, _) => None
326
+ /** Result of matching a part of an expression */
327
+ private opaque type Matching = Option [Tuple ]
328
+
329
+ private object Matching {
330
+
331
+ def notMatched : Matching = None
332
+ val matched : Matching = Some (())
333
+ def matched (x : Any ): Matching = Some (Tuple1 (x))
334
+
335
+ def (self : Matching ) asOptionOfTuple : Option [Tuple ] = self
336
+
337
+ /** Concatenates the contents of two sucessful matchings or return a `notMatched` */
338
+ def (self : Matching ) && (that : Matching ): Matching = self match {
339
+ case Some (x) =>
340
+ that match {
341
+ case Some (y) => Some (x ++ y)
342
+ case _ => None
343
+ }
344
+ case _ => None
331
345
}
346
+
347
+ /** Is this matching the result of a successful match */
348
+ def (self : Matching ) isMatch : Boolean = self.isDefined
349
+
350
+ /** Joins the mattchings into a single matching. If any matching is `None` the result is `None`.
351
+ * Otherwise the result is `Some` of the concatenation of the tupples.
352
+ */
353
+ def foldMatchings (matchings : Matching * ): Matching = {
354
+ // TODO improve performance
355
+ matchings.foldLeft[Matching ](Some (())) {
356
+ case (Some (acc), Some (holes)) => Some (acc ++ holes)
357
+ case (_, _) => None
358
+ }
359
+ }
360
+
332
361
}
333
362
334
363
}
0 commit comments