From 1f397f523626787f8072cc116e34b63556ac9e72 Mon Sep 17 00:00:00 2001 From: Yilin Wei Date: Sat, 13 Feb 2021 16:20:58 +0000 Subject: [PATCH 1/5] Use a dummy trait to restrict Focus actions within a context. --- .../src/main/scala-3.x/monocle/Focus.scala | 19 ++++++++++++--- .../internal/focus/AppliedFocusImpl.scala | 6 ++--- .../monocle/internal/focus/FocusImpl.scala | 23 +++++++++++-------- .../monocle/internal/focus/InFocus.scala | 22 ++++++++++++++++++ .../focus/features/castas/CastAsParser.scala | 8 +++---- .../optionsome/OptionSomeParser.scala | 7 +++--- 6 files changed, 62 insertions(+), 23 deletions(-) create mode 100644 core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala diff --git a/core/shared/src/main/scala-3.x/monocle/Focus.scala b/core/shared/src/main/scala-3.x/monocle/Focus.scala index eb612643d..a7f6c504d 100644 --- a/core/shared/src/main/scala-3.x/monocle/Focus.scala +++ b/core/shared/src/main/scala-3.x/monocle/Focus.scala @@ -1,19 +1,32 @@ package monocle +<<<<<<< HEAD import monocle.function.Each import monocle.internal.focus.{FocusImpl, AppliedFocusImpl} import monocle.syntax.FocusSyntax +======= +import monocle.internal.focus.{FocusImpl, AppliedFocusImpl, InFocus} +>>>>>>> Use a dummy trait to restrict Focus actions within a context. object Focus extends FocusSyntax { - extension [From, To] (from: From) - transparent inline def focus(inline lambda: (From => To)): Any = + extension [From, To] (from: From) + transparent inline def focus(inline lambda: (InFocus ?=> From => To)): Any = ${AppliedFocusImpl[From, To]('from, 'lambda)} +<<<<<<< HEAD +======= + extension [CastTo] (from: Any)(using InFocus) + def as: CastTo = scala.sys.error("Extension method 'as[CastTo]' should only be used within the monocle.Focus macro.") + + extension [A] (opt: Option[A])(using InFocus) + def some: A = scala.sys.error("Extension method 'some' should only be used within the monocle.Focus macro.") + +>>>>>>> Use a dummy trait to restrict Focus actions within a context. def apply[S] = new MkFocus[S] class MkFocus[From] { - transparent inline def apply[To](inline lambda: (From => To)): Any = + transparent inline def apply[To](inline lambda: (InFocus ?=> From => To)): Any = ${ FocusImpl('lambda) } } } diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala index deeb5660a..158259ee1 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala @@ -5,10 +5,10 @@ import scala.quoted.{Type, Expr, Quotes, quotes} private[monocle] object AppliedFocusImpl { - def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[From => To])(using Quotes): Expr[Any] = { + def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[InFocus ?=> From => To])(using Quotes): Expr[Any] = { import quotes.reflect._ - val generatedOptic = new FocusImpl(quotes).run(lambda) + val generatedOptic = FocusImpl(lambda) generatedOptic.asTerm.tpe.asType match { case '[Lens[f, t]] => '{ _root_.monocle.syntax.ApplyLens[From, From, To, To]($from, ${generatedOptic.asExprOf[Lens[From,To]]}) } @@ -17,4 +17,4 @@ private[monocle] object AppliedFocusImpl { case '[Optional[f, t]] => '{ _root_.monocle.syntax.ApplyOptional[From, From, To, To]($from, ${generatedOptic.asExprOf[Optional[From,To]]}) } } } -} \ No newline at end of file +} diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala index 078afe8fa..897f2d4ec 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala @@ -3,21 +3,21 @@ package monocle.internal.focus import monocle.Lens import scala.quoted.{Type, Expr, Quotes, quotes} -private[focus] class FocusImpl(val macroContext: Quotes) - extends FocusBase +private[focus] class FocusImpl(val macroContext: Quotes) + extends FocusBase with ErrorHandling - with ParserLoop with AllParsers + with ParserLoop with AllParsers with GeneratorLoop with AllGenerators { import macroContext.reflect._ def run[From: Type, To: Type](lambda: Expr[From => To]): Expr[Any] = { - val parseResult: FocusResult[List[FocusAction]] = + val parseResult: FocusResult[List[FocusAction]] = parseLambda[From](lambda.asTerm) - val generatedCode: FocusResult[Term] = + val generatedCode: FocusResult[Term] = parseResult.flatMap(generateCode[From]) - + generatedCode match { case Right(code) => code.asExpr case Left(error) => report.error(errorMessage(error)); '{???} @@ -25,7 +25,12 @@ private[focus] class FocusImpl(val macroContext: Quotes) } } + private[monocle] object FocusImpl { - def apply[From: Type, To: Type](lambda: Expr[From => To])(using Quotes): Expr[Any] = - new FocusImpl(quotes).run(lambda) -} \ No newline at end of file + def apply[From: Type, To: Type](contextExpr: Expr[InFocus ?=> From => To])(using Quotes): Expr[Any] = { + InFocus.stripContext[From, To](contextExpr) match { + case Some(lambda) => new FocusImpl(quotes).run(lambda) + case _ => sys.error("Unexpected code structure ${contextExpr.show}") + } + } +} diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala new file mode 100644 index 000000000..d90afe8ae --- /dev/null +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala @@ -0,0 +1,22 @@ +package monocle.internal.focus + +import scala.quoted.{Quotes, Type, Expr} +import scala.annotation.implicitNotFound + +// Marker which gets erased at compile-time +sealed trait InFocus { +} + +private[focus] object InFocus { + def stripContext[From : Type, To: Type]( + contextExpr: Expr[InFocus ?=> From => To] + )(using macroContext: Quotes): Option[Expr[From => To]] = { + import macroContext.reflect._ + // Ideally, a quasi-quote match would be best, but it doesn't work currently for certain cases. + contextExpr.asTerm match { + case Inlined(_, _, Block(List(DefDef(_, _, _, _, Some(lambdaExpr))), _)) => + Some(lambdaExpr.asExprOf[From => To]) + case _ => None + } + } +} diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala index 7c82a9dd7..40ab631d8 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala @@ -3,14 +3,14 @@ package monocle.internal.focus.features.castas import monocle.internal.focus.FocusBase private[focus] trait CastAsParser { - this: FocusBase => + this: FocusBase => import macroContext.reflect._ object CastAs extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(TypeApply(Ident("as"), List(typeArg)), List(remainingCode)) => + case Apply(Apply(TypeApply(Ident("as"), List(typeArg)), List(remainingCode)), _) => val fromType = remainingCode.tpe.widen val toType = typeArg.tpe @@ -19,8 +19,8 @@ private[focus] trait CastAsParser { Some(Right(remainingCode, action)) } else Some(Left(FocusError.InvalidDowncast(fromType.show, toType.show))) - + case _ => None } } -} \ No newline at end of file +} diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala index e818d4c44..ed19aaea4 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala @@ -3,19 +3,18 @@ package monocle.internal.focus.features.optionsome import monocle.internal.focus.FocusBase private[focus] trait OptionSomeParser { - this: FocusBase => + this: FocusBase => import macroContext.reflect._ object OptionSome extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(TypeApply(Ident("some"), List(typeArg)), List(remainingCode)) => + case Apply(Apply(TypeApply(Ident("some"), List(typeArg)), List(remainingCode)), _) => val toType = typeArg.tpe val action = FocusAction.OptionSome(toType) Some(Right(remainingCode, action)) - case _ => None } } -} \ No newline at end of file +} From 8f10927de2a6d6db689f09712fd92ca37e6cecd6 Mon Sep 17 00:00:00 2001 From: Yilin Wei Date: Sun, 14 Feb 2021 22:19:26 +0000 Subject: [PATCH 2/5] Having our cake and eating it --- core/shared/src/main/scala-3.x/monocle/Focus.scala | 11 ++++++++++- .../monocle/internal/focus/AppliedFocusImpl.scala | 3 ++- .../scala-3.x/monocle/internal/focus/FocusImpl.scala | 3 ++- .../scala-3.x/monocle/internal/focus/InFocus.scala | 7 ++----- .../internal/focus/features/castas/CastAsParser.scala | 4 +++- .../focus/features/optionsome/OptionSomeParser.scala | 2 +- .../main/scala-3.x/monocle/syntax/FocusSyntax.scala | 4 ++++ core/shared/src/main/scala/monocle/syntax/All.scala | 2 +- 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/core/shared/src/main/scala-3.x/monocle/Focus.scala b/core/shared/src/main/scala-3.x/monocle/Focus.scala index a7f6c504d..5d89f0343 100644 --- a/core/shared/src/main/scala-3.x/monocle/Focus.scala +++ b/core/shared/src/main/scala-3.x/monocle/Focus.scala @@ -8,10 +8,15 @@ import monocle.syntax.FocusSyntax import monocle.internal.focus.{FocusImpl, AppliedFocusImpl, InFocus} >>>>>>> Use a dummy trait to restrict Focus actions within a context. -object Focus extends FocusSyntax { +object Focus { +<<<<<<< HEAD extension [From, To] (from: From) transparent inline def focus(inline lambda: (InFocus ?=> From => To)): Any = +======= + extension [From, To] (from: From) + transparent inline def focus(inline lambda: (FocusSyntax ?=> From => To)): Any = +>>>>>>> Having our cake and eating it ${AppliedFocusImpl[From, To]('from, 'lambda)} <<<<<<< HEAD @@ -26,7 +31,11 @@ object Focus extends FocusSyntax { def apply[S] = new MkFocus[S] class MkFocus[From] { +<<<<<<< HEAD transparent inline def apply[To](inline lambda: (InFocus ?=> From => To)): Any = +======= + transparent inline def apply[To](inline lambda: (FocusSyntax ?=> From => To)): Any = +>>>>>>> Having our cake and eating it ${ FocusImpl('lambda) } } } diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala index 158259ee1..07947fbc7 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala @@ -1,11 +1,12 @@ package monocle.internal.focus +import monocle.syntax.FocusSyntax import monocle.{Focus, Lens, Iso, Prism, Optional} import scala.quoted.{Type, Expr, Quotes, quotes} private[monocle] object AppliedFocusImpl { - def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[InFocus ?=> From => To])(using Quotes): Expr[Any] = { + def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[FocusSyntax ?=> From => To])(using Quotes): Expr[Any] = { import quotes.reflect._ val generatedOptic = FocusImpl(lambda) diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala index 897f2d4ec..4355b3b5d 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala @@ -1,5 +1,6 @@ package monocle.internal.focus +import monocle.syntax.FocusSyntax import monocle.Lens import scala.quoted.{Type, Expr, Quotes, quotes} @@ -27,7 +28,7 @@ private[focus] class FocusImpl(val macroContext: Quotes) private[monocle] object FocusImpl { - def apply[From: Type, To: Type](contextExpr: Expr[InFocus ?=> From => To])(using Quotes): Expr[Any] = { + def apply[From: Type, To: Type](contextExpr: Expr[FocusSyntax ?=> From => To])(using Quotes): Expr[Any] = { InFocus.stripContext[From, To](contextExpr) match { case Some(lambda) => new FocusImpl(quotes).run(lambda) case _ => sys.error("Unexpected code structure ${contextExpr.show}") diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala index d90afe8ae..affc88716 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala @@ -1,15 +1,12 @@ package monocle.internal.focus +import monocle.syntax.FocusSyntax import scala.quoted.{Quotes, Type, Expr} import scala.annotation.implicitNotFound -// Marker which gets erased at compile-time -sealed trait InFocus { -} - private[focus] object InFocus { def stripContext[From : Type, To: Type]( - contextExpr: Expr[InFocus ?=> From => To] + contextExpr: Expr[FocusSyntax ?=> From => To] )(using macroContext: Quotes): Option[Expr[From => To]] = { import macroContext.reflect._ // Ideally, a quasi-quote match would be best, but it doesn't work currently for certain cases. diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala index 40ab631d8..488570032 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala @@ -10,10 +10,12 @@ private[focus] trait CastAsParser { object CastAs extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(Apply(TypeApply(Ident("as"), List(typeArg)), List(remainingCode)), _) => + case Apply(TypeApply(Select(_, "as"), List(typeArg)), List(remainingCode)) => + val fromType = remainingCode.tpe.widen val toType = typeArg.tpe + if (toType <:< fromType) { val action = FocusAction.CastAs(fromType, toType) Some(Right(remainingCode, action)) diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala index ed19aaea4..cdfbe8534 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala @@ -10,7 +10,7 @@ private[focus] trait OptionSomeParser { object OptionSome extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(Apply(TypeApply(Ident("some"), List(typeArg)), List(remainingCode)), _) => + case Apply(TypeApply(Select(_, "some"), List(typeArg)), List(remainingCode)) => val toType = typeArg.tpe val action = FocusAction.OptionSome(toType) Some(Right(remainingCode, action)) diff --git a/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala b/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala index 22917d8b6..25d0ebdd2 100644 --- a/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala +++ b/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala @@ -1,8 +1,12 @@ package monocle.syntax +<<<<<<< HEAD import monocle.function.Each trait FocusSyntax { +======= +sealed trait FocusSyntax { +>>>>>>> Having our cake and eating it extension [CastTo] (from: Any) def as: CastTo = scala.sys.error("Extension method 'as[CastTo]' should only be used within the monocle.Focus macro.") diff --git a/core/shared/src/main/scala/monocle/syntax/All.scala b/core/shared/src/main/scala/monocle/syntax/All.scala index 08c5d29be..5c619a6e9 100644 --- a/core/shared/src/main/scala/monocle/syntax/All.scala +++ b/core/shared/src/main/scala/monocle/syntax/All.scala @@ -2,4 +2,4 @@ package monocle.syntax object all extends Syntaxes -trait Syntaxes extends ApplySyntax with FocusSyntax with FieldsSyntax +trait Syntaxes extends ApplySyntax with FieldsSyntax From 7bbf179f7b00eac41ae1aeb40d78c08a9bdd3358 Mon Sep 17 00:00:00 2001 From: Ken Scambler Date: Fri, 19 Feb 2021 01:31:26 +1100 Subject: [PATCH 3/5] Yilin's magic syntax lives --- ...sSyntax.scala => AppliedFocusSyntax.scala} | 0 .../src/main/scala-3.x/monocle/Focus.scala | 40 +++++----------- .../internal/focus/AppliedFocusImpl.scala | 16 ++++--- .../internal/focus/ErrorHandling.scala | 5 +- .../monocle/internal/focus/FocusBase.scala | 14 ++++++ .../monocle/internal/focus/FocusImpl.scala | 34 ++++++-------- .../internal/focus/GeneratorLoop.scala | 4 +- .../monocle/internal/focus/InFocus.scala | 19 -------- .../internal/focus/LambdaConfigParser.scala | 43 +++++++++++++++++ .../monocle/internal/focus/ParserLoop.scala | 47 ++++--------------- .../focus/features/castas/CastAsParser.scala | 2 +- .../focus/features/each/EachParser.scala | 2 +- .../optionsome/OptionSomeParser.scala | 2 +- .../monocle/syntax/AppliedFocusSyntax.scala | 11 +++++ .../monocle/syntax/FocusSyntax.scala | 18 ------- 15 files changed, 123 insertions(+), 134 deletions(-) rename core/shared/src/main/scala-2.x/monocle/syntax/{FocusSyntax.scala => AppliedFocusSyntax.scala} (100%) delete mode 100644 core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala create mode 100644 core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala create mode 100644 core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala delete mode 100644 core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala diff --git a/core/shared/src/main/scala-2.x/monocle/syntax/FocusSyntax.scala b/core/shared/src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala similarity index 100% rename from core/shared/src/main/scala-2.x/monocle/syntax/FocusSyntax.scala rename to core/shared/src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala diff --git a/core/shared/src/main/scala-3.x/monocle/Focus.scala b/core/shared/src/main/scala-3.x/monocle/Focus.scala index 5d89f0343..0aa2d5a79 100644 --- a/core/shared/src/main/scala-3.x/monocle/Focus.scala +++ b/core/shared/src/main/scala-3.x/monocle/Focus.scala @@ -1,41 +1,27 @@ package monocle -<<<<<<< HEAD +import monocle.syntax.AppliedFocusSyntax +import monocle.function.Each +import monocle.internal.focus.FocusImpl import monocle.function.Each -import monocle.internal.focus.{FocusImpl, AppliedFocusImpl} -import monocle.syntax.FocusSyntax -======= -import monocle.internal.focus.{FocusImpl, AppliedFocusImpl, InFocus} ->>>>>>> Use a dummy trait to restrict Focus actions within a context. -object Focus { +object Focus extends AppliedFocusSyntax { -<<<<<<< HEAD - extension [From, To] (from: From) - transparent inline def focus(inline lambda: (InFocus ?=> From => To)): Any = -======= - extension [From, To] (from: From) - transparent inline def focus(inline lambda: (FocusSyntax ?=> From => To)): Any = ->>>>>>> Having our cake and eating it - ${AppliedFocusImpl[From, To]('from, 'lambda)} + sealed trait MagicKeywords { + extension [CastTo] (from: Any) + def as: CastTo = scala.sys.error("Extension method 'as[CastTo]' should only be used within the monocle.Focus macro.") -<<<<<<< HEAD -======= - extension [CastTo] (from: Any)(using InFocus) - def as: CastTo = scala.sys.error("Extension method 'as[CastTo]' should only be used within the monocle.Focus macro.") + extension [A] (opt: Option[A]) + def some: A = scala.sys.error("Extension method 'some' should only be used within the monocle.Focus macro.") - extension [A] (opt: Option[A])(using InFocus) - def some: A = scala.sys.error("Extension method 'some' should only be used within the monocle.Focus macro.") + extension [From, To] (from: From)(using Each[From, To]) + def each: To = scala.sys.error("Extension method 'each' should only be used within the monocle.Focus macro.") + } ->>>>>>> Use a dummy trait to restrict Focus actions within a context. def apply[S] = new MkFocus[S] class MkFocus[From] { -<<<<<<< HEAD - transparent inline def apply[To](inline lambda: (InFocus ?=> From => To)): Any = -======= - transparent inline def apply[To](inline lambda: (FocusSyntax ?=> From => To)): Any = ->>>>>>> Having our cake and eating it + transparent inline def apply[To](inline lambda: (MagicKeywords ?=> From => To)): Any = ${ FocusImpl('lambda) } } } diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala index 07947fbc7..56bda3485 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala @@ -1,21 +1,23 @@ package monocle.internal.focus -import monocle.syntax.FocusSyntax -import monocle.{Focus, Lens, Iso, Prism, Optional} +import monocle.{Focus, Lens, Iso, Prism, Optional, Traversal } +import monocle.syntax.{ApplyLens, ApplyPrism, ApplyIso, ApplyOptional, ApplyTraversal } import scala.quoted.{Type, Expr, Quotes, quotes} private[monocle] object AppliedFocusImpl { - def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[FocusSyntax ?=> From => To])(using Quotes): Expr[Any] = { + def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[Focus.MagicKeywords ?=> From => To])(using Quotes): Expr[Any] = { + import quotes.reflect._ val generatedOptic = FocusImpl(lambda) generatedOptic.asTerm.tpe.asType match { - case '[Lens[f, t]] => '{ _root_.monocle.syntax.ApplyLens[From, From, To, To]($from, ${generatedOptic.asExprOf[Lens[From,To]]}) } - case '[Prism[f, t]] => '{ _root_.monocle.syntax.ApplyPrism[From, From, To, To]($from, ${generatedOptic.asExprOf[Prism[From,To]]}) } - case '[Iso[f, t]] => '{ _root_.monocle.syntax.ApplyIso[From, From, To, To]($from, ${generatedOptic.asExprOf[Iso[From,To]]}) } - case '[Optional[f, t]] => '{ _root_.monocle.syntax.ApplyOptional[From, From, To, To]($from, ${generatedOptic.asExprOf[Optional[From,To]]}) } + case '[Lens[f, t]] => '{ ApplyLens[From, From, To, To]($from, ${generatedOptic.asExprOf[Lens[From,To]]}) } + case '[Prism[f, t]] => '{ ApplyPrism[From, From, To, To]($from, ${generatedOptic.asExprOf[Prism[From,To]]}) } + case '[Iso[f, t]] => '{ ApplyIso[From, From, To, To]($from, ${generatedOptic.asExprOf[Iso[From,To]]}) } + case '[Optional[f, t]] => '{ ApplyOptional[From, From, To, To]($from, ${generatedOptic.asExprOf[Optional[From,To]]}) } + case '[Traversal[f, t]] => '{ ApplyTraversal[From, From, To, To]($from, ${generatedOptic.asExprOf[Traversal[From,To]]}) } } } } diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala index 77ddd3e0a..4e7c0d366 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala @@ -6,8 +6,9 @@ private[focus] trait ErrorHandling { def errorMessage(error: FocusError): String = error match { case FocusError.NotACaseClass(fromClass, fieldName) => s"Cannot generate Lens for field '$fieldName', because '$fromClass' is not a case class" case FocusError.NotAConcreteClass(fromClass) => s"Expecting a concrete case class in the 'From' position; cannot reify type $fromClass" - case FocusError.NotASimpleLambdaFunction => s"Expecting a lambda function that directly accesses a field. Example: `GenLens[Address](_.streetNumber)`" - case FocusError.DidNotDirectlyAccessArgument(argName) => s"Expecting a lambda function that directly accesses the argument; other variable `$argName` found. Example: `GenLens[Address](_.streetNumber)`" + case FocusError.NotASimpleLambdaFunction => s"Expecting a lambda function that directly accesses a field. Example: `Focus[Address](_.streetNumber)`" + case FocusError.CouldntRemoveMagicKeywords => s"Internal error in monocle.Focus; cannot access special syntax." + case FocusError.DidNotDirectlyAccessArgument(argName) => s"Expecting a lambda function that directly accesses the argument; other variable `$argName` found. Example: `Focus[Address](_.streetNumber)`" case FocusError.ComposeMismatch(type1, type2) => s"Could not compose $type1.andThen($type2)" case FocusError.UnexpectedCodeStructure(code) => s"Unexpected code structure: $code" case FocusError.CouldntFindFieldType(fromType, fieldName) => s"Couldn't find type for $fromType.$fieldName" diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala index 357d630e2..ed782a6c8 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala @@ -10,6 +10,8 @@ private[focus] trait FocusBase { type Term = macroContext.reflect.Term type TypeRepr = macroContext.reflect.TypeRepr + case class LambdaConfig(argName: String, lambdaBody: Term) + enum FocusAction { case FieldSelect(name: String, fromType: TypeRepr, fromTypeArgs: List[TypeRepr], toType: TypeRepr) case OptionSome(toType: TypeRepr) @@ -29,6 +31,7 @@ private[focus] trait FocusBase { case NotAConcreteClass(className: String) case DidNotDirectlyAccessArgument(argName: String) case NotASimpleLambdaFunction + case CouldntRemoveMagicKeywords case UnexpectedCodeStructure(code: String) case CouldntFindFieldType(fromType: String, fieldName: String) case ComposeMismatch(type1: String, type2: String) @@ -39,7 +42,18 @@ private[focus] trait FocusBase { trait FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] + + object FocusKeyword { + import macroContext.reflect._ + + def unapply(term: Term): Option[String] = term match { + case Select(_, keyword) => Some(keyword) + case _ => None + } + } } + + type FocusResult[+A] = Either[FocusError, A] } \ No newline at end of file diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala index 4355b3b5d..d07fefc1a 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala @@ -1,24 +1,25 @@ package monocle.internal.focus -import monocle.syntax.FocusSyntax -import monocle.Lens +import monocle.{Lens, Focus} import scala.quoted.{Type, Expr, Quotes, quotes} private[focus] class FocusImpl(val macroContext: Quotes) extends FocusBase with ErrorHandling - with ParserLoop with AllParsers - with GeneratorLoop with AllGenerators { + with LambdaConfigParser + with ParserLoop with AllFeatureParsers + with GeneratorLoop with AllFeatureGenerators { import macroContext.reflect._ - def run[From: Type, To: Type](lambda: Expr[From => To]): Expr[Any] = { - val parseResult: FocusResult[List[FocusAction]] = - parseLambda[From](lambda.asTerm) - - val generatedCode: FocusResult[Term] = - parseResult.flatMap(generateCode[From]) - + def run[From: Type, To: Type](lambda: Expr[Focus.MagicKeywords ?=> From => To]): Expr[Any] = { + val generatedCode = + for { + config <- parseLambdaConfig[From](lambda.asTerm) + focusActions <- parseFocusActions(config) + code <- generateCode[From](focusActions) + } yield code + generatedCode match { case Right(code) => code.asExpr case Left(error) => report.error(errorMessage(error)); '{???} @@ -26,12 +27,7 @@ private[focus] class FocusImpl(val macroContext: Quotes) } } - private[monocle] object FocusImpl { - def apply[From: Type, To: Type](contextExpr: Expr[FocusSyntax ?=> From => To])(using Quotes): Expr[Any] = { - InFocus.stripContext[From, To](contextExpr) match { - case Some(lambda) => new FocusImpl(quotes).run(lambda) - case _ => sys.error("Unexpected code structure ${contextExpr.show}") - } - } -} + def apply[From: Type, To: Type](lambda: Expr[Focus.MagicKeywords ?=> From => To])(using Quotes): Expr[Any] = + new FocusImpl(quotes).run(lambda) +} \ No newline at end of file diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/GeneratorLoop.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/GeneratorLoop.scala index 342d11d51..ca8701288 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/GeneratorLoop.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/GeneratorLoop.scala @@ -8,7 +8,7 @@ import monocle.{Lens, Iso, Prism, Optional, Traversal} import scala.quoted.Type -private[focus] trait AllGenerators +private[focus] trait AllFeatureGenerators extends FocusBase with FieldSelectGenerator with OptionSomeGenerator @@ -16,7 +16,7 @@ private[focus] trait AllGenerators with EachGenerator private[focus] trait GeneratorLoop { - this: FocusBase with AllGenerators => + this: FocusBase with AllFeatureGenerators => import macroContext.reflect._ diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala deleted file mode 100644 index affc88716..000000000 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/InFocus.scala +++ /dev/null @@ -1,19 +0,0 @@ -package monocle.internal.focus - -import monocle.syntax.FocusSyntax -import scala.quoted.{Quotes, Type, Expr} -import scala.annotation.implicitNotFound - -private[focus] object InFocus { - def stripContext[From : Type, To: Type]( - contextExpr: Expr[FocusSyntax ?=> From => To] - )(using macroContext: Quotes): Option[Expr[From => To]] = { - import macroContext.reflect._ - // Ideally, a quasi-quote match would be best, but it doesn't work currently for certain cases. - contextExpr.asTerm match { - case Inlined(_, _, Block(List(DefDef(_, _, _, _, Some(lambdaExpr))), _)) => - Some(lambdaExpr.asExprOf[From => To]) - case _ => None - } - } -} diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala new file mode 100644 index 000000000..149fc64f6 --- /dev/null +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala @@ -0,0 +1,43 @@ +package monocle.internal.focus + +import scala.quoted.Type + +private[focus] trait LambdaConfigParser { + this: FocusBase => + + import macroContext.reflect._ + + def parseLambdaConfig[From: Type](lambda: Term): FocusResult[LambdaConfig] = { + val fromTypeIsConcrete = TypeRepr.of[From].classSymbol.isDefined + + lambda match { + case WithMagicKeywords(ExpectedLambdaFunction(config)) if fromTypeIsConcrete => Right(config) + case WithMagicKeywords(ExpectedLambdaFunction(_)) => FocusError.NotAConcreteClass(Type.show[Type[From]]).asResult + case WithMagicKeywords(_) => FocusError.NotASimpleLambdaFunction.asResult + case _ => FocusError.CouldntRemoveMagicKeywords.asResult + } + } + + private object WithMagicKeywords { + def unapply(lambdaWithMagic: Term): Option[Term] = unwrap(lambdaWithMagic) match { + case Block(List(DefDef(_, _, _, _, Some(magicFreeLambda))), _) => Some(magicFreeLambda) + case _ => None + } + } + + private def unwrap(term: Term): Term = { + term match { + case Block(List(), inner) => unwrap(inner) + case Inlined(_, _, inner) => unwrap(inner) + case x => x + } + } + + private object ExpectedLambdaFunction { + def unapply(term: Term): Option[LambdaConfig] = + unwrap(term) match { + case Lambda(List(ValDef(argName, _, _)), body) => Some(LambdaConfig(argName, body)) + case _ => None + } + } +} \ No newline at end of file diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/ParserLoop.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/ParserLoop.scala index 900ec68b1..90327de1d 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/ParserLoop.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/ParserLoop.scala @@ -6,7 +6,7 @@ import monocle.internal.focus.features.optionsome.OptionSomeParser import monocle.internal.focus.features.castas.CastAsParser import monocle.internal.focus.features.each.EachParser -private[focus] trait AllParsers +private[focus] trait AllFeatureParsers extends FocusBase with FieldSelectParser with OptionSomeParser @@ -14,34 +14,15 @@ private[focus] trait AllParsers with EachParser private[focus] trait ParserLoop { - this: FocusBase with AllParsers => + this: FocusBase with AllFeatureParsers => import macroContext.reflect._ - - def parseLambda[From: Type](lambda: Term): FocusResult[List[FocusAction]] = { - val fromTypeIsConcrete = TypeRepr.of[From].classSymbol.isDefined - lambda match { - case ExpectedLambdaFunction(params) if fromTypeIsConcrete => parseLambdaBody(params) - case ExpectedLambdaFunction(_) => FocusError.NotASimpleLambdaFunction.asResult - case _ => FocusError.NotAConcreteClass(Type.show[Type[From]]).asResult - } - } - - private case class ParseParams(argName: String, argType: TypeRepr, lambdaBody: Term) - - private object LambdaArgument { - def unapply(term: Term): Option[String] = term match { - case Ident(idName) => Some(idName) - case _ => None - } - } - - private def parseLambdaBody(params: ParseParams): FocusResult[List[FocusAction]] = { + def parseFocusActions(config: LambdaConfig): FocusResult[List[FocusAction]] = { def loop(remainingBody: Term, listSoFar: List[FocusAction]): FocusResult[List[FocusAction]] = { remainingBody match { - case LambdaArgument(idName) if idName == params.argName => Right(listSoFar) + case LambdaArgument(idName) if idName == config.argName => Right(listSoFar) case LambdaArgument(idName) => FocusError.DidNotDirectlyAccessArgument(idName).asResult case OptionSome(Right(remainingCode, action)) => loop(remainingCode, action :: listSoFar) @@ -59,22 +40,14 @@ private[focus] trait ParserLoop { case unexpected => FocusError.UnexpectedCodeStructure(unexpected.toString).asResult } } - loop(params.lambdaBody, Nil) + loop(config.lambdaBody, Nil) } - - private def unwrap(term: Term): Term = { - term match { - case Block(List(), inner) => unwrap(inner) - case Inlined(_, _, inner) => unwrap(inner) - case x => x + + private object LambdaArgument { + def unapply(term: Term): Option[String] = term match { + case Ident(idName) => Some(idName) + case _ => None } } - private object ExpectedLambdaFunction { - def unapply(term: Term): Option[ParseParams] = - unwrap(term) match { - case Lambda(List(ValDef(argName, typeTree, _)), body) => Some(ParseParams(argName, typeTree.tpe, body)) - case _ => None - } - } } \ No newline at end of file diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala index 488570032..926be5b65 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/castas/CastAsParser.scala @@ -10,7 +10,7 @@ private[focus] trait CastAsParser { object CastAs extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(TypeApply(Select(_, "as"), List(typeArg)), List(remainingCode)) => + case Apply(TypeApply(FocusKeyword("as"), List(typeArg)), List(remainingCode)) => val fromType = remainingCode.tpe.widen val toType = typeArg.tpe diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/each/EachParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/each/EachParser.scala index 26533c238..21350b25d 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/each/EachParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/each/EachParser.scala @@ -10,7 +10,7 @@ private[focus] trait EachParser { object Each extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(Apply(TypeApply(Ident("each"), List(_, toTypeTree)), List(remainingCode)), List(eachInstance)) => + case Apply(Apply(TypeApply(FocusKeyword("each"), List(_, toTypeTree)), List(remainingCode)), List(eachInstance)) => val fromType = remainingCode.tpe.widen val toType = toTypeTree.tpe val action = FocusAction.Each(fromType, toType, eachInstance) diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala index cdfbe8534..d8e7d59c4 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/features/optionsome/OptionSomeParser.scala @@ -10,7 +10,7 @@ private[focus] trait OptionSomeParser { object OptionSome extends FocusParser { def unapply(term: Term): Option[FocusResult[(Term, FocusAction)]] = term match { - case Apply(TypeApply(Select(_, "some"), List(typeArg)), List(remainingCode)) => + case Apply(TypeApply(FocusKeyword("some"), List(typeArg)), List(remainingCode)) => val toType = typeArg.tpe val action = FocusAction.OptionSome(toType) Some(Right(remainingCode, action)) diff --git a/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala b/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala new file mode 100644 index 000000000..d0c41f74f --- /dev/null +++ b/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala @@ -0,0 +1,11 @@ +package monocle.syntax + +import monocle.Focus +import monocle.internal.focus.AppliedFocusImpl + +trait AppliedFocusSyntax { + + extension [From, To] (from: From) + transparent inline def focus(inline lambda: (Focus.MagicKeywords ?=> From => To)): Any = + ${AppliedFocusImpl[From, To]('from, 'lambda)} +} diff --git a/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala b/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala deleted file mode 100644 index 25d0ebdd2..000000000 --- a/core/shared/src/main/scala-3.x/monocle/syntax/FocusSyntax.scala +++ /dev/null @@ -1,18 +0,0 @@ -package monocle.syntax - -<<<<<<< HEAD -import monocle.function.Each - -trait FocusSyntax { -======= -sealed trait FocusSyntax { ->>>>>>> Having our cake and eating it - extension [CastTo] (from: Any) - def as: CastTo = scala.sys.error("Extension method 'as[CastTo]' should only be used within the monocle.Focus macro.") - - extension [A] (opt: Option[A]) - def some: A = scala.sys.error("Extension method 'some' should only be used within the monocle.Focus macro.") - - extension [From, To] (from: From)(using Each[From, To]) - def each: To = scala.sys.error("Extension method 'each' should only be used within the monocle.Focus macro.") -} From 866d7852a36beaeca47048a0a8b540da4ace7e2d Mon Sep 17 00:00:00 2001 From: Ken Scambler Date: Fri, 19 Feb 2021 01:51:26 +1100 Subject: [PATCH 4/5] Buzzkill renaming of MagicKeywords to KeywordContext --- core/shared/src/main/scala-3.x/monocle/Focus.scala | 4 ++-- .../monocle/internal/focus/AppliedFocusImpl.scala | 2 +- .../monocle/internal/focus/ErrorHandling.scala | 2 +- .../scala-3.x/monocle/internal/focus/FocusBase.scala | 2 +- .../scala-3.x/monocle/internal/focus/FocusImpl.scala | 4 ++-- .../monocle/internal/focus/LambdaConfigParser.scala | 10 +++++----- .../scala-3.x/monocle/syntax/AppliedFocusSyntax.scala | 2 +- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/shared/src/main/scala-3.x/monocle/Focus.scala b/core/shared/src/main/scala-3.x/monocle/Focus.scala index 0aa2d5a79..4e39bd439 100644 --- a/core/shared/src/main/scala-3.x/monocle/Focus.scala +++ b/core/shared/src/main/scala-3.x/monocle/Focus.scala @@ -7,7 +7,7 @@ import monocle.function.Each object Focus extends AppliedFocusSyntax { - sealed trait MagicKeywords { + sealed trait KeywordContext { extension [CastTo] (from: Any) def as: CastTo = scala.sys.error("Extension method 'as[CastTo]' should only be used within the monocle.Focus macro.") @@ -21,7 +21,7 @@ object Focus extends AppliedFocusSyntax { def apply[S] = new MkFocus[S] class MkFocus[From] { - transparent inline def apply[To](inline lambda: (MagicKeywords ?=> From => To)): Any = + transparent inline def apply[To](inline lambda: (KeywordContext ?=> From => To)): Any = ${ FocusImpl('lambda) } } } diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala index 56bda3485..4ac2f77f7 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/AppliedFocusImpl.scala @@ -6,7 +6,7 @@ import scala.quoted.{Type, Expr, Quotes, quotes} private[monocle] object AppliedFocusImpl { - def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[Focus.MagicKeywords ?=> From => To])(using Quotes): Expr[Any] = { + def apply[From: Type, To: Type](from: Expr[From], lambda: Expr[Focus.KeywordContext ?=> From => To])(using Quotes): Expr[Any] = { import quotes.reflect._ diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala index 4e7c0d366..15ff5707d 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/ErrorHandling.scala @@ -7,7 +7,7 @@ private[focus] trait ErrorHandling { case FocusError.NotACaseClass(fromClass, fieldName) => s"Cannot generate Lens for field '$fieldName', because '$fromClass' is not a case class" case FocusError.NotAConcreteClass(fromClass) => s"Expecting a concrete case class in the 'From' position; cannot reify type $fromClass" case FocusError.NotASimpleLambdaFunction => s"Expecting a lambda function that directly accesses a field. Example: `Focus[Address](_.streetNumber)`" - case FocusError.CouldntRemoveMagicKeywords => s"Internal error in monocle.Focus; cannot access special syntax." + case FocusError.CouldntUnderstandKeywordContext => s"Internal error in monocle.Focus; cannot access special syntax." case FocusError.DidNotDirectlyAccessArgument(argName) => s"Expecting a lambda function that directly accesses the argument; other variable `$argName` found. Example: `Focus[Address](_.streetNumber)`" case FocusError.ComposeMismatch(type1, type2) => s"Could not compose $type1.andThen($type2)" case FocusError.UnexpectedCodeStructure(code) => s"Unexpected code structure: $code" diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala index ed782a6c8..293a93ed9 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusBase.scala @@ -31,7 +31,7 @@ private[focus] trait FocusBase { case NotAConcreteClass(className: String) case DidNotDirectlyAccessArgument(argName: String) case NotASimpleLambdaFunction - case CouldntRemoveMagicKeywords + case CouldntUnderstandKeywordContext case UnexpectedCodeStructure(code: String) case CouldntFindFieldType(fromType: String, fieldName: String) case ComposeMismatch(type1: String, type2: String) diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala index d07fefc1a..db5a6ec91 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/FocusImpl.scala @@ -12,7 +12,7 @@ private[focus] class FocusImpl(val macroContext: Quotes) import macroContext.reflect._ - def run[From: Type, To: Type](lambda: Expr[Focus.MagicKeywords ?=> From => To]): Expr[Any] = { + def run[From: Type, To: Type](lambda: Expr[Focus.KeywordContext ?=> From => To]): Expr[Any] = { val generatedCode = for { config <- parseLambdaConfig[From](lambda.asTerm) @@ -28,6 +28,6 @@ private[focus] class FocusImpl(val macroContext: Quotes) } private[monocle] object FocusImpl { - def apply[From: Type, To: Type](lambda: Expr[Focus.MagicKeywords ?=> From => To])(using Quotes): Expr[Any] = + def apply[From: Type, To: Type](lambda: Expr[Focus.KeywordContext ?=> From => To])(using Quotes): Expr[Any] = new FocusImpl(quotes).run(lambda) } \ No newline at end of file diff --git a/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala b/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala index 149fc64f6..36b5dfd66 100644 --- a/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala +++ b/core/shared/src/main/scala-3.x/monocle/internal/focus/LambdaConfigParser.scala @@ -11,14 +11,14 @@ private[focus] trait LambdaConfigParser { val fromTypeIsConcrete = TypeRepr.of[From].classSymbol.isDefined lambda match { - case WithMagicKeywords(ExpectedLambdaFunction(config)) if fromTypeIsConcrete => Right(config) - case WithMagicKeywords(ExpectedLambdaFunction(_)) => FocusError.NotAConcreteClass(Type.show[Type[From]]).asResult - case WithMagicKeywords(_) => FocusError.NotASimpleLambdaFunction.asResult - case _ => FocusError.CouldntRemoveMagicKeywords.asResult + case WithKeywordContext(ExpectedLambdaFunction(config)) if fromTypeIsConcrete => Right(config) + case WithKeywordContext(ExpectedLambdaFunction(_)) => FocusError.NotAConcreteClass(Type.show[Type[From]]).asResult + case WithKeywordContext(_) => FocusError.NotASimpleLambdaFunction.asResult + case _ => FocusError.CouldntUnderstandKeywordContext.asResult } } - private object WithMagicKeywords { + private object WithKeywordContext { def unapply(lambdaWithMagic: Term): Option[Term] = unwrap(lambdaWithMagic) match { case Block(List(DefDef(_, _, _, _, Some(magicFreeLambda))), _) => Some(magicFreeLambda) case _ => None diff --git a/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala b/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala index d0c41f74f..1cddf7e3e 100644 --- a/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala +++ b/core/shared/src/main/scala-3.x/monocle/syntax/AppliedFocusSyntax.scala @@ -6,6 +6,6 @@ import monocle.internal.focus.AppliedFocusImpl trait AppliedFocusSyntax { extension [From, To] (from: From) - transparent inline def focus(inline lambda: (Focus.MagicKeywords ?=> From => To)): Any = + transparent inline def focus(inline lambda: (Focus.KeywordContext ?=> From => To)): Any = ${AppliedFocusImpl[From, To]('from, 'lambda)} } From 6d62c43967cb179bf1ca95bd0bee7e59195afb83 Mon Sep 17 00:00:00 2001 From: Ken Scambler Date: Fri, 19 Feb 2021 02:12:51 +1100 Subject: [PATCH 5/5] Added AppliedFocusSyntax to syntax all --- .../src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala | 2 +- core/shared/src/main/scala/monocle/syntax/All.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/shared/src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala b/core/shared/src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala index b7e220f3e..d1e724b9e 100644 --- a/core/shared/src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala +++ b/core/shared/src/main/scala-2.x/monocle/syntax/AppliedFocusSyntax.scala @@ -1,3 +1,3 @@ package monocle.syntax -trait FocusSyntax +trait AppliedFocusSyntax diff --git a/core/shared/src/main/scala/monocle/syntax/All.scala b/core/shared/src/main/scala/monocle/syntax/All.scala index 5c619a6e9..c87a55c4d 100644 --- a/core/shared/src/main/scala/monocle/syntax/All.scala +++ b/core/shared/src/main/scala/monocle/syntax/All.scala @@ -2,4 +2,4 @@ package monocle.syntax object all extends Syntaxes -trait Syntaxes extends ApplySyntax with FieldsSyntax +trait Syntaxes extends ApplySyntax with AppliedFocusSyntax with FieldsSyntax