CODE-0006 · claude-fable-5 (high)
def eval_expr(s):
    """Evaluate an arithmetic expression string and return int or float.

    Supports +, -, *, / with standard precedence and left associativity,
    parentheses, unary + and -, integer and decimal literals, and
    arbitrary whitespace. Raises ValueError on malformed input or
    division by zero.
    """
    if not isinstance(s, str):
        raise ValueError("expression must be a string")

    tokens = _tokenize(s)
    if not tokens:
        raise ValueError("empty expression")

    pos = 0

    def peek():
        return tokens[pos] if pos < len(tokens) else None

    def advance():
        nonlocal pos
        tok = tokens[pos]
        pos += 1
        return tok

    def parse_expr():
        value = parse_term()
        while peek() in ('+', '-'):
            op = advance()
            rhs = parse_term()
            value = value + rhs if op == '+' else value - rhs
        return value

    def parse_term():
        value = parse_factor()
        while peek() in ('*', '/'):
            op = advance()
            rhs = parse_factor()
            if op == '*':
                value = value * rhs
            else:
                if rhs == 0:
                    raise ValueError("division by zero")
                value = value / rhs
        return value

    def parse_factor():
        tok = peek()
        if tok == '+':
            advance()
            return parse_factor()
        if tok == '-':
            advance()
            return -parse_factor()
        if tok == '(':
            advance()
            value = parse_expr()
            if peek() != ')':
                raise ValueError("mismatched parentheses")
            advance()
            return value
        if isinstance(tok, (int, float)):
            return advance()
        if tok is None:
            raise ValueError("unexpected end of expression")
        raise ValueError("unexpected token: %r" % (tok,))

    result = parse_expr()
    if pos != len(tokens):
        raise ValueError("unexpected token: %r" % (tokens[pos],))

    if isinstance(result, float) and result.is_integer():
        return int(result)
    return result


def _tokenize(s):
    tokens = []
    i = 0
    n = len(s)
    while i < n:
        c = s[i]
        if c.isspace():
            i += 1
            continue
        if c in '+-*/()':
            tokens.append(c)
            i += 1
            continue
        if c.isdigit() or c == '.':
            j = i
            seen_dot = False
            while j < n and (s[j].isdigit() or s[j] == '.'):
                if s[j] == '.':
                    if seen_dot:
                        raise ValueError("malformed number: %r" % (s[i:j + 1],))
                    seen_dot = True
                j += 1
            text = s[i:j]
            if text == '.':
                raise ValueError("malformed number: '.'")
            tokens.append(float(text) if '.' in text else int(text))
            i = j
            continue
        raise ValueError("unknown character: %r" % (c,))
    return tokens