from .expression import BinaryExpression, Expression, UnaryExpression, ValueExpression from .operation import ( BraceOperation, FunctionOperation, Operation, OperatorOperation, priorities, ) from .tokenizer import Token, Tokenizer from .types import ValueType from .constants import CONSTANTS class Parser: def __init__(self, input_expr: str): self.input_expr = input_expr self.variables_names: set[str] = set() self.tokenize() self.parse() def tokenize(self): self.tokens = Tokenizer(self.input_expr) def parse(self): self.val_stack: list[Expression] = [] self.op_stack: list[Operation] = [] for t_val, t_type in self.tokens: if t_type in (Token.Number, Token.Variable): self.val_stack.append(ValueExpression(t_val)) if t_type == Token.Variable: self.variables_names.add(t_val) elif t_type == Token.Function: self.op_stack.append(FunctionOperation(t_val)) elif t_type == Token.LBrace: self.op_stack.append(BraceOperation("(")) elif t_type == Token.RBrace: while len(self.op_stack) > 0 and not ( self.op_stack[-1].size == 0 and self.op_stack[-1].priority == 0 ): # until next in stack is lbrace self.do_one() self.op_stack.pop() # pop lbrace elif t_type == Token.Operator: t_priority = priorities[t_val] while ( len(self.op_stack) > 0 and self.op_stack[-1].priority > t_priority ): self.do_one() self.op_stack.append(OperatorOperation(t_val)) while len(self.op_stack) > 0: self.do_one() self._evaluator = self.val_stack[0].evaluate self.__debug_expr = repr(self.val_stack) def evaluate(self, variables: dict[str, ValueType]): variables |= CONSTANTS return self._evaluator(variables) def do_one(self): op = self.op_stack.pop() if op.size == 1: a = self.val_stack.pop() self.val_stack.append(UnaryExpression(op.evaluator, a)) elif op.size == 2: b, a = self.val_stack.pop(), self.val_stack.pop() # inversed pop order self.val_stack.append(BinaryExpression(op.evaluator, a, b)) def __repr__(self): return self.__debug_expr