def visit_ArrayNewNode(self, node): if self.nopython: raise error.NumbaError( node, "Cannot yet allocate new array in nopython context") PyArray_Type = nodes.ObjectInjectNode(np.ndarray) descr = nodes.ObjectInjectNode(node.type.dtype.get_dtype()).cloneable ndim = nodes.const(node.type.ndim, int_) flags = nodes.const(0, int_) args = [PyArray_Type, descr.clone, ndim, node.shape, node.strides, node.data, flags] incref_descr = nodes.IncrefNode(descr) incref_base = None setbase = None if node.base is None: args.append(nodes.NULL_obj) else: base = nodes.CloneableNode(node.base) incref_base = nodes.IncrefNode(base) args.append(base.clone) array = nodes.PyArray_NewFromDescr(args) array = nodes.ObjectTempNode(array).cloneable body = [incref_descr, incref_base, array, setbase] if node.base is not None: body.append(nodes.PyArray_SetBaseObject([array.clone, base.clone])) # TODO: PyArray_UpdateFlags() result = nodes.ExpressionNode(filter(None, body), array.clone) return self.visit(result)
def str_to_int(self, dst_type, node): # 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) return result
def _resolve_int_number(self, func, node, argtype, dst_type, ext_name): assert len(node.args) == 2 arg1, arg2 = node.args if arg1.variable.type.is_string: return nodes.CoercionNode(nodes.ObjectTempNode( self.external_call(ext_name, args=[arg1, nodes.NULL, arg2])), dst_type=dst_type)
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
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
def visit_Tuple(self, node): self.check_context(node) sig, lfunc = self.context.external_library.declare( self.llvm_module, 'PyTuple_Pack') objs = self.visitlist(nodes.CoercionNode.coerce(node.elts, object_)) n = nodes.ConstNode(len(node.elts), minitypes.Py_ssize_t) args = [n] + objs new_node = nodes.NativeCallNode(sig, args, lfunc, name='tuple') # TODO: determine element type of node.elts new_node.type = typesystem.TupleType(object_, size=len(node.elts)) return nodes.ObjectTempNode(new_node)
def visit_ArrayNewEmptyNode(self, node): if self.nopython: raise error.NumbaError( node, "Cannot yet allocate new empty array in nopython context") ndim = nodes.const(node.type.ndim, int_) dtype = nodes.const(node.type.dtype.get_dtype(), object_).cloneable is_fortran = nodes.const(node.is_fortran, int_) result = nodes.PyArray_Empty([ndim, node.shape, dtype, is_fortran]) result = nodes.ObjectTempNode(result) incref_descr = nodes.IncrefNode(dtype) return self.visit(nodes.ExpressionNode([incref_descr], result))
def visit_ObjectCallNode(self, node): # self.generic_visit(node) assert node.function if self.nopython: meth_name = node.name and ' (%r)' % node.name raise error.NumbaError(node, "Cannot use object call in " "nopython context" + meth_name) node.function = self.visit(node.function) node.args_tuple = self.visit(node.args_tuple) node.kwargs_dict = self.visit(node.kwargs_dict) return nodes.ObjectTempNode(node)
def visit_Subscript(self, node): if isinstance(node.value, nodes.ArrayAttributeNode): if node.value.is_read_only and isinstance(node.ctx, ast.Store): raise error.NumbaError("Attempt to load read-only attribute") # Short-circuit visiting a Slice child if this is a nopython # string slice. if (self.nopython and node.value.type.is_c_string and node.type.is_c_string): return self.visit(self._c_string_slice(node)) # logging.debug(ast.dump(node)) # TODO: do this in the respective cases below when needed self.generic_visit(node) node_type = node.value.type if node_type.is_object or (node_type.is_array and node.slice.type.is_object): # Array or object slicing if isinstance(node.ctx, ast.Load): result = function_util.external_call( self.context, self.llvm_module, 'PyObject_GetItem', args=[node.value, node.slice]) node = nodes.CoercionNode(result, dst_type=node.type) node = self.visit(node) else: # This is handled in visit_Assign pass elif (node.value.type.is_array and not node.type.is_array and node.slice.type.is_int): # Array index with integer indices node = nodes.DataPointerNode(node.value, node.slice, node.ctx) elif node.value.type.is_c_string and node.type.is_c_string: node.value = nodes.CoercionNode(node.value, dst_type=object_) node.type = object_ node = nodes.CoercionNode(nodes.ObjectTempNode(node), dst_type=c_string_type) node = self.visit(node) return node
def register_array_expression(self, node, lhs=None): super(ArrayExpressionRewriteUfunc, self).register_array_expression(node, lhs) py_ufunc, signature, ufunc_builder = self.get_py_ufunc(lhs, node) # Vectorize Python function vectorizer = self.vectorizer_cls(py_ufunc) vectorizer.add(restype=signature.return_type, argtypes=signature.args) ufunc = vectorizer.build_ufunc() # Call ufunc args = ufunc_builder.operands if lhs is None: keywords = None else: keywords = [ast.keyword('out', lhs)] func = nodes.ObjectInjectNode(ufunc) call_ufunc = nodes.ObjectCallNode(signature=None, func=func, args=args, keywords=keywords, py_func=ufunc) return nodes.ObjectTempNode(call_ufunc)
def visit_ArrayNewNode(self, node): if self.nopython: # Give the codegen (subclass) a chance to handle this self.generic_visit(node) return node PyArray_Type = nodes.ObjectInjectNode(np.ndarray) descr = nodes.ObjectInjectNode(node.type.dtype.get_dtype()).cloneable ndim = nodes.const(node.type.ndim, int_) flags = nodes.const(0, int_) args = [ PyArray_Type, descr.clone, ndim, node.shape, node.strides, node.data, flags ] incref_descr = nodes.IncrefNode(descr) incref_base = None setbase = None if node.base is None: args.append(nodes.NULL_obj) else: base = nodes.CloneableNode(node.base) incref_base = nodes.IncrefNode(base) args.append(base.clone) array = nodes.PyArray_NewFromDescr(args) array = nodes.ObjectTempNode(array).cloneable body = [incref_descr, incref_base, array, setbase] if node.base is not None: body.append(nodes.PyArray_SetBaseObject([array.clone, base.clone])) # TODO: PyArray_UpdateFlags() result = nodes.ExpressionNode(filter(None, body), array.clone) return self.visit(result)
def visit_Dict(self, node): self.check_context(node) self.generic_visit(node) return nodes.ObjectTempNode(node)
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