3.1 --- a/simplify.py Mon Nov 27 01:06:38 2006 +0100
3.2 +++ b/simplify.py Tue Nov 28 00:37:12 2006 +0100
3.3 @@ -97,16 +97,16 @@
3.4
3.5 # Placeholder or deletion transformations.
3.6
3.7 - def visitStmt(self, stmt):
3.8 - return self.dispatches(stmt.nodes)
3.9 + def visitDiscard(self, discard):
3.10 + return self.dispatch(discard.expr)
3.11
3.12 def visitPass(self, pass_):
3.13 return Pass(pass_, 1)
3.14
3.15 - def visitDiscard(self, discard):
3.16 - return self.dispatch(discard.expr)
3.17 + def visitStmt(self, stmt):
3.18 + return self.dispatches(stmt.nodes)
3.19
3.20 - # Relatively trivial transformations.
3.21 + # Top-level transformation.
3.22
3.23 def visitModule(self, module, name=None):
3.24
3.25 @@ -140,34 +140,36 @@
3.26 result.code = init_code + module_code
3.27 return result
3.28
3.29 - def visitGetattr(self, getattr):
3.30 - result = LoadAttr(getattr, 1,
3.31 - name=getattr.attrname,
3.32 - expr=self.dispatch(getattr.expr)
3.33 - )
3.34 + # Relatively trivial transformations.
3.35 +
3.36 + def _visitBuiltin(self, builtin, name):
3.37 + result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None)
3.38 + return result
3.39 +
3.40 + def visitBreak(self, break_):
3.41 + result = ReturnFromBlock(break_, 1)
3.42 return result
3.43
3.44 - def visitKeyword(self, keyword):
3.45 - result = Keyword(keyword, 1,
3.46 - name=keyword.name,
3.47 - expr=self.dispatch(keyword.expr)
3.48 + def visitConst(self, const):
3.49 + if not self.constants.has_key(const.value):
3.50 + self.constants[const.value] = Constant(name=repr(const.value), value=const.value)
3.51 + result = LoadRef(const, 1, ref=self.constants[const.value])
3.52 + return result
3.53 +
3.54 + def visitContinue(self, continue_):
3.55 + result = InvokeBlock(continue_, 1,
3.56 + expr=LoadRef(ref=self.current_subprograms[-1])
3.57 )
3.58 return result
3.59
3.60 - def visitGlobal(self, global_):
3.61 - result = Global(global_, 1,
3.62 - names=global_.names
3.63 - )
3.64 - return result
3.65 -
3.66 - def visitImport(self, import_):
3.67 - result = Assign(import_, 1)
3.68 - code = []
3.69 - for path, alias in import_.names:
3.70 - importer = Import(name=path)
3.71 - top = alias or path.split(".")[0]
3.72 - code.append(StoreName(expr=importer, name=top))
3.73 - result.code = code
3.74 + def visitDict(self, dict):
3.75 + result = InvokeFunction(dict, 1, expr=LoadName(name="dict"), star=None, dstar=None)
3.76 + args = []
3.77 + for key, value in dict.items:
3.78 + tuple = InvokeFunction(expr=LoadName(name="tuple"), star=None, dstar=None)
3.79 + tuple.set_args([self.dispatch(key), self.dispatch(value)])
3.80 + args.append(tuple)
3.81 + result.set_args(args)
3.82 return result
3.83
3.84 def visitFrom(self, from_):
3.85 @@ -187,32 +189,43 @@
3.86 result.code = code
3.87 return result
3.88
3.89 - def visitName(self, name):
3.90 - result = LoadName(name, 1, name=name.name)
3.91 + def visitGetattr(self, getattr):
3.92 + result = LoadAttr(getattr, 1,
3.93 + name=getattr.attrname,
3.94 + expr=self.dispatch(getattr.expr)
3.95 + )
3.96 return result
3.97
3.98 - def visitConst(self, const):
3.99 - if not self.constants.has_key(const.value):
3.100 - self.constants[const.value] = Constant(name=repr(const.value), value=const.value)
3.101 - result = LoadRef(const, 1, ref=self.constants[const.value])
3.102 - return result
3.103 -
3.104 - def visitReturn(self, return_):
3.105 - result = Return(return_, 1,
3.106 - expr=self.dispatch(return_.value)
3.107 + def visitGlobal(self, global_):
3.108 + result = Global(global_, 1,
3.109 + names=global_.names
3.110 )
3.111 return result
3.112
3.113 - def visitBreak(self, break_):
3.114 - result = Return(break_, 1)
3.115 + def visitImport(self, import_):
3.116 + result = Assign(import_, 1)
3.117 + code = []
3.118 + for path, alias in import_.names:
3.119 + importer = Import(name=path)
3.120 + top = alias or path.split(".")[0]
3.121 + code.append(StoreName(expr=importer, name=top))
3.122 + result.code = code
3.123 return result
3.124
3.125 - def visitContinue(self, continue_):
3.126 - result = InvokeBlock(continue_, 1,
3.127 - expr=LoadRef(ref=self.current_subprograms[-1])
3.128 + def visitKeyword(self, keyword):
3.129 + result = Keyword(keyword, 1,
3.130 + name=keyword.name,
3.131 + expr=self.dispatch(keyword.expr)
3.132 )
3.133 return result
3.134
3.135 + def visitList(self, list):
3.136 + return self._visitBuiltin(list, "list")
3.137 +
3.138 + def visitName(self, name):
3.139 + result = LoadName(name, 1, name=name.name)
3.140 + return result
3.141 +
3.142 def visitRaise(self, raise_):
3.143 result = Raise(raise_, 1)
3.144 if raise_.expr2 is None:
3.145 @@ -230,26 +243,15 @@
3.146 result.traceback = None
3.147 return result
3.148
3.149 - def _visitBuiltin(self, builtin, name):
3.150 - result = InvokeFunction(builtin, 1, expr=LoadName(name=name), args=self.dispatches(builtin.nodes), star=None, dstar=None)
3.151 + def visitReturn(self, return_):
3.152 + result = ReturnFromFunction(return_, 1,
3.153 + expr=self.dispatch(return_.value)
3.154 + )
3.155 return result
3.156
3.157 def visitTuple(self, tuple):
3.158 return self._visitBuiltin(tuple, "tuple")
3.159
3.160 - def visitList(self, list):
3.161 - return self._visitBuiltin(list, "list")
3.162 -
3.163 - def visitDict(self, dict):
3.164 - result = InvokeFunction(dict, 1, expr=LoadName(name="dict"), star=None, dstar=None)
3.165 - args = []
3.166 - for key, value in dict.items:
3.167 - tuple = InvokeFunction(expr=LoadName(name="tuple"), star=None, dstar=None)
3.168 - tuple.set_args([self.dispatch(key), self.dispatch(value)])
3.169 - args.append(tuple)
3.170 - result.set_args(args)
3.171 - return result
3.172 -
3.173 # Logical and comparison operations plus chained statements.
3.174
3.175 def visitIf(self, if_):
3.176 @@ -370,7 +372,7 @@
3.177
3.178 # Always return from conditional sections.
3.179
3.180 - test.body += self.dispatch(stmt) + [Return()]
3.181 + test.body += self.dispatch(stmt) + [ReturnFromBlock()]
3.182 nodes.append(test)
3.183 nodes = test.else_ = []
3.184
3.185 @@ -458,8 +460,8 @@
3.186 dstar=None)
3.187
3.188 elif op_name == "is not":
3.189 - invocation = self._visitNot(
3.190 - InvokeFunction(
3.191 + invocation = Not(
3.192 + expr=InvokeFunction(
3.193 expr=LoadName(name="__is__"),
3.194 args=[previous, expr],
3.195 star=None,
3.196 @@ -477,19 +479,25 @@
3.197 nodes.append(
3.198 Conditional(
3.199 test=self._visitNot(LoadTemp()),
3.200 - body=[Return(expr=LoadTemp())])
3.201 + body=[
3.202 + ReturnFromBlock(expr=LoadTemp())
3.203 + ],
3.204 + else_=[
3.205 + ReleaseTemp()
3.206 + # Subsequent operations go here!
3.207 + ]
3.208 + )
3.209 )
3.210
3.211 # Put subsequent operations in the else section of this conditional.
3.212
3.213 - nodes[-1].else_ = [ReleaseTemp()]
3.214 nodes = nodes[-1].else_
3.215
3.216 # For the last operation, return the result.
3.217
3.218 else:
3.219 nodes.append(
3.220 - Return(expr=LoadTemp(release=1))
3.221 + ReturnFromBlock(expr=LoadTemp(release=1))
3.222 )
3.223
3.224 previous = expr
3.225 @@ -519,8 +527,8 @@
3.226
3.227 ...to:
3.228
3.229 - Subprogram -> Conditional (test) -> Return ...
3.230 - (else) -> Conditional (test) -> Return ...
3.231 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
3.232 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.233 (else) -> ...
3.234 """
3.235
3.236 @@ -540,19 +548,30 @@
3.237 # Return from the subprogram where the test is not satisfied.
3.238
3.239 if node is not last:
3.240 - nodes.append(StoreTemp(expr=expr))
3.241 - #invocation = InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="__bool__"), args=[], star=None, dstar=None)
3.242 - test = Conditional(test=self._visitNot(LoadTemp()), body=[Return(expr=LoadTemp())])
3.243 - nodes.append(test)
3.244 + nodes += [
3.245 + StoreTemp(expr=expr),
3.246 + Conditional(
3.247 + test=self._visitNot(LoadTemp()),
3.248 + body=[
3.249 + ReturnFromBlock(
3.250 + expr=LoadTemp()
3.251 + )
3.252 + ],
3.253 + else_=[
3.254 + ReleaseTemp()
3.255 + # Subsequent operations go here!
3.256 + ]
3.257 + )
3.258 + ]
3.259
3.260 # Put subsequent operations in the else section of this conditional.
3.261
3.262 - nodes = test.else_ = [ReleaseTemp()]
3.263 + nodes = nodes[-1].else_
3.264
3.265 # For the last operation, return the result.
3.266
3.267 else:
3.268 - nodes.append(Return(expr=expr))
3.269 + nodes.append(ReturnFromBlock(expr=expr))
3.270
3.271 # Finish the subprogram definition.
3.272
3.273 @@ -579,8 +598,8 @@
3.274
3.275 ...to:
3.276
3.277 - Subprogram -> Conditional (test) -> Return ...
3.278 - (else) -> Conditional (test) -> Return ...
3.279 + Subprogram -> Conditional (test) -> ReturnFromBlock ...
3.280 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.281 (else) -> ...
3.282 """
3.283
3.284 @@ -602,7 +621,7 @@
3.285 if node is not last:
3.286 nodes.append(StoreTemp(expr=expr))
3.287 invocation = InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="__bool__"), args=[], star=None, dstar=None)
3.288 - test = Conditional(test=invocation, body=[Return(expr=LoadTemp())])
3.289 + test = Conditional(test=invocation, body=[ReturnFromBlock(expr=LoadTemp())])
3.290 nodes.append(test)
3.291
3.292 # Put subsequent operations in the else section of this conditional.
3.293 @@ -613,7 +632,7 @@
3.294
3.295 else:
3.296 nodes.append(
3.297 - Return(expr=expr)
3.298 + ReturnFromBlock(expr=expr)
3.299 )
3.300
3.301 # Finish the subprogram definition.
3.302 @@ -650,49 +669,16 @@
3.303
3.304 # Operators.
3.305
3.306 - def visitUnaryAdd(self, unaryadd):
3.307 - return InvokeFunction(unaryadd, 1,
3.308 - expr=LoadAttr(
3.309 - expr=self.dispatch(unaryadd.expr),
3.310 - name="__pos__"
3.311 - ),
3.312 - args=[],
3.313 - star=None,
3.314 - dstar=None
3.315 - )
3.316 -
3.317 - def visitUnarySub(self, unarysub):
3.318 - return InvokeFunction(unarysub, 1,
3.319 - expr=LoadAttr(
3.320 - expr=self.dispatch(unarysub.expr),
3.321 - name="__neg__"
3.322 - ),
3.323 - args=[],
3.324 - star=None,
3.325 - dstar=None
3.326 - )
3.327 -
3.328 - def visitInvert(self, invert):
3.329 - return InvokeFunction(invert, 1,
3.330 - expr=LoadAttr(
3.331 - expr=self.dispatch(invert.expr),
3.332 - name="__invert__"
3.333 - ),
3.334 - args=[],
3.335 - star=None,
3.336 - dstar=None
3.337 - )
3.338 -
3.339 - def visitAdd(self, add):
3.340 + def _visitBinary(self, binary, left_name, right_name):
3.341
3.342 """
3.343 Emulate the current mechanisms by producing nodes as follows:
3.344
3.345 - InvokeBlock -> Subprogram -> Try (body) -> Return (expr) -> x.__add__(y)
3.346 + InvokeBlock -> Subprogram -> Try (body) -> ReturnFromBlock (expr) -> x.__add__(y)
3.347 (else)
3.348 (handler) -> Conditional (test) -> CheckExc (expr) -> LoadExc
3.349 (choices) -> LoadName TypeError
3.350 - (body) -> Return (expr) -> y.__radd__(x)
3.351 + (body) -> ReturnFromBlock (expr) -> y.__radd__(x)
3.352 (else)
3.353 """
3.354
3.355 @@ -700,12 +686,12 @@
3.356 self.current_subprograms.append(subprogram)
3.357
3.358 subprogram.code = [
3.359 - Try(add, 1,
3.360 + Try(binary, 1,
3.361 body=[
3.362 - Return(
3.363 + ReturnFromBlock(
3.364 expr=InvokeFunction(
3.365 - expr=LoadAttr(expr=self.dispatch(add.left), name="__add__"),
3.366 - args=[self.dispatch(add.right)],
3.367 + expr=LoadAttr(expr=self.dispatch(binary.left), name=left_name),
3.368 + args=[self.dispatch(binary.right)],
3.369 star=None,
3.370 dstar=None)
3.371 )
3.372 @@ -716,10 +702,10 @@
3.373 Conditional(
3.374 test=CheckExc(expr=LoadExc(), choices=[LoadName(name="TypeError")]),
3.375 body=[
3.376 - Return(
3.377 + ReturnFromBlock(
3.378 expr=InvokeFunction(
3.379 - expr=LoadAttr(expr=self.dispatch(add.right), name="__radd__"),
3.380 - args=[self.dispatch(add.left)],
3.381 + expr=LoadAttr(expr=self.dispatch(binary.right), name=right_name),
3.382 + args=[self.dispatch(binary.left)],
3.383 star=None,
3.384 dstar=None)
3.385 )
3.386 @@ -734,6 +720,46 @@
3.387 result.expr = LoadRef(ref=subprogram)
3.388 return result
3.389
3.390 + def visitAdd(self, add):
3.391 + return self._visitBinary(add, "__add__", "__radd__")
3.392 +
3.393 + def visitDiv(self, div):
3.394 + return self._visitBinary(div, "__div__", "__rdiv__")
3.395 +
3.396 + def visitMul(self, mul):
3.397 + return self._visitBinary(mul, "__mul__", "__rmul__")
3.398 +
3.399 + def visitSub(self, sub):
3.400 + return self._visitBinary(sub, "__sub__", "__rsub__")
3.401 +
3.402 + def visitInvert(self, invert):
3.403 + return InvokeFunction(invert, 1,
3.404 + expr=LoadAttr(
3.405 + expr=self.dispatch(invert.expr),
3.406 + name="__invert__"
3.407 + ),
3.408 + args=[],
3.409 + star=None,
3.410 + dstar=None
3.411 + )
3.412 +
3.413 + def _visitUnary(self, unary, name):
3.414 + return InvokeFunction(unary, 1,
3.415 + expr=LoadAttr(
3.416 + expr=self.dispatch(unary.expr),
3.417 + name=name
3.418 + ),
3.419 + args=[],
3.420 + star=None,
3.421 + dstar=None
3.422 + )
3.423 +
3.424 + def visitUnaryAdd(self, unaryadd):
3.425 + return self._visitUnary(unaryadd, "__pos__")
3.426 +
3.427 + def visitUnarySub(self, unarysub):
3.428 + return self._visitUnary(unarysub, "__neg__")
3.429 +
3.430 # Assignments.
3.431
3.432 augassign_methods = {
3.433 @@ -1059,7 +1085,7 @@
3.434
3.435 # The class is initialised using the code found inside.
3.436
3.437 - subprogram.code = self.dispatch(class_.code) + [Return()]
3.438 + subprogram.code = self.dispatch(class_.code) + [ReturnFromBlock()]
3.439
3.440 self.current_structures.pop()
3.441 self.current_subprograms.pop()
3.442 @@ -1155,7 +1181,7 @@
3.443 internal=0, returns_value=1, star=None, dstar=None)
3.444
3.445 self.current_subprograms.append(subprogram)
3.446 - subprogram.code = self.dispatch(function.code) + [Return()]
3.447 + subprogram.code = self.dispatch(function.code) + [ReturnFromFunction()]
3.448 self.current_subprograms.pop()
3.449 self._visitFunction(function, subprogram)
3.450
3.451 @@ -1171,7 +1197,7 @@
3.452
3.453 subprogram = Subprogram(name=None, module=self.module, internal=0, returns_value=1, star=None, dstar=None)
3.454 self.current_subprograms.append(subprogram)
3.455 - subprogram.code = [Return(expr=self.dispatch(lambda_.code))]
3.456 + subprogram.code = [ReturnFromFunction(expr=self.dispatch(lambda_.code))]
3.457 self.current_subprograms.pop()
3.458 self._visitFunction(lambda_, subprogram)
3.459
3.460 @@ -1200,7 +1226,7 @@
3.461 ...to:
3.462
3.463 Subprogram -> Conditional (test) -> (body) -> Invoke subprogram
3.464 - (else) -> Conditional (test) -> Return ...
3.465 + (else) -> Conditional (test) -> ReturnFromBlock ...
3.466 (else) -> ...
3.467 """
3.468
3.469 @@ -1220,12 +1246,12 @@
3.470
3.471 # Return within the main section of the loop.
3.472
3.473 - test.body = self.dispatch(while_.body) + [continuation, Return()]
3.474 + test.body = self.dispatch(while_.body) + [continuation, ReturnFromBlock()]
3.475
3.476 # Provide the else section, if present, along with an explicit return.
3.477
3.478 if while_.else_ is not None:
3.479 - test.else_ = self.dispatch(while_.else_) + [Return()]
3.480 + test.else_ = self.dispatch(while_.else_) + [ReturnFromBlock()]
3.481
3.482 # Finish the subprogram definition.
3.483
3.484 @@ -1266,38 +1292,43 @@
3.485 # Always return from conditional sections/subprograms.
3.486
3.487 if for_.else_ is not None:
3.488 - else_stmt = self.dispatch(for_.else_) + [Return()]
3.489 + else_stmt = self.dispatch(for_.else_) + [ReturnFromBlock()]
3.490 else:
3.491 - else_stmt = [Return()]
3.492 + else_stmt = [ReturnFromBlock()]
3.493
3.494 # Wrap the assignment in a try...except statement.
3.495 -
3.496 - try_except = Try(body=[], else_=[], finally_=[])
3.497 - test = Conditional(
3.498 - test=InvokeFunction(
3.499 - expr=LoadName(name="isinstance"),
3.500 - args=[LoadExc(), LoadName(name="StopIteration")],
3.501 - star=None,
3.502 - dstar=None),
3.503 - body=else_stmt,
3.504 - else_=[Raise(expr=LoadExc())])
3.505 - try_except.handler = [test]
3.506 + # Inside the body, add a recursive invocation to the subprogram.
3.507
3.508 - assign = Assign(
3.509 - code=[
3.510 - StoreTemp(expr=InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="next"), args=[], star=None, dstar=None)),
3.511 - self.dispatch(for_.assign),
3.512 - ReleaseTemp()
3.513 - ])
3.514 -
3.515 - # Inside the conditional, add a recursive invocation to the subprogram
3.516 - # if the test condition was satisfied.
3.517 -
3.518 - continuation = InvokeBlock(
3.519 - expr=LoadRef(ref=subprogram)
3.520 - )
3.521 - try_except.body = [assign] + self.dispatch(for_.body) + [continuation]
3.522 - subprogram.code = [try_except, Return()]
3.523 + subprogram.code = [
3.524 + Try(
3.525 + body=[
3.526 + Assign(
3.527 + code=[
3.528 + StoreTemp(expr=InvokeFunction(expr=LoadAttr(expr=LoadTemp(), name="next"), args=[], star=None, dstar=None)),
3.529 + self.dispatch(for_.assign),
3.530 + ReleaseTemp()
3.531 + ])
3.532 + ] + self.dispatch(for_.body) + [
3.533 + InvokeBlock(
3.534 + expr=LoadRef(ref=subprogram)
3.535 + )
3.536 + ],
3.537 + handler=[
3.538 + Conditional(
3.539 + test=InvokeFunction(
3.540 + expr=LoadName(name="isinstance"),
3.541 + args=[LoadExc(), LoadName(name="StopIteration")],
3.542 + star=None,
3.543 + dstar=None),
3.544 + body=else_stmt,
3.545 + else_=[Raise(expr=LoadExc())]
3.546 + )
3.547 + ],
3.548 + else_=[],
3.549 + finally_=[]
3.550 + ),
3.551 + ReturnFromBlock()
3.552 + ]
3.553
3.554 # Finish the subprogram definition.
3.555
6.1 --- a/viewer.py Mon Nov 27 01:06:38 2006 +0100
6.2 +++ b/viewer.py Tue Nov 28 00:37:12 2006 +0100
6.3 @@ -152,7 +152,9 @@
6.4 .name,
6.5 .attr,
6.6 .conditional,
6.7 - .operator
6.8 + .operator,
6.9 + .iterator,
6.10 + .returns
6.11 {
6.12 position: relative;
6.13 }
6.14 @@ -161,7 +163,9 @@
6.15 .name:hover > .popup,
6.16 .attr:hover > .popup,
6.17 .conditional:hover > .popup,
6.18 - .operator:hover > .popup
6.19 + .operator:hover > .popup,
6.20 + .iterator:hover > .popup,
6.21 + .returns:hover > .popup
6.22 {
6.23 display: block;
6.24 }
6.25 @@ -291,9 +295,19 @@
6.26 def visitFor(self, node):
6.27 self.stream.write("<div class='if'>\n")
6.28 self.stream.write("<div>\n")
6.29 + self.stream.write("<span class='iterator'>\n")
6.30 self._keyword("for")
6.31 + self._popup_start()
6.32 + self._invocations(node._node.code[1].expr.ref.code[0].body[0].code[0].expr) # Link to next call in subprogram.
6.33 + self._popup_end()
6.34 + self.stream.write("</span>\n")
6.35 self.dispatch(node.assign)
6.36 + self.stream.write("<span class='iterator'>\n")
6.37 self._keyword("in")
6.38 + self._popup_start()
6.39 + self._invocations(node._node.code[0].expr) # Link to __iter__ call.
6.40 + self._popup_end()
6.41 + self.stream.write("</span>\n")
6.42 self.dispatch(node.list)
6.43 self.stream.write(":\n")
6.44 self.stream.write("</div>\n")
6.45 @@ -390,7 +404,12 @@
6.46
6.47 def visitReturn(self, node):
6.48 self.stream.write("<div class='return'>\n")
6.49 + self.stream.write("<span class='returns'>\n")
6.50 self._keyword("return")
6.51 + self._popup_start()
6.52 + self._types(node._node)
6.53 + self._popup_end()
6.54 + self.stream.write("</span>\n")
6.55 self.dispatch(node.value)
6.56 self.stream.write("</div>\n")
6.57
6.58 @@ -476,11 +495,11 @@
6.59
6.60 # Expressions.
6.61
6.62 - def visitAdd(self, node):
6.63 - self.stream.write("<span class='add'>\n")
6.64 + def _visitBinary(self, node, name, symbol):
6.65 + self.stream.write("<span class='%s'>\n" % name)
6.66 self.dispatch(node.left)
6.67 self.stream.write("<span class='operator'>\n")
6.68 - self.stream.write("+")
6.69 + self.stream.write(symbol)
6.70 self._popup_start()
6.71 self.stream.write("<div class='invocations'>\n")
6.72 self._invocations_list(node._node.body[0].expr) # NOTE: See visitAdd in simplify.
6.73 @@ -491,6 +510,9 @@
6.74 self.dispatch(node.right)
6.75 self.stream.write("</span>")
6.76
6.77 + def visitAdd(self, node):
6.78 + self._visitBinary(node, "add", "+")
6.79 +
6.80 def visitAnd(self, node):
6.81 self.stream.write("<span class='and'>\n")
6.82 first = 1
6.83 @@ -581,6 +603,9 @@
6.84 def visitConst(self, node):
6.85 self.stream.write(repr(node.value))
6.86
6.87 + def visitDiv(self, node):
6.88 + self._visitBinary(node, "div", "/")
6.89 +
6.90 def visitGetattr(self, node):
6.91 self.stream.write("<span class='getattr'>\n")
6.92 self.dispatch(node.expr)
6.93 @@ -614,6 +639,9 @@
6.94
6.95 visitList = visitAssList
6.96
6.97 + def visitMul(self, node):
6.98 + self._visitBinary(node, "mul", "*")
6.99 +
6.100 def visitName(self, node):
6.101 if hasattr(node, "_node"):
6.102 self._name_start(node._node.name)
6.103 @@ -655,6 +683,9 @@
6.104 self.stream.write("]")
6.105 self.stream.write("</span>\n")
6.106
6.107 + def visitSub(self, node):
6.108 + self._visitBinary(node, "sub", "-")
6.109 +
6.110 def visitSubscript(self, node):
6.111 self.stream.write("<span class='subscript'>\n")
6.112 self.dispatch(node.expr)
6.113 @@ -752,7 +783,10 @@
6.114
6.115 def _op(self, op_name, op):
6.116 if op is not None:
6.117 - self._invocations(op)
6.118 + if isinstance(op, Not):
6.119 + self._invocations(op.expr)
6.120 + else:
6.121 + self._invocations(op)
6.122
6.123 def _invocations(self, node):
6.124 self.stream.write("<div class='invocations'>\n")