使用nom匹配模板过滤器表达式

时间:2017-01-03 18:15:03

标签: rust parser-combinators nom

我正在使用模板引擎,其中一些语法可能是这样的:

{{ somevar|filter }}

代替somevar可以是任意"表达式",也就是说,可以是变量名称,如somevar,也可以是嵌套过滤器表达式(如{{1} }})。我试图使用Rust的nom解析器组合库来解析它,但到目前为止还没有让它工作。

这是我迄今为止提出的解析器:

{{ somevar|filter|anotherfilter }}

playground。当前版本通过堆栈溢出而发生混乱。我可以通过撤消#[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)); 中的expr_var | expr_filter订单来解决此问题,但之后我又回到了与之前基本相同的错误。

2 个答案:

答案 0 :(得分:0)

我不能说我在挖掘你的问题:没有应该解析的文本示例,你也没有描述在构建解析器时遇到的问题。

尽管如此,以下示例可能会有所帮助。一个有效的递归解析器:

#[macro_use]
extern crate nom;

use nom::alphanumeric;

type Variable = String;
type Filter = String;

named! (plain_expression (&str) -> (Variable, Filter), do_parse! (
    tag_s! ("{{") >>
    variable: alphanumeric >>
    tag_s! ("|") >>
    filter: alphanumeric >>
    tag_s! ("}}") >>
    ((variable.into(), filter.into()))));

#[derive(Debug)]
enum Expression {
    Plain(Variable, Filter),
    Recursive(Box<Expression>, Filter),
}

named! (recursive_expression (&str) -> Expression,
  alt_complete! (
    map! (plain_expression, |(v, f)| Expression::Plain (v, f)) |
    do_parse! (
      tag_s! ("{{") >>
      sub: recursive_expression >>
      tag_s! ("|") >>
      filter: alphanumeric >>
      tag_s! ("}}") >>
      (Expression::Recursive (Box::new (sub), filter.into())))));

fn main() {
    let plain = "{{var|fil}}";
    let recursive = "{{{{{{var1|fil1}}|fil2}}|fil3}}";
    // Prints: Done("", ("var", "fil")).
    println!("{:?}", plain_expression(plain));
    // Prints: Done("", Recursive(Recursive(Plain("var1", "fil1"), "fil2"), "fil3")).
    println!("{:?}", recursive_expression(recursive));
}

playground)。

答案 1 :(得分:0)

我通过编写自己的解析器函数来修复它:

named!(expr_var<Expr>, map!(nom::alphanumeric, Expr::Var));

fn expr_filtered(i: &[u8]) -> IResult<&[u8], Expr> {
    let (mut left, mut expr) = match expr_var(i) {
        IResult::Error(err) => { return IResult::Error(err); },
        IResult::Incomplete(needed) => { return IResult::Incomplete(needed); },
        IResult::Done(left, res) => (left, res),
    };
    while left[0] == b'|' {
        match nom::alphanumeric(&left[1..]) {
            IResult::Error(err) => {
                return IResult::Error(err);
            },
            IResult::Incomplete(needed) => {
                return IResult::Incomplete(needed);
            },
            IResult::Done(new_left, res) => {
                left = new_left;
                expr = Expr::Filter(str::from_utf8(res).unwrap(), Box::new(expr));
            },
        };
    }
    return IResult::Done(left, expr);
}

named!(expr_node<Node>, map!(
    delimited!(tag_s!("{{"), ws!(expr_filtered), tag_s!("}}")),
Node::Expr));

使用nom宏可能有一些更好的方法来做同样的事情,但至少我得到了一些工作。