82 lines
2.5 KiB
Python

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