@@ -17,21 +17,48 @@ object Lens {
17
17
import util ._
18
18
import quoted .Toolbox .Default ._
19
19
20
- // obj.copy(field = value)
21
- def setterBody (obj : Expr [S ], value : Expr [T ], field : String ): Expr [S ] =
22
- Term .Select .overloaded(obj.unseal, " copy" , Nil , Term .NamedArg (field, value.unseal) :: Nil ).seal[S ]
20
+
21
+ // obj.copy(a = obj.a.copy(b = a.b.copy(c = v)))
22
+ def setterBody (obj : Term , value : Term , fields : List [String ]): Term = {
23
+ // o.copy(field = value)
24
+ def helper (obj : Term , value : Term , field : String ): Term =
25
+ Term .Select .overloaded(obj, " copy" , Nil , Term .NamedArg (field, value) :: Nil )
26
+
27
+ fields match {
28
+ case field :: Nil => helper(obj, value, field)
29
+ case field :: fields =>
30
+ helper(obj, setterBody(Term .Select .unique(obj, field), value, fields), field)
31
+ }
32
+ }
33
+
34
+ object Path {
35
+ private def recur (tree : Term , selects : List [String ]): Option [(Term , List [String ])] = tree match {
36
+ case Term .Ident (_) if selects.nonEmpty => Some ((tree, selects))
37
+ case Term .Select (qual, name) => recur(qual, name :: selects)
38
+ case _ => None
39
+ }
40
+
41
+ def unapply (t : Term ): Option [(Term , List [String ])] = recur(t, Nil )
42
+ }
43
+
44
+ object Function {
45
+ def unapply (t : Term ): Option [(List [ValDef ], Term )] = t match {
46
+ case Term .Inlined (
47
+ None , Nil ,
48
+ Term .Block (
49
+ (ddef @ DefDef (_, Nil , params :: Nil , _, Some (body))) :: Nil ,
50
+ Term .Lambda (meth, _)
51
+ )
52
+ ) if meth.symbol == ddef.symbol => Some ((params, body))
53
+ case _ => None
54
+ }
55
+ }
23
56
24
57
// exception: getter.unseal.underlyingArgument
25
58
getter.unseal match {
26
- case Term .Inlined (
27
- None , Nil ,
28
- Term .Block (
29
- DefDef (_, Nil , (param :: Nil ) :: Nil , _, Some (Term .Select (o, field))) :: Nil ,
30
- Term .Lambda (meth, _)
31
- )
32
- ) if o.symbol == param.symbol =>
59
+ case Function (param :: Nil , Path (o, fields)) if o.symbol == param.symbol =>
33
60
' {
34
- val setter = (t : T ) => (s : S ) => ~ setterBody('(s), ' (t), field)
61
+ val setter = (t : T ) => (s : S ) => ~ setterBody(( '(s)).unseal, ( ' (t)).unseal, fields).seal[ S ]
35
62
apply(~ getter)(setter)
36
63
}
37
64
case _ =>
0 commit comments