#parser #proc-macro #parser-generator #macro #generator #pest #winnow

winnow-rule

一个用于在简单领域特定语言中定义 winnow 组合器的过程宏

2 个版本

0.1.1 2024年6月9日
0.1.0 2024年6月9日

129解析器工具

Download history 227/week @ 2024-06-06 32/week @ 2024-06-13

每月 259 次下载

MIT 许可证

28KB
579

winnow-rule

Documentation Crates.io LICENSE from upstream

一个用于在简单领域特定语言中定义 winnow 组合器的过程宏。需要 winnow v0.6+。

winnownom 的一个分支,有关更多详细信息,请参阅 为什么是 winnow

因此,winnow-rule 也是 nom-rule 的一个分支,主要目的是创建一个支持 winnow 的类似 DSL,然后我们可能还会添加更多高级功能。

由于 nomwinnow 之间的差异,nom-rulewinnow-rule 之间的语法不完全兼容。然而,它们都是为了提供类似正则表达式的体验而设计的。

目前,该包处于积极开发中,语法尚不稳定。

依赖项

[dependencies]
winnow = "0.6.13"
winnow-rule = "0.1"

语法

此包提供的 rule! 过程宏旨在简化语法规范的编写并提高可维护性,它遵循以下简单规则

  1. #fn_name:一个外部 winnow::Parser。在以下示例中,identTokenKind::* 是预定义的解析器。
  2. a ~ b ~ c:按顺序取一个解析器序列。它将被展开为 (a, b, c)
  3. (...)+:一个或多个重复的模式。它将被展开为 winnow::combinator::repeat(1.., #next)
  4. (...)*:零个或多个重复的模式。它将被展开为 winnow::combinator::repeat(0.., #next)
  5. (...)?:可选解析器。它将被展开为 winnow::combinator::opt
  6. a | b | c:在a、b和c之间进行选择。它将被展开为 winnow::combinator::alt
  7. &a:窥视。它将被展开为 winnow::combinator::peek(a)。注意,它不会消耗输入。
  8. !a:否定谓词。它将被展开为 winnow::combinator::not。注意,它不会消耗输入。
  9. ^a:裁剪解析器。它将被展开为 winnow::combinator::cut_err
  10. ... : "description":错误报告的上下文描述。它将被展开为 winnow::Parser::context

示例

为您的 TokenKind 实现 winnow::Parser,使其可以作为上述描述的外部解析器使用。

use winnow::{Parser, PResult, Stream};

#[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,
}

impl<'a, I, E> Parser<I, Token<'a>, E> for TokenKind
where
    I: Stream<Token = Token<'a>> + StreamIsPartial,
    E: ParserError<I>,
{
    fn parse_next(&mut self, input: &mut I) -> PResult<Token<'a>, E> {
        any.verify(|t: &Token<'a>| t.kind == *self)
            .parse_next(input)
    }
}

定义创建表的SQL解析器

use winnow_rule::rule;
use TokenKind::*;

let mut rule = rule!(
    #CREATE ~ #TABLE ~ #ident ~ ^#LParen ~ (#ident ~ #ident ~ #Comma?)* ~ #RParen ~ #Semicolon : "CREATE TABLE statement"
);

它将被展开为

    let mut rule = ((
        CREATE,
        TABLE,
        ident,
        winnow::combinator::cut_err(LParen),
        winnow::combinator::repeat(
            0..,
            ((ident, ident, winnow::combinator::opt(Comma))),
        ),
        RParen,
        Semicolon,
    ))
    .context(winnow::error::StrContext::Label("CREATE TABLE statement"));

更多示例请参阅 tests/lib.rs

路线图

计划中有几个特性

  • nom-rule 中实现自动序列化特性。
  • 实现捕获组语法,以减少未使用的输出,例如 #CREATE ~ #TABLE ~ (#ident) 只能输出捕获的表名。这个特性可以显著减少调用者的复杂性。
  • 考虑在 nom-rule 中重新添加 match_textmatch_token。尽管winnow可以轻松定义外部解析器,但在某些情况下它仍然可能有用。

依赖项

~2.5MB
~51K SLoC