From f512069fc7446087dff3041515dd6f55dc293f89 Mon Sep 17 00:00:00 2001 From: James Greenwood Date: Sat, 30 Aug 2025 11:33:20 +0100 Subject: [PATCH] dry, black, basic type hints, catch ctrl-d and ctrl-c --- fifth.py | 103 ++++++++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 54 deletions(-) diff --git a/fifth.py b/fifth.py index 161415f..0f6cda7 100644 --- a/fifth.py +++ b/fifth.py @@ -1,79 +1,65 @@ import operator import readline +from typing import Callable + class FifthStack: def __init__(self): - self.stack = [] - self.commands = { - 'push': self.push, - 'pop': self.pop, - 'swap': self.swap, - 'dup': self.dup, - '+': self.add, - '-': self.sub, - '*': self.mul, - '/': self.div, + self.stack: list[int] = [] + self.commands: dict[str, Callable] = { + "push": self.push, + "pop": self.pop, + "swap": self.swap, + "dup": self.dup, } - self.binary_ops = { - '+': operator.add, - '-': operator.sub, - '*': operator.mul, - '/': operator.floordiv, + self.binary_ops: dict[str, Callable[[int, int], int]] = { + "+": operator.add, + "-": operator.sub, + "*": operator.mul, + "/": operator.floordiv, } - + def _require(self, number, message): if len(self.stack) < number: - print(message) + print(f"ERROR: {message}") return False return True - + def _get_binary_op(self, command): return self.binary_ops.get(command) - + def _binary_op(self, operator): if not self._require(2, "two numbers required"): return - a, b = self.stack.pop(), self.stack.pop() + b, a = self.stack.pop(), self.stack.pop() try: self.stack.append(operator(a, b)) - except Exception as e: - print(f"ERROR: {e}") + except ZeroDivisionError as e: + print(f"ERROR: division by zero") self.stack.extend([a, b]) - + def push(self, value): try: self.stack.append(int(value)) except ValueError: print("ERROR: integer required") - def pop(self, _value): + def pop(self): if not self.stack: print("ERROR: stack empty") return self.stack.pop() - def swap(self, _value): - if not self._require(2, 'two numbers required'): + def swap(self): + if not self._require(2, "two numbers required"): return self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1] - def dup(self, _value): - if self._require(1, 'stack empty'): + def dup(self): + if self._require(1, "stack empty"): self.stack.append(self.stack[-1]) - def add(self, _value): - self._binary_op(self._get_binary_op('+')) - - def sub(self, _value): - self._binary_op(self._get_binary_op('-')) - - def mul(self, _value): - self._binary_op(self._get_binary_op('*')) - - def div(self, _value): - self._binary_op(self._get_binary_op('/')) - - def execute(self, command): + def execute(self, command: str): tokens = command.lower().strip().split() if not tokens: return @@ -81,21 +67,30 @@ class FifthStack: command, argument = tokens[0], tokens[1] if len(tokens) > 1 else None function = self.commands.get(command) - try: - if function: function(argument) - else: print("ERROR: unknown command") - except: - print("ERROR: invalid command") + if function: + if command == "push": + function(argument) + else: + function() + elif command in self.binary_ops: + self._binary_op(self._get_binary_op(command)) + else: + print("ERROR: unknown command") + def main(): fifth = FifthStack() - - while True: - print(f'stack is: {fifth.stack}') - command = input() - if command.lower() == 'exit': - break - fifth.execute(command) -if __name__ == '__main__': + while True: + print(f"stack is: {fifth.stack}") + try: + if command := input().strip().lower() == "exit": + break + if command: + fifth.execute(command) + except (EOFError, KeyboardInterrupt): + break + + +if __name__ == "__main__": main()