예제 #1
0
파일: emitwrapper.py 프로젝트: srittau/mypy
def generate_bin_op_forward_only_wrapper(fn: FuncIR,
                                         emitter: Emitter,
                                         gen: 'WrapperGenerator') -> None:
    gen.emit_arg_processing(error=GotoHandler('typefail'), raise_exception=False)
    gen.emit_call(not_implemented_handler='goto typefail;')
    gen.emit_error_handling()
    emitter.emit_label('typefail')
    # If some argument has an incompatible type, treat this the same as
    # returning NotImplemented, and try to call the reverse operator method.
    #
    # Note that in normal Python you'd instead of an explicit
    # return of NotImplemented, but it doesn't generally work here
    # the body won't be executed at all if there is an argument
    # type check failure.
    #
    # The recommended way is to still use a type check in the
    # body. This will only be used in interpreted mode:
    #
    #    def __add__(self, other: int) -> Foo:
    #        if not isinstance(other, int):
    #            return NotImplemented
    #        ...
    rmethod = reverse_op_methods[fn.name]
    emitter.emit_line('_Py_IDENTIFIER({});'.format(rmethod))
    emitter.emit_line(
        'return CPy_CallReverseOpMethod(obj_left, obj_right, "{}", &PyId_{});'.format(
            op_methods_to_symbols[fn.name],
            rmethod))
    gen.finish()
예제 #2
0
파일: emitwrapper.py 프로젝트: srittau/mypy
 def error(self) -> ErrorHandler:
     """Figure out how to deal with errors in the wrapper."""
     if self.cleanups or self.traceback_code:
         # We'll have a label at the end with error handling code.
         return GotoHandler('fail')
     else:
         # Nothing special needs to done to handle errors, so just return.
         return ReturnHandler('NULL')
예제 #3
0
파일: emitwrapper.py 프로젝트: srittau/mypy
def generate_bin_op_reverse_only_wrapper(emitter: Emitter,
                                         gen: 'WrapperGenerator') -> None:
    gen.arg_names = ['right', 'left']
    gen.emit_arg_processing(error=GotoHandler('typefail'), raise_exception=False)
    gen.emit_call()
    gen.emit_error_handling()
    emitter.emit_label('typefail')
    emitter.emit_line('Py_INCREF(Py_NotImplemented);')
    emitter.emit_line('return Py_NotImplemented;')
    gen.finish()
예제 #4
0
def generate_wrapper_core(fn: FuncIR,
                          emitter: Emitter,
                          optional_args: Optional[List[RuntimeArg]] = None,
                          arg_names: Optional[List[str]] = None,
                          cleanups: Optional[List[str]] = None,
                          traceback_code: Optional[str] = None) -> None:
    """Generates the core part of a wrapper function for a native function.

    This expects each argument as a PyObject * named obj_{arg} as a precondition.
    It converts the PyObject *s to the necessary types, checking and unboxing if necessary,
    makes the call, then boxes the result if necessary and returns it.
    """

    optional_args = optional_args or []
    cleanups = cleanups or []
    use_goto = bool(cleanups or traceback_code)
    error = ReturnHandler('NULL') if not use_goto else GotoHandler('fail')

    arg_names = arg_names or [arg.name for arg in fn.args]
    for arg_name, arg in zip(arg_names, fn.args):
        # Suppress the argument check for *args/**kwargs, since we know it must be right.
        typ = arg.type if arg.kind not in (ARG_STAR, ARG_STAR2) else object_rprimitive
        generate_arg_check(arg_name,
                           typ,
                           emitter,
                           error,
                           optional=arg in optional_args)
    native_args = ', '.join('arg_{}'.format(arg) for arg in arg_names)
    if fn.ret_type.is_unboxed or use_goto:
        # TODO: The Py_RETURN macros return the correct PyObject * with reference count handling.
        #       Are they relevant?
        emitter.emit_line('{}retval = {}{}({});'.format(emitter.ctype_spaced(fn.ret_type),
                                                        NATIVE_PREFIX,
                                                        fn.cname(emitter.names),
                                                        native_args))
        emitter.emit_lines(*cleanups)
        if fn.ret_type.is_unboxed:
            emitter.emit_error_check('retval', fn.ret_type, 'return NULL;')
            emitter.emit_box('retval', 'retbox', fn.ret_type, declare_dest=True)

        emitter.emit_line('return {};'.format('retbox' if fn.ret_type.is_unboxed else 'retval'))
    else:
        emitter.emit_line('return {}{}({});'.format(NATIVE_PREFIX,
                                                    fn.cname(emitter.names),
                                                    native_args))
        # TODO: Tracebacks?

    if use_goto:
        emitter.emit_label('fail')
        emitter.emit_lines(*cleanups)
        if traceback_code:
            emitter.emit_lines(traceback_code)
        emitter.emit_lines('return NULL;')
예제 #5
0
파일: emitwrapper.py 프로젝트: srittau/mypy
def generate_bin_op_both_wrappers(cl: ClassIR,
                                  fn: FuncIR,
                                  fn_rev: FuncIR,
                                  emitter: Emitter,
                                  gen: 'WrapperGenerator') -> None:
    # There's both a forward and a reverse operator method. First
    # check if we should try calling the forward one. If the
    # argument type check fails, fall back to the reverse method.
    #
    # Similar to above, we can't perfectly match Python semantics.
    # In regular Python code you'd return NotImplemented if the
    # operand has the wrong type, but in compiled code we'll never
    # get to execute the type check.
    emitter.emit_line('if (PyObject_IsInstance(obj_left, (PyObject *){})) {{'.format(
        emitter.type_struct_name(cl)))
    gen.emit_arg_processing(error=GotoHandler('typefail'), raise_exception=False)
    gen.emit_call(not_implemented_handler='goto typefail;')
    gen.emit_error_handling()
    emitter.emit_line('}')
    emitter.emit_label('typefail')
    emitter.emit_line('if (PyObject_IsInstance(obj_right, (PyObject *){})) {{'.format(
        emitter.type_struct_name(cl)))
    gen.set_target(fn_rev)
    gen.arg_names = ['right', 'left']
    gen.emit_arg_processing(error=GotoHandler('typefail2'), raise_exception=False)
    gen.emit_call()
    gen.emit_error_handling()
    emitter.emit_line('} else {')
    emitter.emit_line('_Py_IDENTIFIER({});'.format(fn_rev.name))
    emitter.emit_line(
        'return CPy_CallReverseOpMethod(obj_left, obj_right, "{}", &PyId_{});'.format(
            op_methods_to_symbols[fn.name],
            fn_rev.name))
    emitter.emit_line('}')
    emitter.emit_label('typefail2')
    emitter.emit_line('Py_INCREF(Py_NotImplemented);')
    emitter.emit_line('return Py_NotImplemented;')
    gen.finish()
예제 #6
0
파일: emitwrapper.py 프로젝트: srittau/mypy
def generate_set_del_item_wrapper_inner(fn: FuncIR, emitter: Emitter,
                                        args: Sequence[RuntimeArg]) -> None:
    for arg in args:
        generate_arg_check(arg.name, arg.type, emitter, GotoHandler('fail'))
    native_args = ', '.join('arg_{}'.format(arg.name) for arg in args)
    emitter.emit_line('{}val = {}{}({});'.format(emitter.ctype_spaced(fn.ret_type),
                                                 NATIVE_PREFIX,
                                                 fn.cname(emitter.names),
                                                 native_args))
    emitter.emit_error_check('val', fn.ret_type, 'goto fail;')
    emitter.emit_dec_ref('val', fn.ret_type)
    emitter.emit_line('return 0;')
    emitter.emit_label('fail')
    emitter.emit_line('return -1;')
    emitter.emit_line('}')
예제 #7
0
파일: emitwrapper.py 프로젝트: srittau/mypy
def generate_wrapper_core(fn: FuncIR,
                          emitter: Emitter,
                          optional_args: Optional[List[RuntimeArg]] = None,
                          arg_names: Optional[List[str]] = None,
                          cleanups: Optional[List[str]] = None,
                          traceback_code: Optional[str] = None) -> None:
    """Generates the core part of a wrapper function for a native function.

    This expects each argument as a PyObject * named obj_{arg} as a precondition.
    It converts the PyObject *s to the necessary types, checking and unboxing if necessary,
    makes the call, then boxes the result if necessary and returns it.
    """
    gen = WrapperGenerator(None, emitter)
    gen.set_target(fn)
    gen.arg_names = arg_names or [arg.name for arg in fn.args]
    gen.cleanups = cleanups or []
    gen.optional_args = optional_args or []
    gen.traceback_code = traceback_code or ''

    error = ReturnHandler('NULL') if not gen.use_goto() else GotoHandler('fail')
    gen.emit_arg_processing(error=error)
    gen.emit_call()
    gen.emit_error_handling()