2017-01-03 44 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