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的问题是,我/真的/需要能够在块内递归解析,因为第一个块中不太可能包含任何有用的信息。是否有人知道任何其他选项可以更好地近似到正确的行?