mice 0.11.1

messing with dice
Documentation
use crate::backend_support::TyTarget;
fn ast_roll(expr: &str) -> (crate::parse::Program, crate::interp::ProgramOutput) {
    let (_input, (_tokens, program)) =
        crate::parse::parse_expression::<TyTarget::AstInterp>(expr.as_bytes()).unwrap();
    let output = crate::interp::interpret(&mut ::rand::thread_rng(), &program).unwrap();
    (program, output)
}
fn stack_roll(expr: &str) -> i64 {
    let (_input, (_tokens, program)) =
        crate::parse::parse_expression::<TyTarget::Stack>(expr.as_bytes()).unwrap();
    let stack_program = crate::stack::compile(&program);
    let mut machine = crate::stack::Machine::new();
    machine
        .eval_with(&mut ::rand::thread_rng(), &stack_program)
        .unwrap()
}
fn mir_stack_roll(expr: &str) -> i64 {
    use crate::mir::stack::Value;
    let (_input, (_tokens, program)) =
        crate::parse::parse_expression::<TyTarget::Mir::Stack>(expr.as_bytes()).unwrap();
    let mir = crate::mir::lower(&program).unwrap();
    let stack_program = crate::mir::stack::lower(&mir);
    let mut machine = crate::mir::stack::Machine::new(&stack_program, 0);
    machine.interpret(&mut ::rand::thread_rng()).unwrap();
    match machine.stack_top().unwrap() {
        &Value::Integer(x) => x,
        Value::Set(set) => set.into_iter().sum(),
        Value::Boolean(_truthy) => unreachable!("AST lowering should never produce this"),
    }
}

#[test]
fn test_arithmetic() {
    #[track_caller]
    fn assert_total(expr: &str, total: i64) {
        assert_eq!(ast_roll(expr).1.total(), total, "AST walker");
        assert_eq!(stack_roll(expr), total, "Stack interpreter");
        assert_eq!(mir_stack_roll(expr), total, "MIR Stack VM");
    }
    assert_total("2 + 2", 4);
    assert_total("2 - 2", 0);
    assert_total("5 - 3", 2);
    assert_total("-4 + 3", -1);
}

fn test_expr(dice_expr: &str) -> Result<String, String> {
    let program = match crate::parse::parse_expression::<TyTarget::Mir::Stack>(dice_expr.as_bytes())
    {
        Ok((_input, (_tokens, proggy))) => proggy,
        Err((_input, e)) => {
            return Err(format!("That's an invalid dice expression. {:?}", e));
        }
    };
    mir_stack_roll(dice_expr);
    let result = crate::interp::interpret(&mut ::rand::thread_rng(), &program);
    match result {
        Ok(output) => Ok(crate::interp::fmt::mbot_format_default(
            program.terms(),
            &output,
        )),
        Err(e) => return Err(format!("{:?}", e)),
    }
}

#[test]
fn test_basic_expressions() {
    println!("{}", test_expr("1d20+1d6+8").unwrap());
    println!("{}", test_expr("2d20+5").unwrap());
    println!("{}", test_expr("32d2").unwrap());
}

#[test]
fn test_leading_whitespace() {
    println!("{}", test_expr("                   1d20+1d6").unwrap());
}

#[test]
fn test_trailing_whitespace() {
    println!("{}", test_expr("1d20+1d6                     ").unwrap());
}

#[test]
fn test_mixed_whitespace() {
    println!("{}", test_expr("1d20       +         1d6").unwrap());
}

#[test]
fn test_maturity() {
    println!("{}", test_expr("69d420   +    13d37").unwrap());
}

#[test]
fn test_zero_sides() {
    println!("{}", test_expr("d0").unwrap_err());
}

#[test]
fn test_one_side() {
    println!("{}", test_expr("d1").unwrap());
}

#[test]
fn test_max_sides() {
    println!("{}", test_expr("d9223372036854775807").unwrap());
}

#[test]
fn test_keeping_highest_dice() {
    println!("{}", test_expr("4d6k3").unwrap());
}