Macros Rust中程序宏解析的怪异之处

Macros Rust中程序宏解析的怪异之处,macros,rust,Macros,Rust,我正在尝试解析一个类似于此的宏: annoying!({ hello({ // some stuff }); }) 尝试使用类似于下面的过程宏定义来实现这一点,但是我得到了一个我没有预料到的行为,我不确定我正在做一些我不应该做的事情,或者我发现了一个bug。在下面的示例中,我试图找到每个块所在的直线, 对于第一个块(就在里面!),它报告正确的行,但是对于内部块,当我尝试打印它们时,它总是1,不管代码在哪里等等 #![crate_type="dylib"] #![

我正在尝试解析一个类似于此的宏:

annoying!({
    hello({
        // some stuff
    });
})
尝试使用类似于下面的过程宏定义来实现这一点,但是我得到了一个我没有预料到的行为,我不确定我正在做一些我不应该做的事情,或者我发现了一个bug。在下面的示例中,我试图找到每个块所在的直线, 对于第一个块(就在里面!),它报告正确的行,但是对于内部块,当我尝试打印它们时,它总是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![])
}
#![板条箱类型=“dylib”]
#![功能(宏规则、插件注册器)]
外部板条箱语法;
外部板条箱生锈;
使用宏结果::宏结果;
使用rustc::plugin::Registry;
使用语法::ext::base::{ExtCtxt,MacResult};
使用语法::ext::quote::rt::ToTokens;
使用syntax::codemap::Span;
使用syntax::ast;
使用syntax::parse::tts_to_解析器;
mod宏_结果;
#[插件注册器]
发布fn插件注册器(注册表:&mut注册表){
注册表。注册表_宏(“烦人”,宏_烦人);
}
pub fn macro_(cx:&mut ExtCtxt,x:Span,tts:&[ast::TokenTree])->框{
让mut parser=cx.new_parser_from_tts(tts);
让lo=cx.codemap().lookup\u char\u pos(parser.span.lo);
让hi=cx.codemap().lookup\u char\u pos(parser.span.hi);
println!(“第一个LO{},LO.line);//真讨厌!都很酷
println!(“第一个HI{},HI.line);//真讨厌!都很酷
设block_tokens=parser.parse_block().to_tokens(cx);
让mut block_parser=tts_to_parser(cx.parse_sess(),block_标记,cx.cfg());
block_parser.bump();//跳过{
block_parser.parse_ident();//您好
block_parser.bump();//跳过(
//封锁线
设lo=cx.codemap().lookup\u char\u pos(block\u parser.span.lo);
设hi=cx.codemap().lookup\u char\u pos(block\u parser.span.hi);
println!(“内部LO{}”,LO.line);//第1行?wtf?
println!(“内部HI{},HI.line);//第1行?wtf?
宏结果::新建(vec![])
}
我认为问题可能在于我正在创建第二个解析器来解析内部块,这可能会使它内部的
Span
类型变得疯狂,但我不确定这就是问题所在,也不确定如何继续下去。我创建第二个解析器的原因是为了能够递归解析每个块中的内容,我可能正在做一些我不应该做的事情,在这种情况下,一个更好的建议是非常受欢迎的。

我相信这是(而且)一个非常糟糕的实现。具体地说,任何非平凡的用途,只要将代码转换成字符串,然后重新排序(是的,这一点都不好!)


在解决这些问题之前,您应该尽可能直接处理原始的
tts
。您可以使用解析块的
.span
近似正确的span(即
parse_block
的返回值),这至少会将用户的注意力集中在正确的区域。

您是否有一些未列出的特性导入?(我特别想到的是
syntax::ext::quote::rt::ToTokens
)是的,我正在导入ToTokens,我只是没有将它发布在这个代码示例上以使其更简单,我在这里使用的
MacroResult
也是出于同样的原因。如果你认为更好的话,我可以发布整件事?导入仅通过其方法使用的特征(即未命名,如
MacroResult
在这里)与代码非常相关。我在那里添加了导入;)太糟糕了:(.处理原始tts的问题是,我/真的/需要能够在块内递归解析,因为第一个块中不太可能包含任何有用的信息。是否有人知道任何其他选项可以更好地近似到正确的行?