Как сопоставить границы черт в макросе?

Я пытаюсь сопоставить границы признаков для универсальных типов:

macro_rules! test {
    (
        where $(
            $bounded_type:ident: $( $bound:tt )++,
        )+
    ) => {
        // Dummy expansion for test:
        struct Foo<T, U>
        where $(
            $bounded_type : $( $bound )++,
        )+
        {
            t: T,
            u: U
        }
    }
}

test! {
    where
        T: PartialEq + Clone,
        U: PartialEq,
}

fn main() {}

К сожалению, если я хорошо понимаю, единственный способ сопоставить черту tt фрагмент, но этот фрагмент может соответствовать практически чему угодно, поэтому, что бы я ни делал, я получаю ошибку:

error: local ambiguity: multiple parsing options: built-in NTs tt ('bound') or 1 other option.

Как я могу сопоставить этот кусок кода?

Обратите внимание, что мне не нужно что-то очень элегантное (мне это не нужно для любителей plublic), но, конечно, чем элегантнее, тем лучше.

2 ответа

Лучше всего прочитать исходный код parse-generics-shim ящик; Это немного стар, но, надеюсь, все еще работает. Это слишком запутанно, чтобы объяснить в вопросе переполнения стека, так как в основном это означает копирование + вставка источника этого ящика в ответ.

Более простой подход состоит в том, чтобы просто не анализировать фактический синтаксис Rust и использовать то, что может обработать синтаксический анализатор макросов, например, обернуть ограничения в группу (например, { ... }).

Я смог сделать так, чтобы это соответствовало, отделяя первую границу от остальных.

macro_rules! test {
    (
        where $(
            $bounded_type:ident: $bound:tt $(+ $others:tt )*,
        )+
    ) => {
        // Dummy expansion for test:
        struct Foo<T, U>
        where $(
            $bounded_type : $bound $(+ $others)*,
        )+

        {
            t: T,
            u: U
        }
    }
}

Однако это не сработает, если у черт есть параметры.

Примерно в 2016 году с закрытием этого номера вы можете использовать path тип макроса для соответствия TypePaths.

Например, из моего собственного кода:

($name:ident<$($l:lifetime, )*$($x:ident : $xt:path),+>($s:ident$(, $a:ident: $t:ty)*) -> $ret:ty  => $body:block) => {
}
Другие вопросы по тегам