From 730ba2da009e7e12cd6e4d7f2bd0190c88ee6fbd Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 5 Nov 2026 08:36:52 +1000 Subject: [PATCH] =?UTF-8?q?=D0=A4=D0=B0=D0=B7=D0=B0=200=20=E2=80=94=20?= =?UTF-8?q?=D0=B1=D0=B0=D0=B3=D0=B8=20=D0=B8=20=D0=BF=D0=BE=D0=BB=D0=B8?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20(#1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- calculator.py | 14 +++++++++++--- cli.py | 2 +- test_calculator.py | 30 +++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/calculator.py b/calculator.py index cc906a6..a2ad643 100644 --- a/calculator.py +++ b/calculator.py @@ -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_("Ожидалось число или скобку") diff --git a/cli.py b/cli.py index 4e78c72..b548e43 100644 --- a/cli.py +++ b/cli.py @@ -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 diff --git a/test_calculator.py b/test_calculator.py index 4a1c725..d7a53bc 100644 --- a/test_calculator.py +++ b/test_calculator.py @@ -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__":