def handle_unpacking_varargs(func, py_func, argtypes): """ Handle unpacking of varargs: f(10, *args) ^^^^^ We assume that unpacking consumes all positional arguments, i.e. we do not support shenanigans such as the following: def f(a, b=2, c=3): ... f(1, *(4,)) To support that we'd have to call a wrapper function, that takes a tuple and supplies missing defaults dynamically. """ argspec = inspect.getargspec(py_func) tuple_type = argtypes[-1] argtypes = argtypes[:-1] missing = compute_missing(py_func, argtypes) # Extract remaining argument types remaining = extract_tuple_eltypes(tuple_type, missing) if len(remaining) > missing and not argspec.varargs: raise TypeError( "Too many arguments supplied to function %s: %s %s %s" % ( py_func, argtypes, remaining, missing)) return tuple(argtypes) + tuple(remaining)
def handle_unpacking_varargs(func, py_func, argtypes): """ Handle unpacking of varargs: f(10, *args) ^^^^^ We assume that unpacking consumes all positional arguments, i.e. we do not support shenanigans such as the following: def f(a, b=2, c=3): ... f(1, *(4,)) To support that we'd have to call a wrapper function, that takes a tuple and supplies missing defaults dynamically. """ argspec = inspect.getargspec(py_func) tuple_type = argtypes[-1] argtypes = argtypes[:-1] missing = compute_missing(py_func, argtypes) # Extract remaining argument types remaining = extract_tuple_eltypes(tuple_type, missing) if len(remaining) > missing and not argspec.varargs: raise TypeError( "Too many arguments supplied to function %s: %s %s %s" % (py_func, argtypes, remaining, missing)) return tuple(argtypes) + tuple(remaining)
def f(context, py_func, f_env, op): f, args = op.args flags = call_flags.get(op, {}) if not flags.get('varargs'): return # Unpack positional and varargs argument # For f(x, *args): positional = [x], varargs = args positional, varargs = args[:-1], args[-1] varargs_type = context[varargs] # Missing number of positional arguments (int) missing = compute_missing(py_func, positional) # Types in the tuple, may be heterogeneous eltypes = extract_tuple_eltypes(varargs_type, missing) # Now supply the missing positional arguments b.position_before(op) for i, argty in zip(range(missing), eltypes): idx = OConst(i) context[idx] = types.int32 #hd = b.getfield(ptypes.Opaque, varargs, 'hd') #tl = b.getfield(ptypes.Opaque, varargs, 'tl') positional_arg = caller.call(phase.typing, primitives.getitem, [varargs, idx]) positional.append(positional_arg) # TODO: For GenericTuple unpacking, assure that # len(remaining_tuple) == missing if len(eltypes) > missing: # In case we have more element types than positional parameters, # we must have a function that takes varargs, e.g. # # def f(x, y, *args): # ... # # That we call as follows (for example): # # f(x, *args) idx = OConst(missing) context[idx] = types.int32 argstup = caller.call(phase.typing, slicetuple, [varargs, idx]) positional.append(argstup) # Update with new positional arguments op.set_args([f, positional])
def f(context, py_func, f_env, op): f, args = op.args flags = call_flags.get(op, {}) if not flags.get('varargs'): return # Unpack positional and varargs argument # For f(x, *args): positional = [x], varargs = args positional, varargs = args[:-1], args[-1] varargs_type = context[varargs] # Missing number of positional arguments (int) missing = compute_missing(py_func, positional) # Types in the tuple, may be heterogeneous eltypes = extract_tuple_eltypes(varargs_type, missing) # Now supply the missing positional arguments b.position_before(op) for i, argty in zip(range(missing), eltypes): idx = OConst(i) context[idx] = types.int32 #hd = b.getfield(ptypes.Opaque, varargs, 'hd') #tl = b.getfield(ptypes.Opaque, varargs, 'tl') positional_arg = caller.call(phase.typing, primitives.getitem, [varargs, idx]) positional.append(positional_arg) # TODO: For GenericTuple unpacking, assure that # len(remaining_tuple) == missing if len(eltypes) > missing: # In case we have more element types than positional parameters, # we must have a function that takes varargs, e.g. # # def f(x, y, *args): # ... # # That we call as follows (for example): # # f(x, *args) idx = OConst(missing) context[idx] = types.int32 argstup = caller.call(phase.typing, slicetuple, [varargs, idx]) positional.append(argstup) # Update with new positional arguments op.set_args([f, positional])