如何从包/模块/函数派生代码?

时间:2018-05-10 06:54:52

标签: rust code-generation

据我所知,Rust支持#[derive]属性,以便在编译时从数据结构生成代码。如何为整个包,模块或函数生成代码?此处不允许使用#[derive]属性。

我想生成一个涉及项目中多个项目(结构/枚举/函数)的函数。

例如,对于给定的示例模块

#[derive(MyAgg)]
mod AAA {
    struct BBB {}
    struct CCC {}
    fn ddd() {}
}

我想制作这个。

fn example1() {
    print("{:?}", AAA::BBB {});
    print("{:?}", AAA::CCC {});
    AAA::ddd()
}

这个例子没有意义,但我认为它提供了重点。

2 个答案:

答案 0 :(得分:3)

模块上不允许#[derive]属性,仅限于结构,枚举和联合:

error: `derive` may only be applied to structs, enums and unions
 --> src/main.rs:1:1
  |
1 | #[derive(MyAgg)]
  | ^^^^^^^^^^^^^^^^

Playground

有关扩展#[derive]宏的更多信息,请参阅Rust书中的Procedural Macros (and custom Derive)

但是,您可以创建自己的过程宏。您可以咨询RFC以了解 proc-macros 。同样看看SerdeDerivative等其他包装箱也不会有什么坏处。

答案 1 :(得分:0)

我找到了解决方法。您可以生成Rust语言解析器并自己解析源代码。

首先,向Cargo.toml添加依赖项。

[dependencies]
syntex_syntax = "0.59.1"

并将这些行添加到src/main.rs

extern crate syntex_syntax;

use std::path::*;
use syntex_syntax::parse::*;
use syntex_syntax::codemap::*;

fn main() {
    let f = file!(); // Get absolute path to this file.
    let p = Path::new(f);
    let m = FilePathMapping::empty();
    let s = ParseSess::new(m);
    let r = parse_crate_from_file(&p, &s);
    println!("{:?}", r);
}

现在你已经解析了AST。

更新

经过几周的尝试,我学会了在语法分析阶段完成宏扩展。当它在类型分析阶段之前执行时,我无法为每种类型查询完全解析的路径,因此从多个模块中稳定地引用多个类型变得非常困难或不可能。最后,我放弃了基于宏观的方法。