From 43d6a39a86afbf68c3aceeefce10ae6663610fff Mon Sep 17 00:00:00 2001 From: Jamie Willis Date: Mon, 14 Aug 2023 22:21:31 +0100 Subject: [PATCH] Removed `unsafe()` method, added Opaque combinator, does the same job but way better --- parsley/shared/src/main/scala/parsley/Parsley.scala | 5 +---- .../deepembedding/backend/PrimitiveEmbedding.scala | 8 ++++++++ .../deepembedding/backend/SequenceEmbedding.scala | 3 +-- .../internal/deepembedding/backend/StrictParsley.scala | 3 --- .../internal/deepembedding/frontend/LazyParsley.scala | 10 +++------- .../deepembedding/frontend/PrimitiveEmbedding.scala | 6 ++++++ 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/parsley/shared/src/main/scala/parsley/Parsley.scala b/parsley/shared/src/main/scala/parsley/Parsley.scala index adff1815d..7943164cc 100644 --- a/parsley/shared/src/main/scala/parsley/Parsley.scala +++ b/parsley/shared/src/main/scala/parsley/Parsley.scala @@ -921,10 +921,7 @@ final class Parsley[+A] private [parsley] (private [parsley] val internal: front * * @group special */ - def unsafe(): Parsley[A] = { - internal.unsafe() - this - } + def unsafe(): Parsley[A] = new Parsley(new frontend.Opaque(this.internal)) // $COVERAGE-ON$ // $COVERAGE-OFF$ diff --git a/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/PrimitiveEmbedding.scala b/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/PrimitiveEmbedding.scala index 4c4154ec9..78db7bd22 100644 --- a/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/PrimitiveEmbedding.scala +++ b/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/PrimitiveEmbedding.scala @@ -77,6 +77,14 @@ private [deepembedding] final class Let[A](val p: StrictParsley[A]) extends Stri def pretty: String = this.toString // $COVERAGE-ON$ } +private [deepembedding] final class Opaque[A](p: StrictParsley[A]) extends StrictParsley[A] { + def inlinable = p.inlinable + override def codeGen[M[_, +_]: ContOps, R](implicit instrs: InstrBuffer, state: CodeGenState): M[R,Unit] = p.codeGen + // $COVERAGE-OFF$ + def pretty: String = p.pretty + // $COVERAGE-ON$ +} + private [deepembedding] final class Put[S](reg: Reg[S], val p: StrictParsley[S]) extends Unary[S, Unit] { override def codeGen[M[_, +_]: ContOps, R](implicit instrs: InstrBuffer, state: CodeGenState): M[R, Unit] = { suspend(p.codeGen[M, R]) |> diff --git a/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/SequenceEmbedding.scala b/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/SequenceEmbedding.scala index 9a9a43c94..47a55985e 100644 --- a/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/SequenceEmbedding.scala +++ b/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/SequenceEmbedding.scala @@ -19,10 +19,9 @@ import StrictParsley.InstrBuffer private [deepembedding] final class <*>[A, B](var left: StrictParsley[A => B], var right: StrictParsley[A]) extends StrictParsley[B] { def inlinable: Boolean = false // TODO: Refactor - // FIXME: Needs more interation with .safe override def optimise: StrictParsley[B] = (left, right) match { // Fusion laws - case (uf, ux@Pure(x)) if (uf.isInstanceOf[Pure[_]] || uf.isInstanceOf[_ <*> _]) && uf.safe && ux.safe => uf match { + case (uf, Pure(x)) if (uf.isInstanceOf[Pure[_]] || uf.isInstanceOf[_ <*> _]) => uf match { // first position fusion case Pure(f) => new Pure(f(x)) // second position fusion diff --git a/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/StrictParsley.scala b/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/StrictParsley.scala index f454d6190..e39626608 100644 --- a/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/StrictParsley.scala +++ b/parsley/shared/src/main/scala/parsley/internal/deepembedding/backend/StrictParsley.scala @@ -82,9 +82,6 @@ private [deepembedding] trait StrictParsley[+A] { */ private [deepembedding] def inlinable: Boolean - /** Is this combinator known to be pure? */ - final private [deepembedding] var safe = true - // $COVERAGE-OFF$ /** Pretty-prints a combinator tree, for internal debugging purposes only. */ private [deepembedding] def pretty: String diff --git a/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/LazyParsley.scala b/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/LazyParsley.scala index 9ae97ea6c..cf3722326 100644 --- a/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/LazyParsley.scala +++ b/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/LazyParsley.scala @@ -27,8 +27,9 @@ import parsley.internal.machine.instructions, instructions.Instr private [parsley] abstract class LazyParsley[+A] private [deepembedding] { // Public API // $COVERAGE-OFF$ + // TODO: remove in 5.0 /** Denotes this parser is unsafe, which will disable certain law-based optimisations that assume purity. */ - private [parsley] final def unsafe(): Unit = sSafe = false + private [parsley] final def unsafe(): Unit = () /** Force the parser, which eagerly computes its instructions immediately */ private [parsley] final def force(): Unit = instrs: @nowarn /** Denote that this parser is large enough that it might stack-overflow during @@ -82,8 +83,6 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] { */ protected def preprocess[M[_, +_]: ContOps, R, A_ >: A](implicit lets: LetMap, recs: RecMap): M[R, StrictParsley[A_]] - /** should the underlying strict tree be considered safe? */ - final private var sSafe = true /** should the `Id` instance be skipped? */ final private var cps = false /** how many registers are used by the ''parent'' of this combinator (this combinator is part of a `flatMap` when this is not -1) */ @@ -181,10 +180,7 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] { } /** Similar to `optimised` but does not check for inclusion in the `lets` or `recs` sets. */ private def unsafeOptimised[M[_, +_]: ContOps, R, A_ >: A](implicit lets: LetMap, recs: RecMap): M[R, StrictParsley[A_]] = { - for {p <- this.preprocess} yield { - p.safe = this.sSafe - p.optimise - } + for { p <- this.preprocess } yield p.optimise } // Processing with visitors. diff --git a/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/PrimitiveEmbedding.scala b/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/PrimitiveEmbedding.scala index 5abff9ba2..cc9290722 100644 --- a/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/PrimitiveEmbedding.scala +++ b/parsley/shared/src/main/scala/parsley/internal/deepembedding/frontend/PrimitiveEmbedding.scala @@ -48,4 +48,10 @@ private [parsley] final class DebugError[A](p: LazyParsley[A], name: String, asc override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, name, ascii, errBuilder) } + +private [parsley] final class Opaque[A](p: LazyParsley[A]) extends Unary[A, A](p) { + override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Opaque(p) + + override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = p.visit(visitor, context) +} // $COVERAGE-ON$