简体   繁体   English

Rust中的程序宏解析怪异

[英]Procedural macro parsing weirdness in Rust

I'm trying to parse a macro similar to this one: 我正在尝试解析与此宏类似的宏:

annoying!({
    hello({
        // some stuff
    });
})

Trying to do this with a procedural macro definition similar to the following, but I'm getting a behaviour I didn't expect and I'm not sure I'm doing something I'm not supposed to or I found a bug. 尝试使用类似于以下内容的过程宏定义来执行此操作,但是我遇到了意外的行为,并且不确定自己是否在做我不应该做的事情,或者发现了错误。 In the following example, I'm trying to find the line where each block is, for the first block (the one just inside annoying!) it reports the correct line, but for the inner block, when I try to print them it's always 1, no matter where the code is etc. 在下面的示例中,我试图找到每个块所在的行,对于第一个块(正好在里面的那个烦人!),它报告正确的行,但是对于内部块,当我尝试打印它们时,它总是1,无论代码在哪里等等

#![crate_type="dylib"]
#![feature(macro_rules, plugin_registrar)]

extern crate syntax;
extern crate rustc;

use macro_result::MacroResult;
use rustc::plugin::Registry;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::ext::quote::rt::ToTokens;
use syntax::codemap::Span;
use syntax::ast;
use syntax::parse::tts_to_parser;

mod macro_result;

#[plugin_registrar]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_macro("annoying", macro_annoying);
}

pub fn macro_annoying(cx: &mut ExtCtxt, _: Span, tts: &[ast::TokenTree]) -> Box<MacResult> {
    let mut parser = cx.new_parser_from_tts(tts);

    let lo = cx.codemap().lookup_char_pos(parser.span.lo);
    let hi = cx.codemap().lookup_char_pos(parser.span.hi);

    println!("FIRST LO {}", lo.line); // real line for annoying! all cool
    println!("FIRST HI {}", hi.line); // real line for annoying! all cool

    let block_tokens = parser.parse_block().to_tokens(cx);
    let mut block_parser = tts_to_parser(cx.parse_sess(), block_tokens, cx.cfg());

    block_parser.bump(); // skip {
    block_parser.parse_ident(); // hello
    block_parser.bump(); // skip (

    // block lines
    let lo = cx.codemap().lookup_char_pos(block_parser.span.lo);
    let hi = cx.codemap().lookup_char_pos(block_parser.span.hi);

    println!("INNER LO {}", lo.line); // line 1? wtf?
    println!("INNER HI {}", hi.line); // line 1? wtf?

    MacroResult::new(vec![])
}

I think the problem might be the fact that I'm creating a second parser to parse the inner block, and that might be making the Span types inside it go crazy, but I'm not sure that's the problem or how to keep going from here. 我认为问题可能是因为我正在创建第二个解析器来解析内部块,并且可能使其中的Span类型变得疯狂,但是我不确定这是问题所在还是如何避免这里。 The reason I'm creating this second parser is so I can recursively parse what's inside each of the blocks, I might be doing something I'm not supposed to, in which case a better suggestion would be very welcome. 我创建第二个解析器的原因是,我可以递归地解析每个块中的内容,我可能正在做我不应该做的事情,在这种情况下,将欢迎更好的建议。

I believe this is #15962 (and #16472 ), to_tokens has a generally horrible implementation. 我相信这是#15962 (和#16472 ), to_tokens具有普遍可怕的实现。 Specifically, anything non-trivial uses ToSource , which just turns the code to a string, and then retokenises that (yes, it's not great at all!). 具体来说,任何不平凡的事情都使用ToSource ,它只是将代码转换为字符串,然后重新标记(是的,一点都不好!)。

Until those issues are fixed, you should just handle the original tts directly as much as possible. 在解决这些问题之前,您应该尽可能直接直接处理原始的tts You could approximate the right span using the .span of the parsed block (ie return value of parse_block ), which will at least focus the user's attention on the right area. 您可以使用已解析块的.span来近似正确的跨度(即parse_block返回值),这至少会将用户的注意力集中在正确的区域上。

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

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