#code-generation #language #generate #plugin #keep #dry #backing

nightly external_mixin_umbrella

rust_mixinexternal_mixin 提供支持库,以保持它们简洁

2 个版本

使用旧的 Rust 2015

0.0.2 2015 年 2 月 27 日
0.0.1 2015 年 2 月 27 日

#2265Rust 模式

23 次每月下载
3 个crate(2 个直接使用)中使用

MIT/Apache

21KB
314

Rust 的混入

Build Status

使用任意语言编写代码,直接在您的crate中生成Rust代码。

#![feature(plugin)]
#![plugin(external_mixin)]
#![plugin(rust_mixin)]

python_mixin! {"
x = 1 + 2
print('fn get_x() -> u64 { %d }' % x)
"}

fn main() {
    let value = get_x();

    let other_value = rust_mixin! {r#"
fn main() {
    println!("{}", 3 + 4);
}
    "#};

    assert_eq!(value, 3);
    assert_eq!(other_value, 7);
}

这包括三个库

我实际上应该使用这些吗?

可能不是,这是我正在尝试更多语言插件的实验。更便携/可用的代码生成方法是使用 一个 Cargo 构建脚本 加上 include! 宏。

一些缺点(不全面)

  • 混入,如 python_mixin! 依赖于用户路径中有正确命名的二进制文件,并且,例如,“python”有时是 Python 2,有时是 Python 3,并且意味着要求用户在 Windows 上安装 Python。(构建脚本只需要 Cargo 和 Rust 编译器,如果用户正在尝试构建您的 Rust 代码,则可以保证用户拥有这些。)

  • 生成的代码中的错误难以调试,尽管宏尝试提供尽可能有用的错误消息,例如,例如,文件/行号对于与原始字符串中包含源代码的相关部分尽可能接近的错误。然而,解析的 Rust 实际上并没有出现在磁盘上或任何其他地方,因此您无法轻松地看到编译器抱怨时的完整上下文(相比之下,构建脚本只需在您的文件系统中生成一个普通文件)。

安装

这两个插件crate都可在crates.io上找到: rust_mixinexternal_mixin。因此,您可以添加任何子集

[dependencies]
rust_mixin = "*"
external_mixin = "*"

将其添加到您的 Cargo.toml 中。

rust_mixin

用Rust编写生成您的Rust代码,直接在您的Rust中(yo dawg)。该插件将其参数编译和运行为Rust程序,然后将输出插入主crate中,类似于 macro_rules! 宏。

rust_mixin 插件接受一个字符串,其中包含一个要使用 rustc 编译的Rust程序。该程序应打印有效的Rust代码到stdout。每个 rust_mixin 调用都是独立的。字符串参数在使用之前先进行宏展开,因此使用 concat!() 构造调用是合法的。

该宏支持在字符串字面量之前有一个可选的 { ... } 块,以指定选项。当前支持的唯一选项是 arg:它可以多次指定,并且按顺序将参数传递给 rustc

示例

尽可能好地计算斐波那契数,通过让Rust打印一个计算每个数的函数

#![feature(plugin)]
#![plugin(rust_mixin)]

rust_mixin! {r#"
fn main() {
    println!("fn fib_0() -> i32 {{ 0 }}");
    println!("fn fib_1() -> i32 {{ 1 }}");

    for i in 2..(40 + 1) {
        println!("fn fib_{}() -> i32 {{ fib_{}() + fib_{}() }}",
                 i, i - 1, i - 2);
    }
}
"#}

fn main() {
    println!("the 30th fibonacci number is {}", fib_30());
}

在编译时进行斐波那契计算,直接了当地,因此我们想要一些优化

#![feature(plugin)]
#![plugin(rust_mixin)]

fn main() {
    let fib_30 = rust_mixin! {
        { arg = "-C", arg = "opt-level=3" }
        r#"
fn fib(n: u64) -> u64 {
    if n <= 1 { n } else { fib(n - 1) + fib(n - 2) }
}
fn main() {
    println!("{}", fib(30))
}
    "#};


    println!("the 30th fibonacci number is {}", fib_30);
}

external_mixin

使用各种脚本语言生成Rust代码。这有一个 external_mixin! 宏,它支持任意解释器,以及为几种语言提供的特殊支持:python_mixin!ruby_mixin!sh_mixin!perl_mixin!

rust_mixin! 一样,这些宏将它们的程序作为字符串接受,该字符串会进行宏展开,并且每个调用都是独立的。程序应打印有效的Rust代码到stdout。可以通过可选的 { ... } 块指定选项,在字符串字面量之前。

external_mixin! 宏是最灵活的形式,它接受一个必选的 interpreter 参数:这个程序会与一个包含代码片段的文件一起调用,该文件作为最后一个参数。

external_mixin! 和语言特定宏都支持 arg 选项,它可以多次指定,并且按顺序传递给主二进制文件。

可移植性?

这些宏依赖于将外壳程序输出到解释器,依赖于用户路径中存在适当命名的可执行文件(希望它是正确的版本……)。因此,这既不可移植也不可靠。至少 rust_mixin! 的用户保证有一个可用的 rustc,这里没有这样的保证。

示例

计算文件/文件夹在(Unix)文件系统顶部的数量。

#![feature(plugin)]
#![plugin(external_mixin)]

fn main() {
    let file_count = sh_mixin!("ls / | wc -l");
    println!("there are {} files in /", file_count);
}

通过Ruby计算程序构建时的Unix时间。

#![feature(plugin)]
#![plugin(external_mixin)]

fn main() {
    let build_time = ruby_mixin!("puts Time.now.to_i");
}

使用Python 2的裸打印语句和Python 3的除法语义(并猜测由 python_mixin! 使用的 python 二进制文件的版本)

#![feature(plugin)]
#![plugin(external_mixin)]

fn main() {
    let value2 = external_mixin! {
        { interpreter = "python2" }
        "print 1 / 2"
    };
    let value3 = external_mixin! {
        { interpreter = "python3" }
        "print(1 / 2)"
    };
    let value_unknown = python_mixin!("print(1 / 2)");

    if value_unknown as f64 == value3 {
        println!("`python_mixin!` is Python 3");
    } else {
        println!("`python_mixin!` is Python 2");
    }
}

external_mixin_umbrella

此存储库的最高级别项是一个库,旨在最大化 external_mixinrust_mixin 之间的代码共享,以便它们的实现分别只有100和50行。

没有运行时依赖项