def inject_print(context, module, node): node = function_util.external_call(context, module, 'PyObject_Str', args=[node]) node = function_util.external_call(context, module, 'puts', args=[node]) return node
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 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
def _object_Pow(self, node): args = [node.left, node.right, nodes.ObjectInjectNode(None)] return self.visit(function_util.external_call(self.context, self.llvm_module, 'PyNumber_Power', args=args), llvm_module=self.llvm_module)
def _object_binop(self, node, api_name): return self.visit( function_util.external_call(self.context, self.llvm_module, api_name, args=[node.left, node.right]))
def getiter(self, context, for_node, llvm_module): iterator = function_util.external_call(context, llvm_module, self.getiter_func, args=[for_node.iter]) iterator = nodes.CloneableNode(iterator) self.iterator = iterator.clone return iterator
def visit_Slice(self, node): """ Rewrite slice objects. Do this late in the pipeline so that other code can still recognize the code structure. """ slice_values = [node.lower, node.upper, node.step] if self.nopython: raise error.NumbaError(node, "Cannot slice in nopython context") if node.variable.is_constant: return self.visit(nodes.ObjectInjectNode(node.variable.constant_value)) bounds = [] for node in slice_values: if node is None: bounds.append(nodes.NULL_obj) else: bounds.append(node) new_slice = function_util.external_call(self.context, self.llvm_module, 'PySlice_New', args=bounds, temp_name='slice') return self.visit(new_slice)
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
def visit_Slice(self, node): """ Rewrite slice objects. Do this late in the pipeline so that other code can still recognize the code structure. """ slice_values = [node.lower, node.upper, node.step] if self.nopython: raise error.NumbaError(node, "Cannot slice in nopython context") if node.variable.is_constant: return self.visit( nodes.ObjectInjectNode(node.variable.constant_value)) bounds = [] for node in slice_values: if node is None: bounds.append(nodes.NULL_obj) else: bounds.append(node) new_slice = function_util.external_call(self.context, self.llvm_module, 'PySlice_New', args=bounds, temp_name='slice') return self.visit(new_slice)
def visit_CoerceToObject(self, node): new_node = node node_type = node.node.type if node_type.is_bool: new_node = function_util.external_call(self.context, self.llvm_module, "PyBool_FromLong", args=[node.node]) elif node_type.is_numeric: cls = None args = node.node, if node_type.is_int: cls = self._get_int_conversion_func(node_type, pyapi._from_long) elif node_type.is_float: cls = pyapi.PyFloat_FromDouble elif node_type.is_complex: cls = pyapi.PyComplex_FromDoubles complex_value = nodes.CloneableNode(node.node) args = [ nodes.ComplexAttributeNode(complex_value, "real"), nodes.ComplexAttributeNode(complex_value.clone, "imag") ] else: raise error.NumbaError( node, "Don't know how to coerce type %r to PyObject" % node_type) if cls: new_node = function_util.external_call(self.context, self.llvm_module, cls.__name__, args=args) elif node_type.is_pointer and not node_type.is_string(): # Create ctypes pointer object ctypes_pointer_type = node_type.to_ctypes() args = [ nodes.CoercionNode(node.node, int64), nodes.ObjectInjectNode(ctypes_pointer_type, object_) ] new_node = nodes.call_pyfunc(ctypes.cast, args) self.generic_visit(new_node) return new_node
def _raise_exception(self, body, node): if node.exc_type: assert node.exc_msg if node.exc_args: args = [node.exc_type, node.exc_msg] + node.exc_args raise_node = function_util.external_call(self.context, self.llvm_module, 'PyErr_Format', args=args) else: args = [node.exc_type, node.exc_msg] raise_node = function_util.external_call(self.context, self.llvm_module, 'PyErr_SetString', args=args) body.append(raise_node)
def _object_Not(self, node): callnode = function_util.external_call(self.function_cache, self.llvm_module, 'PyObject_IsTrue', args=[node.operand]) cmpnode = ast.Compare(callnode, [nodes.Eq()], [nodes.ConstNode(0)]) return self.visit( nodes.IfExp(cmpnode, nodes.ObjectInjectNode(True), nodes.ObjectInjectNode(False)))
def _object_Not(self, node): callnode = function_util.external_call(self.function_cache, self.llvm_module, 'PyObject_IsTrue', args=[node.operand]) cmpnode = ast.Compare(callnode, [nodes.Eq()], [nodes.ConstNode(0)]) return self.visit(nodes.IfExp(cmpnode, nodes.ObjectInjectNode(True), nodes.ObjectInjectNode(False)))
def visit_PyErr_OccurredNode(self, node): check_err = nodes.CheckErrorNode(nodes.ptrtoint( function_util.external_call(self.context, self.llvm_module, 'PyErr_Occurred')), goodval=nodes.ptrtoint(nodes.NULL)) result = nodes.CloneableNode(node.node) result = nodes.ExpressionNode(stmts=[result, check_err], expr=result.clone) return self.visit(result)
def visit_CoerceToObject(self, node): new_node = node node_type = node.node.type if node_type.is_numeric: cls = None args = node.node, if node_type.is_int: cls = self._get_int_conversion_func(node_type, pyapi._from_long) elif node_type.is_float: cls = pyapi.PyFloat_FromDouble elif node_type.is_complex: cls = pyapi.PyComplex_FromDoubles complex_value = nodes.CloneableNode(node.node) args = [ nodes.ComplexAttributeNode(complex_value, "real"), nodes.ComplexAttributeNode(complex_value.clone, "imag") ] else: raise error.NumbaError( node, "Don't know how to coerce type %r to PyObject" % node_type) if cls: new_node = function_util.external_call(self.context, self.llvm_module, cls.__name__, args=args) elif node_type.is_pointer and not node_type.is_string(): # Create ctypes pointer object ctypes_pointer_type = node_type.to_ctypes() args = [nodes.CoercionNode(node.node, int64), nodes.ObjectInjectNode(ctypes_pointer_type, object_)] new_node = nodes.call_pyfunc(ctypes.cast, args) elif node_type.is_bool: new_node = function_util.external_call(self.context, self.llvm_module, "PyBool_FromLong", args=[node.node]) self.generic_visit(new_node) return new_node
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_c_string: return nodes.CoercionNode(nodes.ObjectTempNode( function_util.external_call(self.context, self.llvm_module, ext_name, args=[arg1, nodes.NULL, arg2])), dst_type=dst_type)
def visit_PyErr_OccurredNode(self, node): check_err = nodes.CheckErrorNode( nodes.ptrtoint(function_util.external_call( self.context, self.llvm_module, 'PyErr_Occurred')), goodval=nodes.ptrtoint(nodes.NULL)) result = nodes.CloneableNode(node.node) result = nodes.ExpressionNode(stmts=[result, check_err], expr=result.clone) return self.visit(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_c_string: return nodes.CoercionNode( nodes.ObjectTempNode( function_util.external_call( self.context, self.llvm_module, ext_name, args=[arg1, nodes.NULL, arg2])), dst_type=dst_type)
def _print(self, value, dest=None): signature, lfunc = self.context.external_library.declare( self.llvm_module, 'PyObject_CallMethod') if dest is None: dest = nodes.ObjectInjectNode(sys.stdout) value = function_util.external_call(self.context, self.llvm_module, "PyObject_Str", args=[value]) args = [dest, nodes.ConstNode("write"), nodes.ConstNode("O"), value] return nodes.NativeCallNode(signature, args, lfunc)
def single_compare_objects(self, node): op = type(node.ops[0]) if op not in opmap: raise error.NumbaError( node, "%s comparisons not yet implemented" % (op,)) # Build arguments for PyObject_RichCompareBool operator = nodes.const(opmap[op], int_) args = [node.left, node.comparators[0], operator] # Call PyObject_RichCompareBool compare = function_util.external_call(self.context, self.llvm_module, 'PyObject_RichCompareBool', args=args) # Coerce int result to bool return nodes.CoercionNode(compare, bool_)
def single_compare_objects(self, node): op = type(node.ops[0]) if op not in opmap: raise error.NumbaError( node, "%s comparisons not yet implemented" % (op, )) # Build arguments for PyObject_RichCompareBool operator = nodes.const(opmap[op], int_) args = [node.left, node.comparators[0], operator] # Call PyObject_RichCompareBool compare = function_util.external_call(self.context, self.llvm_module, 'PyObject_RichCompare', args=args) # Coerce int result to bool return nodes.CoercionNode(compare, node.type)
def _print_nopython(self, value, dest=None): if dest is not None: raise error.NumbaError(dest, "No file may be given in nopython mode") # stdin, stdout, stderr = stdio_util.get_stdio_streams() # stdout = stdio_util.get_stream_as_node(stdout) format = codegen.get_printf_specifier(value.type) if format is None: raise error.NumbaError( value, "Printing values of type '%s' is not supported " "in nopython mode" % (value.type,)) return function_util.external_call( self.context, self.llvm_module, 'printf', args=[nodes.const(format, c_string_type), value])
def _print_nopython(self, value, dest=None): if dest is not None: raise error.NumbaError(dest, "No file may be given in nopython mode") # stdin, stdout, stderr = stdio_util.get_stdio_streams() # stdout = stdio_util.get_stream_as_node(stdout) format = codegen.get_printf_specifier(value.type) if format is None: raise error.NumbaError( value, "Printing values of type '%s' is not supported " "in nopython mode" % (value.type, )) return function_util.external_call( self.context, self.llvm_module, 'printf', args=[nodes.const(format, c_string_type), value])
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_string and node.type.is_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 and not node_type.is_array) 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_string and node.type.is_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 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 _resolve_abs(self, func, node, argtype): is_math = is_math_function(node.args, abs) # TODO: generate efficient inline code if is_math and argtype.is_float: return resolve_math_call(node, abs) elif is_math and argtype.is_int: if argtype.signed: type = promote_closest(self.context, argtype, [long_, longlong]) funcs = {long_: 'labs', longlong: 'llabs'} return function_util.external_call( self.context, self.llvm_module, funcs[type], args=[node.args[0]]) else: # abs() on unsigned integral value return node.args[0] return None
def _resolve_abs(self, func, node, argtype): is_math = is_math_function(node.args, abs) # TODO: generate efficient inline code if is_math and argtype.is_float: return resolve_math_call(node, abs) elif is_math and argtype.is_int: if argtype.signed: type = promote_closest(self.context, argtype, [long_, longlong]) funcs = {long_: 'labs', longlong: 'llabs'} return function_util.external_call(self.context, self.llvm_module, funcs[type], args=[node.args[0]]) else: # abs() on unsigned integral value return node.args[0] return None
def _trap(self, body, node): if node.exc_msg and node.print_on_trap: pos = error.format_pos(node) if node.exception_type: exc_type = '%s: ' % node.exception_type.__name__ else: exc_type = '' msg = '%s%s%%s' % (exc_type, pos) format = nodes.const(msg, c_string_type) print_msg = function_util.external_call(self.context, self.llvm_module, 'printf', args=[format, node.exc_msg]) body.append(print_msg) trap = nodes.LLVMIntrinsicNode(signature=void(), args=[], func_name='TRAP') body.append(trap)
def _trap(self, body, node): if node.exc_msg and node.print_on_trap: pos = error.format_pos(node) if node.exception_type: exc_type = '%s: ' % node.exception_type.__name__ else: exc_type = '' msg = '%s%s%%s' % (exc_type, pos) format = nodes.const(msg, c_string_type) print_msg = function_util.external_call( self.context, self.llvm_module, 'printf', args=[format, node.exc_msg]) body.append(print_msg) trap = nodes.LLVMIntrinsicNode(signature=void(), args=[], func_name='TRAP') body.append(trap)
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
def next(self, context, for_node, llvm_module): return function_util.external_call(context, llvm_module, self.next_func, args=[self.iterator])
def inject_print(context, module, node): node = function_util.external_call(context, module, "PyObject_Str", args=[node]) node = function_util.external_call(context, module, "puts", args=[node]) return node
def _object_unaryop(self, node, api_name): return self.visit( function_util.external_call(self.context, self.llvm_module, api_name, args=[node.operand]))
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
def visit_CoerceToNative(self, node): """ Try to perform fast coercion using e.g. PyLong_AsLong(), with a fallback to PyArg_ParseTuple(). """ new_node = None from_type = node.node.type node_type = node.type if node_type.is_numeric: cls = None if node_type == size_t: node_type = ulonglong if node_type.is_int: # and not new_node = self.object_to_int(node.node, node_type) elif node_type.is_float: cls = pyapi.PyFloat_AsDouble elif node_type.is_complex: # FIXME: This conversion has to be pretty slow. We # need to move towards being ABI-savvy enough to just # call PyComplex_AsCComplex(). cloneable = nodes.CloneableNode(node.node) new_node = nodes.ComplexNode( real=function_util.external_call(self.context, self.llvm_module, "PyComplex_RealAsDouble", args=[cloneable]), imag=function_util.external_call(self.context, self.llvm_module, "PyComplex_ImagAsDouble", args=[cloneable.clone])) else: raise error.NumbaError( node, "Don't know how to coerce a Python object to a %r" % node_type) if cls: # TODO: error checking! new_node = function_util.external_call(self.context, self.llvm_module, cls.__name__, args=[node.node]) elif node_type.is_pointer: if from_type.is_jit_function and node_type.base_type.is_function: new_node = self.coerce_to_function_pointer( node, from_type, node_type) else: raise error.NumbaError( node, "Obtaining pointers from objects " "is not yet supported") elif node_type.is_void: raise error.NumbaError(node, "Cannot coerce %s to void" % (from_type, )) if new_node is None: # Create a tuple for PyArg_ParseTuple new_node = node new_node.node = ast.Tuple(elts=[node.node], ctx=ast.Load()) self.generic_visit(node) return node if new_node.type != node.type: # Fast native coercion. E.g. coercing an object to an int_ # will use PyLong_AsLong, but that will return a long_. We # need to coerce the long_ to an int_ new_node = nodes.CoercionNode(new_node, node.type) # Specialize replacement node new_node = self.visit(new_node) return new_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
def visit_CoerceToNative(self, node): """ Try to perform fast coercion using e.g. PyLong_AsLong(), with a fallback to PyArg_ParseTuple(). """ new_node = None from_type = node.node.type node_type = node.type if node_type.is_numeric: cls = None if node_type == size_t: node_type = ulonglong if node_type.is_int: # and not new_node = self.object_to_int(node.node, node_type) elif node_type.is_float: cls = pyapi.PyFloat_AsDouble elif node_type.is_complex: # FIXME: This conversion has to be pretty slow. We # need to move towards being ABI-savvy enough to just # call PyComplex_AsCComplex(). cloneable = nodes.CloneableNode(node.node) new_node = nodes.ComplexNode( real=function_util.external_call( self.context, self.llvm_module, "PyComplex_RealAsDouble", args=[cloneable]), imag=function_util.external_call( self.context, self.llvm_module, "PyComplex_ImagAsDouble", args=[cloneable.clone])) else: raise error.NumbaError( node, "Don't know how to coerce a Python object to a %r" % node_type) if cls: # TODO: error checking! new_node = function_util.external_call(self.context, self.llvm_module, cls.__name__, args=[node.node]) elif node_type.is_pointer and not node_type.is_string: if from_type.is_jit_function and node_type.base_type.is_function: new_node = self.coerce_to_function_pointer( node, from_type, node_type) else: raise error.NumbaError(node, "Obtaining pointers from objects " "is not yet supported (%s)" % node_type) elif node_type.is_void: raise error.NumbaError(node, "Cannot coerce %s to void" % (from_type,)) if new_node is None: # Create a tuple for PyArg_ParseTuple new_node = node new_node.node = ast.Tuple(elts=[node.node], ctx=ast.Load()) self.generic_visit(node) return node if new_node.type != node.type: # Fast native coercion. E.g. coercing an object to an int_ # will use PyLong_AsLong, but that will return a long_. We # need to coerce the long_ to an int_ new_node = nodes.CoercionNode(new_node, node.type) # Specialize replacement node new_node = self.visit(new_node) return new_node