8个版本
0.3.1 | 2024年7月9日 |
---|---|
0.3.0 | 2022年5月8日 |
0.2.2 | 2022年4月27日 |
0.2.1 | 2022年2月6日 |
0.1.1 | 2022年1月31日 |
#340 in 解析工具
7,861 每月下载量
在 2 个crate中使用(通过 databend-common-ast)
28KB
557 行
nom-rule
一个用于在简单DSL中定义nom组合器的过程宏。需要nom v5.0+和nightly Rust工具链。
依赖项
[dependencies]
nom = "7"
nom-rule = "0.2"
语法
此crate提供的过程宏 rule!
旨在简化语法规范的编写并提高可维护性,它遵循以下简单规则
TOKEN
:按token类型匹配token。如果匹配到token类型,应提供解析器来消耗下一个token。它将扩展为match_token(TOKEN)
。";"
:按token文本匹配token。如果匹配到token文本,应提供解析器来消耗下一个token。在这个示例中,它将扩展为match_text(";")
。#fn_name
:外部nom解析器函数。在上面的示例中,ident
是一个预定义的标识符解析器。a ~ b ~ c
:按顺序取一个解析器的解析器序列。它将扩展为nom::sequence::tuple
。(...)+
:一个或多个重复的模式。它将被展开为nom::multi::many1
。(...)*
:零个或多个重复的模式。它将被展开为nom::multi::many0
。(...)?
:可选解析器。它将被展开为nom::combinator::opt
。a | b | c
:在a、b和c之间进行选择。它将被展开为nom::branch::alt
。&a
:窥视。它将被展开为nom::combinator::peek(a)
。注意,它不会消耗输入。!a
:否定谓词。它将被展开为nom::combinator::not
。注意,它不会消耗输入。^a
:Cut解析器。它将被展开为nom::combinator::cut
。... : "description"
:错误报告的上下文描述。它将被展开为nom::error::context
。
示例
定义match_text
解析器和match_token
解析器用于您的自定义令牌类型。如果您解析器使用&str
或&[u8]
作为输入,因为您不会匹配令牌类型,所以可以使用nom::combinator::fail
作为match_token
。
#[derive(Clone, Debug, PartialEq)]
struct Token<'a> {
kind: TokenKind,
text: &'a str,
span: Span,
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum TokenKind {
Whitespace,
// Keywords
CREATE,
TABLE,
// Symbols
LParen,
RParen,
Semicolon,
Comma,
Ident,
}
fn match_text<'a, Error: ParseError<Input<'a>>>(
text: &'a str,
) -> impl FnMut(Input<'a>) -> IResult<Input<'a>, &'a Token<'a>, Error> {
move |i| satisfy(|token: &Token<'a>| token.text == text)(i)
}
fn match_token<'a, Error: ParseError<Input<'a>>>(
kind: TokenKind,
) -> impl FnMut(Input<'a>) -> IResult<Input<'a>, &'a Token<'a>, Error> {
move |i| satisfy(|token: &Token<'a>| token.kind == kind)(i)
}
然后通过自定义宏将其包装,将其两个解析器提供给nom_rule::rule!
。
macro_rules! rule {
($($tt:tt)*) => {
nom_rule::rule!($crate::match_text, $crate::match_token, $($tt)*)
}
}
定义创建表SQL的解析器
let mut rule = rule!(
CREATE ~ TABLE ~ #ident ~ ^"(" ~ (#ident ~ #ident ~ ","?)* ~ ")" ~ ";" : "CREATE TABLE statement"
);
它将被展开为
let mut rule =
nom::error::context(
"CREATE TABLE statement",
nom::sequence::tuple((
(crate::match_token)(CREATE),
(crate::match_token)(TABLE),
ident,
(nom::combinator::cut(crate::match_text)("(")),
nom::multi::many0(nom::sequence::tuple((
ident,
ident,
nom::combinator::opt((crate::match_text)(",")),
))),
(crate::match_text)(")"),
(crate::match_text)(";"),
))
);
更多示例请参考
tests/lib.rs
和主要依赖项 databend。
自动序列
nom-rule
可以在必要时自动在规则中插入~
,以便使上面的示例与以下示例具有相同的工作方式
let mut rule = rule!(
CREATE TABLE #ident "(" (#ident #ident ","?)* ")" ";" : "CREATE TABLE statement"
);
要启用此功能,您需要将以下内容添加到Cargo.toml
nom-rule = { version = "0.2", features = ["auto-sequence"] }
依赖项
~2.5MB
~55K SLoC