I'm working on a templating engine where some of the syntax could be like:
{{ somevar|filter }}
In place of somevar
could be an arbitrary "expression", which is to say, either a variable name like somevar
, or a nested filter expression (like {{ somevar|filter|anotherfilter }}
). I'm trying to parse this using Rust's nom parser combinator library, but failing to get it to work so far.
Here's the parser I've come up with so far:
#[macro_use]
extern crate nom;
use std::str;
#[derive(Debug)]
pub enum Expr<'a> {
Var(&'a [u8]),
Filter(&'a str, Box<Expr<'a>>),
}
#[derive(Debug)]
pub enum Node<'a> {
Lit(&'a [u8]),
Expr(Expr<'a>),
}
named!(expr_var<Expr>, dbg_dmp!(map!(nom::alphanumeric, Expr::Var)));
named!(expr_filter<Expr>,
dbg_dmp!(do_parse!(
val: any_expr >>
tag_s!("|") >>
name: map_res!(nom::alphanumeric, str::from_utf8) >>
(Expr::Filter(name, Box::new(val)))
))
);
named!(any_expr<Expr>, dbg_dmp!(ws!(
alt_complete!(
expr_filter |
expr_var
))));
named!(expr_node<Node>, dbg_dmp!(map!(
delimited!(tag_s!("{{"), any_expr, tag_s!("}}")),
Node::Expr)));
named!(parse_template< Vec<Node> >, many1!(expr_node));
With a playground. The current version panics through a stack overflow. I can fix this by reversing the expr_var | expr_filter
order in any_expr
, but then I'm back to basically the same error as before.
I fixed it by writing my own parser function:
There is probably some nicer way to do the same thing with nom macros, but at least I got something working.