"""Miscellaneous primitive ops.""" from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC, ERR_FALSE, ERR_NEG_INT from mypyc.ir.rtypes import (RTuple, bool_rprimitive, object_rprimitive, str_rprimitive, int_rprimitive, dict_rprimitive, c_int_rprimitive) from mypyc.primitives.registry import (simple_emit, unary_op, func_op, custom_op, call_emit, name_emit, call_negative_magic_emit, c_function_op, c_custom_op, load_address_op) # Get the boxed Python 'None' object none_object_op = custom_op(result_type=object_rprimitive, arg_types=[], error_kind=ERR_NEVER, format_str='{dest} = builtins.None :: object', emit=name_emit('Py_None'), is_borrowed=True) # Get the boxed object '...' ellipsis_op = custom_op(name='...', arg_types=[], result_type=object_rprimitive, error_kind=ERR_NEVER, emit=name_emit('Py_Ellipsis'), is_borrowed=True) # Get the boxed NotImplemented object not_implemented_op = load_address_op(name='builtins.NotImplemented', type=object_rprimitive, src='_Py_NotImplementedStruct')
# 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, ) 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[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) # Version with no int bounds 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,
from mypyc.ir.ops import ERR_MAGIC from mypyc.ir.rtypes import (tuple_rprimitive, int_rprimitive, list_rprimitive, object_rprimitive, c_pyssize_t_rprimitive) from mypyc.primitives.registry import method_op, function_op, custom_op # 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) # 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,
# Get the boxed NotImplemented object not_implemented_op = load_address_op(name='builtins.NotImplemented', type=object_rprimitive, src='_Py_NotImplementedStruct') # 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.
emit=negative_int_emit('{dest} = PyDict_Contains({args[1]}, {args[0]});')) # dict1.update(dict2) dict_update_op = method_op( name='update', arg_types=[dict_rprimitive, dict_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=call_negative_bool_emit('CPyDict_Update'), 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, dict_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=call_negative_bool_emit('CPyDict_UpdateInDisplay'), format_str='{dest} = {args[0]}.update({args[1]}) (display) :: dict',) # dict.update(obj) method_op( name='update', arg_types=[dict_rprimitive, object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=simple_emit('{dest} = CPyDict_UpdateFromAny({args[0]}, {args[1]}) != -1;')) # dict.get(key, default) method_op( name='get', arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive],
int_binary_op('+=', 'CPyTagged_Add') int_binary_op('-=', 'CPyTagged_Subtract') int_binary_op('*=', 'CPyTagged_Multiply') int_binary_op('//=', 'CPyTagged_FloorDivide', error_kind=ERR_MAGIC) int_binary_op('%=', 'CPyTagged_Remainder', error_kind=ERR_MAGIC) int_compare_op('==', 'CPyTagged_IsEq') int_compare_op('!=', 'CPyTagged_IsNe') int_compare_op('<', 'CPyTagged_IsLt') int_compare_op('<=', 'CPyTagged_IsLe') int_compare_op('>', 'CPyTagged_IsGt') int_compare_op('>=', 'CPyTagged_IsGe') unsafe_short_add = custom_op( arg_types=[int_rprimitive, int_rprimitive], result_type=short_int_rprimitive, error_kind=ERR_NEVER, format_str='{dest} = {args[0]} + {args[1]} :: short_int', emit=simple_emit('{dest} = {args[0]} + {args[1]};')) def int_unary_op(op: str, c_func_name: str) -> OpDescription: return unary_op(op=op, arg_type=int_rprimitive, result_type=int_rprimitive, error_kind=ERR_NEVER, format_str='{dest} = %s{args[0]} :: int' % op, emit=call_emit(c_func_name)) int_neg_op = int_unary_op('-', 'CPyTagged_Negate')
# Get the boxed NotImplemented object not_implemented_op = load_address_op(name='builtins.NotImplemented', type=object_rprimitive, src='_Py_NotImplementedStruct') # 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.
emit=negative_int_emit('{dest} = PyDict_Contains({args[1]}, {args[0]});')) # dict1.update(dict2) dict_update_op = method_op(name='update', arg_types=[dict_rprimitive, dict_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=call_negative_bool_emit('CPyDict_Update'), 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, dict_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=call_negative_bool_emit('CPyDict_UpdateInDisplay'), format_str='{dest} = {args[0]}.update({args[1]}) (display) :: dict', ) # dict.update(obj) method_op(name='update', arg_types=[dict_rprimitive, object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=call_negative_bool_emit('CPyDict_UpdateFromAny')) # dict.get(key, default) c_method_op(name='get', arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], return_type=object_rprimitive,
from mypyc.ir.rtypes import tuple_rprimitive, int_rprimitive, list_rprimitive, object_rprimitive from mypyc.primitives.registry import func_op, method_op, custom_op, call_emit, simple_emit tuple_get_item_op = method_op( name='__getitem__', arg_types=[tuple_rprimitive, int_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('CPySequenceTuple_GetItem')) new_tuple_op = custom_op( arg_types=[object_rprimitive], result_type=tuple_rprimitive, is_var_arg=True, error_kind=ERR_MAGIC, steals=False, format_str='{dest} = ({comma_args}) :: tuple', emit=simple_emit('{dest} = PyTuple_Pack({num_args}{pre_comma_args});')) def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None: temp = emitter.temp_name() emitter.emit_declaration('Py_ssize_t %s;' % temp) emitter.emit_line('%s = PyTuple_GET_SIZE(%s);' % (temp, args[0])) emitter.emit_line('%s = CPyTagged_ShortFromSsize_t(%s);' % (dest, temp)) tuple_len_op = func_op( name='builtins.len', arg_types=[tuple_rprimitive],
def emit_new(emitter: EmitterInterface, args: List[str], dest: str) -> None: # TODO: This would be better split into multiple smaller ops. emitter.emit_line('%s = PyList_New(%d); ' % (dest, len(args))) emitter.emit_line('if (likely(%s != NULL)) {' % dest) for i, arg in enumerate(args): emitter.emit_line('PyList_SET_ITEM(%s, %s, %s);' % (dest, i, arg)) emitter.emit_line('}') # Construct a list from values: [item1, item2, ....] new_list_op = custom_op(arg_types=[object_rprimitive], result_type=list_rprimitive, is_var_arg=True, error_kind=ERR_MAGIC, steals=True, format_str='{dest} = [{comma_args}]', emit=emit_new) # list[index] (for an integer index) list_get_item_op = c_method_op( name='__getitem__', arg_types=[list_rprimitive, int_rprimitive], return_type=object_rprimitive, c_function_name='CPyList_GetItem', error_kind=ERR_MAGIC) # Version with no int bounds check for when it is known to be short c_method_op(
# 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 IntComparisonOpDescription = NamedTuple( 'IntComparisonOpDescription', [('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 = { '==': IntComparisonOpDescription(ComparisonOp.EQ, int_equal_, False, False), '!=': IntComparisonOpDescription(ComparisonOp.NEQ, int_equal_, True, False),
extra_int_constants=str_split_constants[i], error_kind=ERR_MAGIC) # str1 += str2 # # PyUnicodeAppend 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[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.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,
from mypyc.ir.rtypes import (tuple_rprimitive, int_rprimitive, list_rprimitive, object_rprimitive, c_pyssize_t_rprimitive, bit_rprimitive) from mypyc.primitives.registry import method_op, function_op, custom_op # 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,
def emit_new(emitter: EmitterInterface, args: List[str], dest: str) -> None: # TODO: This would be better split into multiple smaller ops. emitter.emit_line('%s = PyList_New(%d); ' % (dest, len(args))) emitter.emit_line('if (likely(%s != NULL)) {' % dest) for i, arg in enumerate(args): emitter.emit_line('PyList_SET_ITEM(%s, %s, %s);' % (dest, i, arg)) emitter.emit_line('}') # Construct a list from values: [item1, item2, ....] new_list_op = custom_op(arg_types=[object_rprimitive], result_type=list_rprimitive, is_var_arg=True, error_kind=ERR_MAGIC, steals=True, format_str='{dest} = [{comma_args}]', emit=emit_new) # list[index] (for an integer index) list_get_item_op = c_method_op(name='__getitem__', arg_types=[list_rprimitive, int_rprimitive], return_type=object_rprimitive, c_function_name='CPyList_GetItem', error_kind=ERR_MAGIC) # Version with no int bounds check for when it is known to be short c_method_op(name='__getitem__', arg_types=[list_rprimitive, short_int_rprimitive], return_type=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)
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 a value. # 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. yield_from_rtuple = RTuple([bool_rprimitive, object_rprimitive]) # Op used for "yield from" error handling. # See comment in CPy_YieldFromErrorHandle for more information. yield_from_except_op = custom_op( name='yield_from_except', arg_types=[object_rprimitive], result_type=yield_from_rtuple, error_kind=ERR_MAGIC, emit=simple_emit( '{dest}.f0 = CPy_YieldFromErrorHandle({args[0]}, &{dest}.f1);')) # Create method object from a callable object and self. method_new_op = c_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 = c_custom_op(arg_types=[], return_type=object_rprimitive,
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 a value. # 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. yield_from_rtuple = RTuple([bool_rprimitive, object_rprimitive]) # Op used for "yield from" error handling. # See comment in CPy_YieldFromErrorHandle for more information. yield_from_except_op = custom_op( name='yield_from_except', arg_types=[object_rprimitive], result_type=yield_from_rtuple, error_kind=ERR_MAGIC, emit=simple_emit( '{dest}.f0 = CPy_YieldFromErrorHandle({args[0]}, &{dest}.f1);')) # Create method object from a callable object and self. method_new_op = c_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 = c_custom_op(arg_types=[], return_type=object_rprimitive,
"""Miscellaneous primitive ops.""" from mypyc.ir.ops import ERR_NEVER, ERR_MAGIC, ERR_FALSE, ERR_NEG_INT from mypyc.ir.rtypes import (RTuple, none_rprimitive, bool_rprimitive, object_rprimitive, str_rprimitive, int_rprimitive, dict_rprimitive, c_int_rprimitive) from mypyc.primitives.registry import (name_ref_op, simple_emit, unary_op, func_op, custom_op, call_emit, name_emit, call_negative_magic_emit, c_function_op) # Get the boxed Python 'None' object none_object_op = custom_op(result_type=object_rprimitive, arg_types=[], error_kind=ERR_NEVER, format_str='{dest} = builtins.None :: object', emit=name_emit('Py_None'), is_borrowed=True) # Get an unboxed None value none_op = name_ref_op('builtins.None', result_type=none_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = 1; /* None */')) # Get an unboxed True value true_op = name_ref_op('builtins.True', result_type=bool_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = 1;'))
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,
"""Exception-related primitive ops.""" from mypyc.ir.ops import ERR_NEVER, ERR_FALSE, ERR_ALWAYS from mypyc.ir.rtypes import object_rprimitive, void_rtype, exc_rtuple, bit_rprimitive 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,
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 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,
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)
"""Exception-related primitive ops.""" from mypyc.ir.ops import ERR_NEVER, ERR_FALSE from mypyc.ir.rtypes import bool_rprimitive, object_rprimitive, void_rtype, exc_rtuple from mypyc.primitives.registry import ( simple_emit, custom_op, ) # TODO: Making this raise conditionally is kind of hokey. raise_exception_op = custom_op( arg_types=[object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, format_str='raise_exception({args[0]}); {dest} = 0', emit=simple_emit('CPy_Raise({args[0]}); {dest} = 0;')) set_stop_iteration_value = custom_op( arg_types=[object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, format_str='set_stop_iteration_value({args[0]}); {dest} = 0', emit=simple_emit('CPyGen_SetStopIterationValue({args[0]}); {dest} = 0;')) raise_exception_with_tb_op = custom_op( arg_types=[object_rprimitive, object_rprimitive, object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, format_str='raise_exception_with_tb({args[0]}, {args[1]}, {args[2]}); {dest} = 0', emit=simple_emit('CPyErr_SetObjectAndTraceback({args[0]}, {args[1]}, {args[2]}); {dest} = 0;')) reraise_exception_op = custom_op(
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)
# del obj.attr py_delattr_op = func_op( name='builtins.delattr', arg_types=[object_rprimitive, object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_FALSE, emit=call_negative_bool_emit('PyObject_DelAttr') ) # Call callable object with N positional arguments: func(arg1, ..., argN) # Arguments are (func, arg1, ..., argN). py_call_op = custom_op( arg_types=[object_rprimitive], result_type=object_rprimitive, is_var_arg=True, error_kind=ERR_MAGIC, format_str='{dest} = py_call({comma_args})', emit=simple_emit('{dest} = PyObject_CallFunctionObjArgs({comma_args}, NULL);')) # 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], result_type=object_rprimitive, error_kind=ERR_MAGIC, format_str='{dest} = py_call_with_kwargs({args[0]}, {args[1]}, {args[2]})', emit=call_emit('PyObject_Call')) # Call method with positional arguments: obj.method(arg1, ...) # Arguments are (object, attribute name, arg1, ...).
# 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,
reraise_exception_op = c_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 = c_custom_op(arg_types=[], return_type=bool_rprimitive, c_function_name='CPy_NoErrOccured', error_kind=ERR_FALSE) # Assert that the error indicator has been set. assert_err_occured_op = custom_op( arg_types=[], result_type=void_rtype, error_kind=ERR_NEVER, format_str='assert_err_occurred', emit=simple_emit( 'assert(PyErr_Occurred() != NULL && "failure w/o err!");')) # 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=[], result_type=bool_rprimitive, error_kind=ERR_FALSE, format_str='{dest} = keep_propagating', emit=simple_emit('{dest} = 0;')) # 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