Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nonanti/mathcore/llms.txt

Use this file to discover all available pages before exploring further.

MathCore uses Rust’s standard Result<T, MathError> type throughout its entire public API. There are no panics on bad input, no sentinel values, and no implicit fallbacks — every failure case surfaces as a typed error that you can inspect, match on, and recover from. The MathError enum is derived from thiserror, so all variants implement std::error::Error and produce human-readable messages via Display.

The MathError Enum

#[derive(Debug, thiserror::Error)]
pub enum MathError {
    #[error("Parse error: {0}")]
    ParseError(String),

    #[error("Undefined variable: {0}")]
    UndefinedVariable(String),

    #[error("Undefined function: {0}")]
    UndefinedFunction(String),

    #[error("Invalid operation: {0}")]
    InvalidOperation(String),

    #[error("Division by zero")]
    DivisionByZero,

    #[error("Invalid argument count for function {0}: expected {1}, got {2}")]
    InvalidArgumentCount(String, usize, usize),

    #[error("Cannot solve equation: {0}")]
    SolverError(String),

    #[error("Numeric overflow")]
    Overflow,
}

Variant Reference

ParseError(String)

Returned by MathCore::parse() (and any higher-level method that parses before proceeding) when the input string cannot be interpreted as a valid expression. Common triggers:
  • Mismatched parentheses: "(x + 1"
  • Unexpected or trailing characters: "2 + * 3", "x @@"
  • Malformed number literals
use mathcore::{MathCore, MathError};

let result = MathCore::parse("2 + * 3");
assert!(matches!(result, Err(MathError::ParseError(_))));

if let Err(MathError::ParseError(msg)) = result {
    println!("Bad input: {}", msg);
}

UndefinedVariable(String)

Returned by the engine when it encounters an Expr::Symbol node whose name is not present in the active Context. The payload is the variable name. Common triggers:
  • Calling calculate or evaluate on an expression with free variables
  • Typos in variable names passed to evaluate_with_vars
use mathcore::{MathCore, MathError};

let math = MathCore::new();
let result = math.calculate("x + 1"); // "x" has no value in default context

assert!(matches!(result, Err(MathError::UndefinedVariable(ref s)) if s == "x"));
Use evaluate_with_vars to supply values at call time, or construct a custom Context with ctx.set_var(name, Expr::Number(value)) and pass it to Engine::with_context.

UndefinedFunction(String)

Returned by the engine when a Function node’s name field does not match any built-in or registered custom function. The payload is the function name as written in the source string. Common triggers:
  • Calling an unimplemented function: "foo(x)"
  • Typos in function names: "sni(x)" instead of "sin(x)"
use mathcore::{MathCore, MathError};

let math = MathCore::new();
let result = math.evaluate("foo(x)");

assert!(matches!(result, Err(MathError::UndefinedFunction(ref s)) if s == "foo"));
The parser itself does not validate function names. Parsing "foo(x)" succeeds and produces a valid Expr::Function node. The error only surfaces when the engine tries to evaluate it.

InvalidOperation(String)

A catch-all for operations that are structurally valid but not permitted for the given operand types or values. The payload is a descriptive message. Examples include:
SituationMessage
% applied to complex operands"Modulo not defined for complex numbers"
! applied to a negative or non-integer number"Factorial requires non-negative integer"
min/max called with symbolic arguments"min requires numeric arguments"
calculate on an expression that returns a non-real result"Result is not a real number"
use mathcore::{MathCore, MathError};

let math = MathCore::new();

// Factorial of a float
let result = math.calculate("1.5!");
assert!(matches!(result, Err(MathError::InvalidOperation(_))));

// Complex result from calculate (which only returns f64)
let result = math.calculate("sqrt(-1)");
assert!(matches!(result, Err(MathError::InvalidOperation(_))));

DivisionByZero

Returned by the engine when the right-hand operand of a BinaryOp::Divide expression evaluates to zero (checked within f64::EPSILON). This applies to both real and complex denominators.
use mathcore::{MathCore, MathError};

let math = MathCore::new();
let result = math.calculate("1 / 0");

assert!(matches!(result, Err(MathError::DivisionByZero)));
Division by a symbolic expression that could be zero (e.g. 1 / x when x = 0) is only detected at evaluation time when the concrete value is known. The parser and symbolic manipulation layers do not perform this check.

InvalidArgumentCount(String, usize, usize)

Returned when a built-in function receives the wrong number of arguments. The three fields are:
  1. function name — the name as it appeared in the source
  2. expected — the number of arguments the function requires
  3. got — the number of arguments actually passed
use mathcore::{MathCore, MathError};

let math = MathCore::new();
let result = math.evaluate("sin(1, 2)"); // sin takes exactly 1 argument

if let Err(MathError::InvalidArgumentCount(name, expected, got)) = result {
    println!("{} expected {} args, got {}", name, expected, got);
    // → "sin expected 1 args, got 2"
}

SolverError(String)

Returned by MathCore::solve() when the equation cannot be solved. The payload explains why — for example, the polynomial degree might be unsupported, or the expression may not be in a solvable form.
use mathcore::{MathCore, MathError};

match MathCore::solve("x^2 - 4", "x") {
    Ok(roots) => println!("roots: {:?}", roots),
    Err(MathError::SolverError(msg)) => println!("solver failed: {}", msg),
    Err(e) => println!("error: {}", e),
}
A SolverError is not the same as “no real roots exist”. When the discriminant is negative for a quadratic, the solver may return complex Expr::Complex roots rather than an error, depending on the implementation path taken.

Overflow

Returned by the engine when a binary operation on two Expr::Number values produces a non-finite result (i.e. f64::is_finite() returns false). This catches both f64::INFINITY and f64::NAN.
use mathcore::{MathCore, MathError};

let math = MathCore::new();
let result = math.calculate("1e308 * 1e308"); // overflows f64

assert!(matches!(result, Err(MathError::Overflow)));

Pattern Matching Examples

Matching a Specific Variant

use mathcore::{MathCore, MathError};

fn safe_calculate(expr: &str) -> f64 {
    let math = MathCore::new();
    match math.calculate(expr) {
        Ok(value) => value,
        Err(MathError::DivisionByZero) => {
            eprintln!("Expression contains a division by zero");
            f64::NAN
        }
        Err(MathError::UndefinedVariable(name)) => {
            eprintln!("Variable '{}' has no value", name);
            f64::NAN
        }
        Err(e) => {
            eprintln!("Unexpected error: {}", e);
            f64::NAN
        }
    }
}

Handling Solver Results

use mathcore::{MathCore, MathError};

match MathCore::solve("x^2 - 4", "x") {
    Ok(roots) => println!("roots: {:?}", roots),
    Err(MathError::SolverError(msg)) => println!("solver failed: {}", msg),
    Err(e) => println!("error: {}", e),
}

Matching Parse Errors

use mathcore::{MathCore, MathError};

fn parse_or_default(input: &str) -> Option<mathcore::Expr> {
    match MathCore::parse(input) {
        Ok(expr) => Some(expr),
        Err(MathError::ParseError(msg)) => {
            eprintln!("Could not parse '{}': {}", input, msg);
            None
        }
        Err(_) => None,
    }
}

Using the ? Operator

Because MathError implements std::error::Error, you can propagate it through your own Result-returning functions using the ? operator.
use mathcore::{MathCore, MathError, Expr};

fn compute_discriminant(a: f64, b: f64, c: f64) -> Result<f64, MathError> {
    let math = MathCore::new();

    // Build the discriminant expression: b^2 - 4*a*c
    let expr = format!("{}^2 - 4*{}*{}", b, a, c);
    let result = math.calculate(&expr)?; // propagates MathError on failure
    Ok(result)
}

fn differentiate_twice(input: &str, var: &str) -> Result<Expr, MathError> {
    // Parse once, differentiate twice — any step can fail
    let first  = MathCore::differentiate(input, var)?;
    let second = MathCore::differentiate(&first.to_string(), var)?;
    Ok(second)
}

Common Error Patterns and How to Avoid Them

ErrorCommon causePrevention
ParseErrorUnclosed brackets, operator typosValidate user input; test expressions in unit tests
UndefinedVariableCalling calculate on a symbolic expressionUse evaluate for symbolic results, or supply variables via evaluate_with_vars
UndefinedFunctionMistyped function nameEnsure function names match the built-in list exactly
InvalidArgumentCountWrong arity for log, min, sin, etc.Consult the arity table in the parsing guide
DivisionByZeroDividing by a sub-expression that evaluates to zeroCheck denominators before evaluation, or handle the error gracefully
OverflowVery large exponents or productsClamp inputs or use evaluate and check for Expr::Complex or symbolic fallback
SolverErrorUnsupported equation form or degreeCheck degree() before calling solve; handle non-polynomial equations separately
All MathError variants implement Display via thiserror, so you can always log the full human-readable description with println!("{}", err) or eprintln!("{}", err) without needing to match on the variant.

Build docs developers (and LLMs) love