73 个版本 (36 个稳定版)
2.7.11 | 2024年7月2日 |
---|---|
2.7.9 |
|
2.7.8 | 2024年3月2日 |
2.7.5 | 2023年10月24日 |
0.3.2 | 2016年6月28日 |
#6 in 解析器工具
3,466,431 每月下载量
用于 4,887 个 crate (703 直接使用)
1.5MB
22K SLoC
pest. 优雅的解析器
pest 是一个以可访问性、正确性和性能为重点的通用解析器,用 Rust 编写。它使用解析表达式文法(或 PEG)作为输入,与正则表达式类似,但提供了解析复杂语言所需的表达性。
入门指南
使用 pest 开始解析的推荐方法是阅读官方的 书籍。
其他有用的资源
- 在 docs.rs 上的 API 参考文档
- 在我们的 fiddle 上试用语法并分享它们
- 在 GitHub 讨论区 中找到已回答的常见问题或提出问题
- 在 Gitter 或 Discord 上留下反馈、提问或打招呼
示例
以下是一个列表数字标识符语法的示例,其中所有标识符都不以数字开头
alpha = { 'a'..'z' | 'A'..'Z' }
digit = { '0'..'9' }
ident = { !digit ~ (alpha | digit)+ }
ident_list = _{ ident ~ (" " ~ ident)* }
// ^
// ident_list rule is silent which means it produces no tokens
语法保存在单独的 .pest 文件中,永远不会与过程代码混合。这导致了一种始终是最新的、易于阅读和维护的语言规范。
有意义的错误报告
基于语法定义,解析器还包括自动错误报告。对于上面的例子,输入 "123"
将导致
thread 'main' panicked at ' --> 1:1
|
1 | 123
| ^---
|
= unexpected digit', src/main.rs:12
而 "ab *"
将导致
thread 'main' panicked at ' --> 1:1
|
1 | ab *
| ^---
|
= expected ident', src/main.rs:12
这些错误消息可以从它们的默认 Display
实现中获得,例如 panic!("{}", parser_result.unwrap_err())
或 println!("{}", e)
。
API 对
可以使用语法自动推导出 Parser
实现。解析返回嵌套标记对的迭代器
use pest_derive::Parser;
use pest::Parser;
#[derive(Parser)]
#[grammar = "ident.pest"]
struct IdentParser;
fn main() {
let pairs = IdentParser::parse(Rule::ident_list, "a1 b2").unwrap_or_else(|e| panic!("{}", e));
// Because ident_list is silent, the iterator will contain idents
for pair in pairs {
// A pair is a combination of the rule which matched and a span of input
println!("Rule: {:?}", pair.as_rule());
println!("Span: {:?}", pair.as_span());
println!("Text: {}", pair.as_str());
// A pair can be converted to an iterator of the tokens which make it up:
for inner_pair in pair.into_inner() {
match inner_pair.as_rule() {
Rule::alpha => println!("Letter: {}", inner_pair.as_str()),
Rule::digit => println!("Digit: {}", inner_pair.as_str()),
_ => unreachable!()
};
}
}
}
这会产生以下输出
Rule: ident
Span: Span { start: 0, end: 2 }
Text: a1
Letter: a
Digit: 1
Rule: ident
Span: Span { start: 3, end: 5 }
Text: b2
Letter: b
Digit: 2
在单个文件中定义多个解析器
当前的自动 Parser
推导将产生 Rule
枚举,如果在单个文件中定义多个此类结构体,将会出现名称冲突。一种可能的解决方案是将每个解析器结构体放在单独的命名空间中
mod a {
#[derive(Parser)]
#[grammar = "a.pest"]
pub struct ParserA;
}
mod b {
#[derive(Parser)]
#[grammar = "b.pest"]
pub struct ParserB;
}
其他功能
- 优先级爬升
- 输入处理
- 自定义错误
- 在稳定的 Rust 上运行
使用 pest 的项目
你可以在 awesome-pest 仓库中找到更多项目和生态系统工具。
- pest_meta(自举)
- AshPaper
- 大脑
- 蝉
- comrak
- 弹性-rs
- graphql-parser
- handlebars-rust
- hexdino
- Huia
- insta
- jql
- json5-rs
- mt940
- Myoxine
- py_literal
- rouler
- RuSh
- rs_pbrt
- stache
- tera
- ui_gen
- ukhasnet-parser
- ZoKrates
- 向量
- 自动校正
- yaml-peg
- 量子比特
- caith(一个骰子投掷 crate)
- 旋律
- json5-nodes
- prisma
最低支持的 Rust 版本(MSRV)
此库应始终在 Rust 1.61.0 上使用默认功能编译。
no_std 支持
pest
和 pest_derive
crate 可以在没有 Rust 标准库的情况下构建,并针对嵌入式环境。要做到这一点,您需要禁用它们的默认功能。在您的 Cargo.toml
中,您可以指定如下
[dependencies]
# ...
pest = { version = "2", default-features = false }
pest_derive = { version = "2", default-features = false }
如果您想在 pest 仓库的工作区中构建这些 crate,您可以将 --no-default-features
标志传递给 cargo
并使用 --package
(--p
)标志指定这些 crate。例如
$ cargo build --target thumbv7em-none-eabihf --no-default-features -p pest
$ cargo bootstrap
$ cargo build --target thumbv7em-none-eabihf --no-default-features -p pest_derive
特别感谢
特别感谢马里乌斯·米内亚教授的指导以及所有 pest 贡献者,其中一些是我的朋友。
依赖项
~245–660KB
~16K SLoC