Node data
When parsing, it's often useful to keep track of the positions of nodes for error handling for example. This can be achieved through the use the NodeData
trait and the NodeWrapper
struct.
The NodeData
trait has two functions; NodeData::start
and NodeData::end
to get the start and end data of a node.
The NodeWrapper
struct contains a node (NodeWrapper::node
), and start and end data about that node (NodeWrapper::start
, NodeWrapper::end
).
Example
#[derive(Parser)]
#[parser(Token, TokType, |t| t.t, usize; ([@Add])*)]
pub struct Root(pub Vec<NodeWrapper<Add, usize>>);
In this example, you'll notice that there is an additional field for the metadata. This indicates that any matches should be wrapped in a NodeWrapper
struct with positional data. The type provided is the type returned from the NodeData
trait functions1.
You'll also notice that the inner section of the trait is not a Vec<Add>
, but Vec<NodeWrapper<Add, usize>>
.
Use for one, use for all
If you derive one Parser
impl that's wrapped, all Parser
impls that can be called from the one using it must also be wrapped.
For example, you could not have the following
#[derive(Parser)]
#[parser(Token, TokType, |t| t.t, usize; ([@Add])*)]
pub struct Root(pub Vec<NodeWrapper<Expr, usize>>);
#[derive(Parser)]
#[parser(Token, TokType, |t| t.t)]
pub enum Expr {
/* ... */
}
This would cause an error because the Root
Parser
impl would expect that the Expr
Parser
impl would also be wrapped so it can access the positional data of an Expr
match.
NodeData
impl requirement
If you use wrapped matches, you need to ensure that the input type of your parser (Token
in the example above) needs to implement NodeData
so that Parser
impls that match tokens not calls to other types can access positional data.
This could most likely be included as a generic in the Parser
impl, but is required to ensure the correct NodeData
impl is used in the case that there are multiple NodeData
impls.