0

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?

  • 1
    You have several `unwraps` in your code, to get better debugging output you could convert them to `.expcect("where it did fail or why")` and you'd know which of them returned `None` – cafce25 Dec 05 '22 at 13:07
  • 1
    You should also only post one question per SO question. – cafce25 Dec 05 '22 at 13:08
  • thank-you :) I'm hoping the unwrap is safe if the ```precedence``` function takes an option as its argument instead of the TokenTree. what are your thoughts? – Lyndon Alcock Dec 05 '22 at 14:35
  • also @cafce25: "You should also only post one question per SO question." I will bear this in mind in the future. I just feel like I've been asking a lot of questions because I've been dipping into unfamiliar grounds with the macros and CAS / parsing techniques as its not something I have a lot of experience writing. – Lyndon Alcock Dec 05 '22 at 14:43
  • Adding yet more questions via an edit is not really 'bearing this in mind in the future' If the questions seem to small or insignificant to be posted on their own, it's probably because they are. See [tour] and [ask] – cafce25 Dec 05 '22 at 14:47
  • In all fairness, I feel neither question to be Insignificant but I feel like the two may be related, like is the compiler acting in this way because the unwrap is unsafe? if so what can I change about the design of my code, anyway, I will change the question into a single question somewhere else – Lyndon Alcock Dec 05 '22 at 15:02
  • Use `match` or `?` to handle/forward errors instead as recommended in the [book](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html?highlight=unwrap#shortcuts-for-panic-on-error-unwrap-and-expect). – cafce25 Dec 05 '22 at 15:12
  • something like ```if let Some(punct) = stack.pop(){ que.push() }``` ? – Lyndon Alcock Dec 05 '22 at 15:20

1 Answers1

1

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.

cafce25
  • 15,907
  • 4
  • 25
  • 31