from collections import deque from typing import Iterable from icecream import ic from math_objects import Operator, Parenthesis, Token __left_parenthesis_error = "__left_parenthesis_error" __right_parenthesis_error = "__right_parenthesis_error" __empty_parentheses_error = "__empty_parentheses_error" def translate(tokens: Iterable[Token]) -> Iterable[Token]: operator_stack: deque[Operator] = deque() previous_stacks: deque[deque[Operator]] = deque() previous_precedence = 0 empty_stack = True for token in tokens: if isinstance(token, Parenthesis): match token.value: case "(": previous_stacks.append(operator_stack) operator_stack = deque() empty_stack = True case _: if empty_stack: raise SystemError(__empty_parentheses_error) if operator_stack: for item in reversed(operator_stack): yield item try: operator_stack = previous_stacks.pop() except IndexError: raise SyntaxError(__right_parenthesis_error) continue empty_stack = False if not isinstance(token, Operator): yield token continue if token.precedence <= previous_precedence: for item in reversed(operator_stack): yield item operator_stack.clear() previous_precedence = token.precedence operator_stack.append(token) if previous_stacks: raise SyntaxError(__left_parenthesis_error) if operator_stack: for item in reversed(operator_stack): yield item