2017-06-08 9 views
1

私は多くのオプションの1つである可能性のあるテキストを解析するnomを持つパーサーを作成しようとしています。コンパイル時に値がわかっているのにNomにはalt!がありますが、私の値はそうではありません。どの文字列のベクトルをnomと一致させるには?

これは、一致するようにVec<String>を取ることができる自分のパーサーを作成しようとしています。私はいくつかの問題に取り組んでいます。

#[macro_use] 
extern crate nom; 

use nom::IResult; 

fn alternative_wrapper<'a>(input: &'a [u8], alternatives: Vec<String>) -> IResult<&'a [u8], &'a [u8]> { 
    for alternative in alternatives { 
     // tag!("alternative"); 
     println!("{}", alternative); 
    } 
    return IResult::Done(input, "test".as_bytes()); 
} 

#[test] 
fn test_date() { 
    let input = "May"; 
    named!(alternative, call!(alternative_wrapper)); 
    let months = vec!(
     "January", 
     "February", 
     "March", 
     "April", 
     "May", 
     "June", 
     "July", 
     "August", 
     "September", 
     "October", 
     "November", 
     "December" 
     ).iter().map(|s| s.to_string()).collect(); 
    println!("{:?}", alternative("May".as_bytes(), months)); 
} 

私は私のalternative_wrapper機能は、実際には何も有効ではありませんことを承知しているが、それは問題ではありません。これは、このスニペットでRustが耳を傾けるものです。

error[E0061]: this function takes 1 parameter but 2 parameters were supplied 
    --> src/parser.rs:32:34 
    | 
17 |  named!(alternative, call!(alternative_wrapper)); 
    |  ------------------------------------------------ defined here 
... 
32 |  println!("{:?}", alternative("May".as_bytes(), months)); 
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 parameter 
    | 
    = note: this error originates in a macro outside of the current crate 

error[E0061]: this function takes 2 parameters but 1 parameter was supplied 
    --> src/parser.rs:17:5 
    | 
6 |/fn alternative_wrapper<'a>(input: &'a [u8], alternatives: Vec<String>) -> IResult<&'a [u8], &'a 
[u8]> { 
7 | |  for alternative in alternatives { 
8 | |   // tag!("alternative"); 
9 | |   println!("{}", alternative); 
10 | |  } 
11 | |  return IResult::Done(input, "test".as_bytes()); 
12 | | } 
    | |_- defined here 
... 
17 |  named!(alternative, call!(alternative_wrapper)); 
    |  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 2 parameters 
    | 
    = note: this error originates in a macro outside of the current crate 

私は自分の関数からパーサーを作成できますか?そして、alternative_wrappertag!のような既存のパーサーをどうすれば使用できますか?

答えて

0

私は本当にnomに精通しておらず、まだRustを学んでいませんが、過去にパーサーコンビネータを使用しました。

マクロを除いて、named!マクロは1つのパラメータ、解析する文字列だけを受け取るように見えます。

nomの期待を満たすために、代わりに関数を返す関数としてalternative_wrapperを書いてみます。テストはこのように見える終わるでしょう:

#[test] 
fn test_date() { 
    let months = vec!(
     "January", 
     "February", 
     "March", 
     "April", 
     "May", 
     "June", 
     "July", 
     "August", 
     "September", 
     "October", 
     "November", 
     "December" 
     ).iter().map(|s| s.to_string()).collect(); 
    let parser = generate_alternative_parser(months); 
    named!(alternative, call!(parser)); 
    println!("{:?}", alternative("May".as_bytes())); 
} 

をあなたはtag! sからalt!表現を構築する必要があるだろうように見えますが、それはあなたがそれを行うだろうかドキュメントからすぐに私には明らかではありません。

あなたのオプションリストは最終的にどこから来たのですか?

あなたが達成しようとしているものによっては、やっていることを達成するための他の方法があるかもしれません。たとえば、任意の単語を解析した後に、その単語のオプションの1つを検証することができます。

0

エラーから始めて、最初のエラーはnamed!が1つの引数、つまり入力文字列を取るためです。 named!はあなたのための関数を宣言します。この場合は、署名はfn(&[u8]) -> IResult<&[u8],&[u8]>です。他の引数に関しては魔法はありませんので、monthsベクトルを第2引数として渡そうとするとうまくいきません。 named_args!と呼ばれるバリアントnamed!があります。これは、それを並べ替えるべき入力以上の引数を持つ関数を宣言するために使用できます。

2番目のエラーは似ていますが、逆です。ベクトルcall!を使用して、入力とベクトルなしのalternative_wrapperを呼び出しています。 call!マクロは実際には引数を渡すことができますが、明示的に行う必要があります。つまり、call!(myparser, monts)です。

エラーが分類された理由で、パーサーを作成する方法について質問しています。さて、実際には、alternative_wrapperです。すでにという名前のパーザを署名していますが、nomマクロを使って宣言していないので、魔法の入力が何も起こらないので、tag!は関数本体では機能しません試みた。

自分で宣言した関数で他のコンビネータを使用するには、最も外側のマクロに手動で入力を渡す必要があります。この場合はtag!しかありませんが、たとえばdo_parse!を使用し、その中に複数のマクロを使用する場合は、入力をdo_parse!に渡すだけです。私はここにいくつかの追加の調整で作業バージョンを提供します:

#[macro_use] 
extern crate nom; 

use std::str; 
use nom::IResult; 

fn alternative<'a>(input: &'a [u8], alternatives: &Vec<String>) -> IResult<&'a [u8], &'a [u8]> { 
    for alternative in alternatives { 
     match tag!(input, alternative.as_bytes()) { 
      [email protected]::Done(..) => return done, 
      _ =>() // continue 
     } 
    } 
    IResult::Error(nom::ErrorKind::Tag) // nothing found. 
} 

fn main() { 
    let months: Vec<String> = vec![ 
     "January", "February", "March", "April", "May", "June", "July", 
     "August", "September", "October", "November", "December" 
    ].into_iter().map(String::from).collect(); 

    fn print_res(r: IResult<&[u8],&[u8]>) { 
     println!("{:?}", r); 
     println!("{:?}\n", str::from_utf8(r.unwrap().1).unwrap()); 
    } 
    print_res(alternative(b"May", &months)); 
    print_res(alternative(b"August", &months)); 
    print_res(alternative(b"NoGood", &months)); 
} 

あなたはrust playgroundでそれをチェックアウトすることができます。

関連する問題