Parsley is a modern parser-combinator library for Scala.
The parsley-debug package allows us to debug parsers using a more comprehensive mechanism, though it
only supports printing out-of-the-box. This repo contains the implementations of different debug-views,
which can be used to visualise the results of a parse. This work was originally a Bachelors Project at
Imperial College London by Fawwaz Abdullah (@mf42-dzh).
Each sub-project contains one view, currently:
parsley-debug-sfx(@sfx-ui): A ScalaFX-powered interactive GUI for exploring parser execution trees,FxGUI.parsley-debug-json(@json-info): A JSON string generator,JsonFormatterandJsonStringFormatter.
After adding one of these projects as a dependency, use one of the attach combinators in parsley.debug.combinators to make a parser render the debugging output with the given view. You can find the views within the package parsley.debug.
Currently, these views support:
| Version | parsley-debug |
|---|---|
0.1.0-M1 |
5.0.0-M9 |
| snapshot | 5.0-74d27a2-SNAPSHOT+ |
The different views work on different platforms:
| Version | Scala (JDK8+) | Scala.js (1.16+) | Scala Native (0.5+) |
|---|---|---|---|
| 2.12 | ✔️ | ✔️ | ✔️ |
| 2.13 | ✔️ | ✔️ | ✔️ |
| 3.0 | ✔️ | ✔️ | ✔️ |
| Version | Scala (JDK8+) | Scala.js (1.16+) | Scala Native (0.5+) |
|---|---|---|---|
| 2.12 | ✔️ | ✔️ | ✔️ |
| 2.13 | ✔️ | ✔️ | ✔️ |
| 3.0 | ✔️ | ✔️ | ✔️ |
| Version | Scala (JDK8+) | Scala.js (1.16+) | Scala Native (0.5+) |
|---|---|---|---|
| 2.12 | ✔️ | ❌ | ❌ |
| 2.13 | ✔️ | ❌ | ❌ |
| 3.0 | ✔️ | ❌ | ❌ |
Assuming you have parsley-debug-sfx in your dependencies, this is a small example in debugging an arithmetic parser (with either -experimental for Scala 3 or -Ymacro-annotations for Scala 2.13):
import parsley.quick.*
import parsley.debug.combinator.*
import parsley.debug.FxGUI
import parsley.expr.{InfixL, Ops, precedence}
@parsley.debuggable
object Maths {
val int: Parsley[BigInt] = satisfy(_.isDigit).foldLeft1(BigInt(0))((acc, c) => acc * 10 + c.asDigit)
lazy val expr: Parsley[BigInt] = precedence[BigInt](int, char('(') ~> expr <~ char(')'))(
Ops(InfixL)(char('*') as (_ * _), char('/') as (_ / _)),
Ops(InfixL)(char('+') as (_ + _), char('-') as (_ - _))
)
lazy val prog: Parsley[List[BigInt]] = many(many(endOfLine) ~> expr)
def main(args: Array[String]): Unit = {
// Attach a graphical debugger to our main `prog` parser.
val debugged = prog.attach(FxGUI)
// Show the parse path for this complicated expression.
// The print is to show the result of the parse.
println(debugged.parse("(1+2)*(4-3)"))
}
}The UI is shown as follows:
As parsley-debug itself has PrintView, then you can also easily switch over to using it from the ScalaFX GUI frontend. Simply change these lines:
- import parsley.debug.FxGUI
+ import parsley.debug.PrintView
...
- val debugged = prog.attach(FxGUI)
+ val debugged = prog.attach(PrintView)And your output will be something as follows:
prog's parse tree for input:
(1+2)*(4-3)
[ prog (many) ]: ("{1}" [(1,1) -> (1,12)], Success - [ List(3) ])
|
+-[ ~>(1) ]: ("{1}" [(1,1) -> (1,12)], Success - [ 3 ])
| |
| +-[ many ]: ("" [(1,1) -> (1,1)], Success - [ List() ])
| | |
| | +-[ endOfLine ]: ("" [(1,1) -> (1,1)], Failure)
| |
| +-[ expr (infix.left1(1)) ]: ("{1}" [(1,1) -> (1,12)], Success - [ 3 ])
| |
| +-[ infix.left1(1) ]: ("{1}{2}{3}" [(1,1) -> (1,12)], Success - [ 3 ])
| | |
| | +-[ choice(1) ]: ("{1}" [(1,1) -> (1,6)], Success - [ 3 ])
| | | |
[snip!]
And that is it!
