Skip to content
Snippets Groups Projects
Select Git revision
  • 8b244b333a349a5693c0a1dbb9d1e7497c3e96b7
  • master default
2 results

agent.py

Blame
  • calculator.py 2.27 KiB
    """
    This Calculator holds the logic for the calculator.
    """
    from calculator.operators import Operator, STANDARD_OPERATORS
    from calculator.expression import Term, Expression, TermExpression, OperatorExpression
    
    
    class Calculator:
        """
        Calculator class is a simple calculator that can parse and evaluate expressions of the form:
        expression ::= term | expression operator expression
        operator ::= + | - | * | /
        with the usual precedence rules.
        """
    
        def __init__(self, operators=None):
            if operators is None:
                operators = STANDARD_OPERATORS
            self.operators = operators
    
        def tokenize(self, line: str):
            """
            Tokenize an expression into a list of tokens.
            """
            tokens = []
            for token in line.split():
                if token in self.operators:
                    tokens.append(self.operators[token])
                else:
                    try:
                        if int(token) == float(token):
                            tokens.append(int(token))
                    except ValueError as exc:
                        raise ValueError(f"Invalid token {token}") from exc
            return tokens
    
        def parse(self, tokens) -> Expression:
            """
            Parse a list of tokens into an ordered expression.
            """
            if not tokens:
                raise ValueError("Empty expression")
            if len(tokens) == 1:
                if isinstance(tokens[0], Term):
                    return TermExpression(tokens[0])
                raise ValueError(f"Expected a term, got {tokens[0]}")
            if len(tokens) == 2:
                raise ValueError("Invalid expression")
    
            # Find the rightest operator with the lowest precedence
            operator = None
            for i, token in enumerate(tokens):
                if isinstance(token, Operator):
                    if operator is None or token.precedence <= operator.precedence:
                        operator = token
                        operator_index = i
    
            # Split the expression into two parts
            left = tokens[:operator_index]
            right = tokens[operator_index + 1:]
    
            # Parse the left and right parts recursively
            return OperatorExpression(operator, self.parse(left), self.parse(right))
    
        def __call__(self, expression: str) -> Term:
            return self.parse(self.tokenize(expression))()