Rust TT muncher 具有无限递归

Nat*_*ara 2 rust

我正在尝试使用 TT muncher 创建嵌套哈希映射结构。基本类型定义是

type Object = HashMap<String, Node>;

enum Node {
    Terminal(String),
    Nested(Object),
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以手动创建这些对象:

let mut x: Object = HashMap::new();

x.insert("foo".into(), Node::Terminal("bar".into()));
x.insert("bing".into(), {
    let mut bing = HashMap::new();
    bing.insert("bar".into(), Node::Terminal("baz".into()));
    Node::Nested(bing)
});
Run Code Online (Sandbox Code Playgroud)

这确实生成了预期的结构

{
    "bing": Nested(
        {
            "bar": Terminal(
                "baz"
            )
        }
    ),
    "foo": Terminal(
        "bar"
    )
}
Run Code Online (Sandbox Code Playgroud)

但我有一些这种格式的大文字,而且我更喜欢使用不太难看的语法,所以我尝试制作一个宏。这是我认为应该起作用的最小示例:

use std::collections::HashMap;

type Object = HashMap<String, Node>;


#[derive(Debug)]
enum Node {
    Terminal(String),
    Nested(Object),
}


macro_rules! obj {
    {
        $($tt:tt)*
    } => {
        {
            let map = ::std::collections::HashMap::new();

            obj!(@parse; map; ($($tt)*));

            map
        }
    };
    (@parse; $name:ident; ()) => {};
    (@parse; $name:ident; ($key:expr => $value:expr, $($tail:tt)*)) => {
        $name.insert($key.into(), Node::Terminal($value.into()));
        obj!(@parse; $name; ($($tail)*));
    };
    (@parse; $name:ident; ($key:expr => $value:block, $($tail:tt)*)) => {
        $name.insert($key.into(), Node::Nested(obj!{$value}));
        obj!(@parse; $name; ($($tail)*));
    };
}

fn main() {
    let x: Object = obj!{
        "foo" => "bar",
        "bing" => {
            "bar" => "baz",
        },
    };

    println!("{:#?}", x);
}
Run Code Online (Sandbox Code Playgroud)

这不起作用,当我尝试编译它时出现递归错误:

error: recursion limit reached while expanding the macro `obj`
  --> src/main.rs:22:13
   |
22 |               obj!(@parse; map; ($($tt)*));
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
40 |       let x: Object = obj!{
   |  _____________________-
41 | |         "foo" => "bar",
42 | |         "bing" => {
43 | |             "bar" => "baz",
44 | |         },
45 | |     };
   | |_____- in this macro invocation
   |
   = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
Run Code Online (Sandbox Code Playgroud)

我尝试提高递归限制,但它不会终止。我的宏中缺少什么?

DK.*_*DK. 5

因为第一条规则几乎可以匹配任何内容。没有办法让它递归。

编写宏时,您需要从最具体到最不具体的顺序编写规则。