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:
Binary file not shown.
Binary file not shown.
101
venv/lib/python3.12/site-packages/mypyc/primitives/bytes_ops.py
Normal file
101
venv/lib/python3.12/site-packages/mypyc/primitives/bytes_ops.py
Normal file
@@ -0,0 +1,101 @@
|
||||
"""Primitive bytes ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_MAGIC
|
||||
from mypyc.ir.rtypes import (
|
||||
RUnion,
|
||||
bytes_rprimitive,
|
||||
c_int_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
dict_rprimitive,
|
||||
int_rprimitive,
|
||||
list_rprimitive,
|
||||
object_rprimitive,
|
||||
str_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
ERR_NEG_INT,
|
||||
binary_op,
|
||||
custom_op,
|
||||
function_op,
|
||||
load_address_op,
|
||||
method_op,
|
||||
)
|
||||
|
||||
# Get the 'bytes' type object.
|
||||
load_address_op(name="builtins.bytes", type=object_rprimitive, src="PyBytes_Type")
|
||||
|
||||
# bytes(obj)
|
||||
function_op(
|
||||
name="builtins.bytes",
|
||||
arg_types=[RUnion([list_rprimitive, dict_rprimitive, str_rprimitive])],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="PyBytes_FromObject",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# bytearray(obj)
|
||||
function_op(
|
||||
name="builtins.bytearray",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="PyByteArray_FromObject",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# bytes ==/!= (return -1/0/1)
|
||||
bytes_compare = custom_op(
|
||||
arg_types=[bytes_rprimitive, bytes_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyBytes_Compare",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# bytes + bytes
|
||||
# bytearray + bytearray
|
||||
binary_op(
|
||||
name="+",
|
||||
arg_types=[bytes_rprimitive, bytes_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPyBytes_Concat",
|
||||
error_kind=ERR_MAGIC,
|
||||
steals=[True, False],
|
||||
)
|
||||
|
||||
# bytes[begin:end]
|
||||
bytes_slice_op = custom_op(
|
||||
arg_types=[bytes_rprimitive, int_rprimitive, int_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPyBytes_GetSlice",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# bytes[index]
|
||||
# bytearray[index]
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[bytes_rprimitive, int_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyBytes_GetItem",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# bytes.join(obj)
|
||||
method_op(
|
||||
name="join",
|
||||
arg_types=[bytes_rprimitive, object_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPyBytes_Join",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Join bytes objects and return a new bytes.
|
||||
# The first argument is the total number of the following bytes.
|
||||
bytes_build_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPyBytes_Build",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=bytes_rprimitive,
|
||||
)
|
||||
Binary file not shown.
325
venv/lib/python3.12/site-packages/mypyc/primitives/dict_ops.py
Normal file
325
venv/lib/python3.12/site-packages/mypyc/primitives/dict_ops.py
Normal file
@@ -0,0 +1,325 @@
|
||||
"""Primitive dict ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC, ERR_NEVER
|
||||
from mypyc.ir.rtypes import (
|
||||
bit_rprimitive,
|
||||
bool_rprimitive,
|
||||
c_int_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
dict_next_rtuple_pair,
|
||||
dict_next_rtuple_single,
|
||||
dict_rprimitive,
|
||||
int_rprimitive,
|
||||
list_rprimitive,
|
||||
object_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
ERR_NEG_INT,
|
||||
binary_op,
|
||||
custom_op,
|
||||
function_op,
|
||||
load_address_op,
|
||||
method_op,
|
||||
)
|
||||
|
||||
# Get the 'dict' type object.
|
||||
load_address_op(name="builtins.dict", type=object_rprimitive, src="PyDict_Type")
|
||||
|
||||
# Construct an empty dictionary via dict().
|
||||
function_op(
|
||||
name="builtins.dict",
|
||||
arg_types=[],
|
||||
return_type=dict_rprimitive,
|
||||
c_function_name="PyDict_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Construct an empty dictionary.
|
||||
dict_new_op = custom_op(
|
||||
arg_types=[], return_type=dict_rprimitive, c_function_name="PyDict_New", error_kind=ERR_MAGIC
|
||||
)
|
||||
|
||||
# Construct a dictionary from keys and values.
|
||||
# Positional argument is the number of key-value pairs
|
||||
# Variable arguments are (key1, value1, ..., keyN, valueN).
|
||||
dict_build_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=dict_rprimitive,
|
||||
c_function_name="CPyDict_Build",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=object_rprimitive,
|
||||
)
|
||||
|
||||
# Construct a dictionary from another dictionary.
|
||||
function_op(
|
||||
name="builtins.dict",
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=dict_rprimitive,
|
||||
c_function_name="PyDict_Copy",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=2,
|
||||
)
|
||||
|
||||
# Generic one-argument dict constructor: dict(obj)
|
||||
dict_copy = function_op(
|
||||
name="builtins.dict",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=dict_rprimitive,
|
||||
c_function_name="CPyDict_FromAny",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict[key]
|
||||
dict_get_item_op = method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[dict_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_GetItem",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict[key] = value
|
||||
dict_set_item_op = method_op(
|
||||
name="__setitem__",
|
||||
arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyDict_SetItem",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# key in dict
|
||||
binary_op(
|
||||
name="in",
|
||||
arg_types=[object_rprimitive, dict_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyDict_Contains",
|
||||
error_kind=ERR_NEG_INT,
|
||||
truncated_type=bool_rprimitive,
|
||||
ordering=[1, 0],
|
||||
)
|
||||
|
||||
# dict1.update(dict2)
|
||||
dict_update_op = method_op(
|
||||
name="update",
|
||||
arg_types=[dict_rprimitive, dict_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyDict_Update",
|
||||
error_kind=ERR_NEG_INT,
|
||||
priority=2,
|
||||
)
|
||||
|
||||
# Operation used for **value in dict displays.
|
||||
# This is mostly like dict.update(obj), but has customized error handling.
|
||||
dict_update_in_display_op = custom_op(
|
||||
arg_types=[dict_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyDict_UpdateInDisplay",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# dict.update(obj)
|
||||
method_op(
|
||||
name="update",
|
||||
arg_types=[dict_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyDict_UpdateFromAny",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# dict.get(key, default)
|
||||
method_op(
|
||||
name="get",
|
||||
arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_Get",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.get(key)
|
||||
dict_get_method_with_none = method_op(
|
||||
name="get",
|
||||
arg_types=[dict_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_GetWithNone",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.setdefault(key, default)
|
||||
dict_setdefault_op = method_op(
|
||||
name="setdefault",
|
||||
arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_SetDefault",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.setdefault(key)
|
||||
method_op(
|
||||
name="setdefault",
|
||||
arg_types=[dict_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_SetDefaultWithNone",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.setdefault(key, empty tuple/list/set)
|
||||
# The third argument marks the data type of the second argument.
|
||||
# 1: list 2: dict 3: set
|
||||
# Other number would lead to an error.
|
||||
dict_setdefault_spec_init_op = custom_op(
|
||||
arg_types=[dict_rprimitive, object_rprimitive, c_int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_SetDefaultWithEmptyDatatype",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.keys()
|
||||
method_op(
|
||||
name="keys",
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_KeysView",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.values()
|
||||
method_op(
|
||||
name="values",
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_ValuesView",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.items()
|
||||
method_op(
|
||||
name="items",
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_ItemsView",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# dict.clear()
|
||||
method_op(
|
||||
name="clear",
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyDict_Clear",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
# dict.copy()
|
||||
method_op(
|
||||
name="copy",
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=dict_rprimitive,
|
||||
c_function_name="CPyDict_Copy",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list(dict.keys())
|
||||
dict_keys_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="CPyDict_Keys",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list(dict.values())
|
||||
dict_values_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="CPyDict_Values",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list(dict.items())
|
||||
dict_items_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="CPyDict_Items",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# PyDict_Next() fast iteration
|
||||
dict_key_iter_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_GetKeysIter",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
dict_value_iter_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_GetValuesIter",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
dict_item_iter_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyDict_GetItemsIter",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
dict_next_key_op = custom_op(
|
||||
arg_types=[object_rprimitive, int_rprimitive],
|
||||
return_type=dict_next_rtuple_single,
|
||||
c_function_name="CPyDict_NextKey",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
dict_next_value_op = custom_op(
|
||||
arg_types=[object_rprimitive, int_rprimitive],
|
||||
return_type=dict_next_rtuple_single,
|
||||
c_function_name="CPyDict_NextValue",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
dict_next_item_op = custom_op(
|
||||
arg_types=[object_rprimitive, int_rprimitive],
|
||||
return_type=dict_next_rtuple_pair,
|
||||
c_function_name="CPyDict_NextItem",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# check that len(dict) == const during iteration
|
||||
dict_check_size_op = custom_op(
|
||||
arg_types=[dict_rprimitive, int_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyDict_CheckSize",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
dict_ssize_t_size_op = custom_op(
|
||||
arg_types=[dict_rprimitive],
|
||||
return_type=c_pyssize_t_rprimitive,
|
||||
c_function_name="PyDict_Size",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Delete an item from a dict
|
||||
dict_del_item = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyDict_DelItem",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
supports_mapping_protocol = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyMapping_Check",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
mapping_has_key = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyMapping_HasKey",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
Binary file not shown.
101
venv/lib/python3.12/site-packages/mypyc/primitives/exc_ops.py
Normal file
101
venv/lib/python3.12/site-packages/mypyc/primitives/exc_ops.py
Normal file
@@ -0,0 +1,101 @@
|
||||
"""Exception-related primitive ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_ALWAYS, ERR_FALSE, ERR_NEVER
|
||||
from mypyc.ir.rtypes import bit_rprimitive, exc_rtuple, object_rprimitive, void_rtype
|
||||
from mypyc.primitives.registry import custom_op
|
||||
|
||||
# If the argument is a class, raise an instance of the class. Otherwise, assume
|
||||
# that the argument is an exception object, and raise it.
|
||||
raise_exception_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPy_Raise",
|
||||
error_kind=ERR_ALWAYS,
|
||||
)
|
||||
|
||||
# Raise StopIteration exception with the specified value (which can be NULL).
|
||||
set_stop_iteration_value = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPyGen_SetStopIterationValue",
|
||||
error_kind=ERR_ALWAYS,
|
||||
)
|
||||
|
||||
# Raise exception with traceback.
|
||||
# Arguments are (exception type, exception value, traceback).
|
||||
raise_exception_with_tb_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPyErr_SetObjectAndTraceback",
|
||||
error_kind=ERR_ALWAYS,
|
||||
)
|
||||
|
||||
# Reraise the currently raised exception.
|
||||
reraise_exception_op = custom_op(
|
||||
arg_types=[], return_type=void_rtype, c_function_name="CPy_Reraise", error_kind=ERR_ALWAYS
|
||||
)
|
||||
|
||||
# Propagate exception if the CPython error indicator is set (an exception was raised).
|
||||
no_err_occurred_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPy_NoErrOccured",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
err_occurred_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyErr_Occurred",
|
||||
error_kind=ERR_NEVER,
|
||||
is_borrowed=True,
|
||||
)
|
||||
|
||||
# Keep propagating a raised exception by unconditionally giving an error value.
|
||||
# This doesn't actually raise an exception.
|
||||
keep_propagating_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPy_KeepPropagating",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
# Catches a propagating exception and makes it the "currently
|
||||
# handled exception" (by sticking it into sys.exc_info()). Returns the
|
||||
# exception that was previously being handled, which must be restored
|
||||
# later.
|
||||
error_catch_op = custom_op(
|
||||
arg_types=[], return_type=exc_rtuple, c_function_name="CPy_CatchError", error_kind=ERR_NEVER
|
||||
)
|
||||
|
||||
# Restore an old "currently handled exception" returned from.
|
||||
# error_catch (by sticking it into sys.exc_info())
|
||||
restore_exc_info_op = custom_op(
|
||||
arg_types=[exc_rtuple],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPy_RestoreExcInfo",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Checks whether the exception currently being handled matches a particular type.
|
||||
exc_matches_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPy_ExceptionMatches",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Get the value of the exception currently being handled.
|
||||
get_exc_value_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPy_GetExcValue",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Get exception info (exception type, exception instance, traceback object).
|
||||
get_exc_info_op = custom_op(
|
||||
arg_types=[], return_type=exc_rtuple, c_function_name="CPy_GetExcInfo", error_kind=ERR_NEVER
|
||||
)
|
||||
Binary file not shown.
168
venv/lib/python3.12/site-packages/mypyc/primitives/float_ops.py
Normal file
168
venv/lib/python3.12/site-packages/mypyc/primitives/float_ops.py
Normal file
@@ -0,0 +1,168 @@
|
||||
"""Primitive float ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_MAGIC, ERR_MAGIC_OVERLAPPING, ERR_NEVER
|
||||
from mypyc.ir.rtypes import (
|
||||
bool_rprimitive,
|
||||
float_rprimitive,
|
||||
int_rprimitive,
|
||||
object_rprimitive,
|
||||
str_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import binary_op, function_op, load_address_op
|
||||
|
||||
# Get the 'builtins.float' type object.
|
||||
load_address_op(name="builtins.float", type=object_rprimitive, src="PyFloat_Type")
|
||||
|
||||
binary_op(
|
||||
name="//",
|
||||
arg_types=[float_rprimitive, float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_FloorDivide",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# float(int)
|
||||
int_to_float_op = function_op(
|
||||
name="builtins.float",
|
||||
arg_types=[int_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_FromTagged",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# float(str)
|
||||
function_op(
|
||||
name="builtins.float",
|
||||
arg_types=[str_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyFloat_FromString",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# abs(float)
|
||||
function_op(
|
||||
name="builtins.abs",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="fabs",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# math.sin(float)
|
||||
function_op(
|
||||
name="math.sin",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Sin",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.cos(float)
|
||||
function_op(
|
||||
name="math.cos",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Cos",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.tan(float)
|
||||
function_op(
|
||||
name="math.tan",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Tan",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.sqrt(float)
|
||||
function_op(
|
||||
name="math.sqrt",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Sqrt",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.exp(float)
|
||||
function_op(
|
||||
name="math.exp",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Exp",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.log(float)
|
||||
function_op(
|
||||
name="math.log",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Log",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.floor(float)
|
||||
function_op(
|
||||
name="math.floor",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyFloat_Floor",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# math.ceil(float)
|
||||
function_op(
|
||||
name="math.ceil",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyFloat_Ceil",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# math.fabs(float)
|
||||
function_op(
|
||||
name="math.fabs",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="fabs",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# math.pow(float, float)
|
||||
pow_op = function_op(
|
||||
name="math.pow",
|
||||
arg_types=[float_rprimitive, float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="CPyFloat_Pow",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# math.copysign(float, float)
|
||||
copysign_op = function_op(
|
||||
name="math.copysign",
|
||||
arg_types=[float_rprimitive, float_rprimitive],
|
||||
return_type=float_rprimitive,
|
||||
c_function_name="copysign",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# math.isinf(float)
|
||||
function_op(
|
||||
name="math.isinf",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="CPyFloat_IsInf",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# math.isnan(float)
|
||||
function_op(
|
||||
name="math.isnan",
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="CPyFloat_IsNaN",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
Binary file not shown.
@@ -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,
|
||||
)
|
||||
Binary file not shown.
304
venv/lib/python3.12/site-packages/mypyc/primitives/int_ops.py
Normal file
304
venv/lib/python3.12/site-packages/mypyc/primitives/int_ops.py
Normal file
@@ -0,0 +1,304 @@
|
||||
"""Arbitrary-precision integer primitive ops.
|
||||
|
||||
These mostly operate on (usually) unboxed integers that use a tagged pointer
|
||||
representation (CPyTagged) and correspond to the Python 'int' type.
|
||||
|
||||
See also the documentation for mypyc.rtypes.int_rprimitive.
|
||||
|
||||
Use mypyc.ir.ops.IntOp for operations on fixed-width/C integers.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import NamedTuple
|
||||
|
||||
from mypyc.ir.ops import ERR_ALWAYS, ERR_MAGIC, ERR_MAGIC_OVERLAPPING, ERR_NEVER, ComparisonOp
|
||||
from mypyc.ir.rtypes import (
|
||||
RType,
|
||||
bit_rprimitive,
|
||||
bool_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
float_rprimitive,
|
||||
int16_rprimitive,
|
||||
int32_rprimitive,
|
||||
int64_rprimitive,
|
||||
int_rprimitive,
|
||||
object_rprimitive,
|
||||
str_rprimitive,
|
||||
void_rtype,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
CFunctionDescription,
|
||||
binary_op,
|
||||
custom_op,
|
||||
function_op,
|
||||
load_address_op,
|
||||
unary_op,
|
||||
)
|
||||
|
||||
# Constructors for builtins.int and native int types have the same behavior. In
|
||||
# interpreted mode, native int types are just aliases to 'int'.
|
||||
for int_name in (
|
||||
"builtins.int",
|
||||
"mypy_extensions.i64",
|
||||
"mypy_extensions.i32",
|
||||
"mypy_extensions.i16",
|
||||
"mypy_extensions.u8",
|
||||
):
|
||||
# These int constructors produce object_rprimitives that then need to be unboxed
|
||||
# I guess unboxing ourselves would save a check and branch though?
|
||||
|
||||
# Get the type object for 'builtins.int' or a native int type.
|
||||
# For ordinary calls to int() we use a load_address to the type.
|
||||
# Native ints don't have a separate type object -- we just use 'builtins.int'.
|
||||
load_address_op(name=int_name, type=object_rprimitive, src="PyLong_Type")
|
||||
|
||||
# int(float). We could do a bit better directly.
|
||||
function_op(
|
||||
name=int_name,
|
||||
arg_types=[float_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyTagged_FromFloat",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# int(string)
|
||||
function_op(
|
||||
name=int_name,
|
||||
arg_types=[str_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyLong_FromStr",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# int(string, base)
|
||||
function_op(
|
||||
name=int_name,
|
||||
arg_types=[str_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyLong_FromStrWithBase",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str(int)
|
||||
int_to_str_op = function_op(
|
||||
name="builtins.str",
|
||||
arg_types=[int_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPyTagged_Str",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=2,
|
||||
)
|
||||
|
||||
# We need a specialization for str on bools also since the int one is wrong...
|
||||
function_op(
|
||||
name="builtins.str",
|
||||
arg_types=[bool_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPyBool_Str",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=3,
|
||||
)
|
||||
|
||||
|
||||
def int_binary_op(
|
||||
name: str,
|
||||
c_function_name: str,
|
||||
return_type: RType = int_rprimitive,
|
||||
error_kind: int = ERR_NEVER,
|
||||
) -> None:
|
||||
binary_op(
|
||||
name=name,
|
||||
arg_types=[int_rprimitive, int_rprimitive],
|
||||
return_type=return_type,
|
||||
c_function_name=c_function_name,
|
||||
error_kind=error_kind,
|
||||
)
|
||||
|
||||
|
||||
# Binary, unary and augmented assignment operations that operate on CPyTagged ints
|
||||
# are implemented as C functions.
|
||||
|
||||
int_binary_op("+", "CPyTagged_Add")
|
||||
int_binary_op("-", "CPyTagged_Subtract")
|
||||
int_binary_op("*", "CPyTagged_Multiply")
|
||||
int_binary_op("&", "CPyTagged_And")
|
||||
int_binary_op("|", "CPyTagged_Or")
|
||||
int_binary_op("^", "CPyTagged_Xor")
|
||||
# Divide and remainder we honestly propagate errors from because they
|
||||
# can raise ZeroDivisionError
|
||||
int_binary_op("//", "CPyTagged_FloorDivide", error_kind=ERR_MAGIC)
|
||||
int_binary_op("%", "CPyTagged_Remainder", error_kind=ERR_MAGIC)
|
||||
# Negative shift counts raise an exception
|
||||
int_binary_op(">>", "CPyTagged_Rshift", error_kind=ERR_MAGIC)
|
||||
int_binary_op("<<", "CPyTagged_Lshift", error_kind=ERR_MAGIC)
|
||||
|
||||
int_binary_op(
|
||||
"/", "CPyTagged_TrueDivide", return_type=float_rprimitive, error_kind=ERR_MAGIC_OVERLAPPING
|
||||
)
|
||||
|
||||
# This should work because assignment operators are parsed differently
|
||||
# and the code in irbuild that handles it does the assignment
|
||||
# regardless of whether or not the operator works in place anyway.
|
||||
int_binary_op("+=", "CPyTagged_Add")
|
||||
int_binary_op("-=", "CPyTagged_Subtract")
|
||||
int_binary_op("*=", "CPyTagged_Multiply")
|
||||
int_binary_op("&=", "CPyTagged_And")
|
||||
int_binary_op("|=", "CPyTagged_Or")
|
||||
int_binary_op("^=", "CPyTagged_Xor")
|
||||
int_binary_op("//=", "CPyTagged_FloorDivide", error_kind=ERR_MAGIC)
|
||||
int_binary_op("%=", "CPyTagged_Remainder", error_kind=ERR_MAGIC)
|
||||
int_binary_op(">>=", "CPyTagged_Rshift", error_kind=ERR_MAGIC)
|
||||
int_binary_op("<<=", "CPyTagged_Lshift", error_kind=ERR_MAGIC)
|
||||
|
||||
|
||||
def int_unary_op(name: str, c_function_name: str) -> CFunctionDescription:
|
||||
return unary_op(
|
||||
name=name,
|
||||
arg_type=int_rprimitive,
|
||||
return_type=int_rprimitive,
|
||||
c_function_name=c_function_name,
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
|
||||
int_neg_op = int_unary_op("-", "CPyTagged_Negate")
|
||||
int_invert_op = int_unary_op("~", "CPyTagged_Invert")
|
||||
|
||||
|
||||
# Primitives related to integer comparison operations:
|
||||
|
||||
|
||||
# Description for building int comparison ops
|
||||
#
|
||||
# Fields:
|
||||
# binary_op_variant: identify which IntOp to use when operands are short integers
|
||||
# c_func_description: the C function to call when operands are tagged integers
|
||||
# c_func_negated: whether to negate the C function call's result
|
||||
# c_func_swap_operands: whether to swap lhs and rhs when call the function
|
||||
class IntComparisonOpDescription(NamedTuple):
|
||||
binary_op_variant: int
|
||||
c_func_description: CFunctionDescription
|
||||
c_func_negated: bool
|
||||
c_func_swap_operands: bool
|
||||
|
||||
|
||||
# Equals operation on two boxed tagged integers
|
||||
int_equal_ = custom_op(
|
||||
arg_types=[int_rprimitive, int_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyTagged_IsEq_",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Less than operation on two boxed tagged integers
|
||||
int_less_than_ = custom_op(
|
||||
arg_types=[int_rprimitive, int_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyTagged_IsLt_",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Provide mapping from textual op to short int's op variant and boxed int's description.
|
||||
# Note that these are not complete implementations and require extra IR.
|
||||
int_comparison_op_mapping: dict[str, IntComparisonOpDescription] = {
|
||||
"==": IntComparisonOpDescription(ComparisonOp.EQ, int_equal_, False, False),
|
||||
"!=": IntComparisonOpDescription(ComparisonOp.NEQ, int_equal_, True, False),
|
||||
"<": IntComparisonOpDescription(ComparisonOp.SLT, int_less_than_, False, False),
|
||||
"<=": IntComparisonOpDescription(ComparisonOp.SLE, int_less_than_, True, True),
|
||||
">": IntComparisonOpDescription(ComparisonOp.SGT, int_less_than_, False, True),
|
||||
">=": IntComparisonOpDescription(ComparisonOp.SGE, int_less_than_, True, False),
|
||||
}
|
||||
|
||||
int64_divide_op = custom_op(
|
||||
arg_types=[int64_rprimitive, int64_rprimitive],
|
||||
return_type=int64_rprimitive,
|
||||
c_function_name="CPyInt64_Divide",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
int64_mod_op = custom_op(
|
||||
arg_types=[int64_rprimitive, int64_rprimitive],
|
||||
return_type=int64_rprimitive,
|
||||
c_function_name="CPyInt64_Remainder",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
int32_divide_op = custom_op(
|
||||
arg_types=[int32_rprimitive, int32_rprimitive],
|
||||
return_type=int32_rprimitive,
|
||||
c_function_name="CPyInt32_Divide",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
int32_mod_op = custom_op(
|
||||
arg_types=[int32_rprimitive, int32_rprimitive],
|
||||
return_type=int32_rprimitive,
|
||||
c_function_name="CPyInt32_Remainder",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
int16_divide_op = custom_op(
|
||||
arg_types=[int16_rprimitive, int16_rprimitive],
|
||||
return_type=int16_rprimitive,
|
||||
c_function_name="CPyInt16_Divide",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
int16_mod_op = custom_op(
|
||||
arg_types=[int16_rprimitive, int16_rprimitive],
|
||||
return_type=int16_rprimitive,
|
||||
c_function_name="CPyInt16_Remainder",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
# Convert tagged int (as PyObject *) to i64
|
||||
int_to_int64_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=int64_rprimitive,
|
||||
c_function_name="CPyLong_AsInt64",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
ssize_t_to_int_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyTagged_FromSsize_t",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
int64_to_int_op = custom_op(
|
||||
arg_types=[int64_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyTagged_FromInt64",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Convert tagged int (as PyObject *) to i32
|
||||
int_to_int32_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=int32_rprimitive,
|
||||
c_function_name="CPyLong_AsInt32",
|
||||
error_kind=ERR_MAGIC_OVERLAPPING,
|
||||
)
|
||||
|
||||
int32_overflow = custom_op(
|
||||
arg_types=[],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPyInt32_Overflow",
|
||||
error_kind=ERR_ALWAYS,
|
||||
)
|
||||
|
||||
int16_overflow = custom_op(
|
||||
arg_types=[],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPyInt16_Overflow",
|
||||
error_kind=ERR_ALWAYS,
|
||||
)
|
||||
|
||||
uint8_overflow = custom_op(
|
||||
arg_types=[],
|
||||
return_type=void_rtype,
|
||||
c_function_name="CPyUInt8_Overflow",
|
||||
error_kind=ERR_ALWAYS,
|
||||
)
|
||||
Binary file not shown.
300
venv/lib/python3.12/site-packages/mypyc/primitives/list_ops.py
Normal file
300
venv/lib/python3.12/site-packages/mypyc/primitives/list_ops.py
Normal file
@@ -0,0 +1,300 @@
|
||||
"""List primitive ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC, ERR_NEVER
|
||||
from mypyc.ir.rtypes import (
|
||||
bit_rprimitive,
|
||||
c_int_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
int64_rprimitive,
|
||||
int_rprimitive,
|
||||
list_rprimitive,
|
||||
object_rprimitive,
|
||||
short_int_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
ERR_NEG_INT,
|
||||
binary_op,
|
||||
custom_op,
|
||||
function_op,
|
||||
load_address_op,
|
||||
method_op,
|
||||
)
|
||||
|
||||
# Get the 'builtins.list' type object.
|
||||
load_address_op(name="builtins.list", type=object_rprimitive, src="PyList_Type")
|
||||
|
||||
# list(obj)
|
||||
to_list = function_op(
|
||||
name="builtins.list",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="PySequence_List",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Construct an empty list via list().
|
||||
function_op(
|
||||
name="builtins.list",
|
||||
arg_types=[],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="PyList_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(0, int_rprimitive)],
|
||||
)
|
||||
|
||||
new_list_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="PyList_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
list_build_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="CPyList_Build",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=object_rprimitive,
|
||||
steals=True,
|
||||
)
|
||||
|
||||
# list[index] (for an integer index)
|
||||
list_get_item_op = method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[list_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItem",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list[index] version with no int tag check for when it is known to be short
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[list_rprimitive, short_int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItemShort",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=2,
|
||||
)
|
||||
|
||||
# list[index] that produces a borrowed result
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[list_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItemBorrow",
|
||||
error_kind=ERR_MAGIC,
|
||||
is_borrowed=True,
|
||||
priority=3,
|
||||
)
|
||||
|
||||
# list[index] that produces a borrowed result and index is known to be short
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[list_rprimitive, short_int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItemShortBorrow",
|
||||
error_kind=ERR_MAGIC,
|
||||
is_borrowed=True,
|
||||
priority=4,
|
||||
)
|
||||
|
||||
# Version with native int index
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[list_rprimitive, int64_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItemInt64",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=5,
|
||||
)
|
||||
|
||||
# Version with native int index
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[list_rprimitive, int64_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItemInt64Borrow",
|
||||
is_borrowed=True,
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=6,
|
||||
)
|
||||
|
||||
# This is unsafe because it assumes that the index is a non-negative short integer
|
||||
# that is in-bounds for the list.
|
||||
list_get_item_unsafe_op = custom_op(
|
||||
arg_types=[list_rprimitive, short_int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetItemUnsafe",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# list[index] = obj
|
||||
list_set_item_op = method_op(
|
||||
name="__setitem__",
|
||||
arg_types=[list_rprimitive, int_rprimitive, object_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyList_SetItem",
|
||||
error_kind=ERR_FALSE,
|
||||
steals=[False, False, True],
|
||||
)
|
||||
|
||||
# list[index_i64] = obj
|
||||
method_op(
|
||||
name="__setitem__",
|
||||
arg_types=[list_rprimitive, int64_rprimitive, object_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyList_SetItemInt64",
|
||||
error_kind=ERR_FALSE,
|
||||
steals=[False, False, True],
|
||||
priority=2,
|
||||
)
|
||||
|
||||
# PyList_SET_ITEM does no error checking,
|
||||
# and should only be used to fill in brand new lists.
|
||||
new_list_set_item_op = custom_op(
|
||||
arg_types=[list_rprimitive, int_rprimitive, object_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyList_SetItemUnsafe",
|
||||
error_kind=ERR_FALSE,
|
||||
steals=[False, False, True],
|
||||
)
|
||||
|
||||
# list.append(obj)
|
||||
list_append_op = method_op(
|
||||
name="append",
|
||||
arg_types=[list_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyList_Append",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# list.extend(obj)
|
||||
list_extend_op = method_op(
|
||||
name="extend",
|
||||
arg_types=[list_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_Extend",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list.pop()
|
||||
list_pop_last = method_op(
|
||||
name="pop",
|
||||
arg_types=[list_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_PopLast",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list.pop(index)
|
||||
list_pop = method_op(
|
||||
name="pop",
|
||||
arg_types=[list_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_Pop",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list.count(obj)
|
||||
method_op(
|
||||
name="count",
|
||||
arg_types=[list_rprimitive, object_rprimitive],
|
||||
return_type=short_int_rprimitive,
|
||||
c_function_name="CPyList_Count",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list.insert(index, obj)
|
||||
method_op(
|
||||
name="insert",
|
||||
arg_types=[list_rprimitive, int_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyList_Insert",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# list.sort()
|
||||
method_op(
|
||||
name="sort",
|
||||
arg_types=[list_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyList_Sort",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# list.reverse()
|
||||
method_op(
|
||||
name="reverse",
|
||||
arg_types=[list_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyList_Reverse",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# list.remove(obj)
|
||||
method_op(
|
||||
name="remove",
|
||||
arg_types=[list_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPyList_Remove",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# list.index(obj)
|
||||
method_op(
|
||||
name="index",
|
||||
arg_types=[list_rprimitive, object_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyList_Index",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list * int
|
||||
binary_op(
|
||||
name="*",
|
||||
arg_types=[list_rprimitive, int_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="CPySequence_Multiply",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# int * list
|
||||
binary_op(
|
||||
name="*",
|
||||
arg_types=[int_rprimitive, list_rprimitive],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name="CPySequence_RMultiply",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# list[begin:end]
|
||||
list_slice_op = custom_op(
|
||||
arg_types=[list_rprimitive, int_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyList_GetSlice",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
supports_sequence_protocol = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPySequence_Check",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
sequence_get_item = custom_op(
|
||||
arg_types=[object_rprimitive, c_pyssize_t_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PySequence_GetItem",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
sequence_get_slice = custom_op(
|
||||
arg_types=[object_rprimitive, c_pyssize_t_rprimitive, c_pyssize_t_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PySequence_GetSlice",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
Binary file not shown.
241
venv/lib/python3.12/site-packages/mypyc/primitives/misc_ops.py
Normal file
241
venv/lib/python3.12/site-packages/mypyc/primitives/misc_ops.py
Normal file
@@ -0,0 +1,241 @@
|
||||
"""Miscellaneous primitive ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC, ERR_NEVER
|
||||
from mypyc.ir.rtypes import (
|
||||
bit_rprimitive,
|
||||
bool_rprimitive,
|
||||
c_int_rprimitive,
|
||||
c_pointer_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
dict_rprimitive,
|
||||
int_rprimitive,
|
||||
object_pointer_rprimitive,
|
||||
object_rprimitive,
|
||||
str_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import ERR_NEG_INT, custom_op, function_op, load_address_op
|
||||
|
||||
# Get the 'bool' type object.
|
||||
load_address_op(name="builtins.bool", type=object_rprimitive, src="PyBool_Type")
|
||||
|
||||
# Get the 'range' type object.
|
||||
load_address_op(name="builtins.range", type=object_rprimitive, src="PyRange_Type")
|
||||
|
||||
# Get the boxed Python 'None' object
|
||||
none_object_op = load_address_op(name="Py_None", type=object_rprimitive, src="_Py_NoneStruct")
|
||||
|
||||
# Get the boxed object '...'
|
||||
ellipsis_op = load_address_op(name="...", type=object_rprimitive, src="_Py_EllipsisObject")
|
||||
|
||||
# Get the boxed NotImplemented object
|
||||
not_implemented_op = load_address_op(
|
||||
name="builtins.NotImplemented", type=object_rprimitive, src="_Py_NotImplementedStruct"
|
||||
)
|
||||
|
||||
# Get the boxed StopAsyncIteration object
|
||||
stop_async_iteration_op = load_address_op(
|
||||
name="builtins.StopAsyncIteration", type=object_rprimitive, src="PyExc_StopAsyncIteration"
|
||||
)
|
||||
|
||||
# id(obj)
|
||||
function_op(
|
||||
name="builtins.id",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=int_rprimitive,
|
||||
c_function_name="CPyTagged_Id",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Return the result of obj.__await()__ or obj.__iter__() (if no __await__ exists)
|
||||
coro_op = custom_op(
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPy_GetCoro",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Do obj.send(value), or a next(obj) if second arg is None.
|
||||
# (This behavior is to match the PEP 380 spec for yield from.)
|
||||
# Like next_raw_op, don't swallow StopIteration,
|
||||
# but also don't propagate an error.
|
||||
# Can return NULL: see next_op.
|
||||
send_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyIter_Send",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# This is sort of unfortunate but oh well: yield_from_except performs most of the
|
||||
# error handling logic in `yield from` operations. It returns a bool and passes
|
||||
# a value by address.
|
||||
# If the bool is true, then a StopIteration was received and we should return.
|
||||
# If the bool is false, then the value should be yielded.
|
||||
# The normal case is probably that it signals an exception, which gets
|
||||
# propagated.
|
||||
# Op used for "yield from" error handling.
|
||||
# See comment in CPy_YieldFromErrorHandle for more information.
|
||||
yield_from_except_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_pointer_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="CPy_YieldFromErrorHandle",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Create method object from a callable object and self.
|
||||
method_new_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyMethod_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Check if the current exception is a StopIteration and return its value if so.
|
||||
# Treats "no exception" as StopIteration with a None value.
|
||||
# If it is a different exception, re-reraise it.
|
||||
check_stop_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPy_FetchStopIterationValue",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Determine the most derived metaclass and check for metaclass conflicts.
|
||||
# Arguments are (metaclass, bases).
|
||||
py_calc_meta_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPy_CalculateMetaclass",
|
||||
error_kind=ERR_MAGIC,
|
||||
is_borrowed=True,
|
||||
)
|
||||
|
||||
# Import a module (plain)
|
||||
import_op = custom_op(
|
||||
arg_types=[str_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyImport_Import",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Table-driven import op.
|
||||
import_many_op = custom_op(
|
||||
arg_types=[
|
||||
object_rprimitive,
|
||||
c_pointer_rprimitive,
|
||||
object_rprimitive,
|
||||
object_rprimitive,
|
||||
object_rprimitive,
|
||||
c_pointer_rprimitive,
|
||||
],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyImport_ImportMany",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
# From import helper op
|
||||
import_from_many_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyImport_ImportFromMany",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Get the sys.modules dictionary
|
||||
get_module_dict_op = custom_op(
|
||||
arg_types=[],
|
||||
return_type=dict_rprimitive,
|
||||
c_function_name="PyImport_GetModuleDict",
|
||||
error_kind=ERR_NEVER,
|
||||
is_borrowed=True,
|
||||
)
|
||||
|
||||
# isinstance(obj, cls)
|
||||
slow_isinstance_op = function_op(
|
||||
name="builtins.isinstance",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_IsInstance",
|
||||
error_kind=ERR_NEG_INT,
|
||||
truncated_type=bool_rprimitive,
|
||||
)
|
||||
|
||||
# Faster isinstance(obj, cls) that only works with native classes and doesn't perform
|
||||
# type checking of the type argument.
|
||||
fast_isinstance_op = function_op(
|
||||
"builtins.isinstance",
|
||||
arg_types=[object_rprimitive, object_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="CPy_TypeCheck",
|
||||
error_kind=ERR_NEVER,
|
||||
priority=0,
|
||||
)
|
||||
|
||||
# bool(obj) with unboxed result
|
||||
bool_op = function_op(
|
||||
name="builtins.bool",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyObject_IsTrue",
|
||||
error_kind=ERR_NEG_INT,
|
||||
truncated_type=bool_rprimitive,
|
||||
)
|
||||
|
||||
# slice(start, stop, step)
|
||||
new_slice_op = function_op(
|
||||
name="builtins.slice",
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
c_function_name="PySlice_New",
|
||||
return_type=object_rprimitive,
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# type(obj)
|
||||
type_op = function_op(
|
||||
name="builtins.type",
|
||||
arg_types=[object_rprimitive],
|
||||
c_function_name="PyObject_Type",
|
||||
return_type=object_rprimitive,
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# Get 'builtins.type' (base class of all classes)
|
||||
type_object_op = load_address_op(name="builtins.type", type=object_rprimitive, src="PyType_Type")
|
||||
|
||||
# Create a heap type based on a template non-heap type.
|
||||
# See CPyType_FromTemplate for more docs.
|
||||
pytype_from_template_op = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive, str_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyType_FromTemplate",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Create a dataclass from an extension class. See
|
||||
# CPyDataclass_SleightOfHand for more docs.
|
||||
dataclass_sleight_of_hand = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive, dict_rprimitive, dict_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyDataclass_SleightOfHand",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
# Raise ValueError if length of first argument is not equal to the second argument.
|
||||
# The first argument must be a list or a variable-length tuple.
|
||||
check_unpack_count_op = custom_op(
|
||||
arg_types=[object_rprimitive, c_pyssize_t_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="CPySequence_CheckUnpackCount",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
|
||||
# register an implementation for a singledispatch function
|
||||
register_function = custom_op(
|
||||
arg_types=[object_rprimitive, object_rprimitive, object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPySingledispatch_RegisterFunction",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
Binary file not shown.
313
venv/lib/python3.12/site-packages/mypyc/primitives/registry.py
Normal file
313
venv/lib/python3.12/site-packages/mypyc/primitives/registry.py
Normal file
@@ -0,0 +1,313 @@
|
||||
"""Utilities for defining primitive ops.
|
||||
|
||||
Most of the ops can be automatically generated by matching against AST
|
||||
nodes and types. For example, a func_op is automatically generated when
|
||||
a specific function is called with the specific positional argument
|
||||
count and argument types.
|
||||
|
||||
Example op definition:
|
||||
|
||||
list_len_op = func_op(name='builtins.len',
|
||||
arg_types=[list_rprimitive],
|
||||
result_type=short_int_rprimitive,
|
||||
error_kind=ERR_NEVER,
|
||||
emit=emit_len)
|
||||
|
||||
This op is automatically generated for calls to len() with a single
|
||||
list argument. The result type is short_int_rprimitive, and this
|
||||
never raises an exception (ERR_NEVER). The function emit_len is used
|
||||
to generate C for this op. The op can also be manually generated using
|
||||
"list_len_op". Ops that are only generated automatically don't need to
|
||||
be assigned to a module attribute.
|
||||
|
||||
Ops defined with custom_op are only explicitly generated in
|
||||
mypyc.irbuild and won't be generated automatically. They are always
|
||||
assigned to a module attribute, as otherwise they won't be accessible.
|
||||
|
||||
The actual ops are defined in other submodules of this package, grouped
|
||||
by category.
|
||||
|
||||
Most operations have fallback implementations that apply to all possible
|
||||
arguments and types. For example, there are generic implementations of
|
||||
arbitrary function and method calls, and binary operators. These generic
|
||||
implementations are typically slower than specialized ones, but we tend
|
||||
to rely on them for infrequently used ops. It's impractical to have
|
||||
optimized implementations of all ops.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Final, NamedTuple
|
||||
|
||||
from mypyc.ir.ops import StealsDescription
|
||||
from mypyc.ir.rtypes import RType
|
||||
|
||||
# Error kind for functions that return negative integer on exception. This
|
||||
# is only used for primitives. We translate it away during IR building.
|
||||
ERR_NEG_INT: Final = 10
|
||||
|
||||
|
||||
class CFunctionDescription(NamedTuple):
|
||||
name: str
|
||||
arg_types: list[RType]
|
||||
return_type: RType
|
||||
var_arg_type: RType | None
|
||||
truncated_type: RType | None
|
||||
c_function_name: str
|
||||
error_kind: int
|
||||
steals: StealsDescription
|
||||
is_borrowed: bool
|
||||
ordering: list[int] | None
|
||||
extra_int_constants: list[tuple[int, RType]]
|
||||
priority: int
|
||||
|
||||
|
||||
# A description for C load operations including LoadGlobal and LoadAddress
|
||||
class LoadAddressDescription(NamedTuple):
|
||||
name: str
|
||||
type: RType
|
||||
src: str # name of the target to load
|
||||
|
||||
|
||||
# CallC op for method call(such as 'str.join')
|
||||
method_call_ops: dict[str, list[CFunctionDescription]] = {}
|
||||
|
||||
# CallC op for top level function call(such as 'builtins.list')
|
||||
function_ops: dict[str, list[CFunctionDescription]] = {}
|
||||
|
||||
# CallC op for binary ops
|
||||
binary_ops: dict[str, list[CFunctionDescription]] = {}
|
||||
|
||||
# CallC op for unary ops
|
||||
unary_ops: dict[str, list[CFunctionDescription]] = {}
|
||||
|
||||
builtin_names: dict[str, tuple[RType, str]] = {}
|
||||
|
||||
|
||||
def method_op(
|
||||
name: str,
|
||||
arg_types: list[RType],
|
||||
return_type: RType,
|
||||
c_function_name: str,
|
||||
error_kind: int,
|
||||
var_arg_type: RType | None = None,
|
||||
truncated_type: RType | None = None,
|
||||
ordering: list[int] | None = None,
|
||||
extra_int_constants: list[tuple[int, RType]] = [],
|
||||
steals: StealsDescription = False,
|
||||
is_borrowed: bool = False,
|
||||
priority: int = 1,
|
||||
) -> CFunctionDescription:
|
||||
"""Define a c function call op that replaces a method call.
|
||||
|
||||
This will be automatically generated by matching against the AST.
|
||||
|
||||
Args:
|
||||
name: short name of the method (for example, 'append')
|
||||
arg_types: argument types; the receiver is always the first argument
|
||||
return_type: type of the return value. Use void_rtype to represent void.
|
||||
c_function_name: name of the C function to call
|
||||
error_kind: how errors are represented in the result (one of ERR_*)
|
||||
var_arg_type: type of all variable arguments
|
||||
truncated_type: type to truncated to(See Truncate for info)
|
||||
if it's defined both return_type and it should be non-referenced
|
||||
integer types or bool type
|
||||
ordering: optional ordering of the arguments, if defined,
|
||||
reorders the arguments accordingly.
|
||||
should never be used together with var_arg_type.
|
||||
all the other arguments(such as arg_types) are in the order
|
||||
accepted by the python syntax(before reordering)
|
||||
extra_int_constants: optional extra integer constants as the last arguments to a C call
|
||||
steals: description of arguments that this steals (ref count wise)
|
||||
is_borrowed: if True, returned value is borrowed (no need to decrease refcount)
|
||||
priority: if multiple ops match, the one with the highest priority is picked
|
||||
"""
|
||||
ops = method_call_ops.setdefault(name, [])
|
||||
desc = CFunctionDescription(
|
||||
name,
|
||||
arg_types,
|
||||
return_type,
|
||||
var_arg_type,
|
||||
truncated_type,
|
||||
c_function_name,
|
||||
error_kind,
|
||||
steals,
|
||||
is_borrowed,
|
||||
ordering,
|
||||
extra_int_constants,
|
||||
priority,
|
||||
)
|
||||
ops.append(desc)
|
||||
return desc
|
||||
|
||||
|
||||
def function_op(
|
||||
name: str,
|
||||
arg_types: list[RType],
|
||||
return_type: RType,
|
||||
c_function_name: str,
|
||||
error_kind: int,
|
||||
var_arg_type: RType | None = None,
|
||||
truncated_type: RType | None = None,
|
||||
ordering: list[int] | None = None,
|
||||
extra_int_constants: list[tuple[int, RType]] = [],
|
||||
steals: StealsDescription = False,
|
||||
is_borrowed: bool = False,
|
||||
priority: int = 1,
|
||||
) -> CFunctionDescription:
|
||||
"""Define a c function call op that replaces a function call.
|
||||
|
||||
This will be automatically generated by matching against the AST.
|
||||
|
||||
Most arguments are similar to method_op().
|
||||
|
||||
Args:
|
||||
name: full name of the function
|
||||
arg_types: positional argument types for which this applies
|
||||
"""
|
||||
ops = function_ops.setdefault(name, [])
|
||||
desc = CFunctionDescription(
|
||||
name,
|
||||
arg_types,
|
||||
return_type,
|
||||
var_arg_type,
|
||||
truncated_type,
|
||||
c_function_name,
|
||||
error_kind,
|
||||
steals,
|
||||
is_borrowed,
|
||||
ordering,
|
||||
extra_int_constants,
|
||||
priority,
|
||||
)
|
||||
ops.append(desc)
|
||||
return desc
|
||||
|
||||
|
||||
def binary_op(
|
||||
name: str,
|
||||
arg_types: list[RType],
|
||||
return_type: RType,
|
||||
c_function_name: str,
|
||||
error_kind: int,
|
||||
var_arg_type: RType | None = None,
|
||||
truncated_type: RType | None = None,
|
||||
ordering: list[int] | None = None,
|
||||
extra_int_constants: list[tuple[int, RType]] = [],
|
||||
steals: StealsDescription = False,
|
||||
is_borrowed: bool = False,
|
||||
priority: int = 1,
|
||||
) -> CFunctionDescription:
|
||||
"""Define a c function call op for a binary operation.
|
||||
|
||||
This will be automatically generated by matching against the AST.
|
||||
|
||||
Most arguments are similar to method_op(), but exactly two argument types
|
||||
are expected.
|
||||
"""
|
||||
ops = binary_ops.setdefault(name, [])
|
||||
desc = CFunctionDescription(
|
||||
name,
|
||||
arg_types,
|
||||
return_type,
|
||||
var_arg_type,
|
||||
truncated_type,
|
||||
c_function_name,
|
||||
error_kind,
|
||||
steals,
|
||||
is_borrowed,
|
||||
ordering,
|
||||
extra_int_constants,
|
||||
priority,
|
||||
)
|
||||
ops.append(desc)
|
||||
return desc
|
||||
|
||||
|
||||
def custom_op(
|
||||
arg_types: list[RType],
|
||||
return_type: RType,
|
||||
c_function_name: str,
|
||||
error_kind: int,
|
||||
var_arg_type: RType | None = None,
|
||||
truncated_type: RType | None = None,
|
||||
ordering: list[int] | None = None,
|
||||
extra_int_constants: list[tuple[int, RType]] = [],
|
||||
steals: StealsDescription = False,
|
||||
is_borrowed: bool = False,
|
||||
) -> CFunctionDescription:
|
||||
"""Create a one-off CallC op that can't be automatically generated from the AST.
|
||||
|
||||
Most arguments are similar to method_op().
|
||||
"""
|
||||
return CFunctionDescription(
|
||||
"<custom>",
|
||||
arg_types,
|
||||
return_type,
|
||||
var_arg_type,
|
||||
truncated_type,
|
||||
c_function_name,
|
||||
error_kind,
|
||||
steals,
|
||||
is_borrowed,
|
||||
ordering,
|
||||
extra_int_constants,
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
def unary_op(
|
||||
name: str,
|
||||
arg_type: RType,
|
||||
return_type: RType,
|
||||
c_function_name: str,
|
||||
error_kind: int,
|
||||
truncated_type: RType | None = None,
|
||||
ordering: list[int] | None = None,
|
||||
extra_int_constants: list[tuple[int, RType]] = [],
|
||||
steals: StealsDescription = False,
|
||||
is_borrowed: bool = False,
|
||||
priority: int = 1,
|
||||
) -> CFunctionDescription:
|
||||
"""Define a c function call op for an unary operation.
|
||||
|
||||
This will be automatically generated by matching against the AST.
|
||||
|
||||
Most arguments are similar to method_op(), but exactly one argument type
|
||||
is expected.
|
||||
"""
|
||||
ops = unary_ops.setdefault(name, [])
|
||||
desc = CFunctionDescription(
|
||||
name,
|
||||
[arg_type],
|
||||
return_type,
|
||||
None,
|
||||
truncated_type,
|
||||
c_function_name,
|
||||
error_kind,
|
||||
steals,
|
||||
is_borrowed,
|
||||
ordering,
|
||||
extra_int_constants,
|
||||
priority,
|
||||
)
|
||||
ops.append(desc)
|
||||
return desc
|
||||
|
||||
|
||||
def load_address_op(name: str, type: RType, src: str) -> LoadAddressDescription:
|
||||
assert name not in builtin_names, "already defined: %s" % name
|
||||
builtin_names[name] = (type, src)
|
||||
return LoadAddressDescription(name, type, src)
|
||||
|
||||
|
||||
import mypyc.primitives.bytes_ops
|
||||
import mypyc.primitives.dict_ops
|
||||
import mypyc.primitives.float_ops
|
||||
|
||||
# Import various modules that set up global state.
|
||||
import mypyc.primitives.int_ops
|
||||
import mypyc.primitives.list_ops
|
||||
import mypyc.primitives.misc_ops
|
||||
import mypyc.primitives.str_ops
|
||||
import mypyc.primitives.tuple_ops # noqa: F401
|
||||
Binary file not shown.
121
venv/lib/python3.12/site-packages/mypyc/primitives/set_ops.py
Normal file
121
venv/lib/python3.12/site-packages/mypyc/primitives/set_ops.py
Normal file
@@ -0,0 +1,121 @@
|
||||
"""Primitive set (and frozenset) ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC
|
||||
from mypyc.ir.rtypes import (
|
||||
bit_rprimitive,
|
||||
bool_rprimitive,
|
||||
c_int_rprimitive,
|
||||
object_rprimitive,
|
||||
pointer_rprimitive,
|
||||
set_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
ERR_NEG_INT,
|
||||
binary_op,
|
||||
function_op,
|
||||
load_address_op,
|
||||
method_op,
|
||||
)
|
||||
|
||||
# Get the 'builtins.set' type object.
|
||||
load_address_op(name="builtins.set", type=object_rprimitive, src="PySet_Type")
|
||||
|
||||
# Get the 'builtins.frozenset' tyoe object.
|
||||
load_address_op(name="builtins.frozenset", type=object_rprimitive, src="PyFrozenSet_Type")
|
||||
|
||||
# Construct an empty set.
|
||||
new_set_op = function_op(
|
||||
name="builtins.set",
|
||||
arg_types=[],
|
||||
return_type=set_rprimitive,
|
||||
c_function_name="PySet_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# set(obj)
|
||||
function_op(
|
||||
name="builtins.set",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=set_rprimitive,
|
||||
c_function_name="PySet_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# frozenset(obj)
|
||||
function_op(
|
||||
name="builtins.frozenset",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PyFrozenSet_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# item in set
|
||||
set_in_op = binary_op(
|
||||
name="in",
|
||||
arg_types=[object_rprimitive, set_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PySet_Contains",
|
||||
error_kind=ERR_NEG_INT,
|
||||
truncated_type=bool_rprimitive,
|
||||
ordering=[1, 0],
|
||||
)
|
||||
|
||||
# set.remove(obj)
|
||||
method_op(
|
||||
name="remove",
|
||||
arg_types=[set_rprimitive, object_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPySet_Remove",
|
||||
error_kind=ERR_FALSE,
|
||||
)
|
||||
|
||||
# set.discard(obj)
|
||||
method_op(
|
||||
name="discard",
|
||||
arg_types=[set_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PySet_Discard",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# set.add(obj)
|
||||
set_add_op = method_op(
|
||||
name="add",
|
||||
arg_types=[set_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PySet_Add",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# set.update(obj)
|
||||
#
|
||||
# This is not a public API but looks like it should be fine.
|
||||
set_update_op = method_op(
|
||||
name="update",
|
||||
arg_types=[set_rprimitive, object_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="_PySet_Update",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# set.clear()
|
||||
method_op(
|
||||
name="clear",
|
||||
arg_types=[set_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PySet_Clear",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# set.pop()
|
||||
method_op(
|
||||
name="pop",
|
||||
arg_types=[set_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="PySet_Pop",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
Binary file not shown.
229
venv/lib/python3.12/site-packages/mypyc/primitives/str_ops.py
Normal file
229
venv/lib/python3.12/site-packages/mypyc/primitives/str_ops.py
Normal file
@@ -0,0 +1,229 @@
|
||||
"""Primitive str ops."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_MAGIC, ERR_NEVER
|
||||
from mypyc.ir.rtypes import (
|
||||
RType,
|
||||
bit_rprimitive,
|
||||
bool_rprimitive,
|
||||
bytes_rprimitive,
|
||||
c_int_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
int_rprimitive,
|
||||
list_rprimitive,
|
||||
object_rprimitive,
|
||||
pointer_rprimitive,
|
||||
str_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import (
|
||||
ERR_NEG_INT,
|
||||
binary_op,
|
||||
custom_op,
|
||||
function_op,
|
||||
load_address_op,
|
||||
method_op,
|
||||
)
|
||||
|
||||
# Get the 'str' type object.
|
||||
load_address_op(name="builtins.str", type=object_rprimitive, src="PyUnicode_Type")
|
||||
|
||||
# str(obj)
|
||||
str_op = function_op(
|
||||
name="builtins.str",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="PyObject_Str",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str1 + str2
|
||||
binary_op(
|
||||
name="+",
|
||||
arg_types=[str_rprimitive, str_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="PyUnicode_Concat",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str1 += str2
|
||||
#
|
||||
# PyUnicode_Append makes an effort to reuse the LHS when the refcount
|
||||
# is 1. This is super dodgy but oh well, the interpreter does it.
|
||||
binary_op(
|
||||
name="+=",
|
||||
arg_types=[str_rprimitive, str_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPyStr_Append",
|
||||
error_kind=ERR_MAGIC,
|
||||
steals=[True, False],
|
||||
)
|
||||
|
||||
unicode_compare = custom_op(
|
||||
arg_types=[str_rprimitive, str_rprimitive],
|
||||
return_type=c_int_rprimitive,
|
||||
c_function_name="PyUnicode_Compare",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# str[index] (for an int index)
|
||||
method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[str_rprimitive, int_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPyStr_GetItem",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str[begin:end]
|
||||
str_slice_op = custom_op(
|
||||
arg_types=[str_rprimitive, int_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPyStr_GetSlice",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str.join(obj)
|
||||
method_op(
|
||||
name="join",
|
||||
arg_types=[str_rprimitive, object_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="PyUnicode_Join",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
str_build_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPyStr_Build",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=str_rprimitive,
|
||||
)
|
||||
|
||||
# str.startswith(str)
|
||||
method_op(
|
||||
name="startswith",
|
||||
arg_types=[str_rprimitive, str_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="CPyStr_Startswith",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# str.endswith(str)
|
||||
method_op(
|
||||
name="endswith",
|
||||
arg_types=[str_rprimitive, str_rprimitive],
|
||||
return_type=bool_rprimitive,
|
||||
c_function_name="CPyStr_Endswith",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
# str.split(...)
|
||||
str_split_types: list[RType] = [str_rprimitive, str_rprimitive, int_rprimitive]
|
||||
str_split_functions = ["PyUnicode_Split", "PyUnicode_Split", "CPyStr_Split"]
|
||||
str_split_constants: list[list[tuple[int, RType]]] = [
|
||||
[(0, pointer_rprimitive), (-1, c_int_rprimitive)],
|
||||
[(-1, c_int_rprimitive)],
|
||||
[],
|
||||
]
|
||||
for i in range(len(str_split_types)):
|
||||
method_op(
|
||||
name="split",
|
||||
arg_types=str_split_types[0 : i + 1],
|
||||
return_type=list_rprimitive,
|
||||
c_function_name=str_split_functions[i],
|
||||
extra_int_constants=str_split_constants[i],
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str.replace(old, new)
|
||||
method_op(
|
||||
name="replace",
|
||||
arg_types=[str_rprimitive, str_rprimitive, str_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="PyUnicode_Replace",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(-1, c_int_rprimitive)],
|
||||
)
|
||||
|
||||
# str.replace(old, new, count)
|
||||
method_op(
|
||||
name="replace",
|
||||
arg_types=[str_rprimitive, str_rprimitive, str_rprimitive, int_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPyStr_Replace",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# check if a string is true (isn't an empty string)
|
||||
str_check_if_true = custom_op(
|
||||
arg_types=[str_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPyStr_IsTrue",
|
||||
error_kind=ERR_NEVER,
|
||||
)
|
||||
|
||||
str_ssize_t_size_op = custom_op(
|
||||
arg_types=[str_rprimitive],
|
||||
return_type=c_pyssize_t_rprimitive,
|
||||
c_function_name="CPyStr_Size_size_t",
|
||||
error_kind=ERR_NEG_INT,
|
||||
)
|
||||
|
||||
# obj.decode()
|
||||
method_op(
|
||||
name="decode",
|
||||
arg_types=[bytes_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPy_Decode",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(0, pointer_rprimitive), (0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# obj.decode(encoding)
|
||||
method_op(
|
||||
name="decode",
|
||||
arg_types=[bytes_rprimitive, str_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPy_Decode",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# obj.decode(encoding, errors)
|
||||
method_op(
|
||||
name="decode",
|
||||
arg_types=[bytes_rprimitive, str_rprimitive, str_rprimitive],
|
||||
return_type=str_rprimitive,
|
||||
c_function_name="CPy_Decode",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# str.encode()
|
||||
method_op(
|
||||
name="encode",
|
||||
arg_types=[str_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPy_Encode",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(0, pointer_rprimitive), (0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# str.encode(encoding)
|
||||
method_op(
|
||||
name="encode",
|
||||
arg_types=[str_rprimitive, str_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPy_Encode",
|
||||
error_kind=ERR_MAGIC,
|
||||
extra_int_constants=[(0, pointer_rprimitive)],
|
||||
)
|
||||
|
||||
# str.encode(encoding, errors)
|
||||
method_op(
|
||||
name="encode",
|
||||
arg_types=[str_rprimitive, str_rprimitive, str_rprimitive],
|
||||
return_type=bytes_rprimitive,
|
||||
c_function_name="CPy_Encode",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
Binary file not shown.
@@ -0,0 +1,83 @@
|
||||
"""Primitive tuple ops for *variable-length* tuples.
|
||||
|
||||
Note: Varying-length tuples are represented as boxed Python tuple
|
||||
objects, i.e. tuple_rprimitive (RPrimitive), not RTuple.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.ir.ops import ERR_FALSE, ERR_MAGIC
|
||||
from mypyc.ir.rtypes import (
|
||||
bit_rprimitive,
|
||||
c_pyssize_t_rprimitive,
|
||||
int_rprimitive,
|
||||
list_rprimitive,
|
||||
object_rprimitive,
|
||||
tuple_rprimitive,
|
||||
)
|
||||
from mypyc.primitives.registry import custom_op, function_op, load_address_op, method_op
|
||||
|
||||
# Get the 'builtins.tuple' type object.
|
||||
load_address_op(name="builtins.tuple", type=object_rprimitive, src="PyTuple_Type")
|
||||
|
||||
# tuple[index] (for an int index)
|
||||
tuple_get_item_op = method_op(
|
||||
name="__getitem__",
|
||||
arg_types=[tuple_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPySequenceTuple_GetItem",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# Construct a boxed tuple from items: (item1, item2, ...)
|
||||
new_tuple_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=tuple_rprimitive,
|
||||
c_function_name="PyTuple_Pack",
|
||||
error_kind=ERR_MAGIC,
|
||||
var_arg_type=object_rprimitive,
|
||||
)
|
||||
|
||||
new_tuple_with_length_op = custom_op(
|
||||
arg_types=[c_pyssize_t_rprimitive],
|
||||
return_type=tuple_rprimitive,
|
||||
c_function_name="PyTuple_New",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# PyTuple_SET_ITEM does no error checking,
|
||||
# and should only be used to fill in brand new tuples.
|
||||
new_tuple_set_item_op = custom_op(
|
||||
arg_types=[tuple_rprimitive, int_rprimitive, object_rprimitive],
|
||||
return_type=bit_rprimitive,
|
||||
c_function_name="CPySequenceTuple_SetItemUnsafe",
|
||||
error_kind=ERR_FALSE,
|
||||
steals=[False, False, True],
|
||||
)
|
||||
|
||||
# Construct tuple from a list.
|
||||
list_tuple_op = function_op(
|
||||
name="builtins.tuple",
|
||||
arg_types=[list_rprimitive],
|
||||
return_type=tuple_rprimitive,
|
||||
c_function_name="PyList_AsTuple",
|
||||
error_kind=ERR_MAGIC,
|
||||
priority=2,
|
||||
)
|
||||
|
||||
# Construct tuple from an arbitrary (iterable) object.
|
||||
function_op(
|
||||
name="builtins.tuple",
|
||||
arg_types=[object_rprimitive],
|
||||
return_type=tuple_rprimitive,
|
||||
c_function_name="PySequence_Tuple",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
|
||||
# tuple[begin:end]
|
||||
tuple_slice_op = custom_op(
|
||||
arg_types=[tuple_rprimitive, int_rprimitive, int_rprimitive],
|
||||
return_type=object_rprimitive,
|
||||
c_function_name="CPySequenceTuple_GetSlice",
|
||||
error_kind=ERR_MAGIC,
|
||||
)
|
||||
Reference in New Issue
Block a user