def test_return_in_with(self): def f(x): with x: return 1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getattr': 2, 'simple_call': 2}
def test_delitem(self): def f(c, x): del c[x] graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'delitem': 1}
def test_implicitException_os_stat(self): x = self.codetest(self.implicitException_os_stat) simplify_graph(x) self.show(x) assert len(x.startblock.exits) == 3 d = {} for link in x.startblock.exits: d[link.exitcase] = True assert d == {None: True, OSError: True, Exception: True}
def test_simple_raise(self): def f(): raise ValueError('ouch') x = self.codetest(f) simplify_graph(x) self.show(x) ops = x.startblock.operations assert ops[0].opname == 'simple_call' assert ops[0].args == [Constant(ValueError), Constant('ouch')]
def test_call_os_remove(self): x = self.codetest(self.call_os_remove) simplify_graph(x) self.show(x) ops = x.startblock.operations assert ops[0].opname == 'simple_call' assert ops[0].args[0].value is os.unlink assert ops[1].opname == 'simple_call' assert ops[1].args[0].value is os.unlink
def test_not_combine(self): def f(n): t = not n if not n: t += 1 return t graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'bool': 1, 'inplace_add': 1}
def test_reraiseAnything(self): x = self.codetest(self.reraiseAnything) simplify_graph(x) self.show(x) found = {} for link in x.iterlinks(): if link.target is x.exceptblock: assert isinstance(link.args[0], Constant) found[link.args[0].value] = True assert found == {ValueError: True, ZeroDivisionError: True, OverflowError: True}
def test_remove_dead_ops(self): def f(): a = [1] b = (a, a) c = type(b) graph = self.codetest(f) simplify_graph(graph) assert graph.startblock.operations == [] [link] = graph.startblock.exits assert link.target is graph.returnblock
def test_rabspath(self): import os.path def f(s): return os.path.abspath(s) graph = self.codetest(f) simplify_graph(graph) ops = graph.startblock.operations assert ops[0].opname == 'simple_call' # from rpython.rlib import rpath assert ops[0].args[0].value is rpath.rabspath
def test_unicode(self): def myfunc(n): try: return unicode(chr(n)) except UnicodeDecodeError: return None graph = self.codetest(myfunc) simplify_graph(graph) assert graph.startblock.canraise assert graph.startblock.exits[0].target is graph.returnblock assert graph.startblock.exits[1].target is graph.returnblock
def test_raise_prebuilt(self): error = ValueError('ouch') def g(x): return x def f(): raise g(error) x = self.codetest(f) simplify_graph(x) self.show(x) ops = x.startblock.operations assert ops[0].opname == 'simple_call' assert ops[0].args == [const(g), const(error)]
def test_reraiseAnythingDicCase(self): x = self.codetest(self.reraiseAnythingDicCase) simplify_graph(x) self.show(x) found = {} for link in x.iterlinks(): if link.target is x.exceptblock: if isinstance(link.args[0], Constant): found[link.args[0].value] = True else: found[link.exitcase] = None assert found == {IndexError: True, KeyError: True, Exception: None}
def test_multiple_catch_simple_call(self): graph = self.codetest(self.multiple_catch_simple_call) simplify_graph(graph) assert self.all_operations(graph) == {'simple_call': 1} entrymap = mkentrymap(graph) links = entrymap[graph.returnblock] assert len(links) == 3 assert (dict.fromkeys([link.exitcase for link in links]) == dict.fromkeys([None, IndexError, OSError])) links = entrymap[graph.exceptblock] assert len(links) == 1 assert links[0].exitcase is Exception
def test_raise1(self): x = self.codetest(self.raise1) simplify_graph(x) self.show(x) ops = x.startblock.operations assert len(ops) == 2 assert ops[0].opname == 'simple_call' assert ops[0].args == [Constant(IndexError)] assert ops[1].opname == 'type' assert ops[1].args == [ops[0].result] assert x.startblock.exits[0].args == [ops[1].result, ops[0].result] assert x.startblock.exits[0].target is x.exceptblock
def test_catch_importerror_2(self): def f(): try: from rpython import this_does_not_exist except ImportError: return 1 graph = self.codetest(f) simplify_graph(graph) self.show(graph) assert not graph.startblock.operations assert len(graph.startblock.exits) == 1 assert graph.startblock.exits[0].target is graph.returnblock
def test_translate_cast(): cdef = "typedef ssize_t Py_ssize_t;" cts = parse_source(cdef) def f(): return cts.cast('Py_ssize_t*', 0) graph = build_flow(f) simplify_graph(graph) assert len(graph.startblock.operations) == 1 op = graph.startblock.operations[0] assert op.args[0] == const(rffi.cast) assert op.args[1].value is cts.gettype('Py_ssize_t*')
def test_translate_gettype(): cdef = "typedef ssize_t Py_ssize_t;" cts = parse_source(cdef) def f(): return cts.gettype('Py_ssize_t*') graph = build_flow(f) simplify_graph(graph) # Check that the result is constant-folded assert graph.startblock.operations == [] [link] = graph.startblock.exits assert link.target is graph.returnblock assert link.args[0] == const(rffi.CArrayPtr(rffi.SSIZE_T))
def test_break_from_handler(self): def f(x): while True: try: x() except TypeError: if x: raise break assert f(0) is None graph = self.codetest(f) simplify_graph(graph) entrymap = mkentrymap(graph) links = entrymap[graph.returnblock] assert len(links) == 1
def buildflowgraph(self, func, mute_dot=False): """Get the flow graph for a function.""" if not isinstance(func, types.FunctionType): raise TypeError("buildflowgraph() expects a function, " "got %r" % (func,)) if func in self._prebuilt_graphs: graph = self._prebuilt_graphs.pop(func) else: if self.config.translation.verbose: log(nice_repr_for_func(func)) graph = build_flow(func) simplify.simplify_graph(graph) if self.config.translation.list_comprehension_operations: simplify.detect_list_comprehension(graph) if not self.config.translation.verbose and not mute_dot: log.dot() self.graphs.append(graph) # store the graph in our list return graph
def buildflowgraph(self, func, mute_dot=False): """Get the flow graph for a function.""" if not isinstance(func, types.FunctionType): raise TypeError("buildflowgraph() expects a function, " "got %r" % (func, )) if func in self._prebuilt_graphs: graph = self._prebuilt_graphs.pop(func) else: if self.config.translation.verbose: log(nice_repr_for_func(func)) graph = build_flow(func) simplify.simplify_graph(graph) if self.config.translation.list_comprehension_operations: simplify.detect_list_comprehension(graph) if not self.config.translation.verbose and not mute_dot: log.dot() self.graphs.append(graph) # store the graph in our list return graph
def test_translate_enum(): cdef = """ typedef enum { mp_ass_subscript = 3, mp_length = 4, mp_subscript = 5, } Slot; """ cts = parse_source(cdef) def f(): return cts.gettype('Slot').mp_length graph = build_flow(f) simplify_graph(graph) # Check that the result is constant-folded assert graph.startblock.operations == [] [link] = graph.startblock.exits assert link.target is graph.returnblock assert link.args[0] == const(4)
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 test_implicitAttributeError(self): x = self.codetest(self.implicitAttributeError) simplify_graph(x) self.show(x) for link in x.iterlinks(): assert link.target is not x.exceptblock
def test_implicitException(self): x = self.codetest(self.implicitException) simplify_graph(x) self.show(x) for link in x.iterlinks(): assert link.target is not x.exceptblock
def test_highly_branching_example(self): x = self.codetest(self.highly_branching_example) simplify_graph(x) # roughly 20 blocks + 30 links assert len(list(x.iterblocks())) + len(list(x.iterlinks())) < 60
def test_getitem(self): def f(c, x): try: return c[x] except Exception: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx_key': 1} g = lambda: None def f(c, x): try: return c[x] finally: g() graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == { 'getitem_idx_key': 1, 'simple_call': 2 } def f(c, x): try: return c[x] except IndexError: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx': 1} def f(c, x): try: return c[x] except KeyError: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_key': 1} def f(c, x): try: return c[x] except ValueError: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem': 1} def f(c, x): try: return c[x] except Exception: return -1 graph = self.codetest(f) simplify_graph(graph) self.show(graph) assert self.all_operations(graph) == {'getitem_idx_key': 1} def f(c, x): try: return c[x] except IndexError: return -1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx': 1} def f(c, x): try: return c[x] except KeyError: return -1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_key': 1} def f(c, x): try: return c[x] except ValueError: return -1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem': 1}
def test_loop_in_bare_except_bug(self): x = self.codetest(self.loop_in_bare_except_bug) simplify_graph(x) self.show(x)
def test_implicitException_int_and_id(self): x = self.codetest(self.implicitException_int_and_id) simplify_graph(x) self.show(x) assert len(x.startblock.exits) == 1 assert x.startblock.exits[0].target is x.returnblock
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) # assert graph.startblock.operations[0].opname == 'generator_mark' graph.startblock.operations.pop(0) # insert_empty_startblock(None, graph) _insert_reads(graph.startblock, Entry.varnames) Entry.block = graph.startblock # mappings = [Entry] # stopblock = Block([]) v0 = Variable() v1 = Variable() stopblock.operations = [ SpaceOperation('simple_call', [Constant(StopIteration)], v0), SpaceOperation('type', [v0], v1), ] stopblock.closeblock(Link([v1, v0], 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): op = block.operations[index] if op.opname == 'yield': [v_yielded_value] = op.args del block.operations[index] newlink = split_block(None, 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) # v_resume = Variable('resume') block.operations.append( SpaceOperation('simple_call', [Constant(Resume)], v_resume)) for i, name in enumerate(varnames): block.operations.append( SpaceOperation('setattr', [v_resume, Constant(name), newlink.args[i]], Variable())) v_pair = Variable('pair') block.operations.append( SpaceOperation('newtuple', [v_resume, v_yielded_value], v_pair)) newlink.args = [v_pair] newlink.target = graph.returnblock # regular_entry_block = Block([Variable('entry')]) block = regular_entry_block for Resume in mappings: v_check = Variable() block.operations.append( SpaceOperation('simple_call', [Constant(isinstance), block.inputargs[0], Constant(Resume)], v_check)) block.exitswitch = v_check 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 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(None, 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(None, 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.simple_call( const(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 test_getitem(self): def f(c, x): try: return c[x] except Exception: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx': 1} g = lambda: None def f(c, x): try: return c[x] finally: g() graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx': 1, 'simple_call': 2} def f(c, x): try: return c[x] except IndexError: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx': 1} def f(c, x): try: return c[x] except KeyError: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem': 1} def f(c, x): try: return c[x] except ValueError: raise graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem': 1} def f(c, x): try: return c[x] except Exception: return -1 graph = self.codetest(f) simplify_graph(graph) self.show(graph) assert self.all_operations(graph) == {'getitem_idx': 1} def f(c, x): try: return c[x] except IndexError: return -1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem_idx': 1} def f(c, x): try: return c[x] except KeyError: return -1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem': 1} def f(c, x): try: return c[x] except ValueError: return -1 graph = self.codetest(f) simplify_graph(graph) assert self.all_operations(graph) == {'getitem': 1}