dry, black, basic type hints, catch ctrl-d and ctrl-c

This commit is contained in:
James Greenwood 2025-08-30 11:33:20 +01:00
parent 26aaabe6a7
commit f512069fc7

103
fifth.py
View File

@ -1,79 +1,65 @@
import operator import operator
import readline import readline
from typing import Callable
class FifthStack: class FifthStack:
def __init__(self): def __init__(self):
self.stack = [] self.stack: list[int] = []
self.commands = { self.commands: dict[str, Callable] = {
'push': self.push, "push": self.push,
'pop': self.pop, "pop": self.pop,
'swap': self.swap, "swap": self.swap,
'dup': self.dup, "dup": self.dup,
'+': self.add,
'-': self.sub,
'*': self.mul,
'/': self.div,
} }
self.binary_ops = { self.binary_ops: dict[str, Callable[[int, int], int]] = {
'+': operator.add, "+": operator.add,
'-': operator.sub, "-": operator.sub,
'*': operator.mul, "*": operator.mul,
'/': operator.floordiv, "/": operator.floordiv,
} }
def _require(self, number, message): def _require(self, number, message):
if len(self.stack) < number: if len(self.stack) < number:
print(message) print(f"ERROR: {message}")
return False return False
return True return True
def _get_binary_op(self, command): def _get_binary_op(self, command):
return self.binary_ops.get(command) return self.binary_ops.get(command)
def _binary_op(self, operator): def _binary_op(self, operator):
if not self._require(2, "two numbers required"): if not self._require(2, "two numbers required"):
return return
a, b = self.stack.pop(), self.stack.pop() b, a = self.stack.pop(), self.stack.pop()
try: try:
self.stack.append(operator(a, b)) self.stack.append(operator(a, b))
except Exception as e: except ZeroDivisionError as e:
print(f"ERROR: {e}") print(f"ERROR: division by zero")
self.stack.extend([a, b]) self.stack.extend([a, b])
def push(self, value): def push(self, value):
try: try:
self.stack.append(int(value)) self.stack.append(int(value))
except ValueError: except ValueError:
print("ERROR: integer required") print("ERROR: integer required")
def pop(self, _value): def pop(self):
if not self.stack: if not self.stack:
print("ERROR: stack empty") print("ERROR: stack empty")
return return
self.stack.pop() self.stack.pop()
def swap(self, _value): def swap(self):
if not self._require(2, 'two numbers required'): if not self._require(2, "two numbers required"):
return return
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1] self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
def dup(self, _value): def dup(self):
if self._require(1, 'stack empty'): if self._require(1, "stack empty"):
self.stack.append(self.stack[-1]) self.stack.append(self.stack[-1])
def add(self, _value): def execute(self, command: str):
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):
tokens = command.lower().strip().split() tokens = command.lower().strip().split()
if not tokens: if not tokens:
return return
@ -81,21 +67,30 @@ class FifthStack:
command, argument = tokens[0], tokens[1] if len(tokens) > 1 else None command, argument = tokens[0], tokens[1] if len(tokens) > 1 else None
function = self.commands.get(command) function = self.commands.get(command)
try: if function:
if function: function(argument) if command == "push":
else: print("ERROR: unknown command") function(argument)
except: else:
print("ERROR: invalid command") function()
elif command in self.binary_ops:
self._binary_op(self._get_binary_op(command))
else:
print("ERROR: unknown command")
def main(): def main():
fifth = FifthStack() 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() main()