-
Notifications
You must be signed in to change notification settings - Fork 20
parse trace
When you use apply ⚙️combinators on 🧩parsers you construct a graph structure called a parse tree.
The leaves of the parse tree are building block 🧩parsers, such as char parsers, 🧩int, 🧩bool, and so forth. Parent nodes are combinators such as ⚙️map and ⚙️many.
When a parser returns a failure result, a parse trace is returned together with that result. The parse trace gives information about which parser failed based on its location in the parse tree, as well as why the reason for the failure.
Unless you run with PARJS_TRACE=false environment variable, applying a ⚙️ combinator to a 🧩 parser captures a stack trace, and this stack trace is attached to the node.
When a failure happens, part of the report will include a stack describing the position of the failed parser in the tree, together with where in your code each node was created.
Expected: an integer
Found: end of input
at int
at between
at [5/*] sepr sepr| source-location.ts:10:12
at [1/*] subj subj| source-location.ts:10:12
at [ ] subj subj| source-location.ts:10:12
at [ ] subj subj| source-location.ts:10:12
at [2/3] optn | source-location.ts:10:12
at [ ] |0|
When you start parsing an input, a stack is created that describes the position in the parse tree. Each entry in this stack includes:
- Stage: a string describing a named stage in the parser’s internal logic.
- Index:
- Source stamp: A location in the code where the child was added to the parent.
- Captured range: This describes the text captured by a parser. It’s used in the visual trace of the failure, when required.
Each node in the tree doesn’t always get executed once – in many cases, it gets executed multiple times. This means it has multiple separate captures associated with it.
Applying a ⚙️ combinator to a 🧩 parser captures a stack trace, and this trace is associated with the parent node.
When there is a failure, that failure will be traced to the specific node that failed in the parse tree.
In practice, the parse tree may not look exactly like what you construct. However, there is a one-to-one mapping between your tree and the parse tree that gets executed.
Every node in the parse tree adds some amount of overhead, but gives you the ability to trace failures down to the node in question.
🚀boosters and 🛠️tuners do not contribute to the parse tree. Instead, they modify a node before it’s inserted into one. This has both benefits and drawbacks.
- 🛠️tuners let you construct