How to parse single tokens in rust macros

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-05 21:49:28

You're actually very close! There are only a couple of minor errors left. (If you want to learn more about macros, only read one bullet point at a time and try to progress on your own from there!)

  • When using (repeated) meta variables, you don't specify the meta-variable type again. So it's $($t:tt)* in the pattern of the macro, but if you want to use it, it's $($t)*!

  • If you have multiple rules in a macro definition, you need to end every rule with a semicolon.

    macro_rules! {
        (+ $(t:tt)*) => { ... };
        (- $(t:tt)*) => { ... };
    }
    
  • The Rust compiler always needs to know whether you want to expand your macro into an expression or statement(s). Since you are generating a list of statements and not a single expression, you have to add a semicolon to the invocation of your macros! That means, in main() but also all macro invocation of helper macros inside your macro definition.

  • Since yeah macro invocation creates a new syntax context and all identifiers (names) are only accessible in their syntax context, the helper macro cannot use var (even after fixing the typo val -> var). So instead, you have to pass that name to the helper macro:

    macro_rules! operate_integer {
        ($($all_tokens:tt)*) => {
            let mut var: i32 = 0;
            operate_integer_helper![var $($all_tokens)*];  // <-- pass identifier 
            println!("{}", var);
        }
    }
    
    macro_rules! operate_integer_helper {
        ($var:ident +$($t:tt)*) => {              // <- accept identifier
            $var += 1;                            // <- use identifier
            operate_integer_helper![$var $($t)*]
        };
    
        ($var:ident -$($t:tt)*) => {
            $var -= 1;
            operate_integer_helper![$var $($t)*]
        };
    }
    
  • Having done all that you get the error "unexpected end of macro invocation". This is because you don't have a recursion stop rule! So you have to add a new rule to your helper macro: ($var:ident) => {};. This rule is used when there is only the name and no + or - tokens left.

And now: it works!

I would still change one last thing: usually it's not a good idea to have a second helper macro, because that macro might not be in scope where the main macro is called. Instead, one usually uses internal rules. You can read more about those here.

With this, this is the resulting code.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!