rust_rpn_calc/
lib.rs

1// ドキュメントを記述
2/// Eval RPN
3/// # Example
4/// '''
5/// let src = String::from("1 2 + 3 * ");
6/// let a = rpn_calc::eval(src).unwrap();
7/// println!("{}", a); // ->9
8/// '''
9pub fn eval(src: String) -> Result<f64, String> {
10    // 空白でトークンを区切る
11    let tokens = src.split_whitespace();
12    let mut stack:Vec<f64> = vec![];
13    // 繰り返し要素を計算 ※2
14    for tok in tokens {
15        let t = tok.trim();
16        if t == "" { continue; }
17        // 数値ならスタックにPUSH
18        match t.parse::<f64>() {
19            Ok(v) => { stack.push(v); continue; },
20            Err(_) => 0.0,
21        };
22        //演算子なら2回POPして計算結果をPUSH
23        let b = stack.pop().unwrap_or(0.0);
24        let a = stack.pop().unwrap_or(0.0);
25        match t {
26            "+" => stack.push(a + b),
27            "-" => stack.push(a - b),
28            "*" => stack.push(a * b),
29            "/" => stack.push(a / b),
30            "%" => stack.push(a % b),
31            _ => return Err(format!("inavalid operator: {}", t)),
32        }
33    }
34    // 結果を返す ※3
35    if stack.len() == 0 { return Err(format!("no result")); }
36    if stack.len() > 1 {
37        return Err(format!("too many value in stack"));
38    }
39    Ok(stack.pop().unwrap_or(0.0))
40}
41
42//ライブラリーを利用するテストを記述 ※4
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn it_works() {
49        assert_eq!(eval("1 3 +" .to_string()), Ok(4.0));
50        assert_eq!(eval("2 3 *" .to_string()), Ok(6.0));
51        assert_eq!(eval("6 3 /" .to_string()), Ok(2.0));
52        assert_eq!(eval("6 3 - 1 -" .to_string()), Ok(2.0));
53    }
54}