我正在尝试解析与此类似的宏:
annoying!({
hello({
// some stuff
});
})
尝试使用类似于以下的过程宏定义来执行此操作,但我得到了一个我没想到的行为,我不确定我正在做一些我不应该做的事情或者我找到了一个错误。在下面的例子中,我试图找到每个块所在的行, 对于第一个块(内部烦人!)它报告正确的行,但是对于内部块,当我尝试打印它时,无论代码在哪里等,它总是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![])
}
我认为问题可能是因为我正在创建第二个解析器来解析内部块,这可能会使其中的Span
类型变得疯狂,但是我不确定这是问题还是如何继续离开这里。我正在创建第二个解析器的原因是我可以递归地解析每个块中的内容,我可能正在做一些我不应该做的事情,在这种情况下,更好的建议会非常受欢迎。