# HG changeset patch # User paulb@localhost.localdomain # Date 1172178370 -3600 # Node ID 95ea3c071ed937bce07437353a2c019d45e28a75 # Parent 76b0d12a915cff600599f250ec7e3b2843d584ec Added tentative ListComp, ListCompFor, ListCompIf and Sliceobj support. Changed pop-up element generation so that in cases where no information is available, the pop-up elements are not generated. Added a test of list comprehensions. Added a slice built-in type. diff -r 76b0d12a915c -r 95ea3c071ed9 lib/builtins.py --- a/lib/builtins.py Sun Feb 18 01:39:11 2007 +0100 +++ b/lib/builtins.py Thu Feb 22 22:06:10 2007 +0100 @@ -3,7 +3,7 @@ """ Simple built-in classes and functions. -Copyright (C) 2005, 2006 Paul Boddie +Copyright (C) 2005, 2006, 2007 Paul Boddie This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -611,6 +611,16 @@ def __str__(self): return "None" +class slice: + def __init__(self, start_or_end, end=None, step=None): + if end is None: + self.start = 0 + self.end = start_or_end + else: + self.start = start_or_end + self.end = end + self.step = step + class str: __atomic__ = 1 diff -r 76b0d12a915c -r 95ea3c071ed9 simplify.py --- a/simplify.py Sun Feb 18 01:39:11 2007 +0100 +++ b/simplify.py Thu Feb 22 22:06:10 2007 +0100 @@ -50,13 +50,13 @@ Covered: Add, And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign, Break, CallFunc, Class, Compare, Const, Continue, Dict, Discard, Div, FloorDiv, For, From, Function, Getattr, Global, If, Import, - Invert, Keyword, Lambda, List, Mod, Module, Mul, Name, Not, Or, - Pass, Power, Print, Printnl, Raise, Return, Slice, Stmt, Sub, - Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd, UnarySub. + Invert, Keyword, Lambda, List, ListComp, ListCompFor, ListCompIf, + Mod, Module, Mul, Name, Not, Or, Pass, Power, Print, Printnl, + Raise, Return, Slice, Sliceobj, Stmt, Sub, Subscript, TryExcept, + TryFinally, Tuple, While, UnaryAdd, UnarySub. Missing: Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Ellipsis, - Exec, LeftShift, ListComp, ListCompFor, ListCompIf, RightShift, - Sliceobj, Yield. + Exec, LeftShift, RightShift, Yield. """ def __init__(self, builtins=0): @@ -498,7 +498,9 @@ ">=" : ("__ge__", "__le__"), ">" : ("__gt__", "__lt__"), "is" : None, - "is not" : None + "is not" : None, + "in" : None, + "not in" : None } def visitCompare(self, compare): @@ -566,6 +568,32 @@ star=None, dstar=None) ) + + elif op_name == "in": + invocation = InvokeFunction( + new_op, 1, + expr=LoadAttr( + expr=previous, + name="__contains__" + ), + args=[expr], + star=None, + dstar=None) + + elif op_name == "not in": + invocation = Not( + new_op, 1, + expr=InvokeFunction( + new_op, + expr=LoadAttr( + expr=previous, + name="__contains__" + ), + args=[expr], + star=None, + dstar=None) + ) + else: raise NotImplementedError, op_name @@ -666,13 +694,17 @@ (else) -> ... """ + return self._visitFor(for_, self.dispatches(for_.body), for_.else_) + + def _visitFor(self, node, body_stmt, else_=None): + subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None) self.current_subprograms.append(subprogram) # Always return from conditional sections/subprograms. - if for_.else_ is not None: - else_stmt = self.dispatch(for_.else_) + [ReturnFromBlock()] + if else_ is not None: + else_stmt = self.dispatch(else_) + [ReturnFromBlock()] else: else_stmt = [ReturnFromBlock()] @@ -684,20 +716,20 @@ body=[ Assign( code=[ - StoreTemp(expr=InvokeFunction(for_, expr=LoadAttr(expr=LoadTemp(), name="next"))), - self.dispatch(for_.assign), + StoreTemp(expr=InvokeFunction(node, expr=LoadAttr(expr=LoadTemp(), name="next"))), + self.dispatch(node.assign), ReleaseTemp() ]) - ] + self.dispatch(for_.body) + [ + ] + body_stmt + [ InvokeBlock( - for_, + node, expr=LoadRef(ref=subprogram) ) ], handler=[ Conditional( test=InvokeFunction( - for_, + node, expr=LoadName(name="isinstance"), args=[LoadExc(), LoadName(name="StopIteration")], star=None, @@ -720,26 +752,26 @@ # Obtain an iterator for the sequence involved. # Then, make an invocation of the subprogram. - result = Assign(for_, 1, + result = Assign(node, 1, code=[ StoreTemp( expr=InvokeFunction( - for_, + node, expr=LoadAttr( name="__iter__", - expr=self.dispatch(for_.list) + expr=self.dispatch(node.list) ) ) ), - InvokeBlock(for_, expr=LoadRef(ref=subprogram)), + InvokeBlock(node, expr=LoadRef(ref=subprogram)), ReleaseTemp() ] ) # Make nice annotations for the viewer. - for_._iter_call = result.code[0].expr - for_._next_call = subprogram.code[0].body[0].code[0].expr + node._iter_call = result.code[0].expr + node._next_call = subprogram.code[0].body[0].code[0].expr return result @@ -975,6 +1007,94 @@ def visitList(self, list): return self._visitBuiltin(list, "list") + def visitListComp(self, listcomp): + + # Make a subprogram for the list comprehension and record it outside the + # main tree. + + subprogram = Subprogram(listcomp, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=listcomp) + self.current_subprograms.append(subprogram) + + # Make nice annotations for the viewer. + + listcomp._subprogram = subprogram + + # Add a temporary variable. + # Produce for loops within the subprogram. + # Return the result. + + subprogram.code = [ + StoreTemp( + index="listcomp", + expr=InvokeFunction( + expr=LoadName(name="list"), + args=[], + star=None, + dstar=None + ) + ) + ] + self._visitListCompFor(listcomp, listcomp.quals) + [ + ReturnFromBlock( + expr=LoadTemp( + index="listcomp", + release=1 + ) + ) + ] + + self.current_subprograms.pop() + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram + + # Make an invocation of the subprogram. + + result = InvokeBlock(listcomp, 1, + produces_result=1, + expr=LoadRef(ref=subprogram) + ) + return result + + def _visitListCompFor(self, node, quals): + qual = quals[0] + if len(quals) > 1: + body = self._visitListCompFor(node, quals[1:]) + if qual.ifs: + body = self._visitListCompIf(node, qual.ifs, body) + else: + body = self._visitListCompIf(node, qual.ifs) + return [self._visitFor(qual, body)] + + def _visitListCompIf(self, node, ifs, expr=None): + if_ = ifs[0] + if len(ifs) > 1: + body = self._visitListCompIf(node, ifs[1:], expr) + elif expr is None: + body = [ + InvokeFunction( + expr=LoadAttr( + expr=LoadTemp(index="listcomp"), + name="append" + ), + args=[self.dispatch(node.expr)], + star=None, + dstar=None + ) + ] + else: + body = expr + return [ + Conditional(if_, 1, + test=InvokeFunction( + if_, + expr=LoadAttr( + expr=self.dispatch(if_.test), + name="__bool__" + ), + ), + body=body, + else_=[] + ) + ] + def visitMod(self, mod): return self._visitBinary(mod, "__mod__", "__rmod__") @@ -1060,8 +1180,10 @@ # Make an invocation of the subprogram. - result = InvokeBlock(or_, 1, produces_result=1) - result.expr = LoadRef(ref=subprogram) + result = InvokeBlock(or_, 1, + produces_result=1, + expr=LoadRef(ref=subprogram) + ) return result def visitPass(self, pass_): @@ -1202,6 +1324,14 @@ return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower), self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence)) + def visitSliceobj(self, sliceobj): + return InvokeFunction(sliceobj, 1, + expr=LoadName(name="slice"), + args=self.dispatches(sliceobj.nodes), + star=None, + dstar=None + ) + def visitStmt(self, stmt): return self.dispatches(stmt.nodes) diff -r 76b0d12a915c -r 95ea3c071ed9 tests/listcomp.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/listcomp.py Thu Feb 22 22:06:10 2007 +0100 @@ -0,0 +1,7 @@ +def f(x, y): + return x + +a = [1, 2, 3] +b = ["1", "2", "3"] + +l = [f(x, y) for x in a for y in b if y > "1" if x > 1] diff -r 76b0d12a915c -r 95ea3c071ed9 viewer.py --- a/viewer.py Sun Feb 18 01:39:11 2007 +0100 +++ b/viewer.py Thu Feb 22 22:06:10 2007 +0100 @@ -127,13 +127,13 @@ Covered: Add, And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign, Break, CallFunc, Class, Compare, Const, Continue, Dict, Discard, Div, FloorDiv, For, From, Function, Getattr, Global, If, Import, - Keyword, Lambda, List, Mod, Module, Mul, Name, Not, Or, Pass, - Power, Print, Printnl, Raise, Return, Slice, Stmt, Sub, Subscript, - TryExcept, TryFinally, Tuple, UnaryAdd, UnarySub, While. + Keyword, Lambda, List, ListComp, ListCompFor, ListCompIf, Mod, + Module, Mul, Name, Not, Or, Pass, Power, Print, Printnl, Raise, + Return, Slice, Sliceobj, Stmt, Sub, Subscript, TryExcept, + TryFinally, Tuple, UnaryAdd, UnarySub, While. Missing: Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Ellipsis, - Exec, Invert, LeftShift, ListComp, ListCompFor, ListCompIf, - RightShift, Sliceobj, Yield. + Exec, Invert, LeftShift, RightShift, Yield. """ def __init__(self, stream): @@ -164,11 +164,9 @@ self.dispatch(node.node) self.stream.write("\n") self.stream.write("%s\n" % node.op) - self._popup_start() - self.stream.write("
\n") - self._invocations_list(node._op_call.active()) - self.stream.write("
\n") - self._popup_end() + self._popup( + self._invocations(node._op_call.active()) + ) self.stream.write("
\n") self.dispatch(node.expr) self.stream.write("\n") @@ -186,9 +184,9 @@ self.stream.write("
\n") self._keyword("class") self._name_start(structure.name) - self._popup_start() - self._scopes(definitions) - self._popup_end() + self._popup( + self._scopes(definitions) + ) self._name_end() bases = structure.bases @@ -201,10 +199,10 @@ if not first: self.stream.write(",\n") self._name_start(base.name) - self._popup_start() - self._scopes([base]) - self._types([base]) - self._popup_end() + self._popup( + self._scopes([base]) + + self._types([base]) + ) self._name_end() first = 0 self.stream.write(")") @@ -234,16 +232,16 @@ self.stream.write("
\n") self.stream.write("\n") self._keyword("for") - self._popup_start() - self._invocations(node._next_call.active()) - self._popup_end() + self._popup( + self._invocations(node._next_call.active()) + ) self.stream.write("\n") self.dispatch(node.assign) self.stream.write("\n") self._keyword("in") - self._popup_start() - self._invocations(node._iter_call.active()) - self._popup_end() + self._popup( + self._invocations(node._iter_call.active()) + ) self.stream.write("\n") self.dispatch(node.list) self.stream.write(":\n") @@ -266,9 +264,9 @@ self._keyword("from") self.stream.write("\n") self.stream.write(node.modname) - self._popup_start() - self._types(node._modname.active()) - self._popup_end() + self._popup( + self._types(node._modname.active()) + ) self.stream.write("\n") self._keyword("import") first = 1 @@ -280,9 +278,9 @@ self._keyword("as") self.stream.write("\n") self.stream.write(alias or name) - self._popup_start() - self._types([_name]) - self._popup_end() + self._popup( + self._types([_name]) + ) self.stream.write("\n") first = 0 self.stream.write("
\n") @@ -296,10 +294,10 @@ self.stream.write("
\n") self._keyword("def") self._name_start(subprogram.name) - self._popup_start() - self._scopes([definition]) # not dependent on subprograms - self._raises(subprograms) - self._popup_end() + self._popup( + self._scopes([definition]) + # not dependent on subprograms + self._raises(subprograms) + ) self._name_end() self.stream.write("(") self._parameters(subprogram, subprograms) @@ -337,9 +335,9 @@ self._keyword("if") else: self._keyword("elif") - self._popup_start() - self._invocations([c.test for c in conditionals]) - self._popup_end() + self._popup( + self._invocations([c.test for c in conditionals]) + ) self.stream.write("\n") self.dispatch(compare) self.stream.write(":\n") @@ -349,8 +347,10 @@ self.stream.write("
\n") if conditional.else_: conditional = conditional.else_[0] + conditionals = conditional.active() else: conditional = None + conditionals = [] first = 0 if node.else_ is not None: self.stream.write("
\n") @@ -374,9 +374,9 @@ self._keyword("as") self.stream.write("\n") self.stream.write(alias or name) - self._popup_start() - self._types([_name]) - self._popup_end() + self._popup( + self._types([_name]) + ) self.stream.write("\n") first = 0 self.stream.write("
\n") @@ -429,9 +429,9 @@ self.stream.write("
\n") self.stream.write("\n") self._keyword("return") - self._popup_start() - self._types(values) - self._popup_end() + self._popup( + self._types(values) + ) self.stream.write("\n") self.dispatch(node.value) self.stream.write("
\n") @@ -496,9 +496,9 @@ self.stream.write("
\n") self.stream.write("\n") self._keyword("while") - self._popup_start() - self._invocations(node._test_call.active()) - self._popup_end() + self._popup( + self._invocations(node._test_call.active()) + ) self.stream.write("\n") self.dispatch(node.test) self.stream.write(":\n") @@ -523,11 +523,9 @@ self.dispatch(node.left) self.stream.write("\n") self.stream.write(symbol) - self._popup_start() - self.stream.write("
\n") - self._invocations_list(node._left_call.active() + node._right_call.active()) - self.stream.write("
\n") - self._popup_end() + self._popup( + self._invocations(node._left_call.active() + node._right_call.active()) + ) self.stream.write("
\n") self.dispatch(node.right) self.stream.write("") @@ -536,11 +534,9 @@ self.stream.write("\n" % name) self.stream.write("\n") self.stream.write(symbol) - self._popup_start() - self.stream.write("
\n") - self._invocations_list(node._unary_call.active()) - self.stream.write("
\n") - self._popup_end() + self._popup( + self._invocations(node._unary_call.active()) + ) self.stream.write("
\n") self.dispatch(node.expr) self.stream.write("
") @@ -567,10 +563,10 @@ self.dispatch(node.expr) self.stream.write("\n") self.stream.write(".%s\n" % self._text(node.attrname)) - self._popup_start() - self._scopes(targets) - self._types(targets) - self._popup_end() + self._popup( + self._scopes(targets) + + self._types(targets) + ) self.stream.write("\n") self.stream.write("\n") @@ -585,10 +581,10 @@ target = node._node targets = target.active() self._name_start(target.name) - self._popup_start() - self._scopes(targets) - self._types(targets) - self._popup_end() + self._popup( + self._scopes(targets) + + self._types(targets) + ) self._name_end() def visitAssTuple(self, node): @@ -605,9 +601,9 @@ self.dispatch(node.node) self.stream.write("\n") self.stream.write("(") - self._popup_start() - self._invocations(targets) - self._popup_end() + self._popup( + self._invocations(targets) + ) self.stream.write("\n") first = 1 for arg in node.args: @@ -634,9 +630,9 @@ for op in node._ops: self.stream.write("\n") self.stream.write(op.name) - self._popup_start() - self._op(op) - self._popup_end() + self._popup( + self._op(op) + ) self.stream.write("\n") self.dispatch(op.expr) self.stream.write("\n") @@ -664,10 +660,10 @@ self.dispatch(node.expr) self.stream.write("\n") self.stream.write(".%s\n" % self._text(node.attrname)) - self._popup_start() - self._scopes(targets) - self._types(targets) - self._popup_end() + self._popup( + self._scopes(targets) + + self._types(targets) + ) self.stream.write("\n") self.stream.write("\n") @@ -691,6 +687,48 @@ visitList = visitAssList + def visitListComp(self, node): + self.stream.write("\n") + self.stream.write("[") + self.dispatch(node.expr) + for qual in node.quals: + self.dispatch(qual) + self.stream.write("]\n") + self.stream.write("\n") + + def visitListCompFor(self, node): + self.stream.write("\n") + self.stream.write("\n") + self._keyword("for") + self._popup( + self._invocations(node._next_call.active()) + ) + self.stream.write("\n") + self.dispatch(node.assign) + self.stream.write("\n") + self._keyword("in") + self._popup( + self._invocations(node._iter_call.active()) + ) + self.stream.write("\n") + self.dispatch(node.list) + for if_ in node.ifs: + self.dispatch(if_) + self.stream.write("\n") + + def visitListCompIf(self, node): + conditional = node._node + conditionals = conditional.active() + self.stream.write("\n") + self.stream.write("\n") + self._keyword("if") + self._popup( + self._invocations([c.test for c in conditionals]) + ) + self.stream.write("\n") + self.dispatch(node.test) + self.stream.write("\n") + def visitMod(self, node): self._visitBinary(node, "mod", "%") @@ -701,10 +739,10 @@ target = node._node targets = target.active() self._name_start(target.name) - self._popup_start() - self._scopes(targets) - self._types(targets) - self._popup_end() + self._popup( + self._scopes(targets) + + self._types(targets) + ) self._name_end() def visitNot(self, node): @@ -739,6 +777,15 @@ self.stream.write("]") self.stream.write("\n") + def visitSliceobj(self, node): + self.stream.write("\n") + first = 1 + for n in node.nodes: + if not first: + self.stream.write(":") + self.dispatch(n) + self.stream.write("\n") + def visitSub(self, node): self._visitBinary(node, "sub", "-") @@ -837,11 +884,9 @@ self.stream.write(",\n") main_param, main_default = subprogram.params[n] self._name_start(main_param) - self._popup_start() - self.stream.write("
\n") - self._parameter(subprograms, params, n) - self.stream.write("
\n") - self._popup_end() + self._popup( + self._parameter(subprograms, params, n) + ) self._name_end() self._default(main_default) first = 0 @@ -851,11 +896,9 @@ self.stream.write(", *\n") main_param, main_default = subprogram.star self._name_start(main_param) - self._popup_start() - self.stream.write("
\n") - self._parameter(subprograms, stars) - self.stream.write("
\n") - self._popup_end() + self._popup( + self._parameter(subprograms, stars) + ) self._name_end() self._default(main_default) first = 0 @@ -865,11 +908,9 @@ self.stream.write(", **\n") main_param, main_default = subprogram.dstar self._name_start(main_param) - self._popup_start() - self.stream.write("
\n") - self._parameter(subprograms, dstars) - self.stream.write("
\n") - self._popup_end() + self._popup( + self._parameter(subprograms, dstars) + ) self._name_end() self._default(main_default) first = 0 @@ -884,7 +925,7 @@ param, default = params[i] if hasattr(subprogram, "paramtypes"): types += subprogram.paramtypes[param] - self._types_list(types) + return self._types_container(types, "types") def _default(self, default): if default is not None and default.original is not None: @@ -900,29 +941,28 @@ def _name_end(self): self.stream.write("\n") - def _popup_start(self): - self.stream.write("\n") - - def _popup_end(self): - self.stream.write("\n") + def _popup(self, info): + if info: + self.stream.write("\n") + for section, subsection, labels in info: + self.stream.write("
\n" % section) + for label in labels: + self.stream.write("
\n" % subsection) + self.stream.write(label) + self.stream.write("
\n") + self.stream.write("
\n") + self.stream.write("
\n") def _op(self, node): - self.stream.write("
\n") if hasattr(node, "_left_call") and hasattr(node, "_right_call"): - self._invocations_list(node._left_call.active() + node._right_call.active()) + return self._invocations(node._left_call.active() + node._right_call.active()) else: _node = node._node if isinstance(_node, Not): _node = _node.expr - self._invocations_list(_node.active()) - self.stream.write("
\n") + return self._invocations(_node.active()) def _invocations(self, nodes): - self.stream.write("
\n") - self._invocations_list(nodes) - self.stream.write("
\n") - - def _invocations_list(self, nodes): invocations = [] for node in nodes: if hasattr(node, "invocations"): @@ -946,112 +986,95 @@ # Produce the list. - for label, link in links.items(): - self.stream.write("
") - self.stream.write("" % link) - self.stream.write(label) - self.stream.write("") - self.stream.write("
\n") + if links: + popup_labels = [] + for label, link in links.items(): + popup_labels.append("%s" % (link + (label,))) + else: + popup_labels = [] + + if popup_labels: + return [("invocations", "invocation", popup_labels)] + else: + return [] def _types(self, nodes): - self.stream.write("
\n") all_types = [(getattr(n, "types", []) or flatten(getattr(n, "writes", {}).values())) for n in nodes] types = flatten(all_types) - if not types: - self._no_types() - else: - self._types_list(types) - self.stream.write("
\n") - - def _unvisited(self): - self.stream.write("
") - self.stream.write("unvisited\n") - self.stream.write("
\n") - - def _no_types(self): - self.stream.write("
") - self.stream.write("no types\n") - self.stream.write("
\n") + return self._types_container(types, "types") def _types_container(self, types, style_class): - self.stream.write("
\n" % style_class) - self._types_list(types) - self.stream.write("
\n") - - def _types_list(self, types): types = unique(types) + labels = {} for type in types: fn = type.type.full_name() - self.stream.write("
") - self.stream.write(self._text(fn)) - self.stream.write("
\n") + labels[self._text(fn)] = None + + if labels: + return [(style_class, 'type', labels.keys())] + else: + return [] def _raises(self, nodes): "Output the exception information for the given simplified 'nodes'." - self.stream.write("
\n") + raises = [] for node in nodes: if hasattr(node, "raises") and node.raises: - self._types_list(node.raises) - self.stream.write("
\n") + raises += node.raises + return self._types_container(raises, "raises") def _scopes(self, nodes): "Output the scope information for the given simplified 'nodes'." - self.stream.write("
\n") + labels = {} for node in nodes: - self._scope(node) - self.stream.write("
\n") - def _scope(self, node): - - "Output the scope information for the given simplified 'node'." - - # Straightforward name loading/storing involves the local scope. + # Straightforward name loading/storing involves the local scope. - if isinstance(node, StoreName) or isinstance(node, LoadName): - self.stream.write("
") - self.stream.write("(local)") - self.stream.write("
\n") + if isinstance(node, StoreName) or isinstance(node, LoadName): + labels["(local)"] = None - # Other loading/storing involves attributes accessed on modules, classes - # and objects. + # Other loading/storing involves attributes accessed on modules, classes + # and objects. - else: + else: - # Loading... + # Loading... - if hasattr(node, "accesses") and node.accesses: - for ref, accesses in node.accesses.items(): - fn = ref.full_name() - for attr, access in accesses: - access_fn = access.full_name() - self.stream.write("
") - self.stream.write(self._text(fn)) - if ref != access: - self.stream.write(" (via " + self._text(access_fn) + ")") - self.stream.write("
\n") + if hasattr(node, "accesses") and node.accesses: + for ref, accesses in node.accesses.items(): + fn = ref.full_name() + for attr, access in accesses: + access_fn = access.full_name() + label = self._text(fn) + if ref != access: + label += " (via " + self._text(access_fn) + ")" + labels[label] = None - # Storing... + # Storing... - if hasattr(node, "writes") and node.writes: - for ref in node.writes.keys(): - fn = ref.full_name() - self.stream.write("
") - self.stream.write(self._text(fn)) - self.stream.write("
\n") + if hasattr(node, "writes") and node.writes: + for ref in node.writes.keys(): + fn = ref.full_name() + labels[self._text(fn)] = None + + # Non-loading... + + if hasattr(node, "non_accesses") and node.non_accesses: + self._types_container(node.non_accesses, "non-accesses") - # Non-loading... + # Non-storing... - if hasattr(node, "non_accesses") and node.non_accesses: - self._types_container(node.non_accesses, "non-accesses") + if hasattr(node, "non_writes") and node.non_writes: + self._types_container(node.non_writes, "non-writes") - # Non-storing... - - if hasattr(node, "non_writes") and node.non_writes: - self._types_container(node.non_writes, "non-writes") + if labels: + return [("scopes", "scope", labels.keys())] + else: + return [] # Utility functions.