Why is this procedural macro panicing - rust

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?

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.

Related

How to return moved value as `Err` in loop using question mark operator?

In the code below, version 1 does not compile, whereas version 2 does.
fn foo(text: String) -> Result<u32, String> {
let mut acc: u32 = 0;
for string in text.split("_") {
let result: Option<u32> = string.parse::<u32>().ok();
// version 1
let x: u32 = result.ok_or(text)?;
acc += x;
// version 2
// if let Some(x) = result {
// acc += x;
// } else {
// return Err(text)
// }
}
Ok(acc)
}
error[E0382]: use of moved value: `text`
--> src/main.rs:102:35
|
96 | fn foo(text: String) -> Result<u32, String> {
| ---- move occurs because `text` has type `String`, which does not implement the `Copy` trait
...
102 | let x: u32 = result.ok_or(text)?;
| ^^^^ value moved here, in previous iteration of loop
The issue is that I'm moving text into another function (ok_or) on each loop iteration.
So I understand the error message, but is there still a way out to use the shorthand ? notation in this case? The version 2 is the shortest I could get but it still seems too verbose.
(this is just a MWE / toy example, my question is not about summing numbers in a string)
If you cannot afford a copy on the Err case, and you have a lot of places like that, you can use a macro:
macro_rules! try_opt {
( $v:expr, $e:expr $(,)? ) => {
match $v {
Some(v) => v,
None => return Err($e),
}
}
}
let x: u32 = try_opt!(result, text);
If you can afford a string clone in the Err case (not the happy path), you can just take a reference, as String implements From<&String>:
let x: u32 = result.ok_or(&text)?;

How to return a Result<T, ParseIntError>?

I want a function to take in a reference to input and return a value if the input is valid or an error if its invalid. Here's my attempt but I get an error:
use std::num::ParseIntError;
fn get_fourth(input: &Vec<i32>) -> Result<i32, ParseIntError> {
let q = match input.get(4) {
Some(v) => v,
_ => return Err(ParseIntError {kind: ParseIntError} )
};
Ok(*q)
}
fn main() {
let my_vec = vec![9, 0, 10];
let fourth = get_fourth(&my_vec);
}
error[E0423]: expected value, found struct `ParseIntError`
--> src/main.rs:6:46
|
6 | _ => return Err(ParseIntError {kind: ParseIntError} )
| ^^^^^^^^^^^^^
|
help: use struct literal syntax instead
|
6 | _ => return Err(ParseIntError {kind: ParseIntError { kind: val }} )
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
ParseIntError is just temporary for my testing. How can I return an error? How can I solve this?
You're returning an error just fine, its your use of ParseIntError that is messed up. You cannot construct an instance of ParseIntError yourself because its fields are private and there's no public constructing function.
ParseIntError is just temporary for my testing.
Well go ahead and make your own non-temporary error and you'll see the rest of your code works:
struct LengthError;
fn get_fourth(input: &Vec<i32>) -> Result<i32, LengthError> {
let q = match input.get(4) {
Some(v) => v,
_ => return Err(LengthError)
};
Ok(*q)
}

Temporary value dropped while borrowed while pushing elements into a Vec

I'm trying to solve the RPN calculator exercise at exercism but stumbled upon this temporary value dropped while borrowed error that I can't seem to work out.
Here's my code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(&result.clone());
}
}
}
if stack.len() != 1 {
None
} else {
Some(*stack.pop().unwrap())
}
}
And the error I get:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:32:29
|
32 | stack.push(&result.clone());
| ^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
...
36 | if stack.len() != 1 {
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
If I understand correctly, the variable result is no loger live outside of the for loop (outside of the operator match branch indeed), that's why I cloned it, but it still gives me the same error.
How can I make a copy of the result which is owned by the stack Vec (if that's what I should do)?
Just for reference, and in case anybody fins this useful, this is the final solution taking into account all the help received:
use crate::CalculatorInput::{Add,Subtract,Multiply,Divide,Value};
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
Value(value) => {
stack.push(*value);
},
operator => {
if stack.len() < 2 {
return None;
}
let second: i32 = stack.pop().unwrap();
let first: i32 = stack.pop().unwrap();
let result: i32 = match operator {
Add => first + second,
Subtract => first - second,
Multiply => first * second,
Divide => first / second,
Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
stack.pop()
}
}
No need to clone, because i32 implements the Copy trait.
The problem was that my vec was receiving an &i32 instead of i32, and thus rust infered it to be a Vec<&i32>.
The error is because Rust did not infer the type you expected.
In your code, the type of value is inferred to be &i32 because input is a reference of a element in inputs, and you push a value later, therefore the type of stack is inferred to be Vec<&i32>.
A best fix is to explicitly specify the type of stack:
let mut stack: Vec<i32> = Vec::new();
And because i32 has implemented Copy trait, you should never need to clone a i32 value, if it is a reference, just dereference it.
Fixed code:
#[derive(Debug)]
pub enum CalculatorInput {
Add,
Subtract,
Multiply,
Divide,
Value(i32),
}
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(*value);
}
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result);
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
}
}
You have the same behavior with this simple exemple
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(&a.clone());
//-------- ^
println!("{:?}", stack);
}
and the good way is to not borrow when clone.
fn main() {
let mut stack = Vec::new();
let a = String::from("test");
stack.push(a.clone());
//-------- ^
println!("{:?}", stack);
}
The variable should be used like this stack.push(result.clone()); and change code like this
pub fn evaluate(inputs: &[CalculatorInput]) -> Option<i32> {
let mut stack: Vec<i32> = Vec::new();
//---------------- ^
for input in inputs {
match input {
CalculatorInput::Value(value) => {
stack.push(value.clone());
//----------------- ^
},
operator => {
if stack.len() < 2 {
return None;
}
let second = stack.pop().unwrap();
let first = stack.pop().unwrap();
let result = match operator {
CalculatorInput::Add => first + second,
CalculatorInput::Subtract => first - second,
CalculatorInput::Multiply => first * second,
CalculatorInput::Divide => first / second,
CalculatorInput::Value(_) => return None,
};
stack.push(result.clone());
//-^
}
}
}
if stack.len() != 1 {
None
} else {
Some(stack.pop().unwrap())
//------- ^
}
}

Rust tells ''value moved here, in previous iteration of loop"

I'm implementing a parser combinator library:
#[derive(Debug)]
enum Parser {
Char(char),
Positive(Box<Parser>),
}
impl Parser {
fn run(self, s: &str) -> (bool, &str) {
match self {
Parser::Char(ch) => {
if s[0..1].chars().next().unwrap() == ch {
(true, &s[1..])
} else {
(false, s)
}
}
Parser::Positive(parser) => {
//println!("{:?}", parser);
let mut s = s;
let mut res = (false, s);
let parser = *parser;
loop {
let ret = parser.run(s);
if !ret.0 {
break;
}
res = ret;
s = res.1
}
res
}
_ => (false, s),
}
}
}
pub fn run() {
let x = Parser::Positive(Box::new(Parser::Char('a')));
let ret = x.run("aaa");
println!("{} {}", ret.0, ret.1);
}
I'm getting the error
error[E0382]: use of moved value: `parser`
--> src/lib.rs:25:31
|
22 | let parser = *parser;
| ------ move occurs because `parser` has type `Parser`, which does not implement the `Copy` trait
...
25 | let ret = parser.run(s);
| ^^^^^^ value moved here, in previous iteration of loop
I have no idea why this happens. I've tried to add the Copy trait to the Parser enum, but this causes other errors. Why can't I call parser.run() in a loop, or even twice? A single call compiles and runs perfectly.
Would it be better to use a struct instead of an enum?
OK, changed the function's signature to
fn run<'a>(&self, s: &'a str) -> (bool, &'a str)
now and needed some other lines to be fixed.
Works now, but I don't know why.

Why does matching on the result of Regex::find complain about expecting a struct regex::Match but found tuple?

I copied this code from Code Review into IntelliJ IDEA to try and play around with it. I have a homework assignment that is similar to this one (I need to write a version of Linux's bc in Rust), so I am using this code only for reference purposes.
use std::io;
extern crate regex;
#[macro_use]
extern crate lazy_static;
use regex::Regex;
fn main() {
let tokenizer = Tokenizer::new();
loop {
println!("Enter input:");
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
let tokens = tokenizer.tokenize(&input);
let stack = shunt(tokens);
let res = calculate(stack);
println!("{}", res);
}
}
#[derive(Debug, PartialEq)]
enum Token {
Number(i64),
Plus,
Sub,
Mul,
Div,
LeftParen,
RightParen,
}
impl Token {
/// Returns the precedence of op
fn precedence(&self) -> usize {
match *self {
Token::Plus | Token::Sub => 1,
Token::Mul | Token::Div => 2,
_ => 0,
}
}
}
struct Tokenizer {
number: Regex,
}
impl Tokenizer {
fn new() -> Tokenizer {
Tokenizer {
number: Regex::new(r"^[0-9]+").expect("Unable to create the regex"),
}
}
/// Tokenizes the input string into a Vec of Tokens.
fn tokenize(&self, mut input: &str) -> Vec<Token> {
let mut res = vec![];
loop {
input = input.trim_left();
if input.is_empty() { break }
let (token, rest) = match self.number.find(input) {
Some((_, end)) => {
let (num, rest) = input.split_at(end);
(Token::Number(num.parse().unwrap()), rest)
},
_ => {
match input.chars().next() {
Some(chr) => {
(match chr {
'+' => Token::Plus,
'-' => Token::Sub,
'*' => Token::Mul,
'/' => Token::Div,
'(' => Token::LeftParen,
')' => Token::RightParen,
_ => panic!("Unknown character!"),
}, &input[chr.len_utf8()..])
}
None => panic!("Ran out of input"),
}
}
};
res.push(token);
input = rest;
}
res
}
}
/// Transforms the tokens created by `tokenize` into RPN using the
/// [Shunting-yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm)
fn shunt(tokens: Vec<Token>) -> Vec<Token> {
let mut queue = vec![];
let mut stack: Vec<Token> = vec![];
for token in tokens {
match token {
Token::Number(_) => queue.push(token),
Token::Plus | Token::Sub | Token::Mul | Token::Div => {
while let Some(o) = stack.pop() {
if token.precedence() <= o.precedence() {
queue.push(o);
} else {
stack.push(o);
break;
}
}
stack.push(token)
},
Token::LeftParen => stack.push(token),
Token::RightParen => {
let mut found_paren = false;
while let Some(op) = stack.pop() {
match op {
Token::LeftParen => {
found_paren = true;
break;
},
_ => queue.push(op),
}
}
assert!(found_paren)
},
}
}
while let Some(op) = stack.pop() {
queue.push(op);
}
queue
}
/// Takes a Vec of Tokens converted to RPN by `shunt` and calculates the result
fn calculate(tokens: Vec<Token>) -> i64 {
let mut stack = vec![];
for token in tokens {
match token {
Token::Number(n) => stack.push(n),
Token::Plus => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a + b);
},
Token::Sub => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a - b);
},
Token::Mul => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a * b);
},
Token::Div => {
let (b, a) = (stack.pop().unwrap(), stack.pop().unwrap());
stack.push(a / b);
},
_ => {
// By the time the token stream gets here, all the LeftParen
// and RightParen tokens will have been removed by shunt()
unreachable!();
},
}
}
stack[0]
}
When I run it, however, it gives me this error:
error[E0308]: mismatched types
--> src\main.rs:66:22
|
66 | Some((_, end)) => {
| ^^^^^^^^ expected struct `regex::Match`, found tuple
|
= note: expected type `regex::Match<'_>`
found type `(_, _)`
It's complaining that I am using a tuple for the Some() method when I am supposed to use a token. I am not sure what to pass for the token, because it appears that the tuple is traversing through the Token options. How do I re-write this to make the Some() method recognize the tuple as a Token? I have been working on this for a day but I have not found any really good solutions.
The code you are referencing is over two years old. Notably, that predates regex 1.0. Version 0.1.80 defines Regex::find as:
fn find(&self, text: &str) -> Option<(usize, usize)>
while version 1.0.6 defines it as:
pub fn find<'t>(&self, text: &'t str) -> Option<Match<'t>>
However, Match defines methods to get the starting and ending indices the code was written assuming. In this case, since you only care about the end index, you can call Match::end:
let (token, rest) = match self.number.find(input).map(|x| x.end()) {
Some(end) => {
// ...

Resources