Skip to content

Commit

Permalink
Added register summary to debug combinators
Browse files Browse the repository at this point in the history
  • Loading branch information
j-mie6 committed Sep 9, 2023
1 parent 6e1370d commit 43c6905
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 20 deletions.
25 changes: 20 additions & 5 deletions parsley/shared/src/main/scala/parsley/debug.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package parsley

import parsley.errors.ErrorBuilder
import parsley.registers.Reg

import parsley.internal.deepembedding.frontend

Expand Down Expand Up @@ -117,9 +118,14 @@ object debug {
* @param name The name to be assigned to this parser
* @param break The breakpoint properties of this parser, defaults to NoBreak
* @param coloured Whether to render with colour (default true: render colours)
* @param watchedRegs Which registers to also track the values of and their names, if any
*/
def debug(name: String, break: Breakpoint, coloured: Boolean): Parsley[A] = {
new Parsley(new frontend.Debug[A](con(p).internal, name, !coloured, break))
def debug(name: String, break: Breakpoint, coloured: Boolean, watchedRegs: (Reg[_], String)*): Parsley[A] = {
new Parsley(new frontend.Debug[A](con(p).internal, name, !coloured, break, watchedRegs))
}

private [parsley] def debug(name: String, break: Breakpoint, coloured: Boolean): Parsley[A] = {
debug(name, break, coloured, Seq.empty[(Reg[_], String)]: _*)
}

/** $debug
Expand Down Expand Up @@ -153,8 +159,11 @@ object debug {
*
* @param name The name to be assigned to this parser
* @param break The breakpoint properties of this parser, defaults to NoBreak
* @param watchedRegs Which registers to also track the values of and their names, if any
*/
def debug(name: String, break: Breakpoint): Parsley[A] = debug(name, break, coloured = true)
def debug(name: String, break: Breakpoint, watchedRegs: (Reg[_], String)*): Parsley[A] = debug(name, break, coloured = true, watchedRegs: _*)

private [parsley] def debug(name: String, break: Breakpoint): Parsley[A] = debug(name, break, Seq.empty[(Reg[_], String)]: _*)

/** $debug
*
Expand Down Expand Up @@ -187,8 +196,11 @@ object debug {
*
* @param name The name to be assigned to this parser
* @param coloured Whether to render with colour
* @param watchedRegs Which registers to also track the values of and their names, if any
*/
def debug(name: String, coloured: Boolean): Parsley[A] = debug(name, break = NoBreak, coloured)
def debug(name: String, coloured: Boolean, watchedRegs: (Reg[_], String)*): Parsley[A] = debug(name, break = NoBreak, coloured, watchedRegs: _*)

private [parsley] def debug(name: String, coloured: Boolean): Parsley[A] = debug(name, coloured, Seq.empty[(Reg[_], String)]: _*)

/** $debug
*
Expand Down Expand Up @@ -220,8 +232,11 @@ object debug {
* Renders in colour with no break-point.
*
* @param name The name to be assigned to this parser
* @param watchedRegs Which registers to also track the values of and their names, if any
*/
def debug(name: String): Parsley[A] = debug(name, break = NoBreak, coloured = true)
def debug(name: String, watchedRegs: (Reg[_], String)*): Parsley[A] = debug(name, break = NoBreak, coloured = true, watchedRegs: _*)

private [parsley] def debug(name: String): Parsley[A] = debug(name, Seq.empty[(Reg[_], String)]: _*)

def debugError(name: String, coloured: Boolean)(implicit errBuilder: ErrorBuilder[_]): Parsley[A] = {
new Parsley(new frontend.DebugError[A](con(p).internal, name, !coloured, errBuilder))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,17 @@ private [deepembedding] final class Span(p: StrictParsley[_]) extends StrictPars
}

// $COVERAGE-OFF$
private [deepembedding] final class Debug[A](val p: StrictParsley[A], name: String, ascii: Boolean, break: Breakpoint) extends Unary[A, A] {
private [deepembedding] final class Debug[A](val p: StrictParsley[A], name: String, ascii: Boolean, break: Breakpoint, watchedRegs: scala.Seq[(Reg[_], String)])
extends Unary[A, A] {
override def codeGen[M[_, +_]: ContOps, R](producesResults: Boolean)(implicit instrs: InstrBuffer, state: CodeGenState): M[R, Unit] = {
val watchedAddrs = watchedRegs.map {
case (r, name) => (r.addr, name)
}
val handler = state.freshLabel()
instrs += new instructions.LogBegin(handler, name, ascii, (break eq EntryBreak) || (break eq FullBreak))
instrs += new instructions.LogBegin(handler, name, ascii, (break eq EntryBreak) || (break eq FullBreak), watchedAddrs)
suspend(p.codeGen[M, R](producesResults)) |> {
instrs += new instructions.Label(handler)
instrs += new instructions.LogEnd(name, ascii, (break eq ExitBreak) || (break eq FullBreak))
instrs += new instructions.LogEnd(name, ascii, (break eq ExitBreak) || (break eq FullBreak), watchedAddrs)
}
}
final override def pretty(p: String): String = p
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ private [parsley] final class Span(p: LazyParsley[_]) extends Unary[Any, String]
}

// $COVERAGE-OFF$
private [parsley] final class Debug[A](p: LazyParsley[A], name: String, ascii: Boolean, break: Breakpoint) extends Unary[A, A](p) {
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Debug(p, name, ascii, break)
private [parsley] final class Debug[A](p: LazyParsley[A], name: String, ascii: Boolean, break: Breakpoint, watchedRegs: Seq[(Reg[_], String)]) extends Unary[A, A](p) {
override def make(p: StrictParsley[A]): StrictParsley[A] = new backend.Debug(p, name, ascii, break, watchedRegs)

override def visit[T, U[+_]](visitor: LazyParsleyIVisitor[T, U], context: T): U[A] = visitor.visit(this, context)(p, name, ascii, break)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,16 @@ private [instructions] object InputSlicer {
}

private [instructions] trait Logger extends PrettyPortal with InputSlicer with Colours {
final protected def preludeString(dir: Direction, ctx: Context, ends: String) = {
final protected def preludeString(dir: Direction, ctx: Context, ends: String, watchedRegs: Seq[(Int, String)]) = {
val input = this.slice(ctx)
val prelude = s"${portal(dir, ctx)} (${ctx.line}, ${ctx.col}): "
val caret = (" " * prelude.length) + this.caret(ctx)
indentAndUnlines(ctx, s"$prelude$input$ends", caret)
val regSummary = if (watchedRegs.isEmpty) Seq.empty else {
"watched registers:" +: watchedRegs.map {
case (addr, name) => s" $name = ${ctx.regs(addr)}"
} :+ ""
}
indentAndUnlines(ctx, s"$prelude$input$ends" +: caret +: regSummary: _*)
}
final protected def doBreak(ctx: Context): Unit = {
print(indentAndUnlines(ctx,
Expand All @@ -94,11 +99,11 @@ private [instructions] trait Logger extends PrettyPortal with InputSlicer with C
}
}

private [internal] final class LogBegin(var label: Int, override val name: String, override val ascii: Boolean, break: Boolean)
private [internal] final class LogBegin(var label: Int, override val name: String, override val ascii: Boolean, break: Boolean, watchedRegs: Seq[(Int, String)])
extends InstrWithLabel with Logger {
override def apply(ctx: Context): Unit = {
ensureRegularInstruction(ctx)
println(preludeString(Enter, ctx, ""))
println(preludeString(Enter, ctx, "", watchedRegs))
if (break) doBreak(ctx)
ctx.debuglvl += 1
ctx.pushHandler(label)
Expand All @@ -107,7 +112,7 @@ private [internal] final class LogBegin(var label: Int, override val name: Strin
override def toString: String = s"LogBegin($label, $name)"
}

private [internal] final class LogEnd(val name: String, override val ascii: Boolean, break: Boolean) extends Instr with Logger {
private [internal] final class LogEnd(val name: String, override val ascii: Boolean, break: Boolean, watchedRegs: Seq[(Int, String)]) extends Instr with Logger {
override def apply(ctx: Context): Unit = {
assert(ctx.running, "cannot wrap a Halt with a debug")
ctx.debuglvl -= 1
Expand All @@ -122,7 +127,7 @@ private [internal] final class LogEnd(val name: String, override val ascii: Bool
red("Fail")
}
}
println(preludeString(Exit, ctx, end))
println(preludeString(Exit, ctx, end, watchedRegs))
if (break) doBreak(ctx)
}
override def toString: String = s"LogEnd($name)"
Expand Down
8 changes: 4 additions & 4 deletions parsley/shared/src/main/scala/parsley/registers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,8 @@ object registers {
*
* r.put(0) *>
* many('a' *> r.modify(_+1)) *>
* forYieldP_[Int](r.get, pure(_ != 0), pure(_ - 1)){_ => 'b'} *>
* forYieldP_[Int](r.get, pure(_ != 0), pure(_ - 1)){_ => 'c'}
* forYieldP_[Int, Char](r.get, pure(_ != 0), pure(_ - 1)){_ => 'b'} *>
* forYieldP_[Int, Char](r.get, pure(_ != 0), pure(_ - 1)){_ => 'c'}
* }}}
*
* This will return a list `n` `'c'` characters.
Expand Down Expand Up @@ -496,8 +496,8 @@ object registers {
*
* r.put(0) *>
* many('a' *> r.modify(_+1)) *>
* forYieldP[Int](r.get, pure(_ != 0), pure(_ - 1)){'b'} *>
* forYieldP[Int](r.get, pure(_ != 0), pure(_ - 1)){'c'}
* forYieldP[Int, Char](r.get, pure(_ != 0), pure(_ - 1)){'b'} *>
* forYieldP[Int, Char](r.get, pure(_ != 0), pure(_ - 1)){'c'}
* }}}
*
* This will return a list `n` `'c'` characters.
Expand Down

0 comments on commit 43c6905

Please sign in to comment.