| """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_MAGIC, ERR_NEVER |
| from mypyc.ir.rtypes import ( |
| bit_rprimitive, |
| c_pyssize_t_rprimitive, |
| int_rprimitive, |
| list_rprimitive, |
| object_rprimitive, |
| tuple_rprimitive, |
| void_rtype, |
| ) |
| from mypyc.primitives.registry import binary_op, 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, |
| ) |
| |
| # This is unsafe because it assumes that the index is a non-negative integer |
| # that is in-bounds for the tuple. |
| tuple_get_item_unsafe_op = custom_op( |
| arg_types=[tuple_rprimitive, c_pyssize_t_rprimitive], |
| return_type=object_rprimitive, |
| c_function_name="CPySequenceTuple_GetItemUnsafe", |
| error_kind=ERR_NEVER, |
| ) |
| |
| # 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, |
| ) |
| |
| load_empty_tuple_constant_op = custom_op( |
| arg_types=[], |
| return_type=tuple_rprimitive, |
| c_function_name="CPyTuple_LoadEmptyTupleConstant", |
| error_kind=ERR_NEVER, |
| ) |
| |
| # 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, c_pyssize_t_rprimitive, object_rprimitive], |
| return_type=void_rtype, |
| c_function_name="CPySequenceTuple_SetItemUnsafe", |
| error_kind=ERR_NEVER, |
| 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. |
| sequence_tuple_op = function_op( |
| name="builtins.tuple", |
| arg_types=[object_rprimitive], |
| return_type=tuple_rprimitive, |
| c_function_name="PySequence_Tuple", |
| error_kind=ERR_MAGIC, |
| ) |
| |
| # translate isinstance(obj, tuple) |
| isinstance_tuple = function_op( |
| name="builtins.isinstance", |
| arg_types=[object_rprimitive], |
| return_type=bit_rprimitive, |
| c_function_name="PyTuple_Check", |
| error_kind=ERR_NEVER, |
| ) |
| |
| # tuple + tuple |
| binary_op( |
| name="+", |
| arg_types=[tuple_rprimitive, tuple_rprimitive], |
| return_type=tuple_rprimitive, |
| c_function_name="PySequence_Concat", |
| error_kind=ERR_MAGIC, |
| ) |
| |
| # tuple * int |
| binary_op( |
| name="*", |
| arg_types=[tuple_rprimitive, int_rprimitive], |
| return_type=tuple_rprimitive, |
| c_function_name="CPySequence_Multiply", |
| error_kind=ERR_MAGIC, |
| ) |
| |
| # int * tuple |
| binary_op( |
| name="*", |
| arg_types=[int_rprimitive, tuple_rprimitive], |
| return_type=tuple_rprimitive, |
| c_function_name="CPySequence_RMultiply", |
| 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, |
| ) |