2017-01-03 41 views
1

我工作的一个模板引擎,其中的一些语法可能是这样的:匹配模板过滤器表达式与NOM

{{ somevar|filter }} 

在地方的somevar可以是任意“表达”,这是说,要么是变量名称,如somevar,要么是嵌套的过滤器表达式(如{{ somevar|filter|anotherfilter }})。我试图用Rust的nom分析器组合库来解析这个问题,但是到目前为止还没有得到它的工作。

这里的解析器,我拿出这么远:

#[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)); 

随着playground。当前版本通过堆栈溢出发生混乱。我可以通过逆转any_expr中的expr_var | expr_filter订单来解决此问题,但后来我恢复了与之前基本相同的错误。

+0

我强烈建议在尝试编写代码之前写出实际的语法。解析工具的一个重点是它们帮助将语法映射到代码。 – Shepmaster

+0

我也会推荐1)做一个正确的http://stackoverflow.com/help/mcve(也许用http://play.rust-lang.org/)。另见http://www.sscce.org/。 2)提供一种单元测试,作为解析语法的例子。 – ArtemGr

回答

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宏同样的事情,一些更好的方式,但至少我得到的东西的工作。

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)。

+0

无论如何,感谢您的重击。对不起,我不确定将完整的解析器代码放在我的问题中,感觉它可能是压倒性的。在我的辩护中,我链接到一个GitHub仓库,它应该可以很容易地看到完整的解析器和示例输入,以及一些可以轻松测试的东西(尽管可能不如您的简单操场)。无论如何,我现在试着澄清我的问题。我会更深入地研究你的例子,看看有没有什么可以帮到你的。 – djc

+1

@djc我们不希望*整个解析器*,我们想要一个[MCVE],强调** M **。 – Shepmaster

+0

@djc感谢您的更新。关于“Many1”错误,您应该在启用“verbose-errors”功能的情况下编译nom,以便为您提供解析失败的确切位置。 – ArtemGr