@@ -13,14 +13,19 @@ private[focus] trait SelectFieldParser {
13
13
def unapply (term : Term ): Option [FocusResult [(RemainingCode , FocusAction )]] = term match {
14
14
15
15
case Select (CaseClass (remainingCode, classSymbol), fieldName) =>
16
- val fromType = getType(remainingCode)
17
- val action = if (hasOnlyOneParameterList(classSymbol)) {
18
- getFieldAction(fromType, fieldName)
16
+ if (isCaseField(classSymbol, fieldName)) {
17
+ val fromType = getType(remainingCode)
18
+ val action = (hasOnlyOneParameterList(classSymbol), hasOnlyOneField(classSymbol)) match {
19
+ case (true , false ) => getSelectFieldAction(fromType, fieldName)
20
+ case (false , false ) => getSelectFieldActionWithImplicits(fromType, fieldName)
21
+ case (true , true ) => getSelectOnlyFieldAction(fromType, classSymbol, fieldName)
22
+ case (false , true ) => getSelectOnlyFieldActionWithImplicits(fromType, classSymbol, fieldName)
23
+ }
24
+ val remainingCodeWithAction = action.map(a => (RemainingCode (remainingCode), a))
25
+ Some (remainingCodeWithAction)
19
26
} else {
20
- getFieldActionWithImplicits(fromType , fieldName)
27
+ Some ( FocusError . NotACaseField (remainingCode.tpe.show , fieldName).asResult )
21
28
}
22
- val remainingCodeWithAction = action.map(a => (RemainingCode (remainingCode), a))
23
- Some (remainingCodeWithAction)
24
29
25
30
case Select (remainingCode, fieldName) =>
26
31
Some (FocusError .NotACaseClass (remainingCode.tpe.show, fieldName).asResult)
@@ -29,47 +34,100 @@ private[focus] trait SelectFieldParser {
29
34
}
30
35
}
31
36
37
+ private def isCaseField (classSymbol : Symbol , fieldName : String ): Boolean =
38
+ classSymbol.caseFields.exists(_.name == fieldName)
39
+
40
+ private def hasOnlyOneField (classSymbol : Symbol ): Boolean =
41
+ classSymbol.caseFields.length == 1
42
+
32
43
private def hasOnlyOneParameterList (classSymbol : Symbol ): Boolean =
33
44
classSymbol.primaryConstructor.paramSymss match {
34
45
case _ :: Nil => true
35
46
case (head :: _) :: _ :: Nil if head.isTypeParam => true
36
47
case _ => false
37
48
}
38
49
39
- private def getFieldAction (fromType : TypeRepr , fieldName : String ): FocusResult [FocusAction ] =
50
+ private def getCompanionObject (classSymbol : Symbol ): Term =
51
+ Ref (classSymbol.companionModule)
52
+
53
+ private def getSelectFieldAction (fromType : TypeRepr , fieldName : String ): FocusResult [FocusAction ] =
40
54
getFieldType(fromType, fieldName).flatMap { toType =>
41
55
Right (FocusAction .SelectField (fieldName, fromType, getSuppliedTypeArgs(fromType), toType))
42
56
}
43
57
44
- private def getFieldActionWithImplicits (fromType : TypeRepr , fieldName : String ): FocusResult [FocusAction ] =
58
+ private def getSelectFieldActionWithImplicits (fromType : TypeRepr , fieldName : String ): FocusResult [FocusAction ] =
45
59
getFieldType(fromType, fieldName).flatMap { toType =>
46
60
val typeArgs = getSuppliedTypeArgs(fromType)
47
61
constructSetter(fieldName, fromType, toType, typeArgs).map { setter =>
48
62
FocusAction .SelectFieldWithImplicits (fieldName, fromType, toType, setter)
49
63
}
50
64
}
51
65
66
+ private def getSelectOnlyFieldAction (
67
+ fromType : TypeRepr ,
68
+ fromClassSymbol : Symbol ,
69
+ fieldName : String
70
+ ): FocusResult [FocusAction ] =
71
+ for {
72
+ toType <- getFieldType(fromType, fieldName)
73
+ companion = getCompanionObject(fromClassSymbol)
74
+ supplied = getSuppliedTypeArgs(fromType)
75
+ } yield FocusAction .SelectOnlyField (fieldName, fromType, supplied, companion, toType)
76
+
77
+ private def getSelectOnlyFieldActionWithImplicits (
78
+ fromType : TypeRepr ,
79
+ fromClassSymbol : Symbol ,
80
+ fieldName : String
81
+ ): FocusResult [FocusAction ] =
82
+ for {
83
+ toType <- getFieldType(fromType, fieldName)
84
+ companion = getCompanionObject(fromClassSymbol)
85
+ supplied = getSuppliedTypeArgs(fromType)
86
+ reverseGet <- constructReverseGet(companion, fromType, toType, supplied)
87
+ } yield FocusAction .SelectOnlyFieldWithImplicits (fieldName, fromType, toType, reverseGet)
88
+
52
89
private case class LiftException (error : FocusError ) extends Exception
53
90
91
+ private def liftEtaExpansionResult (term : => Term ): FocusResult [Term ] =
92
+ scala.util.Try (term) match {
93
+ case scala.util.Success (term) => Right (term)
94
+ case scala.util.Failure (LiftException (error)) => Left (error)
95
+ case scala.util.Failure (other) => Left (FocusError .ExpansionFailed (other.toString))
96
+ }
97
+
54
98
private def constructSetter (
55
99
fieldName : String ,
56
100
fromType : TypeRepr ,
57
101
toType : TypeRepr ,
58
102
fromTypeArgs : List [TypeRepr ]
59
103
): FocusResult [Term ] =
60
- // Companion .copy(value)(implicits)*
104
+ // from .copy(value)(implicits)+
61
105
(fromType.asType, toType.asType) match {
62
106
case (' [f], ' [t]) =>
63
- scala.util. Try (' { (to : t) => (from : f) =>
107
+ liftEtaExpansionResult (' { (to : t) => (from : f) =>
64
108
$ {
65
109
etaExpandIfNecessary(
66
110
Select .overloaded(' { from }.asTerm, " copy" , fromTypeArgs, List (NamedArg (fieldName, ' { to }.asTerm)))
67
111
).fold(error => throw new LiftException (error), _.asExprOf[f])
68
112
}
69
- }.asTerm) match {
70
- case scala.util.Success (term) => Right (term)
71
- case scala.util.Failure (LiftException (error)) => Left (error)
72
- case scala.util.Failure (other) => Left (FocusError .ExpansionFailed (other.toString))
73
- }
113
+ }.asTerm)
114
+ }
115
+
116
+ private def constructReverseGet (
117
+ companion : Term ,
118
+ fromType : TypeRepr ,
119
+ toType : TypeRepr ,
120
+ fromTypeArgs : List [TypeRepr ]
121
+ ): FocusResult [Term ] =
122
+ // Companion.apply(value)(implicits)+
123
+ (fromType.asType, toType.asType) match {
124
+ case (' [f], ' [t]) =>
125
+ liftEtaExpansionResult(' { (to : t) =>
126
+ $ {
127
+ etaExpandIfNecessary(
128
+ Select .overloaded(companion, " apply" , fromTypeArgs, List (' { to }.asTerm))
129
+ ).fold(error => throw new LiftException (error), _.asExprOf[f])
130
+ }
131
+ }.asTerm)
74
132
}
75
133
}
0 commit comments