diff --git a/parsley/shared/src/main/scala/parsley/internal/deepembedding/Cont.scala b/parsley/shared/src/main/scala/parsley/internal/deepembedding/Cont.scala index c58494586..4bba457c4 100644 --- a/parsley/shared/src/main/scala/parsley/internal/deepembedding/Cont.scala +++ b/parsley/shared/src/main/scala/parsley/internal/deepembedding/Cont.scala @@ -24,6 +24,7 @@ private [deepembedding] abstract class ContOps[Cont[_, +_]] { def map[R, A, B](c: Cont[R, A], f: A => B): Cont[R, B] def flatMap[R, A, B](c: Cont[R, A], f: A => Cont[R, B]): Cont[R, B] def suspend[R, A](x: =>Cont[R, A]): Cont[R, A] + def isStackSafe: Boolean // $COVERAGE-OFF$ // This needs to be lazy, because I'm an idiot when I use it def `then`[R, A, B](c: Cont[R, A], k: =>Cont[R, B]): Cont[R, B] = flatMap[R, A, B](c, _ => k) @@ -52,6 +53,7 @@ private [deepembedding] object Cont { override def flatMap[R, A, B](mx: Impl[R, A], f: A => Impl[R, B]): Impl[R, B] = k => new Thunk(() => mx(x => f(x)(k))) override def suspend[R, A](x: =>Impl[R, A]): Impl[R, A] = k => new Thunk(() => x(k)) override def `then`[R, A, B](mx: Impl[R, A], my: =>Impl[R, B]): Impl[R, B] = k => new Thunk(() => mx(_ => my(k))) + override def isStackSafe: Boolean = true } } @@ -64,5 +66,6 @@ private [deepembedding] object Id { override def flatMap[R, A, B](c: Impl[R, A], f: A => Impl[R, B]): Impl[R, B] = f(c) override def suspend[R, A](x: =>Impl[R, A]): Impl[R, A] = x override def as[R, A, B](c: Impl[R, A], x: =>B): Impl[R, B] = x + override def isStackSafe: Boolean = false } } 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 22ac2800f..dcc2bbe93 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 @@ -111,7 +111,12 @@ private [deepembedding] final class >>=[A, B](val p: StrictParsley[A], private [ } override def codeGen[M[_, +_]: ContOps, R](implicit instrs: InstrBuffer, state: CodeGenState): M[R, Unit] = { suspend(p.codeGen[M, R]) |> { - instrs += instructions.DynCall[A](x => f(x).demandCalleeSave(state.numRegs).instrs) + instrs += instructions.DynCall[A] { x => + val p = f(x) + p.demandCalleeSave(state.numRegs) + if (implicitly[ContOps[M]].isStackSafe) p.overflows() + p.instrs + } } } // $COVERAGE-OFF$ 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 5892d1d83..9ae97ea6c 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 @@ -46,10 +46,7 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] { * * @param numRegs the number of registers the parent uses (these must be saved) */ - private [deepembedding] def demandCalleeSave(numRegs: Int): this.type = { - numRegsUsedByParent = numRegs - this - } + private [deepembedding] def demandCalleeSave(numRegs: Int): Unit = numRegsUsedByParent = numRegs // Internals // To ensure that stack-overflow cannot occur during the processing of particularly