@@ -17,21 +17,48 @@ object Lens {
1717 import util ._
1818 import quoted .Toolbox .Default ._
1919
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+ }
2356
2457 // exception: getter.unseal.underlyingArgument
2558 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 =>
3360 ' {
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 ]
3562 apply(~ getter)(setter)
3663 }
3764 case _ =>
0 commit comments