Major fixes and new features
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
"""Fallback primitive operations that operate on 'object' operands.
|
||||
|
||||
These just call the relevant Python C API function or a thin wrapper
|
||||
around an API function. Most of these also have faster, specialized
|
||||
ops that operate on some more specific types.
|
||||
|
||||
Many of these ops are given a low priority (0) so that specialized ops
|
||||
will take precedence. If your specialized op doesn't seem to be used,
|
||||
check that the priorities are configured properly.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER
|
||||
from mypyc.ir.rtypes import (
|
||||
bool_rprimitive,
|
||||
c_int_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
c_size_t_rprimitive,
|
||||
int_rprimitive,
|
||||
object_pointer_rprimitive,
|
||||
object_rprimitive,
|
||||
pointer_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
ERR_NEG_INT,
|
||||
binary_op,
|
||||
custom_op,
|
||||
function_op,
|
||||
method_op,
|
||||
unary_op,
|
||||
)
|
||||
|
||||
# Binary operations
|
||||
|
||||
for op, opid in [
|
||||
("==", 2), # PY_EQ
|
||||
("!=", 3), # PY_NE
|
||||
("<", 0), # PY_LT
|
||||
("<=", 1), # PY_LE
|
||||
(">", 4), # PY_GT
|
||||
(">=", 5),
|
||||
]: # PY_GE
|
||||
# The result type is 'object' since that's what PyObject_RichCompare returns.
|
||||
binary_op(
|
||||
name=op,
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyObject_RichCompare",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(opid, c_int_rprimitive)],
|
||||
priority=0,
|
||||
)
|
||||
|
||||
for op, funcname in [
|
||||
("+", "PyNumber_Add"),
|
||||
("-", "PyNumber_Subtract"),
|
||||
("*", "PyNumber_Multiply"),
|
||||
("//", "PyNumber_FloorDivide"),
|
||||
("/", "PyNumber_TrueDivide"),
|
||||
("%", "PyNumber_Remainder"),
|
||||
("<<", "PyNumber_Lshift"),
|
||||
(">>", "PyNumber_Rshift"),
|
||||
("&", "PyNumber_And"),
|
||||
("^", "PyNumber_Xor"),
|
||||
("|", "PyNumber_Or"),
|
||||
("@", "PyNumber_MatrixMultiply"),
|
||||
]:
|
||||
binary_op(
|
||||
name=op,
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name=funcname,
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
|
||||
function_op(
|
||||
name="builtins.divmod",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyNumber_Divmod",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
|
||||
for op, funcname in [
|
||||
("+=", "PyNumber_InPlaceAdd"),
|
||||
("-=", "PyNumber_InPlaceSubtract"),
|
||||
("*=", "PyNumber_InPlaceMultiply"),
|
||||
("@=", "PyNumber_InPlaceMatrixMultiply"),
|
||||
("//=", "PyNumber_InPlaceFloorDivide"),
|
||||
("/=", "PyNumber_InPlaceTrueDivide"),
|
||||
("%=", "PyNumber_InPlaceRemainder"),
|
||||
("<<=", "PyNumber_InPlaceLshift"),
|
||||
(">>=", "PyNumber_InPlaceRshift"),
|
||||
("&=", "PyNumber_InPlaceAnd"),
|
||||
("^=", "PyNumber_InPlaceXor"),
|
||||
("|=", "PyNumber_InPlaceOr"),
|
||||
]:
|
||||
binary_op(
|
||||
name=op,
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name=funcname,
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
for op, c_function in (("**", "CPyNumber_Power"), ("**=", "CPyNumber_InPlacePower")):
|
||||
binary_op(
|
||||
name=op,
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
error_kind=ERR_MAGIC,
|
||||
c_function_name=c_function,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
for arg_count, c_function in ((2, "CPyNumber_Power"), (3, "PyNumber_Power")):
|
||||
function_op(
|
||||
name="builtins.pow",
|
||||
arg_types=[object_rprimitive] * arg_count,
|
||||
return_type=object_rprimitive,
|
||||
error_kind=ERR_MAGIC,
|
||||
c_function_name=c_function,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
binary_op(
|
||||
name="in",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PySequence_Contains",
|
||||
error_kind=ERR_NEG_INT,
|
||||
truncated_type=bool_rprimitive,
|
||||
ordering=[1, 0],
|
||||
priority=0,
|
||||
)
|
||||
|
||||
|
||||
# Unary operations
|
||||
|
||||
for op, funcname in [
|
||||
("-", "PyNumber_Negative"),
|
||||
("+", "PyNumber_Positive"),
|
||||
("~", "PyNumber_Invert"),
|
||||
]:
|
||||
unary_op(
|
||||
name=op,
|
||||
arg_type=object_rprimitive,
|
||||
return_type=object_rprimitive,
|
||||
c_function_name=funcname,
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
unary_op(
|
||||
name="not",
|
||||
arg_type=object_rprimitive,
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_Not",
|
||||
error_kind=ERR_NEG_INT,
|
||||
truncated_type=bool_rprimitive,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
# abs(obj)
|
||||
function_op(
|
||||
name="builtins.abs",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyNumber_Absolute",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
# obj1[obj2]
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyObject_GetItem",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
# obj1[obj2] = obj3
|
||||
method_op(
|
||||
name="__setitem__",
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_SetItem",
|
||||
error_kind=ERR_NEG_INT,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
# del obj1[obj2]
|
||||
method_op(
|
||||
name="__delitem__",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_DelItem",
|
||||
error_kind=ERR_NEG_INT,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
# hash(obj)
|
||||
function_op(
|
||||
name="builtins.hash",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyObject_Hash",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# getattr(obj, attr)
|
||||
py_getattr_op = function_op(
|
||||
name="builtins.getattr",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyObject_GetAttr",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# getattr(obj, attr, default)
|
||||
function_op(
|
||||
name="builtins.getattr",
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyObject_GetAttr3",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# setattr(obj, attr, value)
|
||||
py_setattr_op = function_op(
|
||||
name="builtins.setattr",
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_SetAttr",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# hasattr(obj, attr)
|
||||
py_hasattr_op = function_op(
|
||||
name="builtins.hasattr",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="PyObject_HasAttr",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# del obj.attr
|
||||
py_delattr_op = function_op(
|
||||
name="builtins.delattr",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_DelAttr",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# Call callable object with N positional arguments: func(arg1, ..., argN)
|
||||
# Arguments are (func, arg1, ..., argN).
|
||||
py_call_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyObject_CallFunctionObjArgs",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=object_rprimitive,
|
||||
extra_int_constants=[(0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# Call callable object using positional and/or keyword arguments (Python 3.8+)
|
||||
py_vectorcall_op = custom_op(
|
||||
arg_types=[
|
||||
object_rprimitive, # Callable
|
||||
object_pointer_rprimitive, # Args (PyObject **)
|
||||
c_size_t_rprimitive, # Number of positional args
|
||||
object_rprimitive,
|
||||
], # Keyword arg names tuple (or NULL)
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="_PyObject_Vectorcall",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Call method using positional and/or keyword arguments (Python 3.9+)
|
||||
py_vectorcall_method_op = custom_op(
|
||||
arg_types=[
|
||||
object_rprimitive, # Method name
|
||||
object_pointer_rprimitive, # Args, including self (PyObject **)
|
||||
c_size_t_rprimitive, # Number of positional args, including self
|
||||
object_rprimitive,
|
||||
], # Keyword arg names tuple (or NULL)
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyObject_VectorcallMethod",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Call callable object with positional + keyword args: func(*args, **kwargs)
|
||||
# Arguments are (func, *args tuple, **kwargs dict).
|
||||
py_call_with_kwargs_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyObject_Call",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Call method with positional arguments: obj.method(arg1, ...)
|
||||
# Arguments are (object, attribute name, arg1, ...).
|
||||
py_method_call_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyObject_CallMethodObjArgs",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=object_rprimitive,
|
||||
extra_int_constants=[(0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# len(obj)
|
||||
generic_len_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyObject_Size",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# len(obj)
|
||||
# same as generic_len_op, however return py_ssize_t
|
||||
generic_ssize_t_len_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=c_pyssize_t_rprimitive,
|
||||
c_function_name="PyObject_Size",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# iter(obj)
|
||||
iter_op = function_op(
|
||||
name="builtins.iter",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyObject_GetIter",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
# next(iterator)
|
||||
#
|
||||
# Although the error_kind is set to be ERR_NEVER, this can actually
|
||||
# return NULL, and thus it must be checked using Branch.IS_ERROR.
|
||||
next_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyIter_Next",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
# next(iterator)
|
||||
#
|
||||
# Do a next, don't swallow StopIteration, but also don't propagate an
|
||||
# error. (N.B: This can still return NULL without an error to
|
||||
# represent an implicit StopIteration, but if StopIteration is
|
||||
# *explicitly* raised this will not swallow it.)
|
||||
# Can return NULL: see next_op.
|
||||
next_raw_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyIter_Next",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# this would be aiter(obj) if it existed
|
||||
aiter_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPy_GetAIter",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# this would be anext(obj) if it existed
|
||||
anext_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPy_GetANext",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
Reference in New Issue
Block a user