如何在macro_rules模式中使用 & 和 | 符号

huangapple go评论68阅读模式
英文:

How to use & and | signs in macro_rules pattern

问题

我正在尝试编写一个类似这样的简单宏,以便于编写我的代码:

enum Term {
    Or(Box<Term>, Box<Term>),
    And(Box<Term>, Box<Term>),
    Value(u8),
}

macro_rules! term {
    ($value_1:expr & $value_2:expr) => {
        Term::And(Box::new($value_1), Box::new($value_2))
    };
    ($value_1:expr | $value_2: expr) => {
        Term::Or(Box::new($value_1), Box::new($value_2))
    };
    ($value: expr) => {
        Term::Value($value)
    };
}

然而,我无法在模式中的 expr 后面放置 &|。我尝试使用 tt,但它不起作用,因为我不总是只在 $value 中放置一个标记。pat_param 似乎也不能与 & 一起使用。唯一看起来有效的选项是使用 (($value_1:expr) & ($value_2:expr)),但如果可以不使用额外的括号,那会更好。是否有办法做到这一点?

英文:

I'm trying to write a simple macro like this, to facilitate the writing of my code

enum Term {
    Or(Box&lt;Term&gt;, Box&lt;Term&gt;),
    And(Box&lt;Term&gt;, Box&lt;Term&gt;),
    Value(u8),
}

macro_rules! term {
	($value_1:expr &amp; $value_2:expr) =&gt; {
		Term::And(Box::new($value_1), Box::new($value_2))
	};
	($value_1:expr | $value_2: expr) =&gt; {
		Term::Or(Box::new($value_1), Box::new($value_2))
	};
	($value: expr) =&gt; {
		Term::Value($value)
	};
}

However, I cannot put a &amp; or | after an expr in my pattern. I tried using tt, but it didn't work because I'm not always just putting one token in my $value. pat_param doesn't seem to work with &amp; either.
The only option that seems to work would be to use (($value_1:expr) &amp; ($value_2:expr)), but if I could do without the extra parentheses, it'd be better.
Is there a way to do this?

答案1

得分: 2

&amp; 不允许用于避免歧义,在声明宏中,expr 参数后面直接使用 &amp; 是无法实现的。

exprstmt 只能后跟以下之一:=&gt;,,或 ;

英文:

&amp; isn't allowed to avoid ambiguity, there is no way to have &amp; as a token directly after an expr parameter in a declarative macro.

> expr and stmt may only be followed by one of: =&gt;, ,, or ;.

答案2

得分: 1

如果您只想允许单个变量,可选地跟有方法调用,您可以使用以下宏(请注意它不处理通用方法调用语法):

macro_rules! term {
    (
        $name:ident $( .$method:ident( $($argument:expr),* $(,)? ) )?
        $($rest:tt)+
    ) => {
        term!(@parsed_lhs
            ( $name $( .$method( $($argument),* ) )? )
            $($rest)*
        )
    };
    (@parsed_lhs $value_1:tt & $value_2:expr) => {
        Term::And(Box::new($value_1), Box::new($value_2))
    };
    (@parsed_lhs $value_1:tt | $value_2:expr) => {
        Term::Or(Box::new($value_1), Box::new($value_2))
    };
    ($value:expr) => {
        Term::Value($value)
    };
}

这个宏并不完美,有一些边界情况,但它应该足够好。

英文:

If you only want to allow a single variable, optionally with a method call after, you can use the following macro (note it does not handle generic method call syntax):

macro_rules! term {
    (
        $name:ident $( .$method:ident( $($argument:expr),* $(,)? ) )?
        $($rest:tt)+
    ) =&gt; {
        term!(@parsed_lhs
            ( $name $( .$method( $($argument),* ) )? )
            $($rest)*
        )
    };
    (@parsed_lhs $value_1:tt &amp; $value_2:expr) =&gt; {
        Term::And(Box::new($value_1), Box::new($value_2))
    };
    (@parsed_lhs $value_1:tt | $value_2:expr) =&gt; {
        Term::Or(Box::new($value_1), Box::new($value_2))
    };
    ($value:expr) =&gt; {
        Term::Value($value)
    };
}

This macro is not perfect, it has some edge cases, but it should be good enough.

huangapple
  • 本文由 发表于 2023年3月12日 18:39:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/75712542.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定