Skip to content

matajupi/parsecomb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Parser Combinator Library — API Documentation

本ライブラリは、Rustで構築されたシンプルかつ強力な関数型パーサコンビネータ(Parser Combinator)ライブラリです。 モナド、アプリカティブファンクター、オルタナティブといった関数型プログラミングの概念をRustの型システム上に実現しており、豊富な演算子オーバーロードによって直感的かつ宣言的にパーサを記述できます。


1. コア構造体

Parser<A>

すべてのパーサの基盤となる中心的な構造体です。内部的には文字列のスライス &str を受け取り、パース結果の型 A と「残りの文字列」のペアを返す関数を保持しています。

pub struct Parser<A: 'static>(Rc<dyn Fn(&str) -> Option<(A, &str)>>);
  • 安全な共有: 内部で Rc(参照カウント)を使用しているため、パーサのクローンや組み合わせを安価に行うことができます。

2. 演算子マッピング(Operator Overloading)

本ライブラリの最大の特徴は、Rustの組み込み演算子をオーバーロードすることで、Haskellのパーサコンビネータに近い直感的な記述ができる点です。

演算子 トレイト 戻り値の型 説明 / 対応する概念
& BitAnd Parser<(A, B)> 順次実行 (Sequence): 左のパースに成功した後、右を続けて実行し、両方の結果をタプルで返します。
| BitOr Parser<Either<A, B>> 排他選択 (Either Choose): 左のパースを試し、失敗したら右を試します。結果は Either 型に包まれます。
+ Add Parser<A> 選択 (Alternative): 左のパースを試し、失敗したら右を試します。両者の型 A は共通である必要があります。
* Mul Parser<Vec<A>> 連結: パーサの結果、または結果のリスト(Vec<A>)に、次のパース結果を追加して要素をまとめます。
>> Shr Parser<B> 右を流す: 左と右を順にパースしますが、左の結果を破棄して右の結果のみを返します。
<< Shl Parser<A> 左を流す: 左と右を順にパースしますが、右の結果を破棄して左の結果のみを返します。

3. 主要メソッド(APIリファレンス)

基本メソッド

  • pub fn new(f: impl Fn(&str) -> Option<(A, &str)> + 'static) -> Self

カスタムのパース関数から新しい Parser インスタンスを生成します。

  • pub fn run<'a>(&self, src: &'a str) -> Option<(A, &'a str)>

パース処理を実行します。成功した場合は Some((結果, 残りの文字列)) を返し、失敗した場合は None を返します。

関数型インターフェース (Functor, Applicative, Monad)

  • pub fn map<B, F>(self, f: F) -> Parser<B>

パースに成功した際の中身の結果に対して関数 f を適用し、別の型 B へ変換します(Functor)。

  • pub fn pure(x: A) -> Parser<A>

入力を一切消費せず、常に指定された値 x をパース結果として返すパーサを生成します(Applicative)。

  • pub fn ap<B, F>(self, pf: Parser<F>) -> Parser<B>

関数を返すパーサ pf の結果を、自身のパーサの結果に適用します(Applicative)。

  • pub fn and_then<B, F>(self, f: F) -> Parser<B>

現在のパース結果を利用して、次に実行するパーサを動的に決定・接続します(Monad)。


4. 組み込みコンビネータ

既存のパーサを組み合わせて、より複雑なリピートや条件付けを行うためのメソッドです。

  • pub fn empty() -> Parser<A>

常にパースに失敗する空のパーサを返します。

  • pub fn or_else(self, other: Parser<A>) -> Parser<A>

自身が失敗した際、バックトラックして other を実行します(+ 演算子の実態)。

  • pub fn or_either<B>(self, other: Parser<B>) -> Parser<Either<A, B>>

自身と other のいずれか成功した方の結果を Either 型で返します(| 演算子の実態)。

  • pub fn many(self) -> Parser<Vec<A>>

対象のパーサを0回以上繰り返し適用し、結果をリストとして収集します。

  • pub fn many1(self) -> Parser<Vec<A>>

対象のパーサを1回以上繰り返し適用します。1回もマッチしない場合は失敗します。

  • pub fn optional(self) -> Parser<Option<A>>

パースが成功しても失敗しても全体のパースとしては成功扱いとし、結果を Option<A> で返します。

  • pub fn sep_by<S>(self, sep: Parser<S>) -> Parser<Vec<A>>

区切り文字(パーサ sep)で区切られた、0回以上の要素の並びをパースします。

  • pub fn sep_by1<S>(self, sep: Parser<S>) -> Parser<Vec<A>>

区切り文字で区切られた、1回以上の要素の並びをパースします。

  • pub fn chainl1<F>(self, op: Parser<F>) -> Parser<A>

左結合の演算子(op)を挟んだ1回以上のリピートをパースします。数式の四則演算など、左優先の結合(例:1 - 2 - 3(1 - 2) - 3)を表現する際に使用します。

  • pub fn chainr1<F>(self, op: Parser<F>) -> Parser<A>

右結合の演算子(op)を挟んだ1回以上のリピートをパースします。

  • pub fn lexeme(self) -> Parser<A>

自身のパースに成功した後、続く末尾の空白文字(スペース、タブ、改行等)を自動的に消費します。


5. ユーティリティ関数(基本パーサ)

特定の文字やパターンをパースするための部品となる関数群です。

  • pub fn lazy<A: 'static>(f: impl Fn() -> Parser<A> + 'static) -> Parser<A>

再帰的な文法(例:式の中にさらに括弧で囲まれた式が登場する等)を記述する際、評価を遅延させて無限再帰(スタックオーバーフロー)を防ぎます。

  • pub fn satisfy(f: impl Fn(char) -> bool + 'static) -> Parser<char>

条件 f を満たす1文字を消費します。

  • pub fn charp(c: char) -> Parser<char>

指定された1文字 c と完全に一致する文字を消費します。

  • pub fn digit() -> Parser<char>

0 から 9 までの数字1文字にマッチします。

  • pub fn alpha() -> Parser<char>

アルファベット1文字にマッチします。

  • pub fn alphanum() -> Parser<char>

アルファベット、または数字1文字にマッチします。

  • pub fn number() -> Parser<i64>

連続する数字をパースし、符号なし整数(i64)に変換して返します。

  • pub fn string(expected: &str) -> Parser<String>

指定された文字列 expected と完全に一致する文字列を消費します。

  • pub fn any_char() -> Parser<char>

任意の1文字を消費します。

  • pub fn one_of(chars: Vec<char>) -> Parser<char>

与えられたリスト chars に含まれるいずれかの1文字にマッチします。

  • pub fn whitespace() -> Parser<()>

連続する空白類文字(スペース、タブ、改行など)を消費します。

  • pub fn epsilon() -> Parser<()>

入力を全く消費せず、何もせず成功(())を返します。

  • pub fn regex(re: &'static Regex) -> Parser<String>

正規表現オブジェクト re にマッチする文字列を消費します。

  • pub fn identifier() -> Parser<String>

一般的なプログラミング言語の識別子(例: x_1, total_score)にマッチします。(先頭はアルファベットかアンダースコア、2文字目以降は英数字・アンダースコア)


6. 実装例:数式評価(四則演算)パーサ

本ライブラリを使って、演算子の優先順位(足し引きより掛け割りが優先)や括弧を考慮した、本格的な数式パーサを構築するコード例です。

use your_crate_name::{Parser, number, charp, lazy, Either};

// 式 (足し算・引き算: 左結合)
fn expr() -> Parser<i64> {
    term().chainl1(
        (charp('+') | charp('-')).lexeme().map(|op| move |a, b|
            match op { 
                either::Left(_) => a + b, 
                either::Right(_) => a - b 
            }
        )
    )
}

// 項 (掛け算・割り算: 左結合)
fn term() -> Parser<i64> {
    primitive().chainl1(
        (charp('*') | charp('/')).lexeme().map(|op| move |a, b|
            match op { 
                either::Left(_) => a * b, 
                either::Right(_) => a / b 
            }
        )
    )
}

// 原子式 (数値、または括弧で囲まれた式)
fn primitive() -> Parser<i64> {
    // 数値単体、または `(` + 式 + `)` の構造
    number().lexeme() + (charp('(').lexeme() >> lazy(expr) << charp(')').lexeme())
}

fn main() {
    let parser = expr();
    
    // パース実行結果の検証
    let result1 = parser.run("3 + 4 * 2");
    assert_eq!(result1, Some((11, ""))); // 4 * 2 が優先される
    
    let result2 = parser.run("(3 + 4) * 2");
    assert_eq!(result2, Some((14, ""))); // 括弧内が優先される
}

About

Parser Combinator Library

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages