1

我是 Rust 的新手,甚至是宏引擎的新手,我正在尝试想出一种创建 DSL 的方法,用于 HTML 模板,如下所示,

h! {
  foo(
    "bar",
    tag_with_parens(),
    tag_without_parens,
    "some other expression",
    element(child),
  ), 
  "tags and strings can be siblings",
}

我玩弄了一下,但我不确定这是否可能

macro_rules! h {
    // single idents and strings are matched here
    ($t:tt) => { h!($t(),) };
    ($t:tt( $($inner:tt),* )) => {h!($t($($inner),*),)};
    ($t:tt( $($inner:tt),* ), $($rest:tt),*) => {{
        // recursion with the contents of the tag            
        h!($($inner),*);
        // do something with the rest of the parameters
        h!($($rest),*);
    }};
}

在这个简单的示例中,我使用它是tt因为它同时匹配标识符和字符串文字,但是当令牌后面跟括号时它会中断,因为我认为它认为它是一个单独的令牌。我明白了error: no rules expected the token (。此外,如果我不仅要支持传递字符串,还要支持任何表达式,它必须有所不同

如果我让之前的事情起作用,我下一步要做的额外信用分配将是可选属性作为第一个参数。:)

h!(foo({ident="expr", bar}, "content"))
4

1 回答 1

0

使用当前的 Rust 宏系统似乎不可能实现这样的宏规则。

简化,所需的规则听起来像:

输入是表格和混合的不同模式的"literal"列表tag(elem)

零个或多个文字"a","b" ...可以与规则匹配:

( $(label:tt),* )

零个或多个tag(element)可以匹配:

( $( $tag:ident ( $inner:tt ) ),* )

但是如何定义一个匹配这样一系列不同结构化项目的规则呢?

还有一个像这样的简单规则(零个或多个literal后跟零个或多个tag(element))

$( $literal:tt ),*  $( $tag:ident ( $($inner:tt)* ) ),*

给出错误:

error: local ambiguity: multiple parsing options: built-in NTs tt ('literal') or ident ('tag').
于 2018-04-11T13:40:55.113 回答