5.1 --- a/micropython/report.py Sun Jul 11 02:05:41 2010 +0200
5.2 +++ b/micropython/report.py Sat Aug 07 02:06:15 2010 +0200
5.3 @@ -19,8 +19,9 @@
5.4 this program. If not, see <http://www.gnu.org/licenses/>.
5.5 """
5.6
5.7 +from micropython.common import *
5.8 from micropython.data import *
5.9 -from compiler.visitor import ASTVisitor
5.10 +from os.path import exists, extsep, join
5.11 import sys
5.12 import os
5.13 import textwrap
5.14 @@ -33,7 +34,7 @@
5.15 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5.16 <html xmlns="http://www.w3.org/1999/xhtml">
5.17 <head>
5.18 - <title>Module</title>
5.19 + <title>Module: %(full_name)s</title>
5.20 <style type="text/css">
5.21 html {
5.22 background-color: black; color: white;
5.23 @@ -45,6 +46,10 @@
5.24 background-color: black; color: white;
5.25 }
5.26
5.27 + a {
5.28 + text-decoration: none;
5.29 + }
5.30 +
5.31 .nowrap { white-space: nowrap; }
5.32
5.33 .class { margin-top: 1em; margin-bottom: 1em; }
5.34 @@ -56,7 +61,31 @@
5.35 .function-name { color: cyan; }
5.36 .str { color: #FF00FF; }
5.37 .doc { color: #FF00FF; margin-top: 1em; margin-bottom: 1em; }
5.38 - .invocation a { color: white; text-decoration: none; }
5.39 +
5.40 + .popup {
5.41 + display: none;
5.42 + position: absolute;
5.43 + top: 3ex; left: 0;
5.44 + color: white;
5.45 + z-index: 3;
5.46 + }
5.47 +
5.48 + .scope { padding: 0.5em; background-color: #007700; }
5.49 +
5.50 + .name {
5.51 + position: relative;
5.52 + color: white;
5.53 + }
5.54 +
5.55 + .name:hover {
5.56 + background-color: #003300;
5.57 + padding-bottom: 1ex;
5.58 + z-index: 2;
5.59 + }
5.60 +
5.61 + .name:hover .popup {
5.62 + display: block;
5.63 + }
5.64
5.65 .summary-class {
5.66 background-color: #004400;
5.67 @@ -98,29 +127,34 @@
5.68
5.69 # Methods which write to the stream.
5.70
5.71 + def _span_end(self):
5.72 + self.stream.write("</span>")
5.73 +
5.74 def _comment(self, comment):
5.75 self.stream.write("<span class='comment'># %s</span>\n" % comment)
5.76
5.77 - def _keyword(self, kw):
5.78 - self.stream.write("<span class='keyword'>%s</span> " % kw)
5.79 + def _reserved(self, token, classes, leading=0, trailing=1):
5.80 + if leading:
5.81 + self.stream.write(" ")
5.82 + self.stream.write("<span class='%s'>%s</span>" % (classes, self._text(token)))
5.83 + if trailing:
5.84 + self.stream.write(" ")
5.85 +
5.86 + def _keyword(self, kw, leading=0, trailing=1):
5.87 + self._reserved(kw, "keyword", leading, trailing)
5.88 +
5.89 + def _op(self, symbol, leading=0, trailing=1):
5.90 + self._reserved(symbol, "operator", leading, trailing)
5.91
5.92 def _doc(self, node):
5.93 if node.doc is not None:
5.94 - self.stream.write("<pre class='doc'>\n")
5.95 + self.stream.write("<pre class='doc'>")
5.96 self.stream.write('"""')
5.97 output = textwrap.dedent(node.doc.replace('"""', '\\"\\"\\"'))
5.98 self.stream.write(self._text(output))
5.99 self.stream.write('"""')
5.100 self.stream.write("</pre>\n")
5.101
5.102 - def _name(self, name, classes=None):
5.103 - self.stream.write("<span class='%s'>%s</span>" % (classes or "name", name))
5.104 -
5.105 - def _name_link(self, module_name, full_name, name, classes=None):
5.106 - self.stream.write("<a class='%s' href='%s%sxhtml#%s'>%s</a>" % (
5.107 - classes or "name", module_name, os.path.extsep,
5.108 - self._attr(full_name), self._text(name)))
5.109 -
5.110 def _summary_link(self, module_name, full_name, name, classes=None):
5.111 self._name_link("%s-summary" % module_name, full_name, name, classes)
5.112
5.113 @@ -133,6 +167,29 @@
5.114
5.115 self._summary_link(module.full_name(), obj.full_name(), obj.name, classes)
5.116
5.117 + def _name_start(self, classes=None):
5.118 + self.stream.write("<span class='%s'>" % (classes or "name"))
5.119 +
5.120 + _name_end = _span_end
5.121 +
5.122 + def _name(self, name, classes=None):
5.123 + self._name_start(classes)
5.124 + self.stream.write(name)
5.125 + self._name_end()
5.126 +
5.127 + def _name_link(self, module_name, full_name, name, classes=None):
5.128 + self.stream.write("<a class='%s' href='%s%sxhtml#%s'>%s</a>" % (
5.129 + classes or "name", module_name, os.path.extsep,
5.130 + self._attr(full_name), self._text(name)))
5.131 +
5.132 + def _popup_start(self):
5.133 + self.stream.write("<span class='popup'>")
5.134 +
5.135 + _popup_end = _span_end
5.136 +
5.137 + def _scope(self, scope):
5.138 + self.stream.write("<div class='scope'>%s</div>\n" % scope)
5.139 +
5.140 # Summary classes.
5.141
5.142 class Summary(Writer):
5.143 @@ -148,7 +205,7 @@
5.144
5.145 self.stream = stream
5.146 self._init_details()
5.147 - self.stream.write(html_header)
5.148 + self.stream.write(html_header % {"full_name" : self.module.full_name()})
5.149 self._write_classes(self.module)
5.150 self.stream.write(html_footer)
5.151
5.152 @@ -221,8 +278,8 @@
5.153 "Write the annotated code to the given 'stream'."
5.154
5.155 self.stream = stream
5.156 - self.stream.write(html_header)
5.157 - self.dispatch(self.module.module)
5.158 + self.stream.write(html_header % {"full_name" : self.module.full_name()})
5.159 + self.dispatch(self.module.astnode)
5.160 self.stream.write(html_footer)
5.161
5.162 def visitModule(self, node):
5.163 @@ -243,14 +300,14 @@
5.164 self.stream.write("<div class='assign nowrap'>\n")
5.165 for lvalue in node.nodes:
5.166 self.dispatch(lvalue)
5.167 - self.stream.write("= ")
5.168 + self.stream.write(" = ")
5.169 self.dispatch(node.expr)
5.170 self.stream.write("</div>\n")
5.171
5.172 def visitAugAssign(self, node):
5.173 self.stream.write("<div class='augassign nowrap'>\n")
5.174 self.dispatch(node.node)
5.175 - self.stream.write("%s " % node.op)
5.176 + self.stream.write(" %s " % node.op)
5.177 self.dispatch(node.expr)
5.178 self.stream.write("</div>\n")
5.179
5.180 @@ -260,6 +317,8 @@
5.181 self.stream.write("</div>\n")
5.182
5.183 def visitClass(self, node):
5.184 + if not used_by_unit(node):
5.185 + return
5.186
5.187 # Use inspected details where possible.
5.188
5.189 @@ -317,7 +376,7 @@
5.190 self.stream.write("<div>\n")
5.191 self._keyword("for")
5.192 self.dispatch(node.assign)
5.193 - self._keyword("in")
5.194 + self._keyword("in", 1)
5.195 self.dispatch(node.list)
5.196 self.stream.write(":\n")
5.197 self.stream.write("</div>\n")
5.198 @@ -326,7 +385,7 @@
5.199 self.stream.write("</div>\n")
5.200 if node.else_ is not None:
5.201 self.stream.write("<div>\n")
5.202 - self._keyword("else")
5.203 + self._keyword("else", trailing=0)
5.204 self.stream.write(":\n")
5.205 self.stream.write("</div>\n")
5.206 self.stream.write("<div class='body nowrap'>\n")
5.207 @@ -338,19 +397,22 @@
5.208 self.stream.write("<div class='from nowrap'>\n")
5.209 self._keyword("from")
5.210 self._name(node.modname)
5.211 - self._keyword("import")
5.212 + self._keyword("import", 1)
5.213 first = 1
5.214 for (name, alias), _name in map(None, node.names, node._names):
5.215 if not first:
5.216 self.stream.write(", ")
5.217 if alias:
5.218 self.stream.write(name + " ")
5.219 - self._keyword("as")
5.220 + self._keyword("as", 1)
5.221 self._name(alias or name)
5.222 first = 0
5.223 self.stream.write("</div>\n")
5.224
5.225 def visitFunction(self, node):
5.226 + if not used_by_unit(node):
5.227 + return
5.228 +
5.229 if hasattr(node, "_def"):
5.230 fn = node._def
5.231 self.stream.write("<div class='function nowrap' id='%s'>\n" % fn.full_name())
5.232 @@ -405,7 +467,144 @@
5.233 first = 0
5.234 if node.else_ is not None:
5.235 self.stream.write("<div>\n")
5.236 - self._keyword("else")
5.237 + self._keyword("else", trailing=0)
5.238 + self.stream.write(":\n")
5.239 + self.stream.write("</div>\n")
5.240 + self.stream.write("<div class='body nowrap'>\n")
5.241 + self.dispatch(node.else_)
5.242 + self.stream.write("</div>\n")
5.243 + self.stream.write("</div>\n")
5.244 +
5.245 + def visitImport(self, node):
5.246 + self.stream.write("<div class='import nowrap'>\n")
5.247 + self._keyword("import")
5.248 + first = 1
5.249 + for name, alias in node.names:
5.250 + if not first:
5.251 + self.stream.write(",\n")
5.252 + if alias:
5.253 + self.stream.write(name + " ")
5.254 + self._keyword("as", 1)
5.255 + self._name(alias or name)
5.256 + first = 0
5.257 + self.stream.write("</div>\n")
5.258 +
5.259 + def visitPass(self, node):
5.260 + self.stream.write("<div class='pass nowrap'>\n")
5.261 + self._keyword("pass")
5.262 + self.stream.write("</div>\n")
5.263 +
5.264 + def visitPrint(self, node):
5.265 + self.stream.write("<div class='print nowrap'>\n")
5.266 + self._keyword("print")
5.267 + if node.dest is not None:
5.268 + self.stream.write(">>\n")
5.269 + self.dispatch(node.dest)
5.270 + for n in node.nodes:
5.271 + self.dispatch(n)
5.272 + self.stream.write(",\n")
5.273 + self.stream.write("</div>\n")
5.274 +
5.275 + def visitPrintnl(self, node):
5.276 + self.stream.write("<div class='printnl nowrap'>\n")
5.277 + self._keyword("print")
5.278 + if node.dest is not None:
5.279 + self.stream.write(">>\n")
5.280 + self.dispatch(node.dest)
5.281 + first = 1
5.282 + for n in node.nodes:
5.283 + if not first:
5.284 + self.stream.write(",\n")
5.285 + self.dispatch(n)
5.286 + first = 0
5.287 + self.stream.write("</div>\n")
5.288 +
5.289 + def visitRaise(self, node):
5.290 + self.stream.write("<div class='raise nowrap'>\n")
5.291 + self._keyword("raise")
5.292 + self.dispatch(node.expr1)
5.293 + if node.expr2 is not None:
5.294 + self.stream.write(",\n")
5.295 + self.dispatch(node.expr2)
5.296 + if node.expr3 is not None:
5.297 + self.stream.write(",\n")
5.298 + self.dispatch(node.expr3)
5.299 + self.stream.write("</div>\n")
5.300 +
5.301 + def visitReturn(self, node):
5.302 + self.stream.write("<div class='return nowrap'>\n")
5.303 + self._keyword("return")
5.304 + self.dispatch(node.value)
5.305 + self.stream.write("</div>\n")
5.306 +
5.307 + def visitStmt(self, node):
5.308 + self.stream.write("<div class='stmt nowrap'>\n")
5.309 + self.default(node)
5.310 + self.stream.write("</div>\n")
5.311 +
5.312 + def visitTryExcept(self, node):
5.313 + self.stream.write("<div class='tryexcept nowrap'>\n")
5.314 + self.stream.write("<div>\n")
5.315 + self._keyword("try", trailing=0)
5.316 + self.stream.write(":\n")
5.317 + self.stream.write("</div>\n")
5.318 + self.stream.write("<div class='body nowrap'>\n")
5.319 + self.dispatch(node.body)
5.320 + self.stream.write("</div>\n")
5.321 + for spec, assign, statement in node.handlers:
5.322 + self.stream.write("<div>\n")
5.323 + self._keyword("except")
5.324 + if spec is not None:
5.325 + self.dispatch(spec)
5.326 + if assign is not None:
5.327 + self.stream.write(",\n")
5.328 + self.dispatch(assign)
5.329 + self.stream.write(":\n")
5.330 + self.stream.write("</div>\n")
5.331 + self.stream.write("<div class='body nowrap'>\n")
5.332 + self.dispatch(statement)
5.333 + self.stream.write("</div>\n")
5.334 + if node.else_ is not None:
5.335 + self.stream.write("<div>\n")
5.336 + self._keyword("else", trailing=0)
5.337 + self.stream.write(":\n")
5.338 + self.stream.write("</div>\n")
5.339 + self.stream.write("<div class='body nowrap'>\n")
5.340 + self.dispatch(node.else_)
5.341 + self.stream.write("</div>\n")
5.342 + self.stream.write("</div>\n")
5.343 +
5.344 + def visitTryFinally(self, node):
5.345 + self.stream.write("<div class='tryfinally nowrap'>\n")
5.346 + self.stream.write("<div>\n")
5.347 + self._keyword("try", trailing=0)
5.348 + self.stream.write(":\n")
5.349 + self.stream.write("</div>\n")
5.350 + self.stream.write("<div class='body nowrap'>\n")
5.351 + self.dispatch(node.body)
5.352 + self.stream.write("</div>\n")
5.353 + self.stream.write("<div>\n")
5.354 + self._keyword("finally", trailing=0)
5.355 + self.stream.write(":\n")
5.356 + self.stream.write("</div>\n")
5.357 + self.stream.write("<div class='body nowrap'>\n")
5.358 + self.dispatch(node.final)
5.359 + self.stream.write("</div>\n")
5.360 + self.stream.write("</div>\n")
5.361 +
5.362 + def visitWhile(self, node):
5.363 + self.stream.write("<div class='while nowrap'>\n")
5.364 + self.stream.write("<div>\n")
5.365 + self._keyword("while")
5.366 + self.dispatch(node.test)
5.367 + self.stream.write(":\n")
5.368 + self.stream.write("</div>\n")
5.369 + self.stream.write("<div class='body nowrap'>\n")
5.370 + self.dispatch(node.body)
5.371 + self.stream.write("</div>\n")
5.372 + if node.else_ is not None:
5.373 + self.stream.write("<div>\n")
5.374 + self._keyword("else", trailing=0)
5.375 self.stream.write(":\n")
5.376 self.stream.write("</div>\n")
5.377 self.stream.write("<div class='body nowrap'>\n")
5.378 @@ -413,6 +612,210 @@
5.379 self.stream.write("</div>\n")
5.380 self.stream.write("</div>\n")
5.381
5.382 + # Expression-related helper methods.
5.383 +
5.384 + def _visitBitBinary(self, node, name, symbol):
5.385 + self.stream.write("<span class='%s'>" % name)
5.386 + first = 1
5.387 + for node in node.nodes:
5.388 + if not first:
5.389 + self._op(symbol, 1)
5.390 + self.dispatch(node)
5.391 + first = 0
5.392 + self.stream.write("</span>")
5.393 +
5.394 + def _visitBinary(self, node, name, symbol):
5.395 + self.stream.write("<span class='%s'>" % name)
5.396 + self.dispatch(node.left)
5.397 + self._op(symbol, 1)
5.398 + self.dispatch(node.right)
5.399 + self.stream.write("</span>")
5.400 +
5.401 + def _visitUnary(self, node, name, symbol):
5.402 + self.stream.write("<span class='%s'>" % name)
5.403 + self._op(symbol)
5.404 + self.dispatch(node.expr)
5.405 + self.stream.write("</span>")
5.406 +
5.407 + # Expressions.
5.408 +
5.409 + def visitAdd(self, node):
5.410 + self._visitBinary(node, "add", "+")
5.411 +
5.412 + def visitAnd(self, node):
5.413 + self.stream.write("<span class='and'>")
5.414 + first = 1
5.415 + for n in node.nodes:
5.416 + if not first:
5.417 + self._keyword("and", 1)
5.418 + self.dispatch(n)
5.419 + first = 0
5.420 + self.stream.write("</span>")
5.421 +
5.422 + def visitAssAttr(self, node):
5.423 + self.stream.write("<span class='assattr'>")
5.424 + self.dispatch(node.expr)
5.425 + self.stream.write("<span class='attr'>")
5.426 + self.stream.write(".")
5.427 + self._name(node.attrname)
5.428 + self.stream.write("</span>")
5.429 + self.stream.write("</span>")
5.430 +
5.431 + def visitAssList(self, node):
5.432 + self.stream.write("<span class='list'>")
5.433 + self.stream.write("[")
5.434 + self._sequence(node)
5.435 + self.stream.write("]")
5.436 + self.stream.write("</span>")
5.437 +
5.438 + def visitAssName(self, node):
5.439 + self._name(node.name)
5.440 +
5.441 + def visitAssTuple(self, node):
5.442 + self.stream.write("<span class='tuple'>")
5.443 + self.stream.write("(")
5.444 + self._sequence(node)
5.445 + self.stream.write(")")
5.446 + self.stream.write("</span>")
5.447 +
5.448 + def visitBitand(self, node):
5.449 + self._visitBitBinary(node, "bitand", "&")
5.450 +
5.451 + def visitCallFunc(self, node):
5.452 + self.stream.write("<span class='callfunc'>")
5.453 + self.dispatch(node.node)
5.454 + self.stream.write("<span class='call'>")
5.455 + self.stream.write("(")
5.456 + first = 1
5.457 + for arg in node.args:
5.458 + if not first:
5.459 + self.stream.write(", ")
5.460 + self.dispatch(arg)
5.461 + first = 0
5.462 + if node.star_args is not None:
5.463 + if not first:
5.464 + self.stream.write(", *")
5.465 + self.dispatch(node.star_args)
5.466 + first = 0
5.467 + if node.dstar_args is not None:
5.468 + if not first:
5.469 + self.stream.write(", **")
5.470 + self.dispatch(node.dstar_args)
5.471 + first = 0
5.472 + self.stream.write(")")
5.473 + self.stream.write("</span>")
5.474 + self.stream.write("</span>")
5.475 +
5.476 + def visitCompare(self, node):
5.477 + self.stream.write("<span class='compare'>")
5.478 + self.dispatch(node.expr)
5.479 + for op_name, expr in node.ops:
5.480 + self._op(op_name, 1)
5.481 + self.dispatch(expr)
5.482 + self.stream.write("</span>")
5.483 +
5.484 + def visitConst(self, node):
5.485 + if isinstance(node.value, (str, unicode)):
5.486 + self.stream.write("<span class='str'>")
5.487 + self.stream.write(self._text(repr(node.value)))
5.488 + if isinstance(node.value, (str, unicode)):
5.489 + self.stream.write("</span>")
5.490 +
5.491 + def visitDict(self, node):
5.492 + self.stream.write("<span class='dict'>")
5.493 + self.stream.write("{")
5.494 + self._mapping(node)
5.495 + self.stream.write("}")
5.496 + self.stream.write("</span>")
5.497 +
5.498 + def visitDiv(self, node):
5.499 + self._visitBinary(node, "div", "/")
5.500 +
5.501 + def visitFloorDiv(self, node):
5.502 + self._visitBinary(node, "floordiv", "//")
5.503 +
5.504 + def visitGetattr(self, node):
5.505 + self.stream.write("<span class='getattr'>")
5.506 + self.dispatch(node.expr)
5.507 + self.stream.write("<span class='attr'>")
5.508 + self.stream.write(".")
5.509 + self._name(node.attrname)
5.510 + self.stream.write("</span>")
5.511 + self.stream.write("</span>")
5.512 +
5.513 + def visitKeyword(self, node):
5.514 + self.stream.write("<span class='keyword-arg'>")
5.515 + self.stream.write(node.name)
5.516 + self.stream.write("=")
5.517 + self.dispatch(node.expr)
5.518 + self.stream.write("</span>")
5.519 +
5.520 + def visitLambda(self, node):
5.521 + if hasattr(node, "_def"):
5.522 + fn = node._def
5.523 + else:
5.524 + print "Warning: function %s not recognised!" % node.name
5.525 + return
5.526 +
5.527 + self.stream.write("<span class='lambda'>")
5.528 + self._keyword("lambda")
5.529 + self._parameters(fn)
5.530 + self.stream.write(": <span class='code'>")
5.531 + self.dispatch(node.code)
5.532 + self.stream.write("</span>")
5.533 + self.stream.write("</span>")
5.534 +
5.535 + visitList = visitAssList
5.536 +
5.537 + def visitListComp(self, node):
5.538 + self.stream.write("<span class='listcomp'>")
5.539 + self.stream.write("[")
5.540 + self.dispatch(node.expr)
5.541 + for qual in node.quals:
5.542 + self.dispatch(qual)
5.543 + self.stream.write("]")
5.544 + self.stream.write("</span>")
5.545 +
5.546 + def visitListCompFor(self, node):
5.547 + self.stream.write("<span class='listcompfor'>")
5.548 + self._keyword("for")
5.549 + self.stream.write("<span class='iterator'>")
5.550 + self.dispatch(node.assign)
5.551 + self.stream.write("</span>")
5.552 + self._keyword("in", 1)
5.553 + self.stream.write("<span class='collection'>")
5.554 + self.dispatch(node.list)
5.555 + self.stream.write("</span>")
5.556 + for if_ in node.ifs:
5.557 + self.dispatch(if_)
5.558 + self.stream.write("</span>")
5.559 +
5.560 + def visitListCompIf(self, node):
5.561 + self.stream.write("<span class='listcompif'>")
5.562 + self.stream.write("<span class='conditional'>")
5.563 + self._keyword("if", 1)
5.564 + self.dispatch(node.test)
5.565 + self.stream.write("</span>")
5.566 + self.stream.write("</span>")
5.567 +
5.568 + def visitMod(self, node):
5.569 + self._visitBinary(node, "mod", "%")
5.570 +
5.571 + def visitMul(self, node):
5.572 + self._visitBinary(node, "mul", "*")
5.573 +
5.574 + def visitName(self, node):
5.575 + if hasattr(node, "_scope"):
5.576 + scope = node._scope
5.577 + self._name_start()
5.578 + self.stream.write(node.name)
5.579 + self._popup_start()
5.580 + self._scope(scope)
5.581 + self._popup_end()
5.582 + self._name_end()
5.583 + else:
5.584 + self._name(node.name)
5.585 +
5.586 # Output preparation methods.
5.587
5.588 def _sequence(self, node):
5.589 @@ -480,4 +883,12 @@
5.590 finally:
5.591 stream.close()
5.592
5.593 +def report(importer, directory):
5.594 + if not exists(directory):
5.595 + os.mkdir(directory)
5.596 +
5.597 + for module in importer.get_modules():
5.598 + annotate(module, join(directory, "%s%sxhtml" % (module.full_name(), extsep)))
5.599 + summarise(module, join(directory, "%s-summary%sxhtml" % (module.full_name(), extsep)))
5.600 +
5.601 # vim: tabstop=4 expandtab shiftwidth=4