Skip to content

Commit

Permalink
Remove StackOverflowError catching, use explicit overflows instead (
Browse files Browse the repository at this point in the history
#144)

* Removed safeCall, but still support stack overflow prevention using overflows

* version bump on readme

* Reorder imports
  • Loading branch information
j-mie6 authored Jan 13, 2023
1 parent d947aba commit a78130a
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Parsley is a fast and modern parser combinator library for Scala based loosely o
Parsley is distributed on Maven Central, and can be added to your project via:

```scala
libraryDependencies += "com.github.j-mie6" %% "parsley" % "4.0.2"
libraryDependencies += "com.github.j-mie6" %% "parsley" % "4.0.4"
```

Documentation can be found [**here**](https://javadoc.io/doc/com.github.j-mie6/parsley_2.13/latest/index.html)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ private [deepembedding] object ContOps {
@inline def result[R, A, Cont[_, +_]](x: A)(implicit canWrap: ContOps[Cont]): Cont[R, A] = canWrap.wrap(x)
@inline def perform[Cont[_, +_], R](wrapped: Cont[R, R])(implicit canUnwrap: ContOps[Cont]): R = canUnwrap.unwrap(wrapped)
@inline def suspend[Cont[_, +_], R, A](x: =>Cont[R, A])(implicit ops: ContOps[Cont]): Cont[R, A] = ops.suspend(x)
type GenOps = ContOps[({type C[_, +_]})#C] // scalastyle:ignore structural.type
def safeCall[A](task: GenOps => A): A = {
try task(Id.ops.asInstanceOf[GenOps])
catch { case _: StackOverflowError => task(Cont.ops.asInstanceOf[GenOps]) }
}
// $COVERAGE-OFF$
def sequence[Cont[_, +_]: ContOps, R, A](mxs: List[Cont[R, A]]): Cont[R, List[A]] = mxs match {
case Nil => result(Nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ private [deepembedding] object ContOps {
@inline def result[R, A, Cont[_, +_]](x: A)(implicit canWrap: ContOps[Cont]): Cont[R, A] = canWrap.wrap(x)
@inline def perform[Cont[_, +_], R](wrapped: Cont[R, R])(implicit canUnwrap: ContOps[Cont]): R = canUnwrap.unwrap(wrapped)
@inline def suspend[Cont[_, +_], R, A](x: =>Cont[R, A])(implicit ops: ContOps[Cont]): Cont[R, A] = ops.suspend(x)
type GenOps = ContOps[({type C[_, +_]})#C]
def safeCall[A](task: GenOps => A): A = {
try task(Id.ops.asInstanceOf[GenOps])
catch { case _: StackOverflowError => task(Cont.ops.asInstanceOf[GenOps]) }
}
def sequence[Cont[_, +_]: ContOps, R, A](mxs: List[Cont[R, A]]): Cont[R, List[A]] = mxs match {
case Nil => result(Nil)
case mx :: mxs => for { x <- mx; xs <- sequence(mxs) } yield x :: xs
Expand Down
13 changes: 5 additions & 8 deletions parsley/shared/src/main/scala/parsley/Parsley.scala
Original file line number Diff line number Diff line change
Expand Up @@ -881,22 +881,20 @@ final class Parsley[+A] private [parsley] (private [parsley] val internal: front

// SPECIAL METHODS
// $COVERAGE-OFF$
/**
* Forces the compilation of a parser as opposed to the regular lazy evaluation.
/** Forces the compilation of a parser as opposed to the regular lazy evaluation.
*
* @group special
*/
def force(): Unit = internal.force()

/**
* Provides an indicator that this parser is likely to stack-overflow
/** Provides an indicator that this parser will likely stack-overflow and so a stack-safe
* construction should be used when "compiling" this parser.
*
* @group special
*/
def overflows(): Unit = internal.overflows()

/**
* Using this method signifies that the parser it is invoked on is impure and any optimisations which assume purity
/** Using this method signifies that the parser it is invoked on is impure and any optimisations which assume purity
* are disabled.
*
* @group special
Expand All @@ -908,8 +906,7 @@ final class Parsley[+A] private [parsley] (private [parsley] val internal: front
// $COVERAGE-ON$

// $COVERAGE-OFF$
/**
* This is an alias for `p.filter(pred)`. It is needed to support for-comprehension syntax with `if`s.
/** This is an alias for `p.filter(pred)`. It is needed to support for-comprehension syntax with `if`s.
*
* @since 4.0.0
* @see [[parsley.Parsley.filter `filter`]] for more information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import parsley.XAssert._
import parsley.exceptions.BadLazinessException
import parsley.registers.Reg

import parsley.internal.deepembedding.{Cont, ContOps}, ContOps.{safeCall, GenOps, perform, result, ContAdapter}
import parsley.internal.deepembedding.{Cont, ContOps, Id}, ContOps.{perform, result, ContAdapter}
import parsley.internal.deepembedding.backend, backend.StrictParsley
import parsley.internal.machine.instructions, instructions.Instr

Expand Down Expand Up @@ -91,17 +91,17 @@ private [parsley] abstract class LazyParsley[+A] private [deepembedding] {
final private var numRegsUsedByParent = -1

/** Computes the instructions associated with this parser as well as the number of
* registers it requires in a stack-safe way.
* registers it requires in a (possibly) stack-safe way.
*/
final private def computeInstrs: (Array[Instr], Int) = {
if (cps) computeInstrs(Cont.ops.asInstanceOf[GenOps]) else safeCall(computeInstrs(_))
if (cps) computeInstrs(Cont.ops) else computeInstrs(Id.ops)
}
/** Computes the instructions associated with this parser as well as the number of
* registers it requires within the context of a specific (unknown) monad.
*
* @param ops the instance for the monad to evaluate with
*/
final private def computeInstrs(ops: GenOps): (Array[Instr], Int) = pipeline(ops)
final private def computeInstrs[Cont[_, +_]](ops: ContOps[Cont]): (Array[Instr], Int) = pipeline(ops)

/** Performs the full end-to-end pipeline through both the frontend and the backend.
*
Expand Down

0 comments on commit a78130a

Please sign in to comment.