【问题标题】:Procedural macro parsing weirdness in RustRust 中的程序宏解析怪异
【发布时间】:2014-08-16 18:18:20
【问题描述】:

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

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 类型变得疯狂,但我我不确定这是问题所在或如何从这里继续前进。我创建第二个解析器的原因是我可以递归地解析每个块中的内容,我可能正在做一些我不应该做的事情,在这种情况下,我会非常欢迎更好的建议。

【问题讨论】:

  • 您是否有一些未列出的特征导入? (我特别想syntax::ext::quote::rt::ToTokens。)
  • 是的,我正在导入 ToTokens,我只是没有将其发布在此代码示例中以使其更简单,我在这里使用的 MacroResult 也出于同样的原因.如果您认为它更好,我可以发布整个内容?
  • 仅通过其方法使用的特征的导入(即未命名,如MacroResult 在这里)与代码非常相关。
  • 我在那里添加了导入 ;)

标签: macros rust


【解决方案1】:

我相信这是#15962(和#16472),to_tokens 的实现通常很糟糕。具体来说,任何不平凡的事情都使用ToSource,它只是将代码转换为字符串,然后对其进行重新标记(是的,它一点都不好!)。

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

【讨论】:

  • 这太糟糕了:(。处理原始 tts 的问题是我/真的/需要能够在块内递归解析,因为第一个块不太可能有任何有用的信息my case. 有人知道任何其他选项可以更好地逼近正确的线吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-30
  • 2020-04-17
  • 1970-01-01
相关资源
最近更新 更多