calc 0.5.0

CLI calculator app
Documentation
use calc::Context;
use lazy_static::lazy_static;
use regex::Regex;

lazy_static! {
    static ref INPUT_RE: Regex = Regex::new(r"^\s*\[\d+\]: (.*)$").unwrap();
}

#[derive(Debug)]
struct ShellCase {
    input: String,
    expect: String,
}

fn parse_expressions(input: &str) -> Vec<ShellCase> {
    let mut lines = input.lines();
    let mut out = Vec::new();

    while let Some(line) = lines.next() {
        if line.trim().is_empty() {
            continue;
        }

        let input = INPUT_RE
            .captures(line)
            .expect("line must match the RE")
            .get(1)
            .expect("capture group 1 always exists")
            .as_str()
            .to_owned();
        let expect = lines
            .next()
            .expect("each input has an output")
            .trim()
            .to_owned();
        out.push(ShellCase { input, expect });
    }

    out
}

fn assert_expressions(expressions: &[ShellCase]) {
    let mut context = Context::default();
    for ShellCase { input, expect } in expressions {
        let result = context.evaluate(input).unwrap();
        assert_eq!(&result.to_string(), expect);
    }
}

#[test]
fn readme_2_shell_mode() {
    const CASE: &str = r#"
    [0]: 1 + 1
    2
    [1]: 3*(5/(3-4))
    -15
    [2]: 3*pi**2
    29.608813203268074
    [3]: @+1
    30.608813203268074
    [4]: @@@*2
    -30
    [5]: ln(-1)
    NaN
    "#;

    let expressions = parse_expressions(CASE);
    assert_expressions(&expressions);
}

#[test]
fn issue_14_example_1() {
    const CASE: &str = r#"
    [1]: 528500/100
    5285
    [2]: @/2
    2642.5
    [3]: @@//2
    2642
    "#;

    let expressions = parse_expressions(CASE);
    assert_expressions(&expressions);
}

#[test]
fn issue_14_example_2() {
    const CASE: &str = r#"
    [0]: 2+2*2
    6
    [1]: @*100
    600
    [2]: @*2
    1200
    [3]: @+1
    1201
    "#;

    let expressions = parse_expressions(CASE);
    assert_expressions(&expressions);
}