#parser #framework #error-message #syntax-error #expression-parser #json-parser

untwine_macros

类似BNF的语法进行声明式解析 - 过程宏

13个版本 (7个破坏性更新)

0.8.1 2024年6月15日
0.7.0 2024年5月9日

#2131 in 过程宏

Download history 248/week @ 2024-04-08 311/week @ 2024-04-15 48/week @ 2024-04-22 4/week @ 2024-04-29 163/week @ 2024-05-06 7/week @ 2024-05-13 122/week @ 2024-05-20 1/week @ 2024-05-27 150/week @ 2024-06-10 22/week @ 2024-06-17

每月 1,311 次下载
untwine 中使用

MIT 许可证

56KB
1.5K SLoC

Untwine

具有自动错误恢复功能的更漂亮的模式匹配解析器

Example expression errors

Untwine是一个声明式解析库,它允许使用自定义宏语法进行类似于直接模式匹配的解析风格。这允许创建非常紧凑的解析器,具有合理的性能特征和高质量的错误消息。这些解析器易于实现,一些精选示例包括

  • 12行解析逻辑的近乎完整的JSON解析器
    • 支持所有基本的JSON功能,除特殊转义序列(非\)外
  • 6行解析逻辑的遵循pmdas的四运算表达式解析器
    • 以及一个操作两个数字的辅助函数

使用untwine制作的解析器还具有高质量的错误消息,可以直观地显示错误和相关的语法。

用法

本说明将主要涵盖示例和功能。有关使用分解,请参阅 https://docs.rs/untwine/latest/untwine/macro.parser.html

有关更详细的教程,请参阅 https://github.com/boxbeam/untwine/blob/master/TUTORIAL.md

简单,声明式解析

Untwine允许您通过描述您想要解析的语法并选择您想要的输出部分来解析。以下是在Untwine中实现表达式解析器的代码。

fn operate(left: f64, op: char, right: f64) -> f64 {
    match op {
        '+' => left + right,
        '-' => left - right,
        '/' => left / right,
        '*' => left * right,
        _ => unreachable!(),
    }
}

parser! {
    sep = #{char::is_ascii_whitespace}*;
    num: num=<"-"? '0'-'9'+ ("." '0'-'9'+)?> -> f64 { num.parse().unwrap() }
    term = (num | "(" sep expr sep ")") -> f64;
    add: first=mul sep ops=(["+-"] sep mul)* -> f64 { ops.into_iter().fold(first, |left, (op, right)| operate(left, op, right)) }
    mul: first=term sep ops=(["*/"] sep term)* -> f64 { ops.into_iter().fold(first, |left, (op, right)| operate(left, op, right)) }
    pub expr = add -> f64;
}

尽管本指南不会全面解释解析器,但展示了几个关键特性。首先,语法与Regex或EBNF有些相似。每个解析器都声明它所匹配的模式,并且可以在任何顶级模式前使用name=来提取该模式的值到变量中。一旦结构匹配成功,就在代码块中评估解析器的输出。

这种方法的优点在于利用了形式语法的强大功能,同时仍然允许与类型系统和IDE洞察完全集成。

除了简洁之外,解析器还能自动从您描述的语法中生成色彩丰富的错误,并能有效地展示任何语法错误。

错误

在这里,我将展示由表达式解析器和JSON解析器生成的部分错误。这些是通过示例REPL获得的,可以使用以下命令分别运行:cargo run --example exprcargo run --example json

Example expression errors

Untwine支持自动错误恢复,即使在发生错误后也能继续解析12行代码以发现更多错误。还可以获取包含错误节点的恢复输入。 示例JSON错误

由于错误表示的是范围而不是单个位置,因此也支持多行错误

Example multiline JSON errors

要查看这两个解析器的完整实现,请参阅 examples/json.rsexamples/expr.rs

性能和目标

尽管Untwine目前没有正式的基准测试,但非正式地我发现使用Untwine编写的解析器大约有基本但优化良好的手写解析器三分之二的速度。虽然Untwine寻求提供高性能,但它不适用于高度性能关键的解析器。

大多数解析并不是那么关键,Untwine非常适合构建编程语言或DSL,其中高质量的错误消息更为重要。它试图让解析变得如此简单,以至于在以前可能不会编写解析器的情况下也值得编写解析器,让您能够极快地进行迭代并消除手动解析的大部分痛点。

依赖关系

~260–700KB
~17K SLoC