Search code examples
rusttokenizedslrust-proc-macros

Why is this procedural macro panicing


I am using proc macros to parse a given input into a Node tree, for debugging purposes I want to stringify and print the output to see if I am successfully converting to RPN, my current function:

use proc_macro::*;
#[proc_macro]
pub fn symbolic(body: TokenStream) -> TokenStream {
    // ---shunting yard---
    let mut stack : Vec<TokenTree> = vec![];
    let mut que : Vec<TokenTree> = vec![];

    for tt in body.into_iter(){
        match tt {
            TokenTree::Ident(_) => que.push(tt),
            TokenTree::Punct(_) => {
                while precedence(Some(&tt)) <= precedence(stack.last()){
                    que.push(stack.pop().unwrap());
                }
                stack.push(tt)
            },
            TokenTree::Literal(_) => que.push(tt),
            _ => {}
        }
    }
    while let Some(op) = stack.pop() {
        que.push(op);
    }

    println!(stringify!(output_que));
    "fn answer() -> u32 { 42 }".parse().unwrap()
}
fn precedence(tt: Option<&TokenTree>) -> usize{
    if let Some(TokenTree::Punct(punct)) = tt{
        match punct.as_char() {
            '^' => 3,
            '/' | '*' => 2,
            '-' | '+' => 1,
            _ => 0
        }
    } else {
        0
    }
}

gives me an error

error: proc macro panicked
 --> src\main.rs:5:5
  |
5 |     symbolic!(x^2 + 2*x)
  |     ^^^^^^^^^^^^^^^^^^^^
  |
  = help: message: called `Option::unwrap()` on a `None` value

which I do not understand as this should be outputting an empty token stream since TokenStream::new() -> TokenStream { TokenStream(None) } is this not acceptable, if not I do not understand why. I changed this to the example given in the rust book "fn answer() -> u32 { 42 }".parse().unwrap() and still the same error so I don't know what?


Solution

  • Your macro doesn't work because you never push anything to stack but here:

    while precedence(&tt) <= precedence(stack.last().unwrap()){
        que.push(stack.pop().unwrap());
    

    You unwrap as if stack.pop or stack.last was guaranteed to return Some.