def test_unmatch_signature(self): args = MockArgs([1, 2, 3]) sig = Signature(['a', 'b', 'c'], None, None) data = args.match_signature(sig, []) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = MockArgs([1]) sig = Signature(['a', 'b', 'c'], None, None) data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = MockArgs([1, 2, 3, 4, 5]) sig = Signature(['a', 'b', 'c'], 'r', None) data = args.match_signature(sig, []) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = MockArgs([1], {'c': 3, 'b': 2}) sig = Signature(['a', 'b', 'c'], None, None) data = args.match_signature(sig, []) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack() args = MockArgs([1], {'c': 5}) sig = Signature(['a', 'b', 'c'], None, None) data = args.match_signature(sig, [2, 3]) new_args = args.unmatch_signature(sig, data) assert args.unpack() == new_args.unpack()
def builder(translator, func): # build a hacked graph that doesn't take a *arg any more, but # individual extra arguments graph = translator.buildflowgraph(func) argnames, vararg, kwarg = graph.signature assert vararg, "graph should have a *arg at this point" assert not kwarg, "where does this **arg come from??" argscopy = [Variable(v) for v in graph.getargs()] starargs = [ Variable('stararg%d' % i) for i in range(nb_extra_args) ] newstartblock = Block(argscopy[:-1] + starargs) newtup = op.newtuple(*starargs) newtup.result = argscopy[-1] newstartblock.operations.append(newtup) newstartblock.closeblock(Link(argscopy, graph.startblock)) graph.startblock = newstartblock argnames = argnames + ['.star%d' % i for i in range(nb_extra_args)] graph.signature = Signature(argnames) # note that we can mostly ignore defaults: if nb_extra_args > 0, # then defaults aren't applied. if nb_extra_args == 0, then this # just removes the *arg and the defaults keep their meaning. if nb_extra_args > 0: graph.defaults = None # shouldn't be used in this case checkgraph(graph) return graph
def __init__(self, bookkeeper, pyobj=None, name=None, signature=None, defaults=None, specializer=None): super(FunctionDesc, self).__init__(bookkeeper, pyobj) if name is None: name = pyobj.func_name if signature is None: if hasattr(pyobj, '_generator_next_method_of_'): from rpython.flowspace.argument import Signature signature = Signature(['entry']) # haaaaaack defaults = () else: signature = cpython_code_signature(pyobj.func_code) if defaults is None: defaults = pyobj.func_defaults self.name = name self.signature = signature self.defaults = defaults or () # 'specializer' is a function with the following signature: # specializer(funcdesc, args_s) => graph # or => s_result (overridden/memo cases) self.specializer = specializer self._cache = {} # convenience for the specializer
def cpython_code_signature(code): "([list-of-arg-names], vararg-name-or-None, kwarg-name-or-None)." argcount = code.co_argcount argnames = list(code.co_varnames[:argcount]) if code.co_flags & CO_VARARGS: varargname = code.co_varnames[argcount] argcount += 1 else: varargname = None if code.co_flags & CO_VARKEYWORDS: kwargname = code.co_varnames[argcount] argcount += 1 else: kwargname = None return Signature(argnames, varargname, kwargname)
def newfuncdesc(self, pyfunc): name = pyfunc.__name__ if hasattr(pyfunc, '_generator_next_method_of_'): from rpython.flowspace.argument import Signature signature = Signature(['entry']) # haaaaaack defaults = () else: signature = cpython_code_signature(pyfunc.__code__) defaults = pyfunc.__defaults__ # get the specializer based on the tag of the 'pyobj' # (if any), according to the current policy tag = getattr(pyfunc, '_annspecialcase_', None) specializer = self.annotator.policy.get_specializer(tag) if specializer is memo: return description.MemoDesc(self, pyfunc, name, signature, defaults, specializer) return description.FunctionDesc(self, pyfunc, name, signature, defaults, specializer)
def tweak_generator_body_graph(Entry, graph): # First, always run simplify_graph in order to reduce the number of # variables passed around simplify_graph(graph) insert_empty_startblock(graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) op0 = op.simple_call(const(StopIteration)) op1 = op.type(op0.result) stopblock.operations = [op0, op1] stopblock.closeblock(Link([op1.result, op0.result], graph.exceptblock)) # for block in list(graph.iterblocks()): for exit in block.exits: if exit.target is graph.returnblock: exit.args = [] exit.target = stopblock assert block is not stopblock for index in range(len(block.operations) - 1, -1, -1): hlop = block.operations[index] if hlop.opname == 'yield_': [v_yielded_value] = hlop.args del block.operations[index] newlink = split_block(block, index) newblock = newlink.target # class Resume(AbstractPosition): _immutable_ = True block = newblock Resume.__name__ = 'Resume%d' % len(mappings) mappings.append(Resume) varnames = get_variable_names(newlink.args) # _insert_reads(newblock, varnames) # op_resume = op.simple_call(const(Resume)) block.operations.append(op_resume) v_resume = op_resume.result for i, name in enumerate(varnames): block.operations.append( op.setattr(v_resume, const(name), newlink.args[i])) op_pair = op.newtuple(v_resume, v_yielded_value) block.operations.append(op_pair) newlink.args = [op_pair.result] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: op_check = op.isinstance(block.inputargs[0], const(Resume)) block.operations.append(op_check) block.exitswitch = op_check.result link1 = Link([block.inputargs[0]], Resume.block) link1.exitcase = True nextblock = Block([Variable('entry')]) link2 = Link([block.inputargs[0]], nextblock) link2.exitcase = False block.closeblock(link1, link2) block = nextblock block.closeblock( Link([ Constant(AssertionError), Constant(AssertionError("bad generator class")) ], graph.exceptblock)) graph.startblock = regular_entry_block graph.signature = Signature(['entry']) graph.defaults = () checkgraph(graph) eliminate_empty_blocks(graph)
def normalize_calltable_row_signature(annotator, shape, row): graphs = row.values() assert graphs, "no graph??" sig0 = graphs[0].signature defaults0 = graphs[0].defaults for graph in graphs[1:]: if graph.signature != sig0: break if graph.defaults != defaults0: break else: return False # nothing to do, all signatures already match shape_cnt, shape_keys, shape_star = shape assert not shape_star, "should have been removed at this stage" # for the first 'shape_cnt' arguments we need to generalize to # a common type call_nbargs = shape_cnt + len(shape_keys) did_something = False for graph in graphs: argnames, varargname, kwargname = graph.signature assert not varargname, "XXX not implemented" assert not kwargname, "XXX not implemented" # ? inputargs_s = [annotator.binding(v) for v in graph.getargs()] argorder = range(shape_cnt) for key in shape_keys: i = list(argnames).index(key) assert i not in argorder argorder.append(i) need_reordering = (argorder != range(call_nbargs)) if need_reordering or len(graph.getargs()) != call_nbargs: oldblock = graph.startblock inlist = [] defaults = graph.defaults or () num_nondefaults = len(inputargs_s) - len(defaults) defaults = [description.NODEFAULT ] * num_nondefaults + list(defaults) newdefaults = [] for j in argorder: v = Variable(graph.getargs()[j]) annotator.setbinding(v, inputargs_s[j]) inlist.append(v) newdefaults.append(defaults[j]) newblock = Block(inlist) # prepare the output args of newblock: # 1. collect the positional arguments outlist = inlist[:shape_cnt] # 2. add defaults and keywords for j in range(shape_cnt, len(inputargs_s)): try: i = argorder.index(j) v = inlist[i] except ValueError: default = defaults[j] if default is description.NODEFAULT: raise TyperError( "call pattern has %d positional arguments, " "but %r takes at least %d arguments" % (shape_cnt, graph.name, num_nondefaults)) v = Constant(default) outlist.append(v) newblock.closeblock(Link(outlist, oldblock)) graph.startblock = newblock for i in range(len(newdefaults) - 1, -1, -1): if newdefaults[i] is description.NODEFAULT: newdefaults = newdefaults[i:] break graph.defaults = tuple(newdefaults) graph.signature = Signature([argnames[j] for j in argorder], None, None) # finished checkgraph(graph) annotator.annotated[newblock] = annotator.annotated[oldblock] did_something = True return did_something
def test_helpers(self): sig = Signature(["a", "b", "c"], None, None) assert sig.num_argnames() == 3 assert not sig.has_vararg() assert not sig.has_kwarg() assert sig.scope_length() == 3 assert sig.getallvarnames() == ["a", "b", "c"] sig = Signature(["a", "b", "c"], "c", None) assert sig.num_argnames() == 3 assert sig.has_vararg() assert not sig.has_kwarg() assert sig.scope_length() == 4 assert sig.getallvarnames() == ["a", "b", "c", "c"] sig = Signature(["a", "b", "c"], None, "c") assert sig.num_argnames() == 3 assert not sig.has_vararg() assert sig.has_kwarg() assert sig.scope_length() == 4 assert sig.getallvarnames() == ["a", "b", "c", "c"] sig = Signature(["a", "b", "c"], "d", "c") assert sig.num_argnames() == 3 assert sig.has_vararg() assert sig.has_kwarg() assert sig.scope_length() == 5 assert sig.getallvarnames() == ["a", "b", "c", "d", "c"]
def test_find_argname(self): sig = Signature(["a", "b", "c"], None, None) assert sig.find_argname("a") == 0 assert sig.find_argname("b") == 1 assert sig.find_argname("c") == 2 assert sig.find_argname("d") == -1
def test_tuply(self): sig = Signature(["a", "b", "c"], "d", "e") x, y, z = sig assert x == ["a", "b", "c"] assert y == "d" assert z == "e"
def test_eq(self): sig1 = Signature(["a", "b", "c"], "d", "c") sig2 = Signature(["a", "b", "c"], "d", "c") assert sig1 == sig2