创建混合递归宏以创建HTML模板DSL

时间:2018-04-10 04:08:51

标签: rust rust-macros

我是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"))

1 个答案:

答案 0 :(得分: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').