Macro with a # pattern

Hello, I don't manage to setup a macro mattern for understand CSS selectors : div#foo (where # is hardcoded and div and foo can change).

#[macro_export]
macro_rules! css_selector {
    ($tag_name: tt) => {
        // TODO
    };
    ([$tag_name:tt]#[$id:tt]) => {
        //TODO
    };
}

fn main() {
    // OK
    css_selector!(div);
    // KO
    css_selector!(div#foo);
}

Please advise.
Here is the playground

Moreover, I woud be interested in having a pattern for div.class (where . is hardcoded and div and class can change).

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=178b5f5d31060e49e6bc76d34b7c9a38

#[macro_export]
macro_rules! css_selector {
    ($tag_name: tt) => {
        println!("plain");
    };
    
    ($tag_name:tt # $id:tt) => {
        println!("#");
    };
    
    ($tag_name:tt . $id:tt) => {
        println!(".");
    };
}

fn main() {
    css_selector!(div);
    css_selector!(div#foo);
    css_selector!(div.foo);
}

Not sure why you added the brackets ([ ]) in your macro. IT works just fine without.

1 Like

Your second rule expects the identifiers to be surrounded by square brackets, but there's no square brackets when you call it. Removing them makes the code compile. Also note that r#ident (the first part must be r) is parsed as an identifier, so it's a single token, and that in the 2021 edition this will be the case for any sequence prefix#identifier

2 Likes

Thank you both ! This is clearer now how macros are working.

I though :bulb: we should add this forum as a cargo component. I always get clear and fast (less than an hour) answer from the community !

2 Likes

An other request. What is the macro pattern that will match div[class$="bar"].

I tries this ($tag_name:tt [$attribute_name:tt $= $attribute_value:literal ]) but this does not work as $ can not be matched.

See Macros By Example - The Rust Reference

The character $ cannot be matched or transcribed literally

You'll need to use :tt for it (thus making sure it is the last rule among "ambiguous" ones), and emit the validation against $ later on:

macro_rules! assert_is_dollar {
//    works because there is nothing after the dollar.
//    v
    ( $ ) => ();
}

macro_rules! css_selector {
    ( $tag_name:ident ) => (
        println!("plain");
    );

    ( $tag_name:ident # $id:ident ) => (
        println!("#");
    );

    ( $tag_name:ident . $id:ident ) => (
        println!(".");
    );

    (
        $tag_name:ident
        [ $attribute_name:ident $dol:tt = $attribute_value:literal ]
    ) => (
        assert_is_dollar!($dol);
        println!("$=");
    );
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.