Exemplo n.º 1
0
    def visit_BinOp(self, node):
        if isinstance(node.op, ast.Pow):
            return self.visit(resolve_pow(node.type, [node.left, node.right]))

        self.generic_visit(node)
        if is_obj(node.left.type) or is_obj(node.right.type):
            op_name = type(node.op).__name__
            op_method = getattr(self, '_object_%s' % op_name, None)
            if op_method:
                node = op_method(node)
            else:
                raise error.NumbaError(
                    node,
                    'Unsupported binary operation for object: %s' % op_name)
        return node
Exemplo n.º 2
0
    def visit_BinOp(self, node):
        if isinstance(node.op, ast.Pow):
            return self.visit(resolve_pow(node.type, [node.left, node.right]))

        self.generic_visit(node)
        if is_obj(node.left.type) or is_obj(node.right.type):
            op_name = type(node.op).__name__
            op_method = getattr(self, '_object_%s' % op_name, None)
            if op_method:
                node = op_method(node)
            else:
                raise error.NumbaError(
                    node, 'Unsupported binary operation for object: %s' %
                    op_name)
        return node
Exemplo n.º 3
0
    def single_compare(self, node):
        rhs = node.comparators[0]

        if is_obj(node.left.type):
            node = self.single_compare_objects(node)

        elif node.left.type.is_pointer and rhs.type.is_pointer:
            # Coerce pointers to integer values before comparing
            node.left = nodes.CoercionNode(node.left, Py_uintptr_t)
            node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)]

        elif node.left.type.is_complex and rhs.type.is_complex:
            real1, imag1 = extract(node.left)
            real2, imag2 = extract(rhs)
            op = type(node.ops[0])
            if op == ast.Eq:
                lhs = compare(real1, ast.Eq(), real2)
                rhs = compare(imag1, ast.Eq(), imag2)
                result = ast.BoolOp(ast.And(), [lhs, rhs])
            elif op == ast.NotEq:
                lhs = compare(real1, ast.NotEq(), real2)
                rhs = compare(imag1, ast.NotEq(), imag2)
                result = ast.BoolOp(ast.Or(), [lhs, rhs])
            else:
                raise NotImplementedError("ordered comparisons are not "
                                          "implemented for complex numbers")
            node = nodes.typednode(result, bool_)

        elif node.left.type.is_complex and rhs.type.is_datetime:
            raise error.NumbaError(
                node, "datetime comparisons not yet implemented")

        return node
Exemplo n.º 4
0
    def single_compare(self, node):
        rhs = node.comparators[0]

        if is_obj(node.left.type):
            node = self.single_compare_objects(node)

        elif node.left.type.is_pointer and rhs.type.is_pointer:
            # Coerce pointers to integer values before comparing
            node.left = nodes.CoercionNode(node.left, Py_uintptr_t)
            node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)]

        elif node.left.type.is_complex and rhs.type.is_complex:
            real1, imag1 = extract(node.left)
            real2, imag2 = extract(rhs)
            op = type(node.ops[0])
            if op == ast.Eq:
                lhs = compare(real1, ast.Eq(), real2)
                rhs = compare(imag1, ast.Eq(), imag2)
                result = ast.BoolOp(ast.And(), [lhs, rhs])
            elif op == ast.NotEq:
                lhs = compare(real1, ast.NotEq(), real2)
                rhs = compare(imag1, ast.NotEq(), imag2)
                result = ast.BoolOp(ast.Or(), [lhs, rhs])
            else:
                raise NotImplementedError("ordered comparisons are not "
                                          "implemented for complex numbers")
            node = nodes.typednode(result, bool_)

        return node
Exemplo n.º 5
0
def build_wrapper_function_ast(env, wrapper_lfunc, llvm_module):
    """
    Build AST for LLVM function wrapper.

        lfunc: LLVM function to wrap
        llvm_module: module the wrapper is being defined in

    The resulting AST has a NativeCallNode to the wrapped function. The
    arguments are  LLVMValueRefNode nodes which still need their llvm_value
    set to the object from the tuple. This happens in visit_FunctionWrapperNode
    during codegen.
    """
    func = env.crnt.func
    func_signature = env.crnt.func_signature
    func_name = env.crnt.func_name

    # Insert external declaration
    lfunc = llvm_module.get_or_insert_function(func_signature.to_llvm(env.context), env.crnt.lfunc.name)

    # Build AST
    wrapper = nodes.FunctionWrapperNode(lfunc, func_signature, func, fake_pyfunc, func_name)

    error_return = ast.Return(nodes.CoercionNode(nodes.NULL_obj, object_))

    is_closure = bool(closures.is_closure_signature(func_signature))
    nargs = len(func_signature.args) - is_closure

    # Call wrapped function with unpacked object arguments
    # (delay actual arguments)
    args = [nodes.LLVMValueRefNode(object_, None) for i in range(nargs)]

    if is_closure:
        # Insert m_self as scope argument type
        closure_scope = get_closure_scope(func_signature, wrapper_lfunc.args[0])
        args.insert(0, closure_scope)

    func_call = nodes.NativeCallNode(func_signature, args, lfunc)

    if not is_obj(func_signature.return_type):
        # Check for error using PyErr_Occurred()
        func_call = nodes.PyErr_OccurredNode(func_call)

    # Coerce and return result
    if func_signature.return_type.is_void:
        wrapper.body = func_call
        result_node = nodes.ObjectInjectNode(None)
    else:
        wrapper.body = None
        result_node = func_call

    wrapper.return_result = ast.Return(value=nodes.CoercionNode(result_node, object_))

    # Update wrapper
    wrapper.error_return = error_return
    wrapper.cellvars = []

    wrapper.wrapped_nargs = nargs
    wrapper.wrapped_args = args[is_closure:]

    return wrapper
Exemplo n.º 6
0
    def visit_Attribute(self, node):
        if (self.nopython and not node.value.type.is_module
                and not node.value.type.is_complex):
            raise error.NumbaError(
                node,
                "Cannot access Python attribute in nopython context (%s)" %
                node.attr)

        if node.value.type.is_complex:
            value = self.visit(node.value)
            return nodes.ComplexAttributeNode(value, node.attr)
        elif node.type.is_numpy_attribute:
            return nodes.ObjectInjectNode(node.type.value)
        elif node.type.is_numpy_dtype:
            dtype_type = node.type.dtype
            return nodes.ObjectInjectNode(dtype_type.get_dtype())
        elif is_obj(node.value.type):
            if node.value.type.is_module:
                # Resolve module attributes as constants
                if node.type.is_module_attribute:
                    new_node = nodes.ObjectInjectNode(node.type.value)
                else:
                    new_node = nodes.ConstNode(
                        getattr(node.value.type.module, node.attr))
            else:
                new_node = function_util.external_call(
                    self.context,
                    self.llvm_module,
                    'PyObject_GetAttrString',
                    args=[node.value, nodes.ConstNode(node.attr)])
            return self.visit(new_node)

        self.generic_visit(node)
        return node
Exemplo n.º 7
0
    def visit_Attribute(self, node):
        if (self.nopython and not node.value.type.is_module and
            not node.value.type.is_complex):
            raise error.NumbaError(
                    node, "Cannot access Python attribute in nopython context (%s)" % node.attr)

        if node.value.type.is_complex:
            value = self.visit(node.value)
            return nodes.ComplexAttributeNode(value, node.attr)
        elif node.type.is_numpy_attribute:
            return nodes.ObjectInjectNode(node.type.value)
        elif node.type.is_numpy_dtype:
            dtype_type = node.type.dtype
            return nodes.ObjectInjectNode(dtype_type.get_dtype())
        elif is_obj(node.value.type):
            if node.value.type.is_module:
                # Resolve module attributes as constants
                if node.type.is_module_attribute:
                    new_node = nodes.ObjectInjectNode(node.type.value)
                else:
                    new_node = nodes.ConstNode(getattr(node.value.type.module,
                                                       node.attr))
            else:
                new_node = function_util.external_call(
                                        self.context,
                                        self.llvm_module,
                                        'PyObject_GetAttrString',
                                        args=[node.value,
                                              nodes.ConstNode(node.attr)])
            return self.visit(new_node)

        self.generic_visit(node)
        return node
Exemplo n.º 8
0
def const(obj, type):
    if typesystem.is_obj(type):
        node = ObjectInjectNode(obj, type)
    else:
        node = ConstNode(obj, type)

    return node
Exemplo n.º 9
0
def const(obj, type):
    if typesystem.is_obj(type):
        node = ObjectInjectNode(obj, type)
    else:
        node = ConstNode(obj, type)

    return node
Exemplo n.º 10
0
    def visit_NativeCallNode(self, node):
        if is_obj(node.signature.return_type):
            if self.nopython:
                raise error.NumbaError(node, "Cannot call function returning object in " "nopython context")

            self.generic_visit(node)
            return nodes.ObjectTempNode(node)

        self.generic_visit(node)
        return node
Exemplo n.º 11
0
    def visit_NativeCallNode(self, node):
        if is_obj(node.signature.return_type):
            if self.nopython:
                raise error.NumbaError(
                    node, "Cannot call function returning object in "
                    "nopython context")

            self.generic_visit(node)
            return nodes.ObjectTempNode(node)

        self.generic_visit(node)
        return node
Exemplo n.º 12
0
 def visit_UnaryOp(self, node):
     self.generic_visit(node)
     if is_obj(node.type):
         op_name = type(node.op).__name__
         op_method = getattr(self, '_object_%s' % op_name, None)
         if op_method:
             node = op_method(node)
         else:
             raise error.NumbaError(
                 node,
                 'Unsupported unary operation for objects: %s' % op_name)
     return node
Exemplo n.º 13
0
 def visit_UnaryOp(self, node):
     self.generic_visit(node)
     if is_obj(node.type):
         op_name = type(node.op).__name__
         op_method = getattr(self, '_object_%s' % op_name, None)
         if op_method:
             node = op_method(node)
         else:
             raise error.NumbaError(
                 node, 'Unsupported unary operation for objects: %s' %
                 op_name)
     return node
Exemplo n.º 14
0
    def visit_CoercionNode(self, node):
        if not isinstance(node, nodes.CoercionNode):
            # CoercionNode.__new__ returns the node to be coerced if it doesn't
            # need coercion
            return node

        node_type = node.node.type
        dst_type = node.dst_type
        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('coercion: %s --> %s\n%s', node_type, dst_type,
                         utils.pformat_ast(node))

        # TODO: the below is a problem due to implicit string <-> int coercions!
        if (node_type.is_string and dst_type.is_numeric
                and not (node_type.is_pointer or node_type.is_null)):
            if dst_type.typename in ('char', 'uchar'):
                raise error.NumbaError(
                    node,
                    "Conversion from string to (u)char not yet supported")
            result = self.str_to_int(dst_type, node)
        elif self.nopython and (is_obj(node_type) ^ is_obj(dst_type)):
            raise error.NumbaError(
                node, "Cannot coerce to or from object in "
                "nopython context")
        elif is_obj(node.dst_type) and not is_obj(node_type):
            node = nodes.ObjectTempNode(
                nodes.CoerceToObject(node.node, node.dst_type, name=node.name))
            result = self.visit(node)
        elif is_obj(node_type) and not is_obj(node.dst_type):
            node = nodes.CoerceToNative(node.node,
                                        node.dst_type,
                                        name=node.name)
            result = self.visit(node)
        elif node_type.is_null:
            if not dst_type.is_pointer:
                raise error.NumbaError(
                    node.node, "NULL must be cast or implicitly "
                    "coerced to a pointer type")
            result = self.visit(nodes.NULL.coerce(dst_type))
        elif node_type.is_numeric and dst_type.is_bool:
            to_bool = ast.Compare(node.node, [ast.NotEq()],
                                  [nodes.const(0, node_type)])
            to_bool = nodes.typednode(to_bool, bool_)
            result = self.visit(to_bool)
        else:
            self.generic_visit(node)

            if dst_type == node.node.type:
                result = node.node
            else:
                result = node

        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('result = %s', utils.pformat_ast(result))

        return result
Exemplo n.º 15
0
    def setup_error_return(self, node, ret_type):
        """
        Set FunctionDef.error_return to the AST statement that returns a
        "bad value" that can be used as error indicator.
        """
        value = nodes.badval(ret_type)

        if value is not None:
            value = nodes.CoercionNode(value, dst_type=ret_type).cloneable

        error_return = ast.Return(value=value)

        if self.nopython and is_obj(self.func_signature.return_type):
            error_return = nodes.WithPythonNode(body=[error_return])

        node.error_return = error_return
Exemplo n.º 16
0
    def setup_error_return(self, node, ret_type):
        """
        Set FunctionDef.error_return to the AST statement that returns a
        "bad value" that can be used as error indicator.
        """
        value = nodes.badval(ret_type)

        if value is not None:
            value = nodes.CoercionNode(value, dst_type=ret_type).cloneable

        error_return = ast.Return(value=value)

        if self.nopython and is_obj(self.func_signature.return_type):
            error_return = nodes.WithPythonNode(body=[error_return])

        error_return = self.visit(error_return)
        node.error_return = error_return
Exemplo n.º 17
0
    def visit_CoercionNode(self, node):
        if not isinstance(node, nodes.CoercionNode):
            # CoercionNode.__new__ returns the node to be coerced if it doesn't
            # need coercion
            return node

        node_type = node.node.type
        dst_type = node.dst_type
        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('coercion: %s --> %s\n%s',
                         node_type, dst_type, utils.pformat_ast(node))

        # TODO: the below is a problem due to implicit string <-> int coercions!
        if (node_type.is_string and dst_type.is_numeric and not
            (node_type.is_pointer or node_type.is_null)):
            if dst_type.typename in ('char', 'uchar'):
                raise error.NumbaError(
                    node, "Conversion from string to (u)char not yet supported")
            result = self.str_to_int(dst_type, node)
        elif self.nopython and (is_obj(node_type) ^ is_obj(dst_type)):
            raise error.NumbaError(node, "Cannot coerce to or from object in "
                                         "nopython context")
        elif is_obj(node.dst_type) and not is_obj(node_type):
            node = nodes.ObjectTempNode(nodes.CoerceToObject(
                    node.node, node.dst_type, name=node.name))
            result = self.visit(node)
        elif is_obj(node_type) and not is_obj(node.dst_type):
            node = nodes.CoerceToNative(node.node, node.dst_type,
                                        name=node.name)
            result = self.visit(node)
        elif node_type.is_null:
            if not dst_type.is_pointer:
                raise error.NumbaError(node.node,
                                       "NULL must be cast or implicitly "
                                       "coerced to a pointer type")
            result = self.visit(nodes.NULL.coerce(dst_type))
        elif node_type.is_numeric and dst_type.is_bool:
            to_bool = ast.Compare(node.node, [ast.NotEq()],
                                  [nodes.const(0, node_type)])
            to_bool = nodes.typednode(to_bool, bool_)
            result = self.visit(to_bool)
        else:
            self.generic_visit(node)

            if dst_type == node.node.type:
                result = node.node
            else:
                result = node

        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('result = %s', utils.pformat_ast(result))

        return result
Exemplo n.º 18
0
    def visit_Name(self, node):
        if (is_obj(node.type) and isinstance(node.ctx, ast.Load) and
            getattr(node, 'cf_maybe_null', False)):
            # Check for unbound objects and raise UnboundLocalError if so
            value = nodes.LLVMValueRefNode(Py_uintptr_t, None)
            node.loaded_name = value

            exc_msg = node.variable.name
            if hasattr(node, 'lineno'):
                exc_msg = '%s%s' % (error.format_pos(node), exc_msg)

            check_unbound = nodes.CheckErrorNode(
                value, badval=nodes.const(0, Py_uintptr_t),
                exc_type=UnboundLocalError,
                exc_msg=exc_msg)
            node.check_unbound = self.visit(check_unbound)

        return node
Exemplo n.º 19
0
    def visit_Name(self, node):
        if (is_obj(node.type) and isinstance(node.ctx, ast.Load)
                and getattr(node, 'cf_maybe_null', False)):
            # Check for unbound objects and raise UnboundLocalError if so
            value = nodes.LLVMValueRefNode(Py_uintptr_t, None)
            node.loaded_name = value

            exc_msg = node.variable.name
            if hasattr(node, 'lineno'):
                exc_msg = '%s%s' % (error.format_pos(node), exc_msg)

            check_unbound = nodes.CheckErrorNode(value,
                                                 badval=nodes.const(
                                                     0, Py_uintptr_t),
                                                 exc_type=UnboundLocalError,
                                                 exc_msg=exc_msg)
            node.check_unbound = self.visit(check_unbound)

        return node
Exemplo n.º 20
0
    def single_compare(self, node):
        rhs = node.comparators[0]

        if is_obj(node.left.type):
            node = self.single_compare_objects(node)

        elif node.left.type.is_pointer and rhs.type.is_pointer:
            # Coerce pointers to integer values before comparing
            node.left = nodes.CoercionNode(node.left, Py_uintptr_t)
            node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)]

        elif node.left.type.is_complex and rhs.type.is_complex:
            real1, imag1 = extract(node.left)
            real2, imag2 = extract(rhs)
            lhs = compare(real1, real2)
            rhs = compare(imag1, imag2)
            result = ast.BoolOp(ast.And(), [lhs, rhs])
            node = nodes.typednode(result, bool_)

        return node
Exemplo n.º 21
0
    def single_compare(self, node):
        rhs = node.comparators[0]

        if is_obj(node.left.type):
            node = self.single_compare_objects(node)

        elif node.left.type.is_pointer and rhs.type.is_pointer:
            # Coerce pointers to integer values before comparing
            node.left = nodes.CoercionNode(node.left, Py_uintptr_t)
            node.comparators = [nodes.CoercionNode(rhs, Py_uintptr_t)]

        elif node.left.type.is_complex and rhs.type.is_complex:
            real1, imag1 = extract(node.left)
            real2, imag2 = extract(rhs)
            lhs = compare(real1, real2)
            rhs = compare(imag1, imag2)
            result = ast.BoolOp(ast.And(), [lhs, rhs])
            node = nodes.typednode(result, bool_)

        return node
Exemplo n.º 22
0
    def lstr(self, types, fmt=None):
        "Get an llvm format string for the given types"
        typestrs = []
        result_types = []
        for type in types:
            if is_obj(type):
                type = object_
            elif type.is_int:
                type = promote_to_native(type)

            result_types.append(type)
            typestrs.append(self.type_to_buildvalue_str[type])

        str = "".join(typestrs)
        if fmt is not None:
            str = fmt % str

        if debug.debug_conversion:
            self.translator.puts("fmt: %s" % str)

        result = self._create_llvm_string(str)
        return result_types, result
Exemplo n.º 23
0
    def lstr(self, types, fmt=None):
        "Get an llvm format string for the given types"
        typestrs = []
        result_types = []
        for type in types:
            if is_obj(type):
                type = object_
            elif type.is_int:
                type = promote_to_native(type)

            result_types.append(type)
            typestrs.append(self.type_to_buildvalue_str[type])

        str = "".join(typestrs)
        if fmt is not None:
            str = fmt % str

        if debug_conversion:
            self.translator.puts("fmt: %s" % str)

        result = self._create_llvm_string(str)
        return result_types, result
Exemplo n.º 24
0
    def visit_Assign(self, node):
        target = node.targets[0]
        target_is_subscript = (len(node.targets) == 1 and
                               isinstance(target, ast.Subscript))
        if target_is_subscript and is_obj(target.type):
            # Slice assignment / index assignment w/ objects
            # TODO: discount array indexing with dtype object
            target = self.visit(target)
            obj = target.value
            key = target.slice
            value = self.visit(node.value)
            call = function_util.external_call(self.context,
                                               self.llvm_module,
                                               'PyObject_SetItem',
                                               args=[obj, key, value])
            return self.visit(call)

        elif target.type.is_struct and nodes.is_name(target):
            node = self.allocate_struct_on_stack(node, target)
            return node

        self.generic_visit(node)
        return node
Exemplo n.º 25
0
    def visit_Assign(self, node):
        target = node.targets[0]
        target_is_subscript = (len(node.targets) == 1
                               and isinstance(target, ast.Subscript))
        if target_is_subscript and is_obj(target.type):
            # Slice assignment / index assignment w/ objects
            # TODO: discount array indexing with dtype object
            target = self.visit(target)
            obj = target.value
            key = target.slice
            value = self.visit(node.value)
            call = function_util.external_call(self.context,
                                               self.llvm_module,
                                               'PyObject_SetItem',
                                               args=[obj, key, value])
            return self.visit(call)

        elif target.type.is_struct and nodes.is_name(target):
            node = self.allocate_struct_on_stack(node, target)
            return node

        self.generic_visit(node)
        return node
Exemplo n.º 26
0
    def visit_CoercionNode(self, node):
        if not isinstance(node, nodes.CoercionNode):
            # CoercionNode.__new__ returns the node to be coerced if it doesn't
            # need coercion
            return node

        node_type = node.node.type
        dst_type = node.dst_type
        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('coercion: %s --> %s\n%s', node_type, dst_type,
                         utils.pformat_ast(node))

        if self.nopython and (is_obj(node_type) ^ is_obj(dst_type)):
            raise error.NumbaError(
                node, "Cannot coerce to or from object in "
                "nopython context")

        if is_obj(node.dst_type) and not is_obj(node_type):
            node = nodes.ObjectTempNode(
                nodes.CoerceToObject(node.node, node.dst_type, name=node.name))
            result = self.visit(node)
        elif is_obj(node_type) and not is_obj(node.dst_type):
            node = nodes.CoerceToNative(node.node,
                                        node.dst_type,
                                        name=node.name)
            result = self.visit(node)
        elif node_type.is_null:
            if not dst_type.is_pointer:
                raise error.NumbaError(
                    node.node, "NULL must be cast or implicitly "
                    "coerced to a pointer type")
            result = self.visit(nodes.NULL.coerce(dst_type))
        elif node_type.is_numeric and dst_type.is_bool:
            to_bool = ast.Compare(node.node, [ast.NotEq()],
                                  [nodes.const(0, node_type)])
            to_bool = nodes.typednode(to_bool, bool_)
            result = self.visit(to_bool)
        elif node_type.is_c_string and dst_type.is_numeric:
            # TODO: int <-> string conversions are explicit, this should not
            # TODO: be a coercion
            if self.nopython:
                node = nodes.CoercionNode(
                    function_util.external_call(
                        self.context,
                        self.llvm_module,
                        ('atol' if dst_type.is_int else 'atof'),
                        args=[node.node]),
                    dst_type,
                    name=node.name,
                )
            else:
                if dst_type.is_int:
                    cvtobj = function_util.external_call(
                        self.context,
                        self.llvm_module,
                        'PyInt_FromString' if not PY3 else 'PyLong_FromString',
                        args=[node.node, nodes.NULL,
                              nodes.const(10, int_)])
                else:
                    cvtobj = function_util.external_call(
                        self.context,
                        self.llvm_module,
                        'PyFloat_FromString',
                        args=[node.node, nodes.const(0, Py_ssize_t)])
                node = nodes.CoerceToNative(nodes.ObjectTempNode(cvtobj),
                                            dst_type,
                                            name=node.name)
            result = self.visit(node)
        else:
            self.generic_visit(node)

            if dst_type == node.node.type:
                result = node.node
            else:
                result = node

        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('result = %s', utils.pformat_ast(result))

        return result
Exemplo n.º 27
0
def build_wrapper_function_ast(env, wrapper_lfunc, llvm_module):
    """
    Build AST for LLVM function wrapper.

        lfunc: LLVM function to wrap
        llvm_module: module the wrapper is being defined in

    The resulting AST has a NativeCallNode to the wrapped function. The
    arguments are  LLVMValueRefNode nodes which still need their llvm_value
    set to the object from the tuple. This happens in visit_FunctionWrapperNode
    during codegen.
    """
    func = env.crnt.func
    func_signature = env.crnt.func_signature
    func_name = env.crnt.func_name

    # Insert external declaration
    lfunc = llvm_module.get_or_insert_function(
        func_signature.to_llvm(env.context),
        env.crnt.lfunc.name)

    # Build AST
    wrapper = nodes.FunctionWrapperNode(lfunc,
                                        func_signature,
                                        func,
                                        fake_pyfunc,
                                        func_name)

    error_return = ast.Return(nodes.CoercionNode(nodes.NULL_obj,
                                                 object_))

    is_closure = bool(closures.is_closure_signature(func_signature))
    nargs = len(func_signature.args) - is_closure

    # Call wrapped function with unpacked object arguments
    # (delay actual arguments)
    args = [nodes.LLVMValueRefNode(object_, None)
                for i in range(nargs)]

    if is_closure:
        # Insert m_self as scope argument type
        closure_scope = get_closure_scope(func_signature, wrapper_lfunc.args[0])
        args.insert(0, closure_scope)

    func_call = nodes.NativeCallNode(func_signature, args, lfunc)

    if not is_obj(func_signature.return_type):
        # Check for error using PyErr_Occurred()
        func_call = nodes.PyErr_OccurredNode(func_call)

    # Coerce and return result
    if func_signature.return_type.is_void:
        wrapper.body = func_call
        result_node = nodes.ObjectInjectNode(None)
    else:
        wrapper.body = None
        result_node = func_call

    wrapper.return_result = ast.Return(value=nodes.CoercionNode(result_node,
                                                                object_))

    # Update wrapper
    wrapper.error_return = error_return
    wrapper.cellvars = []

    wrapper.wrapped_nargs = nargs
    wrapper.wrapped_args = args[is_closure:]

    return wrapper
Exemplo n.º 28
0
    def visit_CoercionNode(self, node):
        if not isinstance(node, nodes.CoercionNode):
            # CoercionNode.__new__ returns the node to be coerced if it doesn't
            # need coercion
            return node

        node_type = node.node.type
        dst_type = node.dst_type
        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('coercion: %s --> %s\n%s',
                         node_type, dst_type, utils.pformat_ast(node))

        if self.nopython and is_obj(node_type):
            raise error.NumbaError(node, "Cannot coerce to or from object in "
                                         "nopython context")

        if is_obj(node.dst_type) and not is_obj(node_type):
            node = nodes.ObjectTempNode(nodes.CoerceToObject(
                    node.node, node.dst_type, name=node.name))
            result = self.visit(node)
        elif is_obj(node_type) and not is_obj(node.dst_type):
            node = nodes.CoerceToNative(node.node, node.dst_type,
                                        name=node.name)
            result = self.visit(node)
        elif node_type.is_null:
            if not dst_type.is_pointer:
                raise error.NumbaError(node.node,
                                       "NULL must be cast or implicitly "
                                       "coerced to a pointer type")
            result = self.visit(nodes.NULL.coerce(dst_type))
        elif node_type.is_numeric and dst_type.is_bool:
            to_bool = ast.Compare(node.node, [ast.NotEq()],
                                  [nodes.const(0, node_type)])
            to_bool = nodes.typednode(to_bool, bool_)
            result = self.visit(to_bool)
        elif node_type.is_c_string and dst_type.is_numeric:
            # TODO: int <-> string conversions are explicit, this should not
            # TODO: be a coercion
            if self.nopython:
                node = nodes.CoercionNode(
                    function_util.external_call(
                                self.context,
                                self.llvm_module,
                                ('atol' if dst_type.is_int else 'atof'),
                                args=[node.node]),
                    dst_type, name=node.name,)
            else:
                if dst_type.is_int:
                    cvtobj = function_util.external_call(
                                              self.context,
                                              self.llvm_module,
                                              'PyInt_FromString' if not PY3 else 'PyLong_FromString',
                                              args=[node.node, nodes.NULL,
                                                    nodes.const(10, int_)])
                else:
                    cvtobj = function_util.external_call(
                                          self.context,
                                          self.llvm_module,
                                          'PyFloat_FromString',
                                          args=[node.node,
                                                nodes.const(0, Py_ssize_t)])
                node = nodes.CoerceToNative(nodes.ObjectTempNode(cvtobj),
                                            dst_type, name=node.name)
            result = self.visit(node)
        else:
            self.generic_visit(node)

            if dst_type == node.node.type:
                result = node.node
            else:
                result = node

        if __debug__ and self.env and self.env.debug_coercions:
            logger.debug('result = %s', utils.pformat_ast(result))

        return result