def generic(self, args, kws): assert not kws [it] = args if isinstance(it, types.IteratorType): return signature(types.Pair(it.yield_type, types.boolean), it)
def lower_expr(self, resty, expr): if expr.op == 'binop': return self.lower_binop(resty, expr) elif expr.op == 'inplace_binop': lty = self.typeof(expr.lhs.name) if not lty.mutable: # inplace operators on non-mutable types reuse the same # definition as the corresponding copying operators. return self.lower_binop(resty, expr) elif expr.op == 'unary': val = self.loadvar(expr.value.name) typ = self.typeof(expr.value.name) # Get function signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.fn, signature) # Convert argument to match val = self.context.cast(self.builder, val, typ, signature.args[0]) res = impl(self.builder, [val]) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'call': signature = self.fndesc.calltypes[expr] if isinstance(expr.func, ir.Intrinsic): fnty = expr.func.name castvals = expr.func.args else: fnty = self.typeof(expr.func.name) if expr.kws: # Fold keyword arguments try: pysig = fnty.pysig except AttributeError: raise NotImplementedError("unsupported keyword arguments " "when calling %s" % (fnty,)) ba = pysig.bind(*expr.args, **dict(expr.kws)) assert not ba.kwargs args = ba.args else: args = expr.args argvals = [self.loadvar(a.name) for a in args] argtyps = [self.typeof(a.name) for a in args] castvals = [self.context.cast(self.builder, av, at, ft) for av, at, ft in zip(argvals, argtyps, signature.args)] if isinstance(fnty, types.ExternalFunction): # Handle a named external function fndesc = ExternalFunctionDescriptor( fnty.symbol, fnty.sig.return_type, fnty.sig.args) func = self.context.declare_external_function( cgutils.get_module(self.builder), fndesc) res = self.context.call_external_function( self.builder, func, fndesc.argtypes, castvals) elif isinstance(fnty, types.Method): # Method of objects are handled differently fnobj = self.loadvar(expr.func.name) res = self.context.call_class_method(self.builder, fnobj, signature, castvals) elif isinstance(fnty, types.FunctionPointer): # Handle a C function pointer pointer = fnty.funcptr res = self.context.call_function_pointer(self.builder, pointer, signature, castvals, fnty.cconv) else: if isinstance(signature.return_type, types.Phantom): return self.context.get_dummy_value() # Normal function resolution (for Numba-compiled functions) impl = self.context.get_function(fnty, signature) if signature.recvr: # The "self" object is passed as the function object # for bounded function the_self = self.loadvar(expr.func.name) # Prepend the self reference castvals = [the_self] + castvals res = impl(self.builder, castvals) libs = getattr(impl, "libs", ()) for lib in libs: self.library.add_linking_library(lib) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'pair_first': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) item = self.context.pair_first(self.builder, val, ty) return self.context.get_argument_value(self.builder, ty.first_type, item) elif expr.op == 'pair_second': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) item = self.context.pair_second(self.builder, val, ty) return self.context.get_argument_value(self.builder, ty.second_type, item) elif expr.op in ('getiter', 'iternext'): val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function(expr.op, signature) [fty] = signature.args castval = self.context.cast(self.builder, val, ty, fty) res = impl(self.builder, (castval,)) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == 'exhaust_iter': val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) # If we have a heterogenous tuple, we needn't do anything, # and we can't iterate over it anyway. if isinstance(ty, types.Tuple): return val itemty = ty.iterator_type.yield_type tup = self.context.get_constant_undef(resty) pairty = types.Pair(itemty, types.boolean) getiter_sig = typing.signature(ty.iterator_type, ty) getiter_impl = self.context.get_function('getiter', getiter_sig) iternext_sig = typing.signature(pairty, ty.iterator_type) iternext_impl = self.context.get_function('iternext', iternext_sig) iterobj = getiter_impl(self.builder, (val,)) # We call iternext() as many times as desired (`expr.count`). for i in range(expr.count): pair = iternext_impl(self.builder, (iterobj,)) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, self.builder.not_(is_valid)): self.return_exception(ValueError) item = self.context.pair_first(self.builder, pair, pairty) tup = self.builder.insert_value(tup, item, i) # Call iternext() once more to check that the iterator # is exhausted. pair = iternext_impl(self.builder, (iterobj,)) is_valid = self.context.pair_second(self.builder, pair, pairty) with cgutils.if_unlikely(self.builder, is_valid): self.return_exception(ValueError) return tup elif expr.op == "getattr": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) if isinstance(resty, types.BoundFunction): # if we are getting out a method, assume we have typed this # properly and just build a bound function object res = self.context.get_bound_function(self.builder, val, ty) else: impl = self.context.get_attribute(val, ty, expr.attr) if impl is None: # ignore the attribute res = self.context.get_dummy_value() else: res = impl(self.context, self.builder, ty, val, expr.attr) return res elif expr.op == "static_getitem": baseval = self.loadvar(expr.value.name) indexval = self.context.get_constant(types.intp, expr.index) if cgutils.is_struct(baseval.type): # Statically extract the given element from the structure # (structures aren't dynamically indexable). return self.builder.extract_value(baseval, expr.index) else: # Fall back on the generic getitem() implementation # for this type. signature = typing.signature(resty, self.typeof(expr.value.name), types.intp) impl = self.context.get_function("getitem", signature) argvals = (baseval, indexval) res = impl(self.builder, argvals) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == "getitem": baseval = self.loadvar(expr.value.name) indexval = self.loadvar(expr.index.name) signature = self.fndesc.calltypes[expr] impl = self.context.get_function("getitem", signature) argvals = (baseval, indexval) argtyps = (self.typeof(expr.value.name), self.typeof(expr.index.name)) castvals = [self.context.cast(self.builder, av, at, ft) for av, at, ft in zip(argvals, argtyps, signature.args)] res = impl(self.builder, castvals) return self.context.cast(self.builder, res, signature.return_type, resty) elif expr.op == "build_tuple": itemvals = [self.loadvar(i.name) for i in expr.items] itemtys = [self.typeof(i.name) for i in expr.items] castvals = [self.context.cast(self.builder, val, fromty, toty) for val, toty, fromty in zip(itemvals, resty, itemtys)] tup = self.context.get_constant_undef(resty) for i in range(len(castvals)): tup = self.builder.insert_value(tup, castvals[i], i) return tup elif expr.op == "cast": val = self.loadvar(expr.value.name) ty = self.typeof(expr.value.name) castval = self.context.cast(self.builder, val, ty, resty) return castval raise NotImplementedError(expr)