"""Information about Python operators"""

from typing_extensions import Final


# Map from binary operator id to related method name (in Python 3).
op_methods: Final = {
    '+': '__add__',
    '-': '__sub__',
    '*': '__mul__',
    '/': '__truediv__',
    '%': '__mod__',
    'divmod': '__divmod__',
    '//': '__floordiv__',
    '**': '__pow__',
    '@': '__matmul__',
    '&': '__and__',
    '|': '__or__',
    '^': '__xor__',
    '<<': '__lshift__',
    '>>': '__rshift__',
    '==': '__eq__',
    '!=': '__ne__',
    '<': '__lt__',
    '>=': '__ge__',
    '>': '__gt__',
    '<=': '__le__',
    'in': '__contains__',
}

op_methods_to_symbols: Final = {v: k for (k, v) in op_methods.items()}
op_methods_to_symbols['__div__'] = '/'

comparison_fallback_method: Final = "__cmp__"
ops_falling_back_to_cmp: Final = {"__ne__", "__eq__", "__lt__", "__le__", "__gt__", "__ge__"}


ops_with_inplace_method: Final = {
    "+",
    "-",
    "*",
    "/",
    "%",
    "//",
    "**",
    "@",
    "&",
    "|",
    "^",
    "<<",
    ">>",
}

inplace_operator_methods: Final = set("__i" + op_methods[op][2:] for op in ops_with_inplace_method)

reverse_op_methods: Final = {
    '__add__': '__radd__',
    '__sub__': '__rsub__',
    '__mul__': '__rmul__',
    '__truediv__': '__rtruediv__',
    '__mod__': '__rmod__',
    '__divmod__': '__rdivmod__',
    '__floordiv__': '__rfloordiv__',
    '__pow__': '__rpow__',
    '__matmul__': '__rmatmul__',
    '__and__': '__rand__',
    '__or__': '__ror__',
    '__xor__': '__rxor__',
    '__lshift__': '__rlshift__',
    '__rshift__': '__rrshift__',
    '__eq__': '__eq__',
    '__ne__': '__ne__',
    '__lt__': '__gt__',
    '__ge__': '__le__',
    '__gt__': '__lt__',
    '__le__': '__ge__',
}

reverse_op_method_names: Final = set(reverse_op_methods.values())

# Suppose we have some class A. When we do A() + A(), Python will only check
# the output of A().__add__(A()) and skip calling the __radd__ method entirely.
# This shortcut is used only for the following methods:
op_methods_that_shortcut: Final = {
    '__add__',
    '__sub__',
    '__mul__',
    '__div__',
    '__truediv__',
    '__mod__',
    '__divmod__',
    '__floordiv__',
    '__pow__',
    '__matmul__',
    '__and__',
    '__or__',
    '__xor__',
    '__lshift__',
    '__rshift__',
}

normal_from_reverse_op: Final = dict((m, n) for n, m in reverse_op_methods.items())
reverse_op_method_set: Final = set(reverse_op_methods.values())

unary_op_methods: Final = {
    '-': '__neg__',
    '+': '__pos__',
    '~': '__invert__',
}
