CODE-0006 · kimi-k3 (default)
import re

_NUMBER_RE = re.compile(r"\d+(?:\.\d*)?|\.\d+")


def _tokenize(s):
    tokens = []
    i = 0
    n = len(s)
    while i < n:
        ch = s[i]
        if ch.isspace():
            i += 1
        elif ch.isdigit() or ch == ".":
            m = _NUMBER_RE.match(s, i)
            if m is None:
                raise ValueError("invalid number literal at position %d" % i)
            tokens.append(("NUM", float(m.group())))
            i = m.end()
        elif ch in "+-*/()":
            tokens.append((ch, ch))
            i += 1
        else:
            raise ValueError("unknown character %r at position %d" % (ch, i))
    return tokens


class _Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.pos = 0

    def _peek(self):
        if self.pos < len(self.tokens):
            return self.tokens[self.pos][0]
        return None

    def _advance(self):
        tok = self.tokens[self.pos]
        self.pos += 1
        return tok

    def parse(self):
        value = self._parse_expr()
        if self.pos != len(self.tokens):
            raise ValueError("unexpected token %r" % (self.tokens[self.pos][1],))
        return value

    def _parse_expr(self):
        value = self._parse_term()
        while self._peek() in ("+", "-"):
            op = self._advance()[0]
            rhs = self._parse_term()
            if op == "+":
                value = value + rhs
            else:
                value = value - rhs
        return value

    def _parse_term(self):
        value = self._parse_factor()
        while self._peek() in ("*", "/"):
            op = self._advance()[0]
            rhs = self._parse_factor()
            if op == "*":
                value = value * rhs
            else:
                if rhs == 0:
                    raise ValueError("division by zero")
                value = value / rhs
        return value

    def _parse_factor(self):
        tok = self._peek()
        if tok == "+":
            self._advance()
            return +self._parse_factor()
        if tok == "-":
            self._advance()
            return -self._parse_factor()
        return self._parse_primary()

    def _parse_primary(self):
        tok = self._peek()
        if tok is None:
            raise ValueError("unexpected end of expression")
        if tok == "NUM":
            return self._advance()[1]
        if tok == "(":
            self._advance()
            value = self._parse_expr()
            if self._peek() != ")":
                raise ValueError("mismatched parentheses")
            self._advance()
            return value
        raise ValueError("unexpected token %r" % (self.tokens[self.pos][1],))


def eval_expr(s):
    if not isinstance(s, str):
        raise ValueError("expression must be a string")
    result = _Parser(_tokenize(s)).parse()
    if isinstance(result, float) and result.is_integer():
        return int(result)
    return result