def int_compare_op(op: str, c_func_name: str) -> None: int_binary_op(op, c_func_name, bool_rprimitive) # Generate a straight compare if we know both sides are short binary_op(op=op, arg_types=[short_int_rprimitive, short_int_rprimitive], result_type=bool_rprimitive, error_kind=ERR_NEVER, format_str='{dest} = {args[0]} %s {args[1]} :: short_int' % op, emit=simple_emit( '{dest} = (Py_ssize_t){args[0]} %s (Py_ssize_t){args[1]};' % op), priority=2)
from mypyc.primitives.registry import (func_op, method_op, binary_op, simple_emit, negative_int_emit, call_negative_bool_emit, c_function_op, c_method_op) from mypyc.ir.ops import ERR_MAGIC, ERR_FALSE, ERR_NEVER, ERR_NEG_INT, EmitterInterface from mypyc.ir.rtypes import (object_rprimitive, bool_rprimitive, set_rprimitive, int_rprimitive, c_int_rprimitive) from typing import List # Construct an empty set. new_set_op = func_op(name='builtins.set', arg_types=[], result_type=set_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit('{dest} = PySet_New(NULL);')) # set(obj) c_function_op(name='builtins.set', arg_types=[object_rprimitive], return_type=set_rprimitive, c_function_name='PySet_New', error_kind=ERR_MAGIC) # frozenset(obj) c_function_op(name='builtins.frozenset', arg_types=[object_rprimitive], return_type=object_rprimitive, c_function_name='PyFrozenSet_New', error_kind=ERR_MAGIC)
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;')) # Get an unboxed False value false_op = name_ref_op('builtins.False', result_type=bool_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = 0;')) # Get the boxed object '...' ellipsis_op = custom_op(name='...',
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') # Add short integers and assume that it doesn't overflow or underflow. # Assume that the operands are not big integers. 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')
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], result_type=int_rprimitive, error_kind=ERR_NEVER, emit=emit_len)
from typing import List, Callable from mypyc.ops import ERR_MAGIC, ERR_NEVER, EmitterInterface, EmitCallback from mypyc.rtypes import (RType, object_rprimitive, str_rprimitive, bool_rprimitive, int_rprimitive, list_rprimitive) from mypyc.primitives.registry import func_op, binary_op, simple_emit, name_ref_op, method_op name_ref_op('builtins.str', result_type=object_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = (PyObject *)&PyUnicode_Type;'), is_borrowed=True) func_op(name='builtins.str', arg_types=[object_rprimitive], result_type=str_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit('{dest} = PyObject_Str({args[0]});')) binary_op(op='+', arg_types=[str_rprimitive, str_rprimitive], result_type=str_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit('{dest} = PyUnicode_Concat({args[0]}, {args[1]});')) method_op(name='join', arg_types=[str_rprimitive, object_rprimitive], result_type=str_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit('{dest} = PyUnicode_Join({args[0]}, {args[1]});'))
('>>=', 'PyNumber_InPlaceRshift'), ('&=', 'PyNumber_InPlaceAnd'), ('^=', 'PyNumber_InPlaceXor'), ('|=', 'PyNumber_InPlaceOr')]: binary_op(op=op, arg_types=[object_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=call_emit(funcname), priority=0) binary_op(op='**', arg_types=[object_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit('{dest} = PyNumber_Power({args[0]}, {args[1]}, Py_None);'), priority=0) binary_op('in', arg_types=[object_rprimitive, object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_MAGIC, emit=negative_int_emit('{dest} = PySequence_Contains({args[1]}, {args[0]});'), priority=0) binary_op('is', arg_types=[object_rprimitive, object_rprimitive], result_type=bool_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = {args[0]} == {args[1]};'), priority=0)
('>>=', 'PyNumber_InPlaceRshift'), ('&=', 'PyNumber_InPlaceAnd'), ('^=', 'PyNumber_InPlaceXor'), ('|=', 'PyNumber_InPlaceOr')]: c_binary_op(name=op, arg_types=[object_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name=funcname, error_kind=ERR_MAGIC, priority=0) binary_op(op='**', arg_types=[object_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit( '{dest} = PyNumber_Power({args[0]}, {args[1]}, Py_None);'), priority=0) c_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')]:
"""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(
name_emit, call_negative_bool_emit, call_negative_magic_emit, ) 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) none_op = name_ref_op('builtins.None', result_type=none_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = 1; /* None */')) true_op = name_ref_op('builtins.True', result_type=bool_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = 1;')) false_op = name_ref_op('builtins.False', result_type=bool_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = 0;')) ellipsis_op = custom_op(name='...', arg_types=[], result_type=object_rprimitive, error_kind=ERR_NEVER,
emit=call_and_fail_emit('CPy_Reraise')) # Propagate exception if the CPython error indicator is set (an exception was raised). no_err_occurred_op = custom_op(arg_types=[], result_type=bool_rprimitive, error_kind=ERR_FALSE, format_str='{dest} = no_err_occurred', emit=call_emit('CPy_NoErrOccured')) # 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 # later. error_catch_op = custom_op(arg_types=[], result_type=exc_rtuple,
# 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, c_function_name='CPy_FetchStopIterationValue', error_kind=ERR_MAGIC)
from mypyc.ir.rtypes import object_rprimitive, int_rprimitive, bool_rprimitive from mypyc.primitives.registry import (binary_op, unary_op, func_op, method_op, custom_op, call_emit, simple_emit, call_negative_bool_emit, call_negative_magic_emit, negative_int_emit) for op, opid in [('==', 'Py_EQ'), ('!=', 'Py_NE'), ('<', 'Py_LT'), ('<=', 'Py_LE'), ('>', 'Py_GT'), ('>=', 'Py_GE')]: # The result type is 'object' since that's what PyObject_RichCompare returns. binary_op( op=op, arg_types=[object_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit( '{dest} = PyObject_RichCompare({args[0]}, {args[1]}, %s);' % opid), 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')]: binary_op(op=op, arg_types=[object_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=call_emit(funcname), priority=0)
from typing import List from mypyc.ir.ops import EmitterInterface, ERR_FALSE, ERR_MAGIC, ERR_NEVER from mypyc.ir.rtypes import dict_rprimitive, object_rprimitive, bool_rprimitive, int_rprimitive from mypyc.primitives.registry import ( name_ref_op, method_op, binary_op, func_op, custom_op, simple_emit, negative_int_emit, call_emit, call_negative_bool_emit, ) # Get the 'dict' type object. name_ref_op('builtins.dict', result_type=object_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = (PyObject *)&PyDict_Type;'), is_borrowed=True) # dict[key] dict_get_item_op = method_op( name='__getitem__', arg_types=[dict_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('CPyDict_GetItem')) # dict[key] = value dict_set_item_op = method_op( name='__setitem__', arg_types=[dict_rprimitive, object_rprimitive, object_rprimitive], result_type=bool_rprimitive,
# 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, c_function_name='CPy_FetchStopIterationValue', error_kind=ERR_MAGIC)
binary_op, unary_op, func_op, custom_op, simple_emit, call_emit, ) # These int constructors produce object_rprimitives that then need to be unboxed # I guess unboxing ourselves would save a check and branch though? # For ordinary calls to int() we use a name_ref to the type name_ref_op('builtins.int', result_type=object_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = (PyObject *)&PyLong_Type;'), is_borrowed=True) # Convert from a float. We could do a bit better directly. func_op(name='builtins.int', arg_types=[float_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('CPyLong_FromFloat'), priority=1) def int_binary_op(op: str, c_func_name: str, result_type: RType = int_rprimitive, error_kind: int = ERR_NEVER) -> None:
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, c_function_name='CPyDict_Get', error_kind=ERR_MAGIC) # dict.get(key) method_op( name='get', arg_types=[dict_rprimitive, object_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=simple_emit('{dest} = CPyDict_Get({args[0]}, {args[1]}, Py_None);')) # Construct an empty dictionary. dict_new_op = c_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 = c_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)
arg_types=[str_rprimitive, object_rprimitive], return_type=str_rprimitive, c_function_name='PyUnicode_Join', error_kind=ERR_MAGIC) # str[index] (for an int index) c_method_op(name='__getitem__', arg_types=[str_rprimitive, int_rprimitive], return_type=str_rprimitive, c_function_name='CPyStr_GetItem', error_kind=ERR_MAGIC) # str.split(...) str_split_types = [str_rprimitive, str_rprimitive, int_rprimitive] # type: List[RType] str_split_emits = [simple_emit('{dest} = PyUnicode_Split({args[0]}, NULL, -1);'), simple_emit('{dest} = PyUnicode_Split({args[0]}, {args[1]}, -1);'), call_emit('CPyStr_Split')] \ # type: List[EmitCallback] for i in range(len(str_split_types)): method_op(name='split', arg_types=str_split_types[0:i + 1], result_type=list_rprimitive, error_kind=ERR_MAGIC, emit=str_split_emits[i]) # 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.
list_rprimitive, object_rprimitive, bool_rprimitive) from mypyc.primitives.registry import ( name_ref_op, binary_op, func_op, method_op, custom_op, simple_emit, call_emit, call_negative_bool_emit, ) name_ref_op('builtins.list', result_type=object_rprimitive, error_kind=ERR_NEVER, emit=simple_emit('{dest} = (PyObject *)&PyList_Type;'), is_borrowed=True) to_list = func_op(name='builtins.list', arg_types=[object_rprimitive], result_type=list_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('PySequence_List')) 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))