Skip to content

Commit 4594037

Browse files
committed
Merge very similar Select(Only)FieldGenerator & Parser
1 parent 7b6df5d commit 4594037

File tree

6 files changed

+103
-158
lines changed

6 files changed

+103
-158
lines changed

core/shared/src/main/scala-3.x/monocle/internal/focus/features/GeneratorLoop.scala

-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package monocle.internal.focus.features
22

33
import monocle.internal.focus.FocusBase
44
import monocle.internal.focus.features.selectfield.SelectFieldGenerator
5-
import monocle.internal.focus.features.selectonlyfield.SelectOnlyFieldGenerator
65
import monocle.internal.focus.features.some.SomeGenerator
76
import monocle.internal.focus.features.as.AsGenerator
87
import monocle.internal.focus.features.each.EachGenerator
@@ -15,7 +14,6 @@ import scala.quoted.Type
1514
private[focus] trait AllFeatureGenerators
1615
extends FocusBase
1716
with SelectFieldGenerator
18-
with SelectOnlyFieldGenerator
1917
with SomeGenerator
2018
with AsGenerator
2119
with EachGenerator

core/shared/src/main/scala-3.x/monocle/internal/focus/features/ParserLoop.scala

-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package monocle.internal.focus.features
33
import scala.quoted.Type
44
import monocle.internal.focus.FocusBase
55
import monocle.internal.focus.features.selectfield.SelectFieldParser
6-
import monocle.internal.focus.features.selectonlyfield.SelectOnlyFieldParser
76
import monocle.internal.focus.features.some.SomeParser
87
import monocle.internal.focus.features.as.AsParser
98
import monocle.internal.focus.features.each.EachParser
@@ -16,7 +15,6 @@ private[focus] trait AllFeatureParsers
1615
with SelectParserBase
1716
with KeywordParserBase
1817
with SelectFieldParser
19-
with SelectOnlyFieldParser
2018
with SomeParser
2119
with AsParser
2220
with EachParser
@@ -53,9 +51,6 @@ private[focus] trait ParserLoop {
5351
case KeywordWithDefault(Right(remainingCode, action)) => loop(remainingCode, action :: listSoFar)
5452
case KeywordWithDefault(Left(error)) => Left(error)
5553

56-
case SelectOnlyField(Right(remainingCode, action)) => loop(remainingCode, action :: listSoFar)
57-
case SelectOnlyField(Left(error)) => Left(error)
58-
5954
case SelectField(Right(remainingCode, action)) => loop(remainingCode, action :: listSoFar)
6055
case SelectField(Left(error)) => Left(error)
6156

core/shared/src/main/scala-3.x/monocle/internal/focus/features/selectfield/SelectFieldGenerator.scala

+30
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package monocle.internal.focus.features.selectfield
22

33
import monocle.internal.focus.FocusBase
4+
import monocle.Iso
45
import monocle.Lens
56

67
private[focus] trait SelectFieldGenerator {
@@ -39,4 +40,33 @@ private[focus] trait SelectFieldGenerator {
3940
}.asTerm
4041
}
4142
}
43+
44+
def generateSelectOnlyField(action: FocusAction.SelectOnlyField): Term = {
45+
import action.{fieldName, fromType, fromTypeArgs, fromCompanion, toType}
46+
47+
def generateReverseGet(to: Term): Term =
48+
Select.overloaded(fromCompanion, "apply", fromTypeArgs, List(to)) // Companion.apply(value)
49+
50+
(fromType.asType, toType.asType) match {
51+
case ('[f], '[t]) =>
52+
'{
53+
Iso.apply[f, t]((from: f) => ${ generateGetter('{ from }.asTerm, fieldName).asExprOf[t] })((to: t) =>
54+
${ generateReverseGet('{ to }.asTerm).asExprOf[f] }
55+
)
56+
}.asTerm
57+
}
58+
}
59+
60+
def generateSelectOnlyFieldWithImplicits(action: FocusAction.SelectOnlyFieldWithImplicits): Term = {
61+
import action.{fieldName, fromType, toType, reverseGet}
62+
63+
(fromType.asType, toType.asType) match {
64+
case ('[f], '[t]) =>
65+
'{
66+
Iso.apply[f, t]((from: f) => ${ generateGetter('{ from }.asTerm, fieldName).asExprOf[t] })(
67+
${ reverseGet.asExprOf[t => f] }
68+
)
69+
}.asTerm
70+
}
71+
}
4272
}

core/shared/src/main/scala-3.x/monocle/internal/focus/features/selectfield/SelectFieldParser.scala

+73-15
Original file line numberDiff line numberDiff line change
@@ -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
}

core/shared/src/main/scala-3.x/monocle/internal/focus/features/selectonlyfield/SelectOnlyFieldGenerator.scala

-42
This file was deleted.

core/shared/src/main/scala-3.x/monocle/internal/focus/features/selectonlyfield/SelectOnlyFieldParser.scala

-94
This file was deleted.

0 commit comments

Comments
 (0)