Фаза 0 — баги и полировка (#1)
This commit is contained in:
1 parent
3cafe5993f
commit
730ba2da00
3 files changed
+39
-7
No files matched your search
+11
-3
@@ -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_("Ожидалось число или скобку")
|
||||
|
||||
@@ -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
@@ -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__":
|
||||
|
||||
Reference in new issue
Block a user