59 lines
2.6 KiB
Python
59 lines
2.6 KiB
Python
"""Публичный API калькулятора: вычисление математических выражений.
|
|
|
|
Передана на AST-конвейер: parser.build_ast (токенизация + синтаксический
|
|
анализ) -> ast.Evaluator (вычисление в env) -> format_result (вывод).
|
|
|
|
Поддерживает:
|
|
- операции: + - * / // %(бинарный остаток) и скобки;
|
|
- возведение в степень ** (правостороннее);
|
|
- унарный минус и плюс (-5, +3);
|
|
- проценты (50% => 0.5);
|
|
- экспоненциальную запись (1e3, 2.5E-4) и разделители разрядов (1_000_000);
|
|
- константы: pi, e, tau, inf;
|
|
- функции: sqrt, abs, exp, ln, log, log2, log10, round, floor, ceil,
|
|
sin, cos, tan, asin, acos, atan (аргументы тригонометрии — в радианах).
|
|
|
|
Правило для '%': если после % идёт число, константа, функция или '(' — это
|
|
бинарный остаток от деления (7 % 3 = 1); иначе — постфиксный процент (2 * 50 % = 1).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from nodes import (
|
|
ASTError,
|
|
DivisionByZeroError, # noqa: F401 (re-export для тестов и CLI)
|
|
Evaluator,
|
|
SyntaxError_, # noqa: F401 (re-export)
|
|
format_result,
|
|
)
|
|
from parser import build_ast
|
|
|
|
# Backward-compat: CalcError устарел, используйте ASTError
|
|
CalcError = ASTError
|
|
|
|
|
|
def parse_and_eval(expression: str, env: dict[str, float] | None = None) -> float:
|
|
"""Вычисляет выражение и возвращает float.
|
|
|
|
Raises ASTError (SyntaxError_ / DivisionByZeroError) при некорректном вводе.
|
|
"""
|
|
node = build_ast(expression)
|
|
return Evaluator().eval(node, env or {})
|
|
|
|
|
|
def is_exit_command(text: str) -> bool:
|
|
"""True, если введённое значение — команда выхода ('выход'/'exit')."""
|
|
return text.strip().lower() in {"выход", "exit"}
|
|
|
|
|
|
def try_evaluate(expression: str, env: dict[str, float] | None = None) -> str:
|
|
"""Пытается вычислить выражение.
|
|
|
|
Возвращает человекочитаемый результат или сообщение об ошибке.
|
|
"""
|
|
try:
|
|
return format_result(parse_and_eval(expression, env))
|
|
except ASTError as exc:
|
|
return f"Ошибка: {exc}"
|
|
except Exception as exc: # на всякий случай — не падаем с traceback
|
|
return f"Ошибка: {exc}"
|