from collections import deque from typing import Iterable, Literal, Optional from math_objects import Integer, Operator, Parenthesis, Token def tokenize(string: str) -> Iterable[Token]: buffer: deque[str] = deque() prediction: Optional[Literal["number"]] = None def _take_buffer() -> str: string = "".join(buffer) buffer.clear() return string for c in string: if c.isdigit(): if prediction != "number" and buffer: yield Integer.create_from_string(_take_buffer()) prediction = "number" buffer.append(c) elif c in ["+", "-", "*", "/", "(", ")"]: if buffer: yield Integer.create_from_string(_take_buffer()) prediction = None match c: case "+" | "-": yield Operator(c, precedence=1) case "*" | "/": yield Operator(c, precedence=2) case _: yield Parenthesis(c) # type: ignore prediction = None elif c == " ": pass else: raise SyntaxError() if buffer: yield Integer.create_from_string(_take_buffer())