Skip to content

Commit

Permalink
refactor(debug)!: refactored backend classes to remove implementation…
Browse files Browse the repository at this point in the history
… details
  • Loading branch information
j-mie6 committed Dec 28, 2024
1 parent 233e38c commit d228dc1
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import parsley.debugger.DebugTree
import parsley.debugger.frontend.internal.consolepretty.*

private [frontend] sealed class ConsolePrettyPrinterImpl private[frontend] (ioF: String => Unit) extends ReusableFrontend {
override protected def processImpl(input: => String, tree: => DebugTree): Unit = {
override private [debugger] def process(input: => String, tree: => DebugTree): Unit = {
ioF(s"${tree.parserName}'s parse tree for input:\n\n$input\n\n")
ioF(tree.pretty + "\n")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,53 +26,39 @@ import parsley.debugger.internal.XIllegalStateException
* @since 4.5.0
*/
sealed trait DebugFrontend {
// Is this frontend stateful (and should only be able to run once)?
protected [frontend] val reusable: Boolean

// Tracks if this frontend has run already.
private var hasRun: Boolean = false

// This function localises the use of synchronized down to this expression only.
@inline private def hasBeenRun: Boolean = this.synchronized {
(reusable && hasRun) || { hasRun = true; false }
}

/** Process a debug tree using whatever the frontend is doing to present the tree in some way.
*
* @param input The full input of the parse.
* @param tree Debug tree to process.
*/
final def process(input: => String, tree: => DebugTree): Unit = {
if (hasBeenRun) {
// XXX: There isn't really another way to enforce not running a stateful frontend more than once that isn't just "do nothing".
// Especially since doing nothing turns that action into a silent error, which is generally less preferable to "loud"
// errors. Failing fast may be better for some frontends.
throw new XIllegalStateException("Stateful frontend has already been run.").except // scalastyle:ignore throw
} else {
processImpl(input, tree)
}
}

/** The actual method that does the processing of the tree.
* Override this to process a tree in a custom way.
*/
protected def processImpl(input: => String, tree: => DebugTree): Unit
private [debugger] def process(input: =>String, tree: => DebugTree): Unit
}

/** Signifies that the frontend inheriting from this can be used multiple times.
*
* @see [[DebugFrontend]]
* @since 4.5.0
*/
trait ReusableFrontend extends DebugFrontend {
override protected [frontend] final val reusable: Boolean = false
}
trait ReusableFrontend extends DebugFrontend

/** Signifies that the frontend inheriting from this can only be run once.
*
* @see [[DebugFrontend]]
* @since 4.5.0
*/
trait SingleUseFrontend extends DebugFrontend {
override protected [frontend] final val reusable: Boolean = true
private var hasBeenRun = false
final override private[debugger] def process(input: => String, tree: => DebugTree): Unit = {
if (hasBeenRun) {
// XXX: There isn't really another way to enforce not running a stateful frontend more than once that isn't just "do nothing".
// Especially since doing nothing turns that action into a silent error, which is generally less preferable to "loud"
// errors. Failing fast may be better for some frontends.
throw new XIllegalStateException("Stateful frontend has already been run.").except // scalastyle:ignore throw
} else {
processImpl(input, tree)
hasBeenRun = true
}
}
/** The implementation of the process method above */
private[debugger] def processImpl(input: => String, tree: => DebugTree): Unit
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ class ReuseSpec extends ParsleyTest {
it should "throw when run multiple times, only if the frontend is marked as single-use" in {
// Dummy values.
val reusable: ReusableFrontend = new ReusableFrontend {
override protected def processImpl(input: => String, tree: => DebugTree): Unit = ()
override private [debugger] def process(input: => String, tree: => DebugTree): Unit = ()
}

val singleUse: SingleUseFrontend = new SingleUseFrontend {
override protected def processImpl(input: => String, tree: => DebugTree): Unit = ()
override private [debugger] def processImpl(input: => String, tree: => DebugTree): Unit = ()
}

val tree: DebugTree = new DebugTree {
Expand Down

0 comments on commit d228dc1

Please sign in to comment.