#parser-combinator #streaming #parser #debugging

no-std chomp1

一个专为稳定 Rust 设计的快速单调式解析器组合器

3 个版本

0.3.4 2023年5月7日
0.3.3 2023年5月7日
0.3.2 2022年5月7日

解析工具 中排名 39

Download history 558/week @ 2024-03-11 648/week @ 2024-03-18 555/week @ 2024-03-25 210/week @ 2024-04-01 86/week @ 2024-04-08 100/week @ 2024-04-15 83/week @ 2024-04-22 203/week @ 2024-04-29 670/week @ 2024-05-06 102/week @ 2024-05-13 127/week @ 2024-05-20 53/week @ 2024-05-27 134/week @ 2024-06-03 54/week @ 2024-06-10 82/week @ 2024-06-17 87/week @ 2024-06-24

每月下载量 361
用于 14 个crate(通过 dnssector

MIT/Apache

325KB
6K SLoC

Chomp

Gitter Build Status Coverage Status Crates.io Documentation

Chomp 是一个专为稳定 Rust 设计的快速单调式解析器组合器库。它是通过以下博客文章中详细描述的实验的成果

就其当前功能而言,您会发现 Chomp 的性能与优化后的 C 解析器相当,甚至更好,同时具有更高的可表达性。有关如何使用较小解析器构建性能良好的 HTTP 解析器的示例,请参阅 http_parser.rs

安装

将以下行添加到您的 Cargo.toml 的依赖项部分

[dependencies]
chomp = "0.3.1"

用法

解析器是从输入类型 Input<I> 的切片到 ParseResult<I, T, E> 的函数,这可以被视为成功的结果,结果为类型 T,一个类型为 E 的错误,或者一个可能仍然需要消耗更多类型 I 的部分完成的结果。

输入类型几乎从不手动操作。相反,通过调用 parse! 宏来使用 Chomp 的解析器。这个宏被设计得尽可能接近 Haskell 的 do-语法或 F#'s "计算表达式",这些用于序列化单调计算。在非常高的层次上,此宏的使用允许声明式地

  • 按顺序排列解析器,如果在任何步骤中失败,则短路其余解析器。
  • 将先前成功的结果绑定到以后在计算中使用。
  • 在计算的末尾返回使用先前结果组成的复合数据结构。

换句话说,就像一个正常的 Rust 函数通常看起来像这样

fn f() -> (u8, u8, u8) {
    let a = read_digit();
    let b = read_digit();
    launch_missiles();
    return (a, b, a + b);
}

具有类似结构的 Chomp 解析器看起来像这样

fn f<I: U8Input>(i: I) -> SimpleResult<I, (u8, u8, u8)> {
    parse!{i;
        let a = digit();
        let b = digit();
                string(b"missiles");
        ret (a, b, a + b)
    }
}

要实现 read_digit,我们可以利用 map 函数来操作任何成功值,同时保留任何错误或不完整状态

// Standard rust, no error handling:
fn read_digit() -> u8 {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).unwrap();
    s.trim().parse().unwrap()
}

// Chomp, error handling built in, and we make sure we only get a number:
fn read_digit<I: U8Input>(i: I) -> SimpleResult<I, u8> {
    satisfy(i, |c| b'0' <= c && c <= b'9').map(|c| c - b'0')
}

有关更多文档,请参阅rust-doc输出。

示例

#[macro_use]
extern crate chomp1;

use chomp1::prelude::*;

#[derive(Debug, Eq, PartialEq)]
struct Name<B: Buffer> {
    first: B,
    last:  B,
}

fn name<I: U8Input>(i: I) -> SimpleResult<I, Name<I::Buffer>> {
    parse!{i;
        let first = take_while1(|c| c != b' ');
                    token(b' ');  // skipping this char
        let last  = take_while1(|c| c != b'\n');

        ret Name{
            first: first,
            last:  last,
        }
    }
}

assert_eq!(parse_only(name, "Martin Wernstål\n".as_bytes()), Ok(Name{
    first: &b"Martin"[..],
    last: "Wernstål".as_bytes()
}));

许可证

根据以下任一许可证授权

根据您的要求。

贡献

除非您明确声明,否则您根据Apache-2.0许可证定义提交的任何有意包含在作品中的贡献,将根据上述方式双授权,而不附加任何额外条款或条件。

联系方式

在此处提交问题或在gitter.im/m4rw3r/chomp上访问。

依赖项

~0.5–9.5MB
~73K SLoC