diff --git a/build.sbt b/build.sbt index e9e074867..b32e8e4a9 100644 --- a/build.sbt +++ b/build.sbt @@ -78,22 +78,6 @@ lazy val parsley = crossProject(JSPlatform, JVMPlatform, NativePlatform) Compile / doc / scalacOptions ++= Seq("-doc-root-content", s"${baseDirectory.value.getPath}/rootdoc.md"), ) -lazy val docs = project - .in(file("site")) - .dependsOn(parsley.jvm) - .enablePlugins(ParsleySitePlugin) - .settings( - tlSiteApiModule := Some((parsley.jvm / projectID).value), - libraryDependencySchemes ++= Seq( - // this helps us when parsley-cats is trailing behind us - "com.github.j-mie6" %% "parsley" % VersionScheme.Always, - ), - libraryDependencies ++= Seq( - "org.typelevel" %% "cats-core" % "2.10.0", - "com.github.j-mie6" %% "parsley-cats" % "1.3.0" - ), - ) - lazy val parsleyDebug = crossProject(JSPlatform, JVMPlatform, NativePlatform) .withoutSuffixFor(JVMPlatform) .crossType(CrossType.Full) @@ -128,6 +112,22 @@ lazy val parsleyDebug = crossProject(JSPlatform, JVMPlatform, NativePlatform) ), ) +lazy val docs = project + .in(file("site")) + .dependsOn(parsley.jvm) + .enablePlugins(ParsleySitePlugin) + .settings( + tlSiteApiModule := Some((parsley.jvm / projectID).value), + libraryDependencySchemes ++= Seq( + // this helps us when parsley-cats is trailing behind us + "com.github.j-mie6" %% "parsley" % VersionScheme.Always, + ), + libraryDependencies ++= Seq( + "org.typelevel" %% "cats-core" % "2.10.0", + "com.github.j-mie6" %% "parsley-cats" % "1.3.0" + ), + ) + def testCoverageJob(cacheSteps: List[WorkflowStep]) = WorkflowJob( id = "coverage", name = "Run Test Coverage and Upload", diff --git a/parsley-debug/shared/src/main/scala-2/parsley/debuggable.scala b/parsley-debug/shared/src/main/scala-2/parsley/debuggable.scala index 403eae5a1..494532c90 100644 --- a/parsley-debug/shared/src/main/scala-2/parsley/debuggable.scala +++ b/parsley-debug/shared/src/main/scala-2/parsley/debuggable.scala @@ -8,6 +8,18 @@ package parsley import scala.annotation.{StaticAnnotation, compileTimeOnly} import scala.reflect.macros.blackbox +/** This annotation can be applied to an object or class to record their + * names for the debugging/diagnostic combinators. + * + * @note BE WARNED: this annotation crashes the compiler for objects/classes nested within another type -- this is ok for Scala 3 + * @note It requires that the + * object/class is type-checkable, which due to Scala 2 macro limitations + * involes stripping away the enclosing type itself. This might lead to + * weird edge-cases: if parsley reports that type-checking failed, you + * should report this to the maintainers. + * + * @since 5.0.0 + */ @compileTimeOnly("macros need to be enabled to use this functionality: -Ymacro-annotations in 2.13, or use \"Macro Paradise\" for 2.12") class debuggable extends StaticAnnotation { def macroTransform(annottees: Any*): Any = macro debuggable.impl diff --git a/parsley-debug/shared/src/main/scala-3/parsley/debuggable.scala b/parsley-debug/shared/src/main/scala-3/parsley/debuggable.scala index e4d652788..6447f3f1a 100644 --- a/parsley-debug/shared/src/main/scala-3/parsley/debuggable.scala +++ b/parsley-debug/shared/src/main/scala-3/parsley/debuggable.scala @@ -8,6 +8,15 @@ package parsley import scala.annotation.{experimental, MacroAnnotation} import scala.quoted.* +/** This annotation can be applied to an object or class to record their + * names for the debugging/diagnostic combinators. + * + * @note Currently, macro-annotations in Scala 3 are experimental, which + * means the @experimental annotation will need to be used (or the global + * -experimental flag on 3.4+) to use this functionality. + * + * @since 5.0.0 + */ @experimental class debuggable extends MacroAnnotation { def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] = { import quotes.reflect.* diff --git a/parsley-debug/shared/src/main/scala/parsley/debugger/util/Collector.scala b/parsley-debug/shared/src/main/scala/parsley/debugger/util/Collector.scala index ad2e5de35..6c9664afe 100644 --- a/parsley-debug/shared/src/main/scala/parsley/debugger/util/Collector.scala +++ b/parsley-debug/shared/src/main/scala/parsley/debugger/util/Collector.scala @@ -5,6 +5,8 @@ */ package parsley.debugger.util +import scala.annotation.nowarn + import parsley.Parsley import parsley.debugger.internal.Renamer import parsley.token.Lexer @@ -30,6 +32,7 @@ object Collector { * be advised to manually name one's parsers (to be debugged) using [[assignName]] or * [[parsley.debugger.combinator.named]] if that warning is not desirable. */ + @deprecated("The functionality of this class has been subsumed by the `parsley.debuggable` annotation", "5.0.0-M7") def names(obj: Any): Unit = { collectDefault() // Runs only once, ever, for a program execution. Renamer.addNames(XCollector.collectNames(obj)) @@ -47,6 +50,7 @@ object Collector { * being deprecated. * @see [[names]] for more information regarding the warning. */ + //@deprecated("This functionality has been absorbed into parsley itself", "5.0.0-M7") def lexer(lexer: Lexer): Unit = { collectDefault() Renamer.addNames(XCollector.collectLexer(lexer)) @@ -79,10 +83,10 @@ object Collector { if (!defaultCollected) { defaultCollected = true - names(parsley.character) - names(parsley.combinator) - names(parsley.Parsley) - names(parsley.position) + names(parsley.character): @nowarn + names(parsley.combinator): @nowarn + names(parsley.Parsley): @nowarn + names(parsley.position): @nowarn } } } diff --git a/parsley-debug/shared/src/test/scala/annotation/AnnotationTestObjects.scala b/parsley-debug/shared/src/test/scala/annotation/AnnotationTestObjects.scala index d0a8842e6..1b317a2a1 100644 --- a/parsley-debug/shared/src/test/scala/annotation/AnnotationTestObjects.scala +++ b/parsley-debug/shared/src/test/scala/annotation/AnnotationTestObjects.scala @@ -16,7 +16,7 @@ object otherParsers { @experimental @parsley.debuggable class parsers(val x: Int) { - val p = char('a') + val p = satisfy(_.isDigit) val q = p ~> p lazy val r: Parsley[Char] = ~r ~> q def s = otherParsers.a diff --git a/parsley-debug/shared/src/test/scala/parsley/debugger/DebuggerUsageSpec.scala b/parsley-debug/shared/src/test/scala/parsley/debugger/DebuggerUsageSpec.scala index cdc25e197..59bd0e145 100644 --- a/parsley-debug/shared/src/test/scala/parsley/debugger/DebuggerUsageSpec.scala +++ b/parsley-debug/shared/src/test/scala/parsley/debugger/DebuggerUsageSpec.scala @@ -5,8 +5,10 @@ */ package parsley.debugger +import scala.annotation.experimental + // scalastyle:off underscore.import -import DebuggerUsageSpec.Arithmetic +//import DebuggerUsageSpec.Arithmetic import org.typelevel.scalaccompat.annotation.unused import parsley.Parsley, Parsley._ import parsley.ParsleyTest @@ -18,6 +20,7 @@ import parsley.internal.deepembedding.frontend.debugger.TaggedWith import parsley.internal.deepembedding.backend.debugger.Debugging // scalastyle:on underscore.import +@experimental class DebuggerUsageSpec extends ParsleyTest { "the Debugged internal frontend class" should "not allow nesting of Debugged nodes" in { val factory = new Debugging(new DebugContext()) @@ -37,14 +40,14 @@ class DebuggerUsageSpec extends ParsleyTest { } "the debugger runtime" should "preserve the result of parsers" in { - val debugMath = attachDebugger(Arithmetic.prog) + val (_, debugMath) = attachDebugger(Arithmetic.prog) - debugMath._2.parse("1+1").get.head shouldBe 2 - debugMath._2.parse("2*3").get.head shouldBe 6 - debugMath._2.parse("9-4").get.head shouldBe 5 - debugMath._2.parse("6/2").get.head shouldBe 3 + debugMath.parse("1+1").get.head shouldBe 2 + debugMath.parse("2*3").get.head shouldBe 6 + debugMath.parse("9-4").get.head shouldBe 5 + debugMath.parse("6/2").get.head shouldBe 3 - debugMath._2.parse("1+2+3+4+5\n2*3*4").get shouldBe List(15, 24) // scalastyle:ignore magic.number + debugMath.parse("1+2+3+4+5\n2*3*4").get shouldBe List(15, 24) // scalastyle:ignore magic.number } it should "not cause references to be unallocated" in { @@ -87,28 +90,16 @@ class DebuggerUsageSpec extends ParsleyTest { } } -object DebuggerUsageSpec { +// Look, for some reason the annotation dies if it's nested, I don't know why, it's impossible to diagnose +//object DebuggerUsageSpec { + @experimental @parsley.debuggable private [parsley] object Arithmetic { - val int: Parsley[BigInt] = - satisfy(_.isDigit) - .foldLeft1(BigInt(0))((acc, c) => acc * 10 + c.asDigit) - + val int: Parsley[BigInt] = satisfy(_.isDigit).foldLeft1(BigInt(0))((acc, c) => acc * 10 + c.asDigit) lazy val expr: Parsley[BigInt] = - precedence[BigInt]( - int, - char('(') ~> expr <~ char(')') - )( - Ops(InfixL)( - char('*') #> (_ * _), - char('/') #> (_ / _) - ), - Ops(InfixL)( - char('+') #> (_ + _), - char('-') #> (_ - _) - ) + precedence[BigInt](int, char('(') ~> expr <~ char(')'))( + Ops(InfixL)(char('*') #> (_ * _), char('/') #> (_ / _)), + Ops(InfixL)(char('+') #> (_ + _), char('-') #> (_ - _)) ) - - lazy val prog: Parsley[List[BigInt]] = - many(many(satisfy("\r\n".contains(_))) ~> expr) + lazy val prog: Parsley[List[BigInt]] = many(many(satisfy("\r\n".contains(_))) ~> expr) } -} +//} diff --git a/parsley-debug/shared/src/test/scala/parsley/internal/deepembedding/RenameSpec.scala b/parsley-debug/shared/src/test/scala/parsley/internal/deepembedding/RenameSpec.scala index 21ac0c847..d1ca30ae9 100644 --- a/parsley-debug/shared/src/test/scala/parsley/internal/deepembedding/RenameSpec.scala +++ b/parsley-debug/shared/src/test/scala/parsley/internal/deepembedding/RenameSpec.scala @@ -5,9 +5,11 @@ */ package parsley.internal.deepembedding +import scala.annotation.experimental + import org.scalatest.Assertions.fail import parsley.ParsleyTest -import parsley.debugger.DebuggerUsageSpec +import parsley.debugger.Arithmetic import parsley.debugger.internal.{DebugContext, Renamer} import parsley.debugger.util.Collector import parsley.internal.deepembedding.backend.StrictParsley @@ -17,6 +19,7 @@ import parsley.token.Lexer import parsley.token.descriptions.LexicalDesc import parsley.internal.deepembedding.backend.debugger.Debugging +@experimental class RenameSpec extends ParsleyTest { "the Renamer object" should "not rename a parser it does not know of" in { val exampleParser = new DummyParser @@ -51,12 +54,12 @@ class RenameSpec extends ParsleyTest { "the Collector implementations" should "collect names of parsers from objects (on supported platforms)" in { if (Collector.isSupported) { - Collector.names(DebuggerUsageSpec.Arithmetic) - Renamer.nameOf(None, DebuggerUsageSpec.Arithmetic.prog.internal) shouldBe "prog" + //Collector.names(Arithmetic) + Renamer.nameOf(None, Arithmetic.prog.internal) shouldBe "prog" info("it should also allow overriding the name") - Collector.assignName(DebuggerUsageSpec.Arithmetic.prog, "foo") - Renamer.nameOf(None, DebuggerUsageSpec.Arithmetic.prog.internal) shouldBe "foo" + Collector.assignName(Arithmetic.prog, "foo") + Renamer.nameOf(None, Arithmetic.prog.internal) shouldBe "foo" } else alert("the current platform does not support Collector") } @@ -70,22 +73,22 @@ class RenameSpec extends ParsleyTest { } } -object RenameSpec { +object Utils { def crash(): Nothing = fail("Should not have been run.") } // These are dummy parsers used for the above tests. // We don't actually care that they don't implement anything. private class DummyParser extends LazyParsley[Any] { - override protected def findLetsAux[M[_, +_] : ContOps, R](seen: Set[LazyParsley[_]])(implicit state: LetFinderState): M[R, Unit] = RenameSpec.crash() - override protected def preprocess[M[_, +_] : ContOps, R, A_ >: Any](implicit lets: LetMap): M[R, StrictParsley[A_]] = RenameSpec.crash() + override protected def findLetsAux[M[_, +_] : ContOps, R](seen: Set[LazyParsley[_]])(implicit state: LetFinderState): M[R, Unit] = Utils.crash() + override protected def preprocess[M[_, +_] : ContOps, R, A_ >: Any](implicit lets: LetMap): M[R, StrictParsley[A_]] = Utils.crash() override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Any] = visitor.visitUnknown(this, context) override private [parsley] def prettyName = "dummyParser" } private class <**> extends LazyParsley[Any] { - override protected def findLetsAux[M[_, +_] : ContOps, R](seen: Set[LazyParsley[_]])(implicit state: LetFinderState): M[R, Unit] = RenameSpec.crash() - override protected def preprocess[M[_, +_] : ContOps, R, A_ >: Any](implicit lets: LetMap): M[R, StrictParsley[A_]] = RenameSpec.crash() + override protected def findLetsAux[M[_, +_] : ContOps, R](seen: Set[LazyParsley[_]])(implicit state: LetFinderState): M[R, Unit] = Utils.crash() + override protected def preprocess[M[_, +_] : ContOps, R, A_ >: Any](implicit lets: LetMap): M[R, StrictParsley[A_]] = Utils.crash() override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[Any] = visitor.visitUnknown(this, context) override private [parsley] def prettyName = "<**>" }