chasa-recover

Crates.iochasa-recover
lib.rschasa-recover
version0.1.0
created_at2025-12-15 06:14:48.785111+00
updated_at2025-12-15 06:14:48.785111+00
descriptionExperimental recoverable parser combinators (procedural parsers).
homepage
repository
max_upload_size
id1985633
size181,322
Conashimi (momota1029)

documentation

README

chasa-recover

回復可能(recoverable)パーサを組み立てるための、実験的なパーサコンビネータ群です。

この crate のコアは「手続きがそのままパーサになる」ところにあります。 つまり、|i: In<...>| { ... } という関数(クロージャ)自体が ParserOnce/ParserMut/Parser として動作し、In のメソッドを呼びながら手続き的にパースできます。

前提(重要)

  • Err は例外ではなく 出力の一部(呼び出し側が受け取って回復を組む)。
  • 「出力を捨てる」操作は原則禁止に近い扱いで、やるなら 入力消費も捨てる(巻き戻す)
    • maybe: Result<T, E> -> Option<T>Err を消すので入力も戻す)
    • attempt: Result<T, E> -> bool(成功/失敗だけを見るので入力も戻す)
  • rollback(save/load)は combinator が必要な範囲だけ使う:
    • many 系:終端判定の最後の失敗だけ戻す
    • choice/or 系:別枝を試すための局所探索

主要な型

  • Input: 1要素ずつ読む入力。pos() を持つ(比較可能な位置)。
  • In<'a, I, E, L>: 実際にパースに渡す「入力+環境」。
    • env / local を持つ(巻き戻しポリシーは合意に従う。現状 InBack は入力のみ巻き戻し)。

使い方(手続き=パーサ)

プリミティブ(例: parser::item::any)や In のメソッドからパースを記述できます。

use chasa_recover::input::In;
use chasa_recover::parser::ParserOnce;
use chasa_recover::parser::item::any;
use std::ops::ControlFlow;

let mut s = "abc!def";
let out: String = any
    .flow(String::new(), |mut st, r| match r {
        Ok('!') | Err(_) => ControlFlow::Break(st),
        Ok(c) => { st.push(c); ControlFlow::Continue(st) }
    })
    .run_once(In::new(&mut s));

assert_eq!(out, "abc");
assert_eq!(s, "def");

また、In 自体にもプリミティブを生やしているので、 より手続き的に(「関数=パーサ」を前提に)書けます。

use chasa_recover::input::In;

let mut s = "ab]c";
let mut i = In::new(&mut s);

let v = i.take_until(|c: &char| *c == ']'); // stop文字は差し戻し
assert_eq!(v, vec!['a','b']);
assert_eq!(s, "]c");

プリミティブ(例)

item / set

  • one_of("abc") / none_of("abc")ItemSet
  • any / eoi

text

  • tag("abc"):先頭一致。失敗時は「失敗した文字を含む、消費した全て」を TagError::consumed に入れて返す(入力は戻さない)。
  • take_while(pred):最初に pred == false の文字は差し戻して終了(エラーなし)。
  • take_while1(pred):1文字目が不一致なら Err(1文字目は消費)、それ以外の不一致は差し戻して Ok 終了。
  • take_until(stop):stop文字は差し戻して終了。
  • take_until1(stop):1文字目が stop なら Err(1文字目は消費)、それ以外は take_until と同様。

繰り返し(many)

  • many: Result<T, E> を繰り返し、Err が出た回は 入力を戻して終了(終端判定)。
  • many1: 最初が Err なら 入力を戻さず Err を返す。最初が Ok なら、その後は many と同様。
  • many_map / many1_map: iterator を渡して集計をカスタマイズできる。

回復(Result系)

  • map / map_err / and_then
  • or_else: Err(E) を受け取り、追加でパースして Result<O, E2> を返す(回復して Ok(O) にもできる)。
  • recover: Err(E) を受け取り、値パーサに切り替えて O を返す。
  • ignore: Result<T, E> -> ()(成功/失敗に関わらず出力を捨て、入力も戻す)

合成(combinator)

map / map_ok のように、「通常出力」と「Result 出力」は分けています。

  • left: P: OQ: () を合成して O を返す。Q は常に実行される。
  • left_ok: P: Result<O, E>Q: () を合成して Result<O, E> を返す。QOk のときだけ実行される。
  • right: P: ()Q: O を合成して O を返す。P の後に Q を実行する。
  • right_ok: P: ()Q: Result<O, E> を合成して Result<O, E> を返す。

実装メモ

この crate の設計意図・合意済みの細かい挙動は crates/chasa-recover/AGENTS.md にもまとめています。

Commit count: 0

cargo fmt