0

I'm new to Rust and even more to the macro engine, I'm trying to come up with a way of creating a DSL that I'll use for HTML templating that looks like the following,

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

I've toyed around a bit but I'm not sure if it's even possible

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),*);
    }};
}

In this simple example, I'm using tt since it matches both identifiers and the string literals but it breaks when the token is followed by the parenthesis because I imagine it considers it a separate token. I get error: no rules expected the token (. Also if I want to support not only passing a string but any expression it would have to be different

An extra credit assignment that would be my next step if I get the previous thing to work would be optional attributes as first argument. :)

h!(foo({ident="expr", bar}, "content"))
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
olanod
  • 30,306
  • 7
  • 46
  • 75
  • In my opinion, a compiler plugin is more suitable for this kind of use case. But unfortunately, it is not yet stabilized :( – Boiethios Apr 10 '18 at 08:10
  • 3
    In case you're not aware of the existing libraries in this space - [Horrowshow](https://github.com/Stebalien/horrorshow-rs) is written with `macro_rules` and [Maud](https://github.com/lfairy/maud) is a procedural macro. If you're totally stuck, maybe looking at their code could help you out. Totally understand if you're wanting to figure it out for yourself, though :) – Joe Clay Apr 10 '18 at 10:21

1 Answers1

0

With the current Rust macro system it seems that it is not possible to implements such macro rule.

Simplifying, the needed rule sounds like:

the input is a list of different and intermixed patterns of the form "literal" and tag(elem).

Zero or more literals "a","b" ... can be matched with the rule:

( $(label:tt),* )

Zero or more tag(element) can be matched with:

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

But how to define a rule that match such a sequence of different structured items?

Also a simple rule like this (zero or more literal followed by zero or more tag(element)):

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

gives the error:

error: local ambiguity: multiple parsing options: built-in NTs tt ('literal') or ident ('tag').
attdona
  • 17,196
  • 7
  • 49
  • 60