Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
                                       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='...',
Ejemplo n.º 4
0
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')
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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]});'))
Ejemplo n.º 7
0
                     ('>>=', '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)
Ejemplo n.º 8
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')]:
Ejemplo n.º 9
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(
Ejemplo n.º 10
0
    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,
Ejemplo n.º 11
0
                                 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,
Ejemplo n.º 12
0
# 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)
Ejemplo n.º 13
0
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)
Ejemplo n.º 14
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,
Ejemplo n.º 15
0
# 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)
Ejemplo n.º 16
0
    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:
Ejemplo n.º 17
0
          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)
Ejemplo n.º 18
0
            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.
Ejemplo n.º 19
0
                          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))