docs: improvement plan (phases 0-3 from code review)

This commit is contained in:
OpenClaw Coder committed 2026-11-05 08:34:34 +10:00
1 parent 4e3d898ec8
commit 3cafe5993f
1 file changed
+58
+58
View File
@@ -0,0 +1,58 @@
# План доработки калькулятора
Ревизия кода: `calculator.py` (227 строк, рекурсивный спуск), `cli.py` (53), `test_calculator.py` (136, 22 теста, unittest).
Оценка объёма: ~14–20 ч суммарно, фазы независимы, каждую можно релизить отдельно.
## Фаза 0 — баги и полировка (P0, ~1–2 ч)
1. **Ложный символ в сообщении об ошибке** — `calculator.py`, `_atom()`:
`"Не хватает закрывающей скобки '}'"` → должно быть `')'`.
2. **Хрупкое `tok.value or 0.0`** в `_atom()` — чинит число `0`, но маскирует `None`. Заменить на явную проверку `tok.value is None`.
3. **Комплексные результаты**: `(-8) ** 0.5` возвращает Python-complex, аннотация обещает `float`. Либо ловить и давать «Ошибка: комплексный результат», либо поддержать явно (см. Фазу 2).
4. **OverflowError при `2 ** 100000`** — `parse_and_eval` бросает не-CalcError. Обернуть возведение в try/except → `CalcError`.
5. **Мусорный тест**: `TestExitCommands.test_non_exit` содержит `"exit"` в цикле с заглушкой-условием. Переписать: `assertFalse` для `"выходить"`, `"exit!"`, `"2 + 2"`.
6. **Docstring `cli.py`** — пример `python cli.py "sqrt"` недостижим (функций нет). Актуализировать после Фазы 1.
Критерий: все существующие тесты зелёные + новые регрессионные на 1–5.
## Фаза 1 — расширения языка (P1, ~3–4 ч)
Порядок по частоте запросов:
1. **Экспоненциальная запись**: `1e3`, `2.5E-4`. Поправить `_tokenize` (сейчас `e` → «Недопустимый символ»). Аккуратно: `e` после числа, опциональный `+/-`.
2. **Целочисленные операции**: `//` (floor div) и настоящий бинарный `%` (mod). Конфликт с постфиксным `%`: правило — `%` без правого операнда = процент, с операндом = mod; либо ввести `mod` как слово. Обсудить и зафиксировать в README.
3. **Константы**: `pi`, `e`, `tau`, `inf`. Через `_KEYWORDS`-подобный словарь в `_atom()`.
4. **Функции**: `sqrt`, `abs`, `round`, `floor`, `ceil`, `sin/cos/tan/asin/...`, `log`, `log2`, `ln`, `exp`. Синтаксис `имя ( args )` или `имя args` (без скобок для одноаргументных). Реализация: таблица `{name: (arity, callable)}` + разбор аргументов через существующий `_expr`.
5. **Разделители разрядов**: `1_000_000` → парсить как число.
Критерий: таблица «приммер → ожидание» в README, тесты на каждую функцию/константу/оператор + приоритеты (`2 ** 1e2`, `sqrt 16 + 1`).
## Фаза 2 — состояние и UX (P1–P2, ~3–5 ч)
1. **Настоящий REPL для TTY**: сейчас `cli.py` читает весь stdin до EOF и печатает приветствие *после* — в терминале это выглядит как зависание. Ветвление: `sys.stdin.isatty()` → цикл с `input("calc> ")`, иначе текущий батч-режим.
2. **`ans` / `Ans`**: последнее значение как идентификатор; плюс `_` не нужен (конфликт с литералом из Фазы 1.5 — решить в пользу `ans`).
3. **История и редактирование**: `readline` (`import readline` в cli) — стрелки ↑/↓, history-файл `~/.calc_history`.
4. **Команды сессии**: `help`, `hist`, `vars`, `reset` (очистить ans/переменные).
5. **Форматирование вывода**: float-артефакты (`0.1 + 0.2`). Сейчас лечится `%.17g→round` эвристикой в `try_evaluate`; надёжнее — округление до 12 значащих цифр при *представлении*, вычисления оставлять float. Опционально: переписать ядро на `decimal.Decimal` (скачок точности, но ломает функции из math — завести на Фазу 3).
6. **Немного дружелюбнее сообщения об ошибках**: указывать позицию символа в строке (токенизатор уже знает `i`).
Критерий: ручной прогон в TTY + юнит-тесты форматирования/ans.
## Фаза 3 — архитектура и инфраструктура (P2, ~4–6 ч)
1. **AST вместо eval-во-время**: `_Parser` строит дерево узлов (Node/Num/Binary/Unary/Postfix/FCall), затем `eval(node, env)`. Зачем: переменные (`x = 5`), история выражений для `hist`, повторный вывод (`pprint`), тестирование парсера отдельно от вычисления. Это фундамент для всего, что дальше.
2. **Переменные и присваивание**: `x = 2 + 3`, потом `x * 2`. Env как dict, `vars` из Фазы 2.
3. **Пакетизация**: `pyproject.toml`, entry point `calc = calculator.cli:main`, убрать PyInstaller-помойку (`build/`, `dist/`, `калькулятор.spec` — в gitignore, либо собрать отдельно как артефакт CI).
4. **pytest + coverage + CI**: миграция unittest→pytest (параметризованные таблицы тестов), `--cov`, min 90%; Gitea Actions pipeline: lint (ruff) + type-check (mypy) + pytest.
5. **Типы**: `mypy --strict calculator/` после рефакторинга (value: float | None решается нормализацией AST).
6. Опционально/далеко: `decimal`-режим, комплексные числа как тип, unit-тесты фuzz-подобным перебором строк (property-based, hypothesis).
## Не делать (осознанно)
- Графический интерфейс — вне SCOPE CLI-калькулятора.
- Свой токенизатор с zero-copy/скоростью — узкое место отсутствует, не профиль.
- Поддержка «2+3*4-1%100» как калькулятора скидок (процент от чего?) — семантика постфикса задокументирована, не трогаем.
## Порядок работ
Фаза 0 → 1 → 2 → 3. Каждая фаза = отдельная ветка + PR в `admin/calculator`, squash-merge, тег `v0.x`.