@@ -45,7 +45,22 @@ trait Reifiers { self: Quasiquotes =>
45
45
}
46
46
}
47
47
48
+ object AnnotPlaceholder {
49
+
50
+ def unapply (tree : Tree ): Option [(String , List [Tree ])] = tree match {
51
+ case Apply (Select (New (Placeholder (name)), nme.CONSTRUCTOR ), args) => Some ((name, args))
52
+ case _ => None
53
+ }
54
+ }
55
+
48
56
override def reifyTree (tree : Tree ): Tree = reifyBasicTree(tree)
57
+
58
+ /** Reifies modifiers with custom list reifier for the annotations.
59
+ */
60
+ override def reifyModifiers (m : Modifiers ) =
61
+ mirrorFactoryCall(nme.Modifiers , mirrorBuildCall(nme.flagsFromBits, reify(m.flags)), reify(m.privateWithin), reifyAnnotsList(m.annotations))
62
+
63
+ def reifyAnnotsList (annots : List [Tree ]): Tree = ???
49
64
}
50
65
51
66
class ApplyReifier (universe : Tree , placeholders : Placeholders ) extends Reifier (universe, placeholders) {
@@ -64,7 +79,11 @@ trait Reifiers { self: Quasiquotes =>
64
79
case (card, iterable) if card > 0 && iterable <:< iterableType =>
65
80
extractIterableN(card, iterable).map {
66
81
case tpe if tpe <:< treeType =>
67
- Some ((wrapIterableN(tree, card) { t => t }, iterableN(card, tpe)))
82
+ if (iterable <:< listTreeType || iterable <:< listListTreeType) {
83
+ Some (tree, iterable)
84
+ } else {
85
+ Some ((wrapIterableN(tree, card) { t => t }, iterableN(card, tpe)))
86
+ }
68
87
case LiftableType (lift) =>
69
88
Some ((wrapIterableN(tree, card) { t => wrapLift(lift, t) }, iterableN(card, treeType)))
70
89
case tpe =>
@@ -139,25 +158,83 @@ trait Reifiers { self: Quasiquotes =>
139
158
super .reifyName(name)
140
159
}
141
160
142
- override def reifyList (xs : List [Any ]): Tree =
143
- Select (
144
- mkList(xs.map {
145
- case Placeholder (CorrespondsTo (tree, tpe)) if tpe <:< iterableTreeType => tree
146
- case List (Placeholder (CorrespondsTo (tree, tpe))) if tpe <:< iterableIterableTreeType => tree
147
- case x @ _ => mkList(List (reify(x)))
148
- }),
149
- nme.flatten)
161
+ /** Splits list into a list of groups where subsequent elements are condidered
162
+ * similar by the corresponding function.
163
+ *
164
+ * For example:
165
+ *
166
+ * > group(List(1, 1, 0, 0, 1, 0)) { _ == _ }
167
+ * List(List(1, 1), List(0, 0), List(1), List(0))
168
+ *
169
+ */
170
+ def group [T ](lst : List [T ])(similar : (T , T ) => Boolean ) = lst.foldLeft[List [List [T ]]](List ()) {
171
+ case (Nil , el) => List (List (el))
172
+ case (ll :+ (last @ (lastinit :+ lastel)), el) if similar(lastel, el) => ll :+ (last :+ el)
173
+ case (ll, el) => ll :+ List (el)
174
+ }
175
+
176
+ /** Reifies list filling all the valid placeholders.
177
+ *
178
+ * Reification of non-trivial list is done in two steps:
179
+ * 1. split the list into groups where every placeholder is always
180
+ * put in a group of it's own and all subsquent non-placeholders are
181
+ * grouped together; element is considered to be a placeholder if it's
182
+ * in the domain of the fill function;
183
+ * 2. fold the groups into a sequence of lists added together with ++ using
184
+ * fill reification for placeholders and fallback reification for non-placeholders.
185
+ */
186
+ def reifyListGeneric [T ](xs : List [T ])(fill : PartialFunction [T , Tree ])(fallback : T => Tree ): Tree =
187
+ xs match {
188
+ case Nil => mkList(Nil )
189
+ case _ =>
190
+ def reifyGroup (group : List [T ]): Tree = group match {
191
+ case List (elem) if fill.isDefinedAt(elem) => fill(elem)
192
+ case elems => mkList(elems.map(fallback))
193
+ }
194
+ val head :: tail = group(xs) { (a, b) => ! fill.isDefinedAt(a) && ! fill.isDefinedAt(b) }
195
+ tail.foldLeft[Tree ](reifyGroup(head)) { (tree, lst) => q " $tree ++ ${reifyGroup(lst)}" }
196
+ }
197
+
198
+ /** Reifies arbitrary list filling ..$x and ...$y placeholders when they are put
199
+ * in the correct position. Fallbacks to super.reifyList for non-placeholders.
200
+ */
201
+ override def reifyList (xs : List [Any ]): Tree = reifyListGeneric(xs) {
202
+ case Placeholder (CorrespondsTo (tree, tpe)) if tpe <:< iterableTreeType => tree
203
+ case List (Placeholder (CorrespondsTo (tree, tpe))) if tpe <:< iterableIterableTreeType => tree
204
+ } {
205
+ reify(_)
206
+ }
207
+
208
+ /** Custom list reifier for annotations. It's required because they have different shape
209
+ * and additional $u.build.annotationRepr wrapping is needed to ensure that user won't
210
+ * splice a non-constructor call in this position.
211
+ */
212
+ override def reifyAnnotsList (annots : List [Tree ]): Tree = reifyListGeneric(annots) {
213
+ case AnnotPlaceholder (CorrespondsTo (tree, tpe), args) if tpe <:< iterableTreeType =>
214
+ val x : TermName = c.freshName()
215
+ q " $tree.map { $x => $u.build.annotationRepr( $x, ${reify(args)}) } "
216
+ } {
217
+ case AnnotPlaceholder (CorrespondsTo (tree, tpe), args) if tpe <:< treeType =>
218
+ q " $u.build.annotationRepr( $tree, ${reify(args)}) "
219
+ case other => reify(other)
220
+ }
150
221
}
151
222
152
223
class UnapplyReifier (universe : Tree , placeholders : Placeholders ) extends Reifier (universe, placeholders) {
153
224
225
+ val u = universe
226
+
227
+ object CorrespondsTo {
228
+ def unapply (name : String ): Option [(Tree , Int )] =
229
+ placeholders.get(name)
230
+ }
231
+
154
232
override def reifyBasicTree (tree : Tree ): Tree = tree match {
155
233
case global.emptyValDef =>
156
234
mirrorBuildCall(" EmptyValDefLike" )
157
235
case global.pendingSuperCall =>
158
236
mirrorBuildCall(" PendingSuperCallLike" )
159
- case Placeholder (name) =>
160
- val (tree, card) = placeholders(name.toString)
237
+ case Placeholder (CorrespondsTo (tree, card)) =>
161
238
if (card > 0 )
162
239
c.abort(tree.pos, s " Can't extract a part of the tree with ' ${fmtCard(card)}' cardinality in this position. " )
163
240
tree
@@ -180,27 +257,40 @@ trait Reifiers { self: Quasiquotes =>
180
257
placeholders(name.toString)._1
181
258
}
182
259
183
- override def reifyModifiers (m : global.Modifiers ) =
184
- mirrorFactoryCall(nme.Modifiers , mirrorBuildCall(" FlagsAsBits" , reify(m.flags)), reify(m.privateWithin), reify(m.annotations))
185
-
186
- override def reifyList (xs : List [Any ]): Tree = {
187
- val last = if (xs.length > 0 ) xs.last else EmptyTree
188
- last match {
189
- case Placeholder (name) if placeholders(name)._2 == 1 =>
190
- val bnd = placeholders(name.toString)._1
191
- xs.init.foldRight[Tree ](bnd) { (el, rest) =>
192
- scalaFactoryCall(" collection.immutable.$colon$colon" , reify(el), rest)
193
- }
194
- case List (Placeholder (name)) if placeholders(name)._2 == 2 =>
195
- val bnd = placeholders(name.toString)._1
196
- xs.init.foldRight[Tree ](bnd) { (el, rest) =>
197
- scalaFactoryCall(" collection.immutable.$colon$colon" , reify(el), rest)
260
+ def reifyListGeneric (xs : List [Any ])(fill : PartialFunction [Any , Tree ])(fallback : Any => Tree ) =
261
+ xs match {
262
+ case init :+ last if fill.isDefinedAt(last) =>
263
+ init.foldRight[Tree ](fill(last)) { (el, rest) =>
264
+ q " scala.collection.immutable. $$ colon $$ colon( ${fallback(el)}, $rest) "
198
265
}
199
266
case _ =>
200
- super .reifyList (xs)
267
+ mkList (xs.map(fallback) )
201
268
}
269
+
270
+ override def reifyList (xs : List [Any ]): Tree = reifyListGeneric(xs) {
271
+ case Placeholder (CorrespondsTo (tree, 1 )) => tree
272
+ case List (Placeholder (CorrespondsTo (tree, 2 ))) => tree
273
+ } {
274
+ reify _
275
+ }
276
+
277
+ override def reifyAnnotsList (annots : List [Tree ]): Tree = reifyListGeneric(annots) {
278
+ case AnnotPlaceholder (CorrespondsTo (tree, 1 ), Nil ) => tree
279
+ } {
280
+ case AnnotPlaceholder (CorrespondsTo (tree, 0 ), args) =>
281
+ args match {
282
+ case Nil => tree
283
+ case _ => q " $u.Apply( $u.Select( $u.New( $tree), $u.nme.CONSTRUCTOR), ${reify(args)}) "
284
+ }
285
+ case other =>
286
+ reify(other)
202
287
}
203
288
289
+ override def reifyModifiers (m : global.Modifiers ) =
290
+ mirrorFactoryCall(nme.Modifiers , mirrorBuildCall(" FlagsAsBits" , reify(m.flags)),
291
+ reify(m.privateWithin), reifyAnnotsList(m.annotations))
292
+
293
+
204
294
override def mirrorSelect (name : String ): Tree =
205
295
Select (universe, TermName (name))
206
296
@@ -224,6 +314,9 @@ trait Reifiers { self: Quasiquotes =>
224
314
lazy val iterableType = appliedType(IterableClass .toType, List (AnyTpe ))
225
315
lazy val iterableTreeType = appliedType(iterableType, List (treeType))
226
316
lazy val iterableIterableTreeType = appliedType(iterableType, List (iterableTreeType))
317
+ lazy val listType = appliedType(ListClass .toType, List (AnyTpe ))
318
+ lazy val listTreeType = appliedType(listType, List (treeType))
319
+ lazy val listListTreeType = appliedType(listType, List (listTreeType))
227
320
lazy val optionTreeType = appliedType(OptionClass .toType, List (treeType))
228
321
lazy val optionNameType = appliedType(OptionClass .toType, List (nameType))
229
322
}
0 commit comments