13个版本 (4个重大更新)

0.5.6 2020年4月13日
0.5.5 2020年4月13日
0.5.3 2020年3月23日
0.5.1 2020年1月16日
0.1.2 2020年1月1日

#2089 in 开发工具

每月 30 次下载

MIT 协议

25KB
457

Sexpy

从Rust类型定义中自动推导s表达式解析器。这个库旨在用于简单编程语言定义,并允许您对语言的解析进行一些控制。

文档

查看文档了解如何使用此库。


lib.rs:

Sexpy从Rust类型定义中自动推导s表达式解析器。目标是能够从AST定义中进行,只需最少的注解。这适用于需要具有信息性解析错误消息和可读性语法(即非JSON)但不想编写完整解析器的原型编程语言。

为类型生成的默认解析器

为了了解如何使用此库,让我们看看为不同类型自动生成的解析器。

生成的默认解析器匹配“头部模式”。这些匹配一个关键字后面跟着一系列参数。例如,foo <string> <u32>是一个头部模式,头部为foo,它接受一个字符串参数和一个无符号32位整数作为第二个参数。这匹配foo cactus 20但不匹配foo big cactus

结构体

struct类型生成的默认解析器使用结构体名称的小写版本作为头部,并将字段类型作为参数。它解析括号、方括号或花括号包围的头部模式。

例如,考虑以下内容

#[derive(Sexpy)]
struct Port {
name: String,
width: u64
}

这生成了一个解析器,用于处理以下形式的模式:(端口 <字符串> <u64>)。例如,(端口 foo 10)被解析为Port { name: ""foo"".to_string(), width: 10 }port foo 10,而(端口 10 foo)则无法解析。

枚举

对于枚举,为枚举中的每个情况生成一个解析器。默认情况下,每个解析器使用枚举名作为头部,将变体参数作为模式参数。每个解析器匹配括号、方括号或花括号包围的模式。

例如,考虑以下枚举定义

#[derive(Sexpy)]
enum Plant {
PalmTree(String, u64),      // parses pattern: (plant <string> <u64>)
SageBush { height: u64 },   // parses pattern: (plant <u64>)
BarrelCactus                // parses pattern: (plant)
}

这将在注释中生成三个解析器。如果有两个变体有相同的参数,会发生什么?

#[derive(Sexpy)]
enum Plant {
Palm(String, u64),   // parses pattern: (plant <string> <u64>)
Cactus(String, u64)  // parses pattern: (plant <string> <u64>)
}

默认情况下,cactus变体将永远不会被解析。原因是无法区分Palm变体子解析器和Cactus变体子解析器;它们接受相同的参数!有几种处理方法,但最简单的方法是强制变体子解析器使用头部。您可以使用#[sexpy(head = ""<str>"")]选项来完成此操作。

#[derive(Sexpy)]
enum Plant {
#[sexpy(head = "palm")]
Palm(String, u64),      // parses pattern: (plant palm <string> <u64>)
#[sexpy(head = "cactus")]
Cactus(String, u64)     // parses pattern: (plant cactus <string> <u64>)
}

注意事项

可能有两个解析器解析相同的模式。目前,Sexpy没有做任何检测和防止这种行为。解决这些冲突的责任在于程序员。解析选项应使解决这些冲突变得容易。

选项

您可以通过指定一些属性来修改派生解析器匹配的模式。以下是一些在类型级别工作的属性,即

#[derive(Sexpy)]
#[sexpy(...)] // <-----
enum Plant { ... }

// or

#[derive(Sexpy)]
#[sexpy(...)] // <-----
struct Plant { ... }

所有属性都以逗号分隔的列表指定,如下所示:#[sexpy(attr = val, attr, ...)]参数的形式为<attr> = <val>。例如,当提供一个字符串参数的头部时,它看起来像head = ""custom-name""。布尔参数看起来像surround = true

属性 参数 效果
nohead none 忽略头部,只从参数生成模式
head string 使用自定义字符串作为头部,而不是小写类型名称
包围 bool 当为true时,匹配被括号、方括号或花括号包围的模式(默认为true)
nosurround none 快捷方式为surround = false

以下为变体级别的属性。它们看起来像

#[derive(Sexpy)]
enum Plant {
#[sexpy(head = "palm")]  // <-----
Palm(String, u64),
...
}
属性 参数 效果
head string 使用自定义字符串作为头部,而不是小写类型名称
包围 bool 当为true时,匹配被括号、方括号或花括号包围的模式(默认为false)

!

依赖关系

~2.5MB
~55K SLoC