@@ -13,14 +13,19 @@ private[focus] trait SelectFieldParser {
1313 def unapply (term : Term ): Option [FocusResult [(RemainingCode , FocusAction )]] = term match {
1414
1515 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)
1926 } else {
20- getFieldActionWithImplicits(fromType , fieldName)
27+ Some ( FocusError . NotACaseField (remainingCode.tpe.show , fieldName).asResult )
2128 }
22- val remainingCodeWithAction = action.map(a => (RemainingCode (remainingCode), a))
23- Some (remainingCodeWithAction)
2429
2530 case Select (remainingCode, fieldName) =>
2631 Some (FocusError .NotACaseClass (remainingCode.tpe.show, fieldName).asResult)
@@ -29,47 +34,100 @@ private[focus] trait SelectFieldParser {
2934 }
3035 }
3136
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+
3243 private def hasOnlyOneParameterList (classSymbol : Symbol ): Boolean =
3344 classSymbol.primaryConstructor.paramSymss match {
3445 case _ :: Nil => true
3546 case (head :: _) :: _ :: Nil if head.isTypeParam => true
3647 case _ => false
3748 }
3849
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 ] =
4054 getFieldType(fromType, fieldName).flatMap { toType =>
4155 Right (FocusAction .SelectField (fieldName, fromType, getSuppliedTypeArgs(fromType), toType))
4256 }
4357
44- private def getFieldActionWithImplicits (fromType : TypeRepr , fieldName : String ): FocusResult [FocusAction ] =
58+ private def getSelectFieldActionWithImplicits (fromType : TypeRepr , fieldName : String ): FocusResult [FocusAction ] =
4559 getFieldType(fromType, fieldName).flatMap { toType =>
4660 val typeArgs = getSuppliedTypeArgs(fromType)
4761 constructSetter(fieldName, fromType, toType, typeArgs).map { setter =>
4862 FocusAction .SelectFieldWithImplicits (fieldName, fromType, toType, setter)
4963 }
5064 }
5165
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+
5289 private case class LiftException (error : FocusError ) extends Exception
5390
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+
5498 private def constructSetter (
5599 fieldName : String ,
56100 fromType : TypeRepr ,
57101 toType : TypeRepr ,
58102 fromTypeArgs : List [TypeRepr ]
59103 ): FocusResult [Term ] =
60- // Companion .copy(value)(implicits)*
104+ // from .copy(value)(implicits)+
61105 (fromType.asType, toType.asType) match {
62106 case (' [f], ' [t]) =>
63- scala.util. Try (' { (to : t) => (from : f) =>
107+ liftEtaExpansionResult (' { (to : t) => (from : f) =>
64108 $ {
65109 etaExpandIfNecessary(
66110 Select .overloaded(' { from }.asTerm, " copy" , fromTypeArgs, List (NamedArg (fieldName, ' { to }.asTerm)))
67111 ).fold(error => throw new LiftException (error), _.asExprOf[f])
68112 }
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)
74132 }
75133}
0 commit comments