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))
|