简体   繁体   English

如何从板条箱/模块/功能派生代码?

[英]How to derive code from crate/module/functions?

As far as I know, Rust supports #[derive] attribute to generate code at compile time from data structures. 据我所知,Rust支持#[derive]属性,以便在编译时从数据结构生成代码。 How can I generate code for whole crate, module or functions? 如何为整个包装箱,模块或功能生成代码? The #[derive] attribute is not allowed here. 这里不允许使用#[derive]属性。

I want to generate a function which involves multiple items (structs/enums/functions) in the project. 我想生成一个在项目中涉及多个项目(结构/枚举/函数)的函数。

For example, for given example module here 例如,此处给定的示例模块

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

I want to produce this. 我要生产这个。

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

This example doesn't make sense, but I think it delivers the point. 这个例子没有道理,但我认为这是正确的。

The #[derive] attribute is not allowed on modules, only on structs, enums and unions: #[derive]属性仅在结构,枚举和联合上不允许在模块上使用:

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

Playground 操场

Further information on extending the #[derive] macro can be found in Procedural Macros (and custom Derive) in the Rust book. 有关扩展#[derive]宏的更多信息,请参见Rust手册中的过程宏(和自定义Derive)

However, you could create your own procedural macro. 但是,您可以创建自己的程序宏。 You may consult the RFC to understand proc-macros . 您可以参考RFC了解proc-macros It wouldn't hurt to also take a look at other crates like Serde or Derivative . 看看诸如SerdeDerivative之类的其他板条箱也没有什么坏处。

I found a workaround. 我找到了解决方法。 You can spawn a Rust language parser and parse source code yourself. 您可以生成Rust语言解析器并自己解析源代码。

First, add a dependency to Cargo.toml . 首先,将依赖项添加到Cargo.toml

[dependencies]
syntex_syntax = "0.59.1"

And add these lines to src/main.rs . 并将这些行添加到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);
}

Now you have a parsed AST. 现在您已经解析了AST。


Update 更新

After several weeks of tries, I learned macro-expansion is done at syntax parsing stage. 经过几周的尝试,我学会了在语法分析阶段完成宏扩展。 As it gets executed before type analysis stage, I cannot query fully resolved paths for each types, therefore stable referencing of multiple types from multiple module becomes very hard or impossible. 由于它是在类型分析阶段之前执行的,因此我无法查询每种类型的完全解析的路径,因此很难从多个模块中稳定引用多个类型。 Finally, I abandoned macro-based approach. 最后,我放弃了基于宏的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM