mathexpr 0.1.1

A fast, safe mathematical expression parser and evaluator with bytecode compilation
Documentation
//! Error handling examples for mathexpr.
//!
//! Run with: cargo run --example errors
//!
//! This example demonstrates all the error types that mathexpr can return
//! and how to handle them.

use mathexpr::{eval, CompileError, EvalError, Expression, ParseError};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Error Handling Examples ===\n");

    // =====================
    // Parse Errors
    // =====================
    println!("--- Parse Errors ---\n");

    // Invalid syntax - completely unparseable input
    match Expression::parse("@#$") {
        Ok(_) => println!("Unexpected success"),
        Err(ParseError::InvalidSyntax(msg)) => {
            println!("ParseError::InvalidSyntax");
            println!("  Input: @#$");
            println!("  Message: {}\n", msg);
        }
        Err(e) => println!("Other error: {}", e),
    }

    // Trailing input - valid expression followed by garbage
    match Expression::parse("2 + 3 @") {
        Ok(_) => println!("Unexpected success"),
        Err(ParseError::UnexpectedTrailingInput(trailing)) => {
            println!("ParseError::UnexpectedTrailingInput");
            println!("  Input: 2 + 3 @");
            println!("  Trailing: '{}'\n", trailing);
        }
        Err(e) => println!("Other error: {}", e),
    }

    // =====================
    // Compile Errors
    // =====================
    println!("--- Compile Errors ---\n");

    // Undefined variable - using a variable not in the compile list
    match Expression::parse("x + y")?.compile(&["x"]) {
        Ok(_) => println!("Unexpected success"),
        Err(CompileError::UndefinedVariable(name)) => {
            println!("CompileError::UndefinedVariable");
            println!("  Expression: x + y");
            println!("  Variables provided: [\"x\"]");
            println!("  Undefined: '{}'\n", name);
        }
        Err(e) => println!("Other error: {}", e),
    }

    // Unknown function - calling a function that doesn't exist
    match Expression::parse("foo(5)")?.compile(&[]) {
        Ok(_) => println!("Unexpected success"),
        Err(CompileError::UnknownFunction(name)) => {
            println!("CompileError::UnknownFunction");
            println!("  Expression: foo(5)");
            println!("  Unknown function: '{}'\n", name);
        }
        Err(e) => println!("Other error: {}", e),
    }

    // Wrong arity - wrong number of arguments to a function
    match Expression::parse("sqrt(1, 2)")?.compile(&[]) {
        Ok(_) => println!("Unexpected success"),
        Err(CompileError::WrongArity {
            name,
            expected,
            got,
        }) => {
            println!("CompileError::WrongArity");
            println!("  Expression: sqrt(1, 2)");
            println!(
                "  Function '{}' expects {} arg(s), got {}\n",
                name, expected, got
            );
        }
        Err(e) => println!("Other error: {}", e),
    }

    // =====================
    // Eval Errors
    // =====================
    println!("--- Eval Errors ---\n");

    // Division by zero
    let expr = Expression::parse("1 / x")?.compile(&["x"])?;
    match expr.eval(&[0.0]) {
        Ok(_) => println!("Unexpected success"),
        Err(EvalError::DivisionByZero) => {
            println!("EvalError::DivisionByZero");
            println!("  Expression: 1 / x");
            println!("  x = 0\n");
        }
        Err(e) => println!("Other error: {}", e),
    }

    // Modulo by zero
    let expr = Expression::parse("x % y")?.compile(&["x", "y"])?;
    match expr.eval(&[10.0, 0.0]) {
        Ok(_) => println!("Unexpected success"),
        Err(EvalError::DivisionByZero) => {
            println!("EvalError::DivisionByZero (modulo)");
            println!("  Expression: x % y");
            println!("  x = 10, y = 0\n");
        }
        Err(e) => println!("Other error: {}", e),
    }

    // =====================
    // Domain Errors -> NaN
    // =====================
    println!("--- Domain Errors (return NaN, not errors) ---\n");

    // sqrt of negative number
    let result = eval("sqrt(-1)", &[], &[])?;
    println!("sqrt(-1) = {}", result);
    println!("  Returns NaN, not an error\n");

    // log of negative number
    let result = eval("log(-1)", &[], &[])?;
    println!("log(-1) = {}", result);
    println!("  Returns NaN, not an error\n");

    // log of zero
    let result = eval("log(0)", &[], &[])?;
    println!("log(0) = {}", result);
    println!("  Returns -inf, not an error\n");

    // asin out of domain
    let result = eval("asin(2)", &[], &[])?;
    println!("asin(2) = {}", result);
    println!("  Returns NaN, not an error (|x| > 1)\n");

    println!("Done!");
    Ok(())
}