5 个稳定版本

2.0.2 2024年7月25日
2.0.1 2024年2月27日
1.1.2 2024年2月27日
1.1.1 2023年10月20日
1.1.0 2023年8月23日

166解析工具 中排名

Download history 374/week @ 2024-05-01 414/week @ 2024-05-08 402/week @ 2024-05-15 449/week @ 2024-05-22 484/week @ 2024-05-29 441/week @ 2024-06-05 331/week @ 2024-06-12 564/week @ 2024-06-19 477/week @ 2024-06-26 424/week @ 2024-07-03 465/week @ 2024-07-10 397/week @ 2024-07-17 586/week @ 2024-07-24 598/week @ 2024-07-31 586/week @ 2024-08-07 596/week @ 2024-08-14

2,416 每月下载量
67 个crate(直接使用3个) 中使用

MIT/Apache

115KB
3.5K SLoC

静态正则文法

Build Crate informations License Documentation

此库提供了方便的 RegularGrammar 推导宏,帮助您创建由正则文法验证的字节或字符字符串的无大小类型包装。它通过解析文件或您的类型文档中指定的文法,将其静态编译成确定性的、最小的、正则自动机,然后将其转换为Rust验证函数来实现。

目前,仅支持 ABNF 文法格式。

基本用法

文法由类型文档中的代码块指定。该类型本身必须是具有单个未命名字段的简单元组结构,该字段指定文法 "token 字符串类型"。此标记字符串类型可以是

  • [u8]:文法是在字节上定义的。
  • str:文法是在Unicode字符上定义的。

示例

use static_regular_grammar::RegularGrammar;

/// Example grammar.
///
/// ```abnf
/// foo = "f" 1*("oo") ; the first non-terminal is used as entry point.
/// ```
#[derive(RegularGrammar)]
pub struct Foo([u8]);

let foo = Foo::new(b"foooooo").unwrap();

推导宏还提供了一个 grammar 属性来配置文法和生成的代码。使用此属性,您可以使用文件路径指定文法,而不是使用文档

/// Example grammar.
#[derive(RegularGrammar)]
#[grammar(file = "examples/test.abnf")]
pub struct Foo([u8]);

let foo = Foo::new(b"foooooo").unwrap();

文法入口点

默认情况下,使用文法中定义的第一个非终结符作为入口点。您可以使用 grammar 属性的 entry_point 子属性指定不同的入口点

/// Example grammar.
#[derive(RegularGrammar)]
#[grammar(file = "examples/test.abnf", entry_point = "bar")]
pub struct Bar([u8]);

let bar = Bar::new(b"baaaar").unwrap();

ASCII

使用 [u8] 标记字符串类型,可以指定值可以解释为ASCII文本字符串。然后,生成的类型将实现 DisplayDeref<Target=str>AsRef<str> 等。

#[derive(RegularGrammar)]
#[grammar(file = "examples/test.abnf", ascii)]
pub struct Bar([u8]);

let bar = Bar::new(b"baaaar").unwrap();
println!("{bar}");

有大小类型

《RegularGrammar》宏在未指定大小类型上工作,但通常需要一个可以拥有数据同时保证数据有效性的指定大小等效类型。使用《grammar》属性的《sized》子属性,衍生宏可以为你完成这项工作。

/// Example grammar, with sized variant.
///
/// ```abnf
/// foo = "f" 1*("oo")
/// ```
#[derive(RegularGrammar)]
#[grammar(sized(FooBuf))] // this will generate a `FooBuf` type.
pub struct Foo([u8]);

let foo = FooBuf::new(b"foooooo".to_vec()).unwrap();

指定大小的类型将实现《Deref》、《Borrow》和《AsRef》到未指定大小类型。它还将包含一个名为《as_unsized_type_name》的方法(例如上面示例中的《as_foo》),返回未指定类型的引用。

常见特质实现

您可以使用《derive》子属性指定为指定大小类型自动实现的常见特质。

#[grammar(sized(FooBuf, derive(PartialEq, Eq)))]

支持的特质包括

  • Debug
  • Display
  • PartialEq
  • Eq
  • PartialOrd
  • Ord
  • Hash

所有这些都将依赖于未指定类型的等效实现。

缓存

编译时,输入语法将被确定化和最小化。这些是成本较高的操作,在大语法中可能需要几秒钟的时间。为了避免不必要的操作,生成的自动机将存储在磁盘上,直到对语法进行更改。默认情况下,自动机将存储在《target》文件夹中,例如《regular-grammar/TypeName.automaton.cbor》。例如,在上面的示例中,路径将是《target/regular-grammar/Foo.automaton.cbor》。您可以使用《cache》子属性指定文件路径。

#[grammar(cache = "path/to/cache.automaton.cbor")]

路径必须是相对路径,并且不得包含《..》段。如果您有多个具有相同名称的语法类型,请使用此属性以避免冲突,否则缓存将不会工作。对于大型语法,直接将自动机与源代码一起缓存可能是一个好主意,并将其与您的库/应用程序一起分发,以减少用户机器上的编译时间。

禁用自动机生成

当使用如《rust-analyzer》之类的lint工具时,即使有缓存,持续重新生成语法自动机也可能过于昂贵。在大语法中,生成的自动机代码可能跨越数百甚至数千行。在这种情况下,您可以完全禁用自动机生成,使用《disable》选项。

#[grammar(disable)]

当然,最好在仅由linter使用的功能后使用此选项

#[cfg_attr(feature = "disable-grammars", grammar(disable))]

rust-analyzer

许可证

根据您的要求,许可在以下任一项下

  • Apache License,版本2.0(《LICENSE-APACHE》或《https://apache.ac.cn/licenses/LICENSE-2.0》)
  • MIT许可证(《LICENSE-MIT》或《http://opensource.org/licenses/MIT》)

任选其一。

贡献

除非您明确声明,否则根据Apache-2.0许可证定义的任何有意提交的工作,都应按上述方式双许可,不附加任何额外条款或条件。

依赖关系

~2.6-3.5MB
~75K SLoC