How to write macro accept flexible struct


point!(M {
    a: "b" + (1, 2, 3, 4) + TopRight,
    a: "b" + TopRight,
    a: "b",
    a: ["b", "c"],
    a: M {
        a: "b" + (1, 2, 3, 4) + TopRight,
    },
});

I am constructing a macro, that accpet above struct where the value is any of

  1. add-style-expr( <= 3 elements)
  2. a similar struct
  3. a similar array

My problem is how to make such a macro.

If I use expr to extract struct value, the expr can't be accept by the next rule. There seems no way to revert expr to tt.

macro_rules! point {
    (M { $($k:ident : $v:expr ),* $(,)? }) => {{
        $( point!($v); )*
    }};
    ($x:tt + ($l:expr, $t:expr, $r:expr, $b:expr) + $loc:tt) => {
        ()
    };
}

If I use tt, the add-style-expr can't be matched. Wrapping all add-style-expr in () works but there are lots of waste typing.

macro_rules! point {
    (M { $($k:ident : $v:tt ),* $(,)? }) => {{
        $( point!($v); )*
    }};
}

If I use tt*, the comma after add-style-expr is ambiguous.

macro_rules! point {
    (M { $($k:ident : $($v:tt)* ),* $(,)? }) => {{
        $( point!($v); )*
    }};
}
point!(M {
    a: "b" + (1, 2, 3, 4) + TopRight, <-- ambiguous
});

Figure out!
+ is not easy to use as a delimiter. But - or / is ok.

macro_rules! point {
    // Map
    ((M { $($k:ty : $($v:tt)-*),* $(,)? })) => {{
        $(
            point!($($v)-*);
        )*
    }};
    // Vec
    ([ $( $($v:tt)-* ),* $(,)? ]) => {{
        $(
            point!($($v)-*);
        )*
    }};
    //Fn
    ( $b :block ) =>{{
        ()
    }};
    // ColorMove
    ( ($l:expr,$t:expr,$r:expr,$b:expr) ) => {
        point!("0|0|000000",($l,$t,$r,$b), TopLeft)
    };
    ( ($l:expr,$t:expr,$r:expr,$b:expr) - $loc:expr) => {
        point!("0|0|000000",($l,$t,$r,$b),$loc)
    };
    ( $x:tt - ($l:expr,$t:expr,$r:expr,$b:expr)) => {
        point!("0|0|000000",($l,$t,$r,$b),TopLeft)
    };
    ( $x:tt - ($l:expr,$t:expr,$r:expr,$b:expr) - $loc:expr) => {
        ()
    };
    //ColorStill
    ( ($x:expr, $y:expr) ) => {
        point!(format!("{}|{}|000000", $x, $y).as_str())
    };
    ( $x:tt ) => {
        point!($x - TopLeft)
    };
    ( $x:tt - $loc:expr ) => {{
        ()
    }};
}

point!((M {
    a: "b" - (1, 2, 3, 4) - TopRight,
    a: "b" - TopRight,
    a: "b",
    a: ["b", "c"],
    a: (M {
        a: "b" - (1, 2, 3, 4) - TopRight,
    }),
}));