1.1 --- a/lib/builtins.py Sun Feb 18 01:39:11 2007 +0100
1.2 +++ b/lib/builtins.py Thu Feb 22 22:06:10 2007 +0100
1.3 @@ -3,7 +3,7 @@
1.4 """
1.5 Simple built-in classes and functions.
1.6
1.7 -Copyright (C) 2005, 2006 Paul Boddie <paul@boddie.org.uk>
1.8 +Copyright (C) 2005, 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.9
1.10 This software is free software; you can redistribute it and/or
1.11 modify it under the terms of the GNU General Public License as
1.12 @@ -611,6 +611,16 @@
1.13 def __str__(self):
1.14 return "None"
1.15
1.16 +class slice:
1.17 + def __init__(self, start_or_end, end=None, step=None):
1.18 + if end is None:
1.19 + self.start = 0
1.20 + self.end = start_or_end
1.21 + else:
1.22 + self.start = start_or_end
1.23 + self.end = end
1.24 + self.step = step
1.25 +
1.26 class str:
1.27 __atomic__ = 1
1.28
2.1 --- a/simplify.py Sun Feb 18 01:39:11 2007 +0100
2.2 +++ b/simplify.py Thu Feb 22 22:06:10 2007 +0100
2.3 @@ -50,13 +50,13 @@
2.4 Covered: Add, And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign,
2.5 Break, CallFunc, Class, Compare, Const, Continue, Dict, Discard,
2.6 Div, FloorDiv, For, From, Function, Getattr, Global, If, Import,
2.7 - Invert, Keyword, Lambda, List, Mod, Module, Mul, Name, Not, Or,
2.8 - Pass, Power, Print, Printnl, Raise, Return, Slice, Stmt, Sub,
2.9 - Subscript, TryExcept, TryFinally, Tuple, While, UnaryAdd, UnarySub.
2.10 + Invert, Keyword, Lambda, List, ListComp, ListCompFor, ListCompIf,
2.11 + Mod, Module, Mul, Name, Not, Or, Pass, Power, Print, Printnl,
2.12 + Raise, Return, Slice, Sliceobj, Stmt, Sub, Subscript, TryExcept,
2.13 + TryFinally, Tuple, While, UnaryAdd, UnarySub.
2.14
2.15 Missing: Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Ellipsis,
2.16 - Exec, LeftShift, ListComp, ListCompFor, ListCompIf, RightShift,
2.17 - Sliceobj, Yield.
2.18 + Exec, LeftShift, RightShift, Yield.
2.19 """
2.20
2.21 def __init__(self, builtins=0):
2.22 @@ -498,7 +498,9 @@
2.23 ">=" : ("__ge__", "__le__"),
2.24 ">" : ("__gt__", "__lt__"),
2.25 "is" : None,
2.26 - "is not" : None
2.27 + "is not" : None,
2.28 + "in" : None,
2.29 + "not in" : None
2.30 }
2.31
2.32 def visitCompare(self, compare):
2.33 @@ -566,6 +568,32 @@
2.34 star=None,
2.35 dstar=None)
2.36 )
2.37 +
2.38 + elif op_name == "in":
2.39 + invocation = InvokeFunction(
2.40 + new_op, 1,
2.41 + expr=LoadAttr(
2.42 + expr=previous,
2.43 + name="__contains__"
2.44 + ),
2.45 + args=[expr],
2.46 + star=None,
2.47 + dstar=None)
2.48 +
2.49 + elif op_name == "not in":
2.50 + invocation = Not(
2.51 + new_op, 1,
2.52 + expr=InvokeFunction(
2.53 + new_op,
2.54 + expr=LoadAttr(
2.55 + expr=previous,
2.56 + name="__contains__"
2.57 + ),
2.58 + args=[expr],
2.59 + star=None,
2.60 + dstar=None)
2.61 + )
2.62 +
2.63 else:
2.64 raise NotImplementedError, op_name
2.65
2.66 @@ -666,13 +694,17 @@
2.67 (else) -> ...
2.68 """
2.69
2.70 + return self._visitFor(for_, self.dispatches(for_.body), for_.else_)
2.71 +
2.72 + def _visitFor(self, node, body_stmt, else_=None):
2.73 +
2.74 subprogram = Subprogram(name=None, module=self.module, internal=1, returns_value=0, params=[], star=None, dstar=None)
2.75 self.current_subprograms.append(subprogram)
2.76
2.77 # Always return from conditional sections/subprograms.
2.78
2.79 - if for_.else_ is not None:
2.80 - else_stmt = self.dispatch(for_.else_) + [ReturnFromBlock()]
2.81 + if else_ is not None:
2.82 + else_stmt = self.dispatch(else_) + [ReturnFromBlock()]
2.83 else:
2.84 else_stmt = [ReturnFromBlock()]
2.85
2.86 @@ -684,20 +716,20 @@
2.87 body=[
2.88 Assign(
2.89 code=[
2.90 - StoreTemp(expr=InvokeFunction(for_, expr=LoadAttr(expr=LoadTemp(), name="next"))),
2.91 - self.dispatch(for_.assign),
2.92 + StoreTemp(expr=InvokeFunction(node, expr=LoadAttr(expr=LoadTemp(), name="next"))),
2.93 + self.dispatch(node.assign),
2.94 ReleaseTemp()
2.95 ])
2.96 - ] + self.dispatch(for_.body) + [
2.97 + ] + body_stmt + [
2.98 InvokeBlock(
2.99 - for_,
2.100 + node,
2.101 expr=LoadRef(ref=subprogram)
2.102 )
2.103 ],
2.104 handler=[
2.105 Conditional(
2.106 test=InvokeFunction(
2.107 - for_,
2.108 + node,
2.109 expr=LoadName(name="isinstance"),
2.110 args=[LoadExc(), LoadName(name="StopIteration")],
2.111 star=None,
2.112 @@ -720,26 +752,26 @@
2.113 # Obtain an iterator for the sequence involved.
2.114 # Then, make an invocation of the subprogram.
2.115
2.116 - result = Assign(for_, 1,
2.117 + result = Assign(node, 1,
2.118 code=[
2.119 StoreTemp(
2.120 expr=InvokeFunction(
2.121 - for_,
2.122 + node,
2.123 expr=LoadAttr(
2.124 name="__iter__",
2.125 - expr=self.dispatch(for_.list)
2.126 + expr=self.dispatch(node.list)
2.127 )
2.128 )
2.129 ),
2.130 - InvokeBlock(for_, expr=LoadRef(ref=subprogram)),
2.131 + InvokeBlock(node, expr=LoadRef(ref=subprogram)),
2.132 ReleaseTemp()
2.133 ]
2.134 )
2.135
2.136 # Make nice annotations for the viewer.
2.137
2.138 - for_._iter_call = result.code[0].expr
2.139 - for_._next_call = subprogram.code[0].body[0].code[0].expr
2.140 + node._iter_call = result.code[0].expr
2.141 + node._next_call = subprogram.code[0].body[0].code[0].expr
2.142
2.143 return result
2.144
2.145 @@ -975,6 +1007,94 @@
2.146 def visitList(self, list):
2.147 return self._visitBuiltin(list, "list")
2.148
2.149 + def visitListComp(self, listcomp):
2.150 +
2.151 + # Make a subprogram for the list comprehension and record it outside the
2.152 + # main tree.
2.153 +
2.154 + subprogram = Subprogram(listcomp, name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None, original_def=listcomp)
2.155 + self.current_subprograms.append(subprogram)
2.156 +
2.157 + # Make nice annotations for the viewer.
2.158 +
2.159 + listcomp._subprogram = subprogram
2.160 +
2.161 + # Add a temporary variable.
2.162 + # Produce for loops within the subprogram.
2.163 + # Return the result.
2.164 +
2.165 + subprogram.code = [
2.166 + StoreTemp(
2.167 + index="listcomp",
2.168 + expr=InvokeFunction(
2.169 + expr=LoadName(name="list"),
2.170 + args=[],
2.171 + star=None,
2.172 + dstar=None
2.173 + )
2.174 + )
2.175 + ] + self._visitListCompFor(listcomp, listcomp.quals) + [
2.176 + ReturnFromBlock(
2.177 + expr=LoadTemp(
2.178 + index="listcomp",
2.179 + release=1
2.180 + )
2.181 + )
2.182 + ]
2.183 +
2.184 + self.current_subprograms.pop()
2.185 + self.subprograms.append(subprogram); self.subnames[subprogram.full_name()] = subprogram
2.186 +
2.187 + # Make an invocation of the subprogram.
2.188 +
2.189 + result = InvokeBlock(listcomp, 1,
2.190 + produces_result=1,
2.191 + expr=LoadRef(ref=subprogram)
2.192 + )
2.193 + return result
2.194 +
2.195 + def _visitListCompFor(self, node, quals):
2.196 + qual = quals[0]
2.197 + if len(quals) > 1:
2.198 + body = self._visitListCompFor(node, quals[1:])
2.199 + if qual.ifs:
2.200 + body = self._visitListCompIf(node, qual.ifs, body)
2.201 + else:
2.202 + body = self._visitListCompIf(node, qual.ifs)
2.203 + return [self._visitFor(qual, body)]
2.204 +
2.205 + def _visitListCompIf(self, node, ifs, expr=None):
2.206 + if_ = ifs[0]
2.207 + if len(ifs) > 1:
2.208 + body = self._visitListCompIf(node, ifs[1:], expr)
2.209 + elif expr is None:
2.210 + body = [
2.211 + InvokeFunction(
2.212 + expr=LoadAttr(
2.213 + expr=LoadTemp(index="listcomp"),
2.214 + name="append"
2.215 + ),
2.216 + args=[self.dispatch(node.expr)],
2.217 + star=None,
2.218 + dstar=None
2.219 + )
2.220 + ]
2.221 + else:
2.222 + body = expr
2.223 + return [
2.224 + Conditional(if_, 1,
2.225 + test=InvokeFunction(
2.226 + if_,
2.227 + expr=LoadAttr(
2.228 + expr=self.dispatch(if_.test),
2.229 + name="__bool__"
2.230 + ),
2.231 + ),
2.232 + body=body,
2.233 + else_=[]
2.234 + )
2.235 + ]
2.236 +
2.237 def visitMod(self, mod):
2.238 return self._visitBinary(mod, "__mod__", "__rmod__")
2.239
2.240 @@ -1060,8 +1180,10 @@
2.241
2.242 # Make an invocation of the subprogram.
2.243
2.244 - result = InvokeBlock(or_, 1, produces_result=1)
2.245 - result.expr = LoadRef(ref=subprogram)
2.246 + result = InvokeBlock(or_, 1,
2.247 + produces_result=1,
2.248 + expr=LoadRef(ref=subprogram)
2.249 + )
2.250 return result
2.251
2.252 def visitPass(self, pass_):
2.253 @@ -1202,6 +1324,14 @@
2.254 return self._visitSlice(slice, self.dispatch(slice.expr), self.dispatch_or_none(slice.lower),
2.255 self.dispatch_or_none(slice.upper), slice.flags, self._visitAssNameOrAttr(slice, in_sequence))
2.256
2.257 + def visitSliceobj(self, sliceobj):
2.258 + return InvokeFunction(sliceobj, 1,
2.259 + expr=LoadName(name="slice"),
2.260 + args=self.dispatches(sliceobj.nodes),
2.261 + star=None,
2.262 + dstar=None
2.263 + )
2.264 +
2.265 def visitStmt(self, stmt):
2.266 return self.dispatches(stmt.nodes)
2.267
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/tests/listcomp.py Thu Feb 22 22:06:10 2007 +0100
3.3 @@ -0,0 +1,7 @@
3.4 +def f(x, y):
3.5 + return x
3.6 +
3.7 +a = [1, 2, 3]
3.8 +b = ["1", "2", "3"]
3.9 +
3.10 +l = [f(x, y) for x in a for y in b if y > "1" if x > 1]
4.1 --- a/viewer.py Sun Feb 18 01:39:11 2007 +0100
4.2 +++ b/viewer.py Thu Feb 22 22:06:10 2007 +0100
4.3 @@ -127,13 +127,13 @@
4.4 Covered: Add, And, AssAttr, AssList, AssName, AssTuple, Assign, AugAssign,
4.5 Break, CallFunc, Class, Compare, Const, Continue, Dict, Discard,
4.6 Div, FloorDiv, For, From, Function, Getattr, Global, If, Import,
4.7 - Keyword, Lambda, List, Mod, Module, Mul, Name, Not, Or, Pass,
4.8 - Power, Print, Printnl, Raise, Return, Slice, Stmt, Sub, Subscript,
4.9 - TryExcept, TryFinally, Tuple, UnaryAdd, UnarySub, While.
4.10 + Keyword, Lambda, List, ListComp, ListCompFor, ListCompIf, Mod,
4.11 + Module, Mul, Name, Not, Or, Pass, Power, Print, Printnl, Raise,
4.12 + Return, Slice, Sliceobj, Stmt, Sub, Subscript, TryExcept,
4.13 + TryFinally, Tuple, UnaryAdd, UnarySub, While.
4.14
4.15 Missing: Assert, Backquote, Bitand, Bitor, Bitxor, Decorators, Ellipsis,
4.16 - Exec, Invert, LeftShift, ListComp, ListCompFor, ListCompIf,
4.17 - RightShift, Sliceobj, Yield.
4.18 + Exec, Invert, LeftShift, RightShift, Yield.
4.19 """
4.20
4.21 def __init__(self, stream):
4.22 @@ -164,11 +164,9 @@
4.23 self.dispatch(node.node)
4.24 self.stream.write("<span class='operator'>\n")
4.25 self.stream.write("%s\n" % node.op)
4.26 - self._popup_start()
4.27 - self.stream.write("<div class='invocations'>\n")
4.28 - self._invocations_list(node._op_call.active())
4.29 - self.stream.write("</div>\n")
4.30 - self._popup_end()
4.31 + self._popup(
4.32 + self._invocations(node._op_call.active())
4.33 + )
4.34 self.stream.write("</span>\n")
4.35 self.dispatch(node.expr)
4.36 self.stream.write("</div>\n")
4.37 @@ -186,9 +184,9 @@
4.38 self.stream.write("<div>\n")
4.39 self._keyword("class")
4.40 self._name_start(structure.name)
4.41 - self._popup_start()
4.42 - self._scopes(definitions)
4.43 - self._popup_end()
4.44 + self._popup(
4.45 + self._scopes(definitions)
4.46 + )
4.47 self._name_end()
4.48 bases = structure.bases
4.49
4.50 @@ -201,10 +199,10 @@
4.51 if not first:
4.52 self.stream.write(",\n")
4.53 self._name_start(base.name)
4.54 - self._popup_start()
4.55 - self._scopes([base])
4.56 - self._types([base])
4.57 - self._popup_end()
4.58 + self._popup(
4.59 + self._scopes([base]) +
4.60 + self._types([base])
4.61 + )
4.62 self._name_end()
4.63 first = 0
4.64 self.stream.write(")")
4.65 @@ -234,16 +232,16 @@
4.66 self.stream.write("<div>\n")
4.67 self.stream.write("<span class='iterator'>\n")
4.68 self._keyword("for")
4.69 - self._popup_start()
4.70 - self._invocations(node._next_call.active())
4.71 - self._popup_end()
4.72 + self._popup(
4.73 + self._invocations(node._next_call.active())
4.74 + )
4.75 self.stream.write("</span>\n")
4.76 self.dispatch(node.assign)
4.77 self.stream.write("<span class='iterator'>\n")
4.78 self._keyword("in")
4.79 - self._popup_start()
4.80 - self._invocations(node._iter_call.active())
4.81 - self._popup_end()
4.82 + self._popup(
4.83 + self._invocations(node._iter_call.active())
4.84 + )
4.85 self.stream.write("</span>\n")
4.86 self.dispatch(node.list)
4.87 self.stream.write(":\n")
4.88 @@ -266,9 +264,9 @@
4.89 self._keyword("from")
4.90 self.stream.write("<span class='name'>\n")
4.91 self.stream.write(node.modname)
4.92 - self._popup_start()
4.93 - self._types(node._modname.active())
4.94 - self._popup_end()
4.95 + self._popup(
4.96 + self._types(node._modname.active())
4.97 + )
4.98 self.stream.write("</span>\n")
4.99 self._keyword("import")
4.100 first = 1
4.101 @@ -280,9 +278,9 @@
4.102 self._keyword("as")
4.103 self.stream.write("<span class='name'>\n")
4.104 self.stream.write(alias or name)
4.105 - self._popup_start()
4.106 - self._types([_name])
4.107 - self._popup_end()
4.108 + self._popup(
4.109 + self._types([_name])
4.110 + )
4.111 self.stream.write("</span>\n")
4.112 first = 0
4.113 self.stream.write("</div>\n")
4.114 @@ -296,10 +294,10 @@
4.115 self.stream.write("<div>\n")
4.116 self._keyword("def")
4.117 self._name_start(subprogram.name)
4.118 - self._popup_start()
4.119 - self._scopes([definition]) # not dependent on subprograms
4.120 - self._raises(subprograms)
4.121 - self._popup_end()
4.122 + self._popup(
4.123 + self._scopes([definition]) + # not dependent on subprograms
4.124 + self._raises(subprograms)
4.125 + )
4.126 self._name_end()
4.127 self.stream.write("(")
4.128 self._parameters(subprogram, subprograms)
4.129 @@ -337,9 +335,9 @@
4.130 self._keyword("if")
4.131 else:
4.132 self._keyword("elif")
4.133 - self._popup_start()
4.134 - self._invocations([c.test for c in conditionals])
4.135 - self._popup_end()
4.136 + self._popup(
4.137 + self._invocations([c.test for c in conditionals])
4.138 + )
4.139 self.stream.write("</span>\n")
4.140 self.dispatch(compare)
4.141 self.stream.write(":\n")
4.142 @@ -349,8 +347,10 @@
4.143 self.stream.write("</div>\n")
4.144 if conditional.else_:
4.145 conditional = conditional.else_[0]
4.146 + conditionals = conditional.active()
4.147 else:
4.148 conditional = None
4.149 + conditionals = []
4.150 first = 0
4.151 if node.else_ is not None:
4.152 self.stream.write("<div>\n")
4.153 @@ -374,9 +374,9 @@
4.154 self._keyword("as")
4.155 self.stream.write("<span class='name'>\n")
4.156 self.stream.write(alias or name)
4.157 - self._popup_start()
4.158 - self._types([_name])
4.159 - self._popup_end()
4.160 + self._popup(
4.161 + self._types([_name])
4.162 + )
4.163 self.stream.write("</span>\n")
4.164 first = 0
4.165 self.stream.write("</div>\n")
4.166 @@ -429,9 +429,9 @@
4.167 self.stream.write("<div class='return'>\n")
4.168 self.stream.write("<span class='returns'>\n")
4.169 self._keyword("return")
4.170 - self._popup_start()
4.171 - self._types(values)
4.172 - self._popup_end()
4.173 + self._popup(
4.174 + self._types(values)
4.175 + )
4.176 self.stream.write("</span>\n")
4.177 self.dispatch(node.value)
4.178 self.stream.write("</div>\n")
4.179 @@ -496,9 +496,9 @@
4.180 self.stream.write("<div>\n")
4.181 self.stream.write("<span class='conditional'>\n")
4.182 self._keyword("while")
4.183 - self._popup_start()
4.184 - self._invocations(node._test_call.active())
4.185 - self._popup_end()
4.186 + self._popup(
4.187 + self._invocations(node._test_call.active())
4.188 + )
4.189 self.stream.write("</span>\n")
4.190 self.dispatch(node.test)
4.191 self.stream.write(":\n")
4.192 @@ -523,11 +523,9 @@
4.193 self.dispatch(node.left)
4.194 self.stream.write("<span class='operator'>\n")
4.195 self.stream.write(symbol)
4.196 - self._popup_start()
4.197 - self.stream.write("<div class='invocations'>\n")
4.198 - self._invocations_list(node._left_call.active() + node._right_call.active())
4.199 - self.stream.write("</div>\n")
4.200 - self._popup_end()
4.201 + self._popup(
4.202 + self._invocations(node._left_call.active() + node._right_call.active())
4.203 + )
4.204 self.stream.write("</span>\n")
4.205 self.dispatch(node.right)
4.206 self.stream.write("</span>")
4.207 @@ -536,11 +534,9 @@
4.208 self.stream.write("<span class='%s'>\n" % name)
4.209 self.stream.write("<span class='operator'>\n")
4.210 self.stream.write(symbol)
4.211 - self._popup_start()
4.212 - self.stream.write("<div class='invocations'>\n")
4.213 - self._invocations_list(node._unary_call.active())
4.214 - self.stream.write("</div>\n")
4.215 - self._popup_end()
4.216 + self._popup(
4.217 + self._invocations(node._unary_call.active())
4.218 + )
4.219 self.stream.write("</span>\n")
4.220 self.dispatch(node.expr)
4.221 self.stream.write("</span>")
4.222 @@ -567,10 +563,10 @@
4.223 self.dispatch(node.expr)
4.224 self.stream.write("<span class='attr'>\n")
4.225 self.stream.write(".%s\n" % self._text(node.attrname))
4.226 - self._popup_start()
4.227 - self._scopes(targets)
4.228 - self._types(targets)
4.229 - self._popup_end()
4.230 + self._popup(
4.231 + self._scopes(targets) +
4.232 + self._types(targets)
4.233 + )
4.234 self.stream.write("</span>\n")
4.235 self.stream.write("</span>\n")
4.236
4.237 @@ -585,10 +581,10 @@
4.238 target = node._node
4.239 targets = target.active()
4.240 self._name_start(target.name)
4.241 - self._popup_start()
4.242 - self._scopes(targets)
4.243 - self._types(targets)
4.244 - self._popup_end()
4.245 + self._popup(
4.246 + self._scopes(targets) +
4.247 + self._types(targets)
4.248 + )
4.249 self._name_end()
4.250
4.251 def visitAssTuple(self, node):
4.252 @@ -605,9 +601,9 @@
4.253 self.dispatch(node.node)
4.254 self.stream.write("<span class='call'>\n")
4.255 self.stream.write("(")
4.256 - self._popup_start()
4.257 - self._invocations(targets)
4.258 - self._popup_end()
4.259 + self._popup(
4.260 + self._invocations(targets)
4.261 + )
4.262 self.stream.write("</span>\n")
4.263 first = 1
4.264 for arg in node.args:
4.265 @@ -634,9 +630,9 @@
4.266 for op in node._ops:
4.267 self.stream.write("<span class='op'>\n")
4.268 self.stream.write(op.name)
4.269 - self._popup_start()
4.270 - self._op(op)
4.271 - self._popup_end()
4.272 + self._popup(
4.273 + self._op(op)
4.274 + )
4.275 self.stream.write("</span>\n")
4.276 self.dispatch(op.expr)
4.277 self.stream.write("</span>\n")
4.278 @@ -664,10 +660,10 @@
4.279 self.dispatch(node.expr)
4.280 self.stream.write("<span class='attr'>\n")
4.281 self.stream.write(".%s\n" % self._text(node.attrname))
4.282 - self._popup_start()
4.283 - self._scopes(targets)
4.284 - self._types(targets)
4.285 - self._popup_end()
4.286 + self._popup(
4.287 + self._scopes(targets) +
4.288 + self._types(targets)
4.289 + )
4.290 self.stream.write("</span>\n")
4.291 self.stream.write("</span>\n")
4.292
4.293 @@ -691,6 +687,48 @@
4.294
4.295 visitList = visitAssList
4.296
4.297 + def visitListComp(self, node):
4.298 + self.stream.write("<span class='listcomp'>\n")
4.299 + self.stream.write("[")
4.300 + self.dispatch(node.expr)
4.301 + for qual in node.quals:
4.302 + self.dispatch(qual)
4.303 + self.stream.write("]\n")
4.304 + self.stream.write("</span>\n")
4.305 +
4.306 + def visitListCompFor(self, node):
4.307 + self.stream.write("<span class='listcompfor'>\n")
4.308 + self.stream.write("<span class='iterator'>\n")
4.309 + self._keyword("for")
4.310 + self._popup(
4.311 + self._invocations(node._next_call.active())
4.312 + )
4.313 + self.stream.write("</span>\n")
4.314 + self.dispatch(node.assign)
4.315 + self.stream.write("<span class='iterator'>\n")
4.316 + self._keyword("in")
4.317 + self._popup(
4.318 + self._invocations(node._iter_call.active())
4.319 + )
4.320 + self.stream.write("</span>\n")
4.321 + self.dispatch(node.list)
4.322 + for if_ in node.ifs:
4.323 + self.dispatch(if_)
4.324 + self.stream.write("</span>\n")
4.325 +
4.326 + def visitListCompIf(self, node):
4.327 + conditional = node._node
4.328 + conditionals = conditional.active()
4.329 + self.stream.write("<span class='listcompif'>\n")
4.330 + self.stream.write("<span class='conditional'>\n")
4.331 + self._keyword("if")
4.332 + self._popup(
4.333 + self._invocations([c.test for c in conditionals])
4.334 + )
4.335 + self.stream.write("</span>\n")
4.336 + self.dispatch(node.test)
4.337 + self.stream.write("</span>\n")
4.338 +
4.339 def visitMod(self, node):
4.340 self._visitBinary(node, "mod", "%")
4.341
4.342 @@ -701,10 +739,10 @@
4.343 target = node._node
4.344 targets = target.active()
4.345 self._name_start(target.name)
4.346 - self._popup_start()
4.347 - self._scopes(targets)
4.348 - self._types(targets)
4.349 - self._popup_end()
4.350 + self._popup(
4.351 + self._scopes(targets) +
4.352 + self._types(targets)
4.353 + )
4.354 self._name_end()
4.355
4.356 def visitNot(self, node):
4.357 @@ -739,6 +777,15 @@
4.358 self.stream.write("]")
4.359 self.stream.write("</span>\n")
4.360
4.361 + def visitSliceobj(self, node):
4.362 + self.stream.write("<span class='sliceobj'>\n")
4.363 + first = 1
4.364 + for n in node.nodes:
4.365 + if not first:
4.366 + self.stream.write(":")
4.367 + self.dispatch(n)
4.368 + self.stream.write("</span>\n")
4.369 +
4.370 def visitSub(self, node):
4.371 self._visitBinary(node, "sub", "-")
4.372
4.373 @@ -837,11 +884,9 @@
4.374 self.stream.write(",\n")
4.375 main_param, main_default = subprogram.params[n]
4.376 self._name_start(main_param)
4.377 - self._popup_start()
4.378 - self.stream.write("<div class='types'>\n")
4.379 - self._parameter(subprograms, params, n)
4.380 - self.stream.write("</div>\n")
4.381 - self._popup_end()
4.382 + self._popup(
4.383 + self._parameter(subprograms, params, n)
4.384 + )
4.385 self._name_end()
4.386 self._default(main_default)
4.387 first = 0
4.388 @@ -851,11 +896,9 @@
4.389 self.stream.write(", *\n")
4.390 main_param, main_default = subprogram.star
4.391 self._name_start(main_param)
4.392 - self._popup_start()
4.393 - self.stream.write("<div class='types'>\n")
4.394 - self._parameter(subprograms, stars)
4.395 - self.stream.write("</div>\n")
4.396 - self._popup_end()
4.397 + self._popup(
4.398 + self._parameter(subprograms, stars)
4.399 + )
4.400 self._name_end()
4.401 self._default(main_default)
4.402 first = 0
4.403 @@ -865,11 +908,9 @@
4.404 self.stream.write(", **\n")
4.405 main_param, main_default = subprogram.dstar
4.406 self._name_start(main_param)
4.407 - self._popup_start()
4.408 - self.stream.write("<div class='types'>\n")
4.409 - self._parameter(subprograms, dstars)
4.410 - self.stream.write("</div>\n")
4.411 - self._popup_end()
4.412 + self._popup(
4.413 + self._parameter(subprograms, dstars)
4.414 + )
4.415 self._name_end()
4.416 self._default(main_default)
4.417 first = 0
4.418 @@ -884,7 +925,7 @@
4.419 param, default = params[i]
4.420 if hasattr(subprogram, "paramtypes"):
4.421 types += subprogram.paramtypes[param]
4.422 - self._types_list(types)
4.423 + return self._types_container(types, "types")
4.424
4.425 def _default(self, default):
4.426 if default is not None and default.original is not None:
4.427 @@ -900,29 +941,28 @@
4.428 def _name_end(self):
4.429 self.stream.write("</span>\n")
4.430
4.431 - def _popup_start(self):
4.432 - self.stream.write("<span class='popup'>\n")
4.433 -
4.434 - def _popup_end(self):
4.435 - self.stream.write("</span>\n")
4.436 + def _popup(self, info):
4.437 + if info:
4.438 + self.stream.write("<span class='popup'>\n")
4.439 + for section, subsection, labels in info:
4.440 + self.stream.write("<div class='%s'>\n" % section)
4.441 + for label in labels:
4.442 + self.stream.write("<div class='%s'>\n" % subsection)
4.443 + self.stream.write(label)
4.444 + self.stream.write("</div>\n")
4.445 + self.stream.write("</div>\n")
4.446 + self.stream.write("</span>\n")
4.447
4.448 def _op(self, node):
4.449 - self.stream.write("<div class='invocations'>\n")
4.450 if hasattr(node, "_left_call") and hasattr(node, "_right_call"):
4.451 - self._invocations_list(node._left_call.active() + node._right_call.active())
4.452 + return self._invocations(node._left_call.active() + node._right_call.active())
4.453 else:
4.454 _node = node._node
4.455 if isinstance(_node, Not):
4.456 _node = _node.expr
4.457 - self._invocations_list(_node.active())
4.458 - self.stream.write("</div>\n")
4.459 + return self._invocations(_node.active())
4.460
4.461 def _invocations(self, nodes):
4.462 - self.stream.write("<div class='invocations'>\n")
4.463 - self._invocations_list(nodes)
4.464 - self.stream.write("</div>\n")
4.465 -
4.466 - def _invocations_list(self, nodes):
4.467 invocations = []
4.468 for node in nodes:
4.469 if hasattr(node, "invocations"):
4.470 @@ -946,112 +986,95 @@
4.471
4.472 # Produce the list.
4.473
4.474 - for label, link in links.items():
4.475 - self.stream.write("<div class='invocation'>")
4.476 - self.stream.write("<a href='%s.html#%s'>" % link)
4.477 - self.stream.write(label)
4.478 - self.stream.write("</a>")
4.479 - self.stream.write("</div>\n")
4.480 + if links:
4.481 + popup_labels = []
4.482 + for label, link in links.items():
4.483 + popup_labels.append("<a href='%s.html#%s'>%s</a>" % (link + (label,)))
4.484 + else:
4.485 + popup_labels = []
4.486 +
4.487 + if popup_labels:
4.488 + return [("invocations", "invocation", popup_labels)]
4.489 + else:
4.490 + return []
4.491
4.492 def _types(self, nodes):
4.493 - self.stream.write("<div class='types'>\n")
4.494 all_types = [(getattr(n, "types", []) or flatten(getattr(n, "writes", {}).values())) for n in nodes]
4.495 types = flatten(all_types)
4.496 - if not types:
4.497 - self._no_types()
4.498 - else:
4.499 - self._types_list(types)
4.500 - self.stream.write("</div>\n")
4.501 -
4.502 - def _unvisited(self):
4.503 - self.stream.write("<div class='type'>")
4.504 - self.stream.write("unvisited\n")
4.505 - self.stream.write("</div>\n")
4.506 -
4.507 - def _no_types(self):
4.508 - self.stream.write("<div class='type'>")
4.509 - self.stream.write("no types\n")
4.510 - self.stream.write("</div>\n")
4.511 + return self._types_container(types, "types")
4.512
4.513 def _types_container(self, types, style_class):
4.514 - self.stream.write("<div class='%s'>\n" % style_class)
4.515 - self._types_list(types)
4.516 - self.stream.write("</div>\n")
4.517 -
4.518 - def _types_list(self, types):
4.519 types = unique(types)
4.520 + labels = {}
4.521 for type in types:
4.522 fn = type.type.full_name()
4.523 - self.stream.write("<div class='type'>")
4.524 - self.stream.write(self._text(fn))
4.525 - self.stream.write("</div>\n")
4.526 + labels[self._text(fn)] = None
4.527 +
4.528 + if labels:
4.529 + return [(style_class, 'type', labels.keys())]
4.530 + else:
4.531 + return []
4.532
4.533 def _raises(self, nodes):
4.534
4.535 "Output the exception information for the given simplified 'nodes'."
4.536
4.537 - self.stream.write("<div class='raises'>\n")
4.538 + raises = []
4.539 for node in nodes:
4.540 if hasattr(node, "raises") and node.raises:
4.541 - self._types_list(node.raises)
4.542 - self.stream.write("</div>\n")
4.543 + raises += node.raises
4.544 + return self._types_container(raises, "raises")
4.545
4.546 def _scopes(self, nodes):
4.547
4.548 "Output the scope information for the given simplified 'nodes'."
4.549
4.550 - self.stream.write("<div class='scopes'>\n")
4.551 + labels = {}
4.552 for node in nodes:
4.553 - self._scope(node)
4.554 - self.stream.write("</div>\n")
4.555
4.556 - def _scope(self, node):
4.557 -
4.558 - "Output the scope information for the given simplified 'node'."
4.559 -
4.560 - # Straightforward name loading/storing involves the local scope.
4.561 + # Straightforward name loading/storing involves the local scope.
4.562
4.563 - if isinstance(node, StoreName) or isinstance(node, LoadName):
4.564 - self.stream.write("<div class='scope'>")
4.565 - self.stream.write("(local)")
4.566 - self.stream.write("</div>\n")
4.567 + if isinstance(node, StoreName) or isinstance(node, LoadName):
4.568 + labels["(local)"] = None
4.569
4.570 - # Other loading/storing involves attributes accessed on modules, classes
4.571 - # and objects.
4.572 + # Other loading/storing involves attributes accessed on modules, classes
4.573 + # and objects.
4.574
4.575 - else:
4.576 + else:
4.577
4.578 - # Loading...
4.579 + # Loading...
4.580
4.581 - if hasattr(node, "accesses") and node.accesses:
4.582 - for ref, accesses in node.accesses.items():
4.583 - fn = ref.full_name()
4.584 - for attr, access in accesses:
4.585 - access_fn = access.full_name()
4.586 - self.stream.write("<div class='scope'>")
4.587 - self.stream.write(self._text(fn))
4.588 - if ref != access:
4.589 - self.stream.write(" (via " + self._text(access_fn) + ")")
4.590 - self.stream.write("</div>\n")
4.591 + if hasattr(node, "accesses") and node.accesses:
4.592 + for ref, accesses in node.accesses.items():
4.593 + fn = ref.full_name()
4.594 + for attr, access in accesses:
4.595 + access_fn = access.full_name()
4.596 + label = self._text(fn)
4.597 + if ref != access:
4.598 + label += " (via " + self._text(access_fn) + ")"
4.599 + labels[label] = None
4.600
4.601 - # Storing...
4.602 + # Storing...
4.603
4.604 - if hasattr(node, "writes") and node.writes:
4.605 - for ref in node.writes.keys():
4.606 - fn = ref.full_name()
4.607 - self.stream.write("<div class='scope'>")
4.608 - self.stream.write(self._text(fn))
4.609 - self.stream.write("</div>\n")
4.610 + if hasattr(node, "writes") and node.writes:
4.611 + for ref in node.writes.keys():
4.612 + fn = ref.full_name()
4.613 + labels[self._text(fn)] = None
4.614 +
4.615 + # Non-loading...
4.616 +
4.617 + if hasattr(node, "non_accesses") and node.non_accesses:
4.618 + self._types_container(node.non_accesses, "non-accesses")
4.619
4.620 - # Non-loading...
4.621 + # Non-storing...
4.622
4.623 - if hasattr(node, "non_accesses") and node.non_accesses:
4.624 - self._types_container(node.non_accesses, "non-accesses")
4.625 + if hasattr(node, "non_writes") and node.non_writes:
4.626 + self._types_container(node.non_writes, "non-writes")
4.627
4.628 - # Non-storing...
4.629 -
4.630 - if hasattr(node, "non_writes") and node.non_writes:
4.631 - self._types_container(node.non_writes, "non-writes")
4.632 + if labels:
4.633 + return [("scopes", "scope", labels.keys())]
4.634 + else:
4.635 + return []
4.636
4.637 # Utility functions.
4.638