Esempio n. 1
0
"""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')
Esempio n. 2
0
# 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,
Esempio n. 3
0
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,
Esempio n. 4
0
# 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.
Esempio n. 5
0
          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],
Esempio n. 6
0
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')
Esempio n. 7
0
# 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.
Esempio n. 8
0
    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,
Esempio n. 9
0
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],
Esempio n. 10
0

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),
Esempio n. 12
0
              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,
Esempio n. 13
0
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,
Esempio n. 14
0

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,
Esempio n. 15
0
                            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)
Esempio n. 16
0
                      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,
Esempio n. 17
0
                      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,
Esempio n. 18
0
"""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;'))
Esempio n. 19
0
    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,
Esempio n. 20
0
"""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,
Esempio n. 21
0
                            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,
Esempio n. 22
0
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)
Esempio n. 23
0
"""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(
Esempio n. 24
0
          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)
Esempio n. 25
0
# 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, ...).
Esempio n. 26
0
# 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,
Esempio n. 27
0
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