有没有办法在宏中实现可选表达式?

时间:2018-06-06 11:06:42

标签: parsing macros rust

我有一个宏,它简化了以下形式的字符串解析枚举:

enum_printer!(Bar { fun1["AB","CD"]; fun2[] });

为了使其更容易使用,我想使[]可选,即能够指定

enum_printer!(Bar { fun1["AB","CD"]; fun2; fun3 });

这里是代码

use failure::Error;
use std::convert::TryFrom;

macro_rules! enum_printer {
    ($name:ident { $($enumeration:ident [$($v:expr),*]);* }) => {
        #[derive(Debug)]
        enum $name {
            $(
                $enumeration,
            )*
        }
        impl<'a> TryFrom<&'a str> for $name {
            type Error = Error;
            fn try_from(value : &'a str) -> Result<$name,Error> {
            match value {
                $(
                    stringify!($enumeration) 
                    $(
                        | $v
                    )*                        
                    => Ok($name::$enumeration),
                )*
                _ => Err(err_msg("Could not convert from string to"))
            }                
            }
        }
    };
}

我试图修改第一行:

($name:ident { $($enumeration:ident [$($v:expr),*]?);* }) => {
error: no rules expected the token `;`
  --> src/main.rs:30:36
   |
30 | enum_printer!(Bar { fun1["AB","CD"]; fun2; fun3 });
   |                                    ^

有没有办法实现这个目标?

1 个答案:

答案 0 :(得分:2)

?的语法与*+的语法相同:您必须包围可选模式,如$( <pattern> )?

示例:

#![feature(macro_at_most_once_rep)]

macro_rules! foo {
    ( $( $e:expr )? ) => {
        $( $e )?
    }
}

在您的示例中,您必须写:

($name:ident {
    $(
        $enumeration:ident $(
            [$( $v:expr ),*]
        )? // optional parameter
    );* // possible multiple parameters
}) => {

(我把这条线拆分得更清楚了)