1 个不稳定版本
0.1.0 | 2023年4月23日 |
---|
#533 在 过程宏
12KB
141 行
script-macro
一种在与其他源代码内联编写简单过程宏的实验性方法。
在编写过程宏时,你是否曾经因为样板代码而感到沮丧,并希望能够直接编写Python或Bash脚本来生成代码呢?
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[script_macro::run_script_on(r##"
let output = item;
for x in 0..10 {
for y in 0..10 {
output += `
#[test]
fn it_works_${x}_${y}() {
it_works(${x}, ${y}, ${x + y});
}`;
}
}
return output;
"##)]
fn it_works(x: usize, y: usize, out: usize) {
assert_eq!(add(x, y), out);
}
}
宏不是Rust源代码,而是用RHAI脚本语言编写的。这既有优点也有缺点
-
缺点:无法访问Rust crate生态系统 -- RHAI是其自己的独立语言,因此你无法在其中使用Rust crate。RHAI 可以 通过自定义Rust函数进行扩展,但
script-macro
目前还不支持。目前,script-macro
公开了一些在代码生成中常用的辅助工具。 -
优点:可沙箱化 -- 使用
script-macro
执行的进程宏无法访问互联网或执行任意系统调用。进程宏 可以 通过rhai-fs
中提供的函数完全访问文件系统,但未来版本中这可能可配置,例如只读访问或限制访问特定目录。 -
缺点:依赖RHAI运行时 -- RHAI是一个完整的语言运行时,必须在运行任何进程宏之前编译一次。
-
优点:编辑进程宏时无需重新编译。 -- 进程宏是解释型脚本。在编辑时,只需要重新编译包含的crate,而不需要重新编译
script-macro
本身。这 可能 在处理大量进程宏时更快。另请参阅watt,它似乎在编译速度(一次编译所有宏的运行时,运行所有宏而不需要编译)方面具有类似的权衡
真的吗?
我真心希望过程宏(proc_macros)更容易编写(与其它代码一起编写)并且不会对编译时间产生那么大的影响。对我来说,这种情况特别常见的一个领域是程序化测试生成(或,参数化)。
这是我今天能做的最好的尝试,但这并不意味着我确信最终结果适用于生产使用。我希望它能激励其他人构建更好的东西。
API
可以选择的两个主要宏:
-
script_macro::run_script_on
-- 属性宏,执行给定脚本,同时将注解函数/模块的源代码作为全局字符串在item
下提供。脚本的返回值是替换项目将使用的源代码。
这是一个简单的脚本宏,它将
#[test]
添加到注解函数中。#[script_macro::run_script_on(r##" return "#[test]" + item; "##)] fn it_works(x: usize, y: usize, out: usize) { assert_eq!(add(x, y), out); }
-
script_macro::run_script
-- 函数宏,执行给定脚本。没有输入。script_macro::run_script!(r##" return `fn main() { println!("hello world"); }`; "##);
脚本 API
在脚本内部,整个 RHAI stdlib 以及 rhai-fs
中的函数都可用。
此外,还定义了以下函数:
-
parse_yaml(String) -> Dynamic
-- 将 YAML 有效负载作为字符串接收,并返回解析后的有效负载作为非结构化数据(例如,RHAI 对象映射或数组)。 -
parse_json(String) -> Dynamic
-- 将 JSON 有效负载作为字符串接收,并返回解析后的有效负载作为非结构化数据(例如,RHAI 对象映射或数组)。 -
stringify_yaml(Dynamic) -> String
-- 将 RHAI 对象转换为 YAML 字符串,与parse_yaml
相反。 -
stringify_json(Dynamic) -> String
-- 将 RHAI 对象转换为 YAML 字符串,与parse_json
相反。 -
glob(String) -> Vec<PathBuf>
-- 接收一个 glob 模式,并返回匹配该模式的路径列表。 -
basename(PathBuf) -> String
-- 返回给定路径的.file_name()
,如果没有,则返回整个路径。
示例
查看 示例库,了解上述所有功能的应用。
许可证
在 MIT 许可下发布,请参阅 ./LICENSE
。
依赖项
~7MB
~133K SLoC