def int_binary_op(op: str, c_func_name: str, result_type: RType = int_rprimitive, error_kind: int = ERR_NEVER) -> None: binary_op(op=op, arg_types=[int_rprimitive, int_rprimitive], result_type=result_type, error_kind=error_kind, format_str='{dest} = {args[0]} %s {args[1]} :: int' % op, emit=call_emit(c_func_name))
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)
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)
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(
# 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],
error_kind=ERR_MAGIC, steals=[True, False]) def emit_str_compare( comparison: str) -> Callable[[EmitterInterface, List[str], str], None]: def emit(emitter: EmitterInterface, args: List[str], dest: str) -> None: temp = emitter.temp_name() emitter.emit_declaration('int %s;' % temp) emitter.emit_lines( '%s = PyUnicode_Compare(%s, %s);' % (temp, args[0], args[1]), 'if (%s == -1 && PyErr_Occurred())' % temp, ' %s = 2;' % dest, 'else', ' %s = (%s %s);' % (dest, temp, comparison)) return emit # str1 == str2 binary_op(op='==', arg_types=[str_rprimitive, str_rprimitive], result_type=bool_rprimitive, error_kind=ERR_MAGIC, emit=emit_str_compare('== 0')) # str1 != str2 binary_op(op='!=', arg_types=[str_rprimitive, str_rprimitive], result_type=bool_rprimitive, error_kind=ERR_MAGIC, emit=emit_str_compare('!= 0'))
('<<=', 'PyNumber_InPlaceLshift'), ('>>=', '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
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',
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, error_kind=ERR_FALSE, emit=call_negative_bool_emit('CPyDict_SetItem')) # key in dict binary_op(op='in', arg_types=[object_rprimitive, dict_rprimitive], result_type=bool_rprimitive, error_kind=ERR_MAGIC, format_str='{dest} = {args[0]} in {args[1]} :: dict', 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(
result_type=object_rprimitive, error_kind=ERR_NEVER, emit=name_emit('&PyUnicode_Type', target_type='PyObject *'), is_borrowed=True) # str(obj) func_op(name='builtins.str', arg_types=[object_rprimitive], result_type=str_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('PyObject_Str')) # str1 + str2 binary_op(op='+', arg_types=[str_rprimitive, str_rprimitive], result_type=str_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('PyUnicode_Concat')) # str.join(obj) c_method_op(name='join', 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) method_op(name='__getitem__', arg_types=[str_rprimitive, int_rprimitive], result_type=str_rprimitive, error_kind=ERR_MAGIC,
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]});')) 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);'), simple_emit('{dest} = CPyStr_Split({args[0]}, {args[1]}, {args[2]});')] \ # type: List[EmitCallback]
# 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 + 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.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)
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) 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 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')]: binary_op(name=op, arg_types=[object_rprimitive, object_rprimitive], return_type=object_rprimitive, c_function_name=funcname,
arg_types=[list_rprimitive, int_rprimitive], result_type=object_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('CPyList_Pop')) # list.count(obj) method_op(name='count', arg_types=[list_rprimitive, object_rprimitive], result_type=short_int_rprimitive, error_kind=ERR_MAGIC, emit=call_emit('CPyList_Count')) # list * int binary_op(op='*', arg_types=[list_rprimitive, int_rprimitive], result_type=list_rprimitive, error_kind=ERR_MAGIC, format_str='{dest} = {args[0]} * {args[1]} :: list', emit=call_emit("CPySequence_Multiply")) # int * list binary_op(op='*', arg_types=[int_rprimitive, list_rprimitive], result_type=list_rprimitive, error_kind=ERR_MAGIC, format_str='{dest} = {args[0]} * {args[1]} :: list', emit=call_emit("CPySequence_RMultiply")) def emit_len(emitter: EmitterInterface, args: List[str], dest: str) -> None: temp = emitter.temp_name() emitter.emit_declaration('Py_ssize_t %s;' % temp)
"%s = PySequence_Repeat(%s, %s);" % (dest, lst, temp)) def emit_multiply(emitter: EmitterInterface, args: List[str], dest: str) -> None: emit_multiply_helper(emitter, dest, args[0], args[1]) def emit_multiply_reversed(emitter: EmitterInterface, args: List[str], dest: str) -> None: emit_multiply_helper(emitter, dest, args[1], args[0]) binary_op(op='*', arg_types=[list_rprimitive, int_rprimitive], result_type=list_rprimitive, error_kind=ERR_MAGIC, format_str='{dest} = {args[0]} * {args[1]} :: list', emit=emit_multiply) binary_op(op='*', arg_types=[int_rprimitive, list_rprimitive], result_type=list_rprimitive, error_kind=ERR_MAGIC, format_str='{dest} = {args[0]} * {args[1]} :: list', emit=emit_multiply_reversed) 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 = PyList_GET_SIZE(%s);' % (temp, args[0]))