#language #convert #enums #input #path #cargo #specr

app specr-transpile

将Specr语言代码转换为Rust

31个版本

0.1.30 2024年7月30日
0.1.27 2024年5月14日
0.1.26 2023年9月27日
0.1.20 2023年7月28日
0.1.13 2023年3月26日

#38 in 过程宏

Download history 89/week @ 2024-05-08 51/week @ 2024-05-15 13/week @ 2024-05-22 8/week @ 2024-05-29 4/week @ 2024-06-05 251/week @ 2024-06-12 21/week @ 2024-06-19 8/week @ 2024-06-26 31/week @ 2024-07-03 18/week @ 2024-07-10 11/week @ 2024-07-17 373/week @ 2024-07-24 127/week @ 2024-07-31 10/week @ 2024-08-07

529次每月下载

MIT/Apache

37KB
759

specr-transpile

specr-transpile将specr语言代码转换为Rust代码。使用cargo r <config-file>运行。

配置文件

配置文件是由换行符分隔的语句列表。

每个语句是以下之一

  • input <path>:查找输入.md文件的路径。
  • output <path>:生成输出crate的路径。
  • attr <attribute>:提供额外的Rust crate属性,如attr #![feature(never_type)]

当前转换

枚举间接引用

如果你有一个由于类型递归而具有无限大小的枚举,你可能想要添加一个间接引用,如下所示

enum List<T> {
    Cons {
        val: T,
        #[specr::indirection]
        next: List<T>,
    },
    Nil,
}

这将把next封装在指针中。

缺点

  1. 您不应该匹配枚举的引用,如果您想使用具有 #[specr::indirection] 字段的值。当匹配 &List<T>(或 &mut List<T>)时,您会发现您仍然获得 next 类型为 List<T>,而不是 &List<T>(或 &mut List<T>),这在 Rust 中是正确的。因此,这样的代码将无法正常工作
match &mut l {
    List::Cons { val, next } => {
        *next = Nil;
    },
    _ => {},
}

类似地,使用 refref mut 不支持在 #[specr::indirection] 之后的字段。

  1. Specr 不会首先解析名称,因此不同枚举和结构体变体之间可能会发生命名冲突。未来我们打算在发现此类歧义时发出警告。

垃圾收集和复制

specr 提供的所有类型,如 ListSetMapBigInt 都是 Copy 类型的,因为它们只包含垃圾收集数据结构中的索引。此外,之前讨论的枚举间接引用通过使用相同的垃圾收集索引来应用间接引用。

因此,用户定义的类型也可以实现 Copy,因此不应使用标准库中的非 Copy 类型。specr 会自动添加此 #[derive(Copy, Clone)]

请注意,对 ListSetMap 的每次修改目前都需要对该数据结构进行完整复制。因此,例如,应尽可能使用 collect() 而不是 push()

待办事项:解释如何使用 mark_and_sweep 函数。

Argmatch

方法可以像这样匹配参数

impl Foo {
    #[specr::argmatch(x)]
    fn foo(&self, x: Option<i32>) -> i32;
}

impl Foo {
    fn foo(&self, Some(a): Option<i32>) -> i32 { a }
    fn foo(&self, None: Option<i32>) -> i32 { 0 }
}

Argmatch 也可以应用于 self

Merge Trait Impls

每当一个 trait 实现被分割成多个部分时,specr-transpile 会将它们合并在一起。

示例

trait Foo {
    fn foo1(&self);
    fn foo2(&self);
}

impl Foo for () {
    fn foo1(&self) { ... }
}

impl Foo for () { // invalid in Rust!
    fn foo2(&self) { ... }
}

变为

trait Foo {
    fn foo1(&self);
    fn foo2(&self);
}

impl Foo for () {
    fn foo1(&self) { ... }
    fn foo2(&self) { ... }
}

模块结构和 .md 文件

specr 会搜索包含 markdown 文件的文件夹,specr 会查看配置文件中指定的 input 目录。每个文件夹将生成一个 Rust 模块。这是通过过滤每个 .md 文件的 rust 代码并将它们连接起来实现的。

依赖项

~0.8–1.4MB
~31K SLoC