Skip to content

calculator

calculator

Calculator tool — safe math evaluation via ast module.

Classes

CalculatorTool

Bases: BaseTool

Safe math calculator using AST-based evaluation.

Functions:

safe_eval

safe_eval(expression: str) -> float

Evaluate a math expression safely — Rust backend with Python fallback.

Source code in src/diapason/tools/calculator.py
def safe_eval(expression: str) -> float:
    """Evaluate a math expression safely — Rust backend with Python fallback."""
    try:
        from diapason._rust_bridge import get_rust_module

        _rust = get_rust_module()
        native_result = _rust.CalculatorTool().execute(expression)
        try:
            native_float = float(native_result)
        except (TypeError, ValueError):
            # The native result includes a human-readable failure string.
            # Re-evaluate with the canonical AST path to preserve the public
            # Python exceptions and exact supported-function contract.
            pass
        else:
            # The Rust path yields inf/nan where Python raises. Fall through
            # so the AST path can raise the precise exception — "division by
            # zero" is a better thing to tell someone than "out of range".
            if math.isfinite(native_float):
                return native_float
    except (AttributeError, ImportError, RuntimeError):
        pass

    # Support ^ as the power operator (common math/calculator notation).
    expression = expression.replace("^", "**")
    try:
        tree = ast.parse(expression, mode="eval")
    except SyntaxError as exc:
        raise ValueError(f"Syntax error in expression: {exc}") from exc
    # ZeroDivisionError is deliberately *not* caught here. Converting it to
    # ``inf`` made the caller's own "division by zero" branch unreachable, and
    # handed the model a float it reads as an answer: asked to split a bill
    # among zero people, the assistant answers "inf" rather than saying the
    # question has no answer.
    return float(_safe_eval_node(tree.body))