Фаза 0 — баги и полировка (#1)

This commit is contained in:
admin committed 2026-11-05 08:36:52 +10:00
1 parent 3cafe5993f
commit 730ba2da00
3 files changed
+39 -7

No files matched your search

+11 -3
View File
@@ -176,7 +176,13 @@ class _Parser:
if tok and tok.type == _TokenType.POW:
self._advance()
exponent = self._factor()
return base ** exponent
try:
value = base ** exponent
except OverflowError as exc:
raise CalcError(f"Переполнение при возведении в степень: {exc}") from exc
if isinstance(value, complex):
raise CalcError("Комплексный результат не поддерживается")
return value
return base
def _atom(self) -> float:
@@ -185,13 +191,15 @@ class _Parser:
raise SyntaxError_("Неожиданный конец выражения")
if tok.type == _TokenType.NUMBER:
self._advance()
return tok.value or 0.0
if tok.value is None:
raise SyntaxError_("Пустое число")
return tok.value
if tok.type == _TokenType.LPAREN:
self._advance()
value = self._expr()
close = self._peek()
if not close or close.type != _TokenType.RPAREN:
raise SyntaxError_("Не хватает закрывающей скобки '}'")
raise SyntaxError_("Не хватает закрывающей скобки ')'")
self._advance()
return value
raise SyntaxError_("Ожидалось число или скобку")
+1 -1
View File
@@ -4,7 +4,7 @@
Читает выражения из stdin до ключевых слов «выход» / "exit".
Можно запускать:
python cli.py
python cli.py "2 + 2" "sqrt" ... # аргументы — как входные строки
python cli.py "2 + 2" "3 * (4 - 1)" # аргументы — как входные строки
"""
from __future__ import annotations
+27 -3
View File
@@ -10,6 +10,7 @@ import math
import unittest
from calculator import (
CalcError,
DivisionByZeroError,
SyntaxError_,
is_exit_command,
@@ -127,9 +128,32 @@ class TestExitCommands(unittest.TestCase):
self.assertTrue(is_exit_command(cmd), msg=cmd)
def test_non_exit(self):
for cmd in ("выходить", "exit", "2 + 2", "exit!"):
if cmd not in ("exit",):
self.assertFalse(is_exit_command(cmd), msg=cmd)
for cmd in ("выходить", "exit!", "2 + 2", "exit exit"):
self.assertFalse(is_exit_command(cmd), msg=cmd)
class TestPhase0Regressions(unittest.TestCase):
def test_zero_number_atom(self):
# 0 как атом должен работать (не превращаться в 0.0 через `or`)
self.assertAlmostEqual(parse_and_eval("0"), 0.0)
self.assertAlmostEqual(parse_and_eval("0 * 5"), 0.0)
def test_unbalanced_paren_message(self):
with self.assertRaises(SyntaxError_) as ctx:
parse_and_eval("(2 + 3")
self.assertIn("')'", str(ctx.exception))
self.assertNotIn("'}'", str(ctx.exception))
def test_complex_result_raises_calc_error(self):
with self.assertRaises(CalcError):
parse_and_eval("(-8) ** 0.5")
def test_overflow_raises_calc_error(self):
with self.assertRaises(CalcError):
parse_and_eval("2 ** 100000")
def test_try_evaluate_never_raises_on_overflow(self):
self.assertIn("Ошибка", try_evaluate("2 ** 100000"))
if __name__ == "__main__":