実現したいこと
パーサコンビネータを実装しています。
このパーサコンビネータは、パースしたい対象にParserトレイトとその派生トレイトを実装することで汎用パーサを利用できるようにする形式です。例えば特定のパーサを5回繰り返すことを意味するrepeat関数は引数がrepeat(parser: impl Parser)->Repeat
になっています。ここで、例えば&strはParserを実装しているのでrepeat("hello")
とすることができます。また、RepeatもParserを実装しているので、repeatの結果もrepeatに渡すことができます。
Parserはパースする入力型、パーサが返す出力型、エラーの型と入力型に対するラッパ型であるInputを型引数で指定できます。例えば、「文字列をJson
という構造体にパースしたい。失敗したらJsonParseErrとしたい。入力型に追加情報はいらない」場合は、「Parse<&str, Json, JsonParseErr, SimpleInput<&str, JsonParseErr>>>
」となります。Inputについては入力型のラッパ型です。例えば、「現在パースしている位置」を追加情報にしたい場合などに役立ちます。
Parserのスーパートレイトとして、TeminateParserトレイトがあります。これは、文脈自由文法でいう終端記号に対してパースを行います。ただしただの終端記号ではなく、Iterator的な終端記号のみ実装することができます。これが必要なのは、「x文字目でパースが失敗した」ということを表せるようにするためです。これを作ることで、「x文字目」という概念がない終端記号とを分類することができます。
発生している問題・分からないこと
提供しているコードで、タイトルのエラーが発生します。
一応このエラーについては調べて大枠は理解していますが、エラーの原因と回避策が思いつきませんでした。
特に私が理解できなかったのは、コード例のmain()内のケース1についてはエラーが出ますが、ケース2についてはエラーが出ないことです。
このエラーはケース2が実際にはエラーでもその前の行が同様にこのエラーだと、ケース2の診断を隠す場合があるので、ケース1をコメントアウトしてみましたが、それでもエラーは出ず、コンパイルが通りました。
エラーメッセージ
error
1error[E0275]: overflow evaluating the requirement `SimpleInput<String, ()>: Input<String, ()>` 2 --> src/main.rs:6:5 3 | 46 | <P as Parser<String, (), (), SimpleInput<String, ()>>>::parse(&mut P, &new::<String, (), SimpleInput<String, ()>>(format!(""))); 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 6 | 7note: required by a bound in `Parser::parse` 8 --> src/main.rs:12:61 9 | 1012 | trait Parser<I: Parser<I, I, E, Input>, O, E: Clone, Input: crate::Input<I, E>>: Clone { 11 | ^^^^^^^^^^^^^^^^^^ required by this bound in `Parser::parse` 1213 | fn parse(&mut self, input: &Input); 13 | ----- required by a bound in this associated function
該当のソースコード
rust
1fn main() { 2 // ケース1 3 <P as Parser<String, (), (), SimpleInput<String, ()>>>::parse(&mut P, &new::<String, (), SimpleInput<String, ()>>(format!(""))); 4 // ケース2 5 <P as Parser<String, (), WrapperErr<()>, WrapperInput<_, _>>>::parse(&mut P, &new(format!(""))); 6} 7fn new<I: Parser<I, I, E, Input>, E: Clone, Input: crate::Input<I, E>>(input: I) -> Input { 8 Input::new(input) 9} 10trait Parser<I: Parser<I, I, E, Input>, O, E: Clone, Input: crate::Input<I, E>>: Clone { 11 fn parse(&mut self, input: &Input)->Result<(Input, O),()>; 12} 13 14trait Input<I: Parser<I, I, E, Self>, E: Clone>: Sized { 15 fn new(input: I) -> Self; 16 fn input(&self)->&I; 17 fn errs(&self)->&Vec<E>; 18} 19trait TerminateParser<E: Clone>: Parser<Self, Self, WrapperErr<E>, WrapperInput<Self, E>> {} 20 21struct SimpleInput<I: Parser<I, I, E, Self>, E: Clone> { 22 input: I, 23 errs: Vec<E>, 24} 25impl<I: Parser<I, I, E, Self>, E: Clone> Input<I, E> for SimpleInput<I, E> { 26 fn new(input: I) -> Self { 27 SimpleInput { 28 input, 29 errs: vec![], 30 } 31 } 32 fn input(&self)->&I { 33 &self.input 34 } 35 fn errs(&self)->&Vec<E> { 36 &self.errs 37 } 38} 39 40#[derive(Clone)] 41struct WrapperErr<E: Clone>(E); 42#[derive(Clone)] 43struct WrapperInput<I: TerminateParser<E>, E: Clone> { 44 source: I, 45 index: usize, 46 errs: Vec<WrapperErr<E>>, 47} 48impl<I: TerminateParser<E>, E: Clone> Input<I, WrapperErr<E>> for WrapperInput<I, E> { 49 fn new(input: I) -> Self { 50 WrapperInput { 51 source: input, 52 index: 0, 53 errs: vec![], 54 } 55 } 56 fn input(&self)->&I { 57 todo!() //提示していないコードに依存した処理 58 } 59 fn errs(&self)->&Vec<WrapperErr<E>> { 60 &self.errs 61 } 62} 63 64//終端記号パーサの実装 65impl<E: Clone, Input: crate::Input<String, E>> Parser<String, String, E, Input> for String { 66 fn parse(&mut self, _input: &Input) -> Result<(Input, String), ()> { 67 todo!() 68 } 69} 70impl<E: Clone> TerminateParser<E> for String {} 71 72#[derive(Clone)] 73struct P; 74impl<I: Parser<I, I, E, Input>, O, E: Clone, Input: crate::Input<I, E>> Parser<I, O, E, Input> 75 for P 76{ 77 fn parse(&mut self, _input: &Input) -> Result<(Input, O), ()> { 78 todo!() 79 } 80}
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
Rustのエラー情報でエラーの理解を試みました。
しかし、私のコードにこのコード例を落とし込む方法と、このエラーの回避策はわかりませんでした。
補足
環境
>rustup --version rustup 1.27.1 (54dd3d00f 2024-04-24) info: This is the version for the rustup toolchain manager, not the rustc compiler. info: The currently active `rustc` version is `rustc 1.82.0 (f6e511eec 2024-10-15)`
できれば回避したいこと
このエラーを解決するうえで、できれば回避したい設計の改変
- Parserのエラーのラッパ型を一律にすること。つまり、現状のSimpleInputのラッパ型がないEも、WrapperErrのエラー位置付きエラーもすべて一緒くたにErrorラッパとし、SimpleInputなどを使う場面でもOpiton<usize>でエラー位置情報を保持しなくてはならないタイプの設計。
- Parse::parseの引数をInputトレイトではなくすこと。「位置付きエラーを利用できない」とはそもそもWrapperInputの{source, index}で実装できないということでまた「位置付きエラーを実現する」ためには、SimpleInputでは実現できない。なので、Inputトレイトを用いた今の実装が一番表現力が高い実装と考えている。
これらを避けることができない場合は、エラー解決のほうを優先します。
回答1件
あなたの回答
tips
プレビュー