1.1 --- a/micropython/report.py Sun Jul 11 02:05:41 2010 +0200
1.2 +++ b/micropython/report.py Sat Aug 07 02:06:15 2010 +0200
1.3 @@ -19,8 +19,9 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 +from micropython.common import *
1.8 from micropython.data import *
1.9 -from compiler.visitor import ASTVisitor
1.10 +from os.path import exists, extsep, join
1.11 import sys
1.12 import os
1.13 import textwrap
1.14 @@ -33,7 +34,7 @@
1.15 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1.16 <html xmlns="http://www.w3.org/1999/xhtml">
1.17 <head>
1.18 - <title>Module</title>
1.19 + <title>Module: %(full_name)s</title>
1.20 <style type="text/css">
1.21 html {
1.22 background-color: black; color: white;
1.23 @@ -45,6 +46,10 @@
1.24 background-color: black; color: white;
1.25 }
1.26
1.27 + a {
1.28 + text-decoration: none;
1.29 + }
1.30 +
1.31 .nowrap { white-space: nowrap; }
1.32
1.33 .class { margin-top: 1em; margin-bottom: 1em; }
1.34 @@ -56,7 +61,31 @@
1.35 .function-name { color: cyan; }
1.36 .str { color: #FF00FF; }
1.37 .doc { color: #FF00FF; margin-top: 1em; margin-bottom: 1em; }
1.38 - .invocation a { color: white; text-decoration: none; }
1.39 +
1.40 + .popup {
1.41 + display: none;
1.42 + position: absolute;
1.43 + top: 3ex; left: 0;
1.44 + color: white;
1.45 + z-index: 3;
1.46 + }
1.47 +
1.48 + .scope { padding: 0.5em; background-color: #007700; }
1.49 +
1.50 + .name {
1.51 + position: relative;
1.52 + color: white;
1.53 + }
1.54 +
1.55 + .name:hover {
1.56 + background-color: #003300;
1.57 + padding-bottom: 1ex;
1.58 + z-index: 2;
1.59 + }
1.60 +
1.61 + .name:hover .popup {
1.62 + display: block;
1.63 + }
1.64
1.65 .summary-class {
1.66 background-color: #004400;
1.67 @@ -98,29 +127,34 @@
1.68
1.69 # Methods which write to the stream.
1.70
1.71 + def _span_end(self):
1.72 + self.stream.write("</span>")
1.73 +
1.74 def _comment(self, comment):
1.75 self.stream.write("<span class='comment'># %s</span>\n" % comment)
1.76
1.77 - def _keyword(self, kw):
1.78 - self.stream.write("<span class='keyword'>%s</span> " % kw)
1.79 + def _reserved(self, token, classes, leading=0, trailing=1):
1.80 + if leading:
1.81 + self.stream.write(" ")
1.82 + self.stream.write("<span class='%s'>%s</span>" % (classes, self._text(token)))
1.83 + if trailing:
1.84 + self.stream.write(" ")
1.85 +
1.86 + def _keyword(self, kw, leading=0, trailing=1):
1.87 + self._reserved(kw, "keyword", leading, trailing)
1.88 +
1.89 + def _op(self, symbol, leading=0, trailing=1):
1.90 + self._reserved(symbol, "operator", leading, trailing)
1.91
1.92 def _doc(self, node):
1.93 if node.doc is not None:
1.94 - self.stream.write("<pre class='doc'>\n")
1.95 + self.stream.write("<pre class='doc'>")
1.96 self.stream.write('"""')
1.97 output = textwrap.dedent(node.doc.replace('"""', '\\"\\"\\"'))
1.98 self.stream.write(self._text(output))
1.99 self.stream.write('"""')
1.100 self.stream.write("</pre>\n")
1.101
1.102 - def _name(self, name, classes=None):
1.103 - self.stream.write("<span class='%s'>%s</span>" % (classes or "name", name))
1.104 -
1.105 - def _name_link(self, module_name, full_name, name, classes=None):
1.106 - self.stream.write("<a class='%s' href='%s%sxhtml#%s'>%s</a>" % (
1.107 - classes or "name", module_name, os.path.extsep,
1.108 - self._attr(full_name), self._text(name)))
1.109 -
1.110 def _summary_link(self, module_name, full_name, name, classes=None):
1.111 self._name_link("%s-summary" % module_name, full_name, name, classes)
1.112
1.113 @@ -133,6 +167,29 @@
1.114
1.115 self._summary_link(module.full_name(), obj.full_name(), obj.name, classes)
1.116
1.117 + def _name_start(self, classes=None):
1.118 + self.stream.write("<span class='%s'>" % (classes or "name"))
1.119 +
1.120 + _name_end = _span_end
1.121 +
1.122 + def _name(self, name, classes=None):
1.123 + self._name_start(classes)
1.124 + self.stream.write(name)
1.125 + self._name_end()
1.126 +
1.127 + def _name_link(self, module_name, full_name, name, classes=None):
1.128 + self.stream.write("<a class='%s' href='%s%sxhtml#%s'>%s</a>" % (
1.129 + classes or "name", module_name, os.path.extsep,
1.130 + self._attr(full_name), self._text(name)))
1.131 +
1.132 + def _popup_start(self):
1.133 + self.stream.write("<span class='popup'>")
1.134 +
1.135 + _popup_end = _span_end
1.136 +
1.137 + def _scope(self, scope):
1.138 + self.stream.write("<div class='scope'>%s</div>\n" % scope)
1.139 +
1.140 # Summary classes.
1.141
1.142 class Summary(Writer):
1.143 @@ -148,7 +205,7 @@
1.144
1.145 self.stream = stream
1.146 self._init_details()
1.147 - self.stream.write(html_header)
1.148 + self.stream.write(html_header % {"full_name" : self.module.full_name()})
1.149 self._write_classes(self.module)
1.150 self.stream.write(html_footer)
1.151
1.152 @@ -221,8 +278,8 @@
1.153 "Write the annotated code to the given 'stream'."
1.154
1.155 self.stream = stream
1.156 - self.stream.write(html_header)
1.157 - self.dispatch(self.module.module)
1.158 + self.stream.write(html_header % {"full_name" : self.module.full_name()})
1.159 + self.dispatch(self.module.astnode)
1.160 self.stream.write(html_footer)
1.161
1.162 def visitModule(self, node):
1.163 @@ -243,14 +300,14 @@
1.164 self.stream.write("<div class='assign nowrap'>\n")
1.165 for lvalue in node.nodes:
1.166 self.dispatch(lvalue)
1.167 - self.stream.write("= ")
1.168 + self.stream.write(" = ")
1.169 self.dispatch(node.expr)
1.170 self.stream.write("</div>\n")
1.171
1.172 def visitAugAssign(self, node):
1.173 self.stream.write("<div class='augassign nowrap'>\n")
1.174 self.dispatch(node.node)
1.175 - self.stream.write("%s " % node.op)
1.176 + self.stream.write(" %s " % node.op)
1.177 self.dispatch(node.expr)
1.178 self.stream.write("</div>\n")
1.179
1.180 @@ -260,6 +317,8 @@
1.181 self.stream.write("</div>\n")
1.182
1.183 def visitClass(self, node):
1.184 + if not used_by_unit(node):
1.185 + return
1.186
1.187 # Use inspected details where possible.
1.188
1.189 @@ -317,7 +376,7 @@
1.190 self.stream.write("<div>\n")
1.191 self._keyword("for")
1.192 self.dispatch(node.assign)
1.193 - self._keyword("in")
1.194 + self._keyword("in", 1)
1.195 self.dispatch(node.list)
1.196 self.stream.write(":\n")
1.197 self.stream.write("</div>\n")
1.198 @@ -326,7 +385,7 @@
1.199 self.stream.write("</div>\n")
1.200 if node.else_ is not None:
1.201 self.stream.write("<div>\n")
1.202 - self._keyword("else")
1.203 + self._keyword("else", trailing=0)
1.204 self.stream.write(":\n")
1.205 self.stream.write("</div>\n")
1.206 self.stream.write("<div class='body nowrap'>\n")
1.207 @@ -338,19 +397,22 @@
1.208 self.stream.write("<div class='from nowrap'>\n")
1.209 self._keyword("from")
1.210 self._name(node.modname)
1.211 - self._keyword("import")
1.212 + self._keyword("import", 1)
1.213 first = 1
1.214 for (name, alias), _name in map(None, node.names, node._names):
1.215 if not first:
1.216 self.stream.write(", ")
1.217 if alias:
1.218 self.stream.write(name + " ")
1.219 - self._keyword("as")
1.220 + self._keyword("as", 1)
1.221 self._name(alias or name)
1.222 first = 0
1.223 self.stream.write("</div>\n")
1.224
1.225 def visitFunction(self, node):
1.226 + if not used_by_unit(node):
1.227 + return
1.228 +
1.229 if hasattr(node, "_def"):
1.230 fn = node._def
1.231 self.stream.write("<div class='function nowrap' id='%s'>\n" % fn.full_name())
1.232 @@ -405,7 +467,144 @@
1.233 first = 0
1.234 if node.else_ is not None:
1.235 self.stream.write("<div>\n")
1.236 - self._keyword("else")
1.237 + self._keyword("else", trailing=0)
1.238 + self.stream.write(":\n")
1.239 + self.stream.write("</div>\n")
1.240 + self.stream.write("<div class='body nowrap'>\n")
1.241 + self.dispatch(node.else_)
1.242 + self.stream.write("</div>\n")
1.243 + self.stream.write("</div>\n")
1.244 +
1.245 + def visitImport(self, node):
1.246 + self.stream.write("<div class='import nowrap'>\n")
1.247 + self._keyword("import")
1.248 + first = 1
1.249 + for name, alias in node.names:
1.250 + if not first:
1.251 + self.stream.write(",\n")
1.252 + if alias:
1.253 + self.stream.write(name + " ")
1.254 + self._keyword("as", 1)
1.255 + self._name(alias or name)
1.256 + first = 0
1.257 + self.stream.write("</div>\n")
1.258 +
1.259 + def visitPass(self, node):
1.260 + self.stream.write("<div class='pass nowrap'>\n")
1.261 + self._keyword("pass")
1.262 + self.stream.write("</div>\n")
1.263 +
1.264 + def visitPrint(self, node):
1.265 + self.stream.write("<div class='print nowrap'>\n")
1.266 + self._keyword("print")
1.267 + if node.dest is not None:
1.268 + self.stream.write(">>\n")
1.269 + self.dispatch(node.dest)
1.270 + for n in node.nodes:
1.271 + self.dispatch(n)
1.272 + self.stream.write(",\n")
1.273 + self.stream.write("</div>\n")
1.274 +
1.275 + def visitPrintnl(self, node):
1.276 + self.stream.write("<div class='printnl nowrap'>\n")
1.277 + self._keyword("print")
1.278 + if node.dest is not None:
1.279 + self.stream.write(">>\n")
1.280 + self.dispatch(node.dest)
1.281 + first = 1
1.282 + for n in node.nodes:
1.283 + if not first:
1.284 + self.stream.write(",\n")
1.285 + self.dispatch(n)
1.286 + first = 0
1.287 + self.stream.write("</div>\n")
1.288 +
1.289 + def visitRaise(self, node):
1.290 + self.stream.write("<div class='raise nowrap'>\n")
1.291 + self._keyword("raise")
1.292 + self.dispatch(node.expr1)
1.293 + if node.expr2 is not None:
1.294 + self.stream.write(",\n")
1.295 + self.dispatch(node.expr2)
1.296 + if node.expr3 is not None:
1.297 + self.stream.write(",\n")
1.298 + self.dispatch(node.expr3)
1.299 + self.stream.write("</div>\n")
1.300 +
1.301 + def visitReturn(self, node):
1.302 + self.stream.write("<div class='return nowrap'>\n")
1.303 + self._keyword("return")
1.304 + self.dispatch(node.value)
1.305 + self.stream.write("</div>\n")
1.306 +
1.307 + def visitStmt(self, node):
1.308 + self.stream.write("<div class='stmt nowrap'>\n")
1.309 + self.default(node)
1.310 + self.stream.write("</div>\n")
1.311 +
1.312 + def visitTryExcept(self, node):
1.313 + self.stream.write("<div class='tryexcept nowrap'>\n")
1.314 + self.stream.write("<div>\n")
1.315 + self._keyword("try", trailing=0)
1.316 + self.stream.write(":\n")
1.317 + self.stream.write("</div>\n")
1.318 + self.stream.write("<div class='body nowrap'>\n")
1.319 + self.dispatch(node.body)
1.320 + self.stream.write("</div>\n")
1.321 + for spec, assign, statement in node.handlers:
1.322 + self.stream.write("<div>\n")
1.323 + self._keyword("except")
1.324 + if spec is not None:
1.325 + self.dispatch(spec)
1.326 + if assign is not None:
1.327 + self.stream.write(",\n")
1.328 + self.dispatch(assign)
1.329 + self.stream.write(":\n")
1.330 + self.stream.write("</div>\n")
1.331 + self.stream.write("<div class='body nowrap'>\n")
1.332 + self.dispatch(statement)
1.333 + self.stream.write("</div>\n")
1.334 + if node.else_ is not None:
1.335 + self.stream.write("<div>\n")
1.336 + self._keyword("else", trailing=0)
1.337 + self.stream.write(":\n")
1.338 + self.stream.write("</div>\n")
1.339 + self.stream.write("<div class='body nowrap'>\n")
1.340 + self.dispatch(node.else_)
1.341 + self.stream.write("</div>\n")
1.342 + self.stream.write("</div>\n")
1.343 +
1.344 + def visitTryFinally(self, node):
1.345 + self.stream.write("<div class='tryfinally nowrap'>\n")
1.346 + self.stream.write("<div>\n")
1.347 + self._keyword("try", trailing=0)
1.348 + self.stream.write(":\n")
1.349 + self.stream.write("</div>\n")
1.350 + self.stream.write("<div class='body nowrap'>\n")
1.351 + self.dispatch(node.body)
1.352 + self.stream.write("</div>\n")
1.353 + self.stream.write("<div>\n")
1.354 + self._keyword("finally", trailing=0)
1.355 + self.stream.write(":\n")
1.356 + self.stream.write("</div>\n")
1.357 + self.stream.write("<div class='body nowrap'>\n")
1.358 + self.dispatch(node.final)
1.359 + self.stream.write("</div>\n")
1.360 + self.stream.write("</div>\n")
1.361 +
1.362 + def visitWhile(self, node):
1.363 + self.stream.write("<div class='while nowrap'>\n")
1.364 + self.stream.write("<div>\n")
1.365 + self._keyword("while")
1.366 + self.dispatch(node.test)
1.367 + self.stream.write(":\n")
1.368 + self.stream.write("</div>\n")
1.369 + self.stream.write("<div class='body nowrap'>\n")
1.370 + self.dispatch(node.body)
1.371 + self.stream.write("</div>\n")
1.372 + if node.else_ is not None:
1.373 + self.stream.write("<div>\n")
1.374 + self._keyword("else", trailing=0)
1.375 self.stream.write(":\n")
1.376 self.stream.write("</div>\n")
1.377 self.stream.write("<div class='body nowrap'>\n")
1.378 @@ -413,6 +612,210 @@
1.379 self.stream.write("</div>\n")
1.380 self.stream.write("</div>\n")
1.381
1.382 + # Expression-related helper methods.
1.383 +
1.384 + def _visitBitBinary(self, node, name, symbol):
1.385 + self.stream.write("<span class='%s'>" % name)
1.386 + first = 1
1.387 + for node in node.nodes:
1.388 + if not first:
1.389 + self._op(symbol, 1)
1.390 + self.dispatch(node)
1.391 + first = 0
1.392 + self.stream.write("</span>")
1.393 +
1.394 + def _visitBinary(self, node, name, symbol):
1.395 + self.stream.write("<span class='%s'>" % name)
1.396 + self.dispatch(node.left)
1.397 + self._op(symbol, 1)
1.398 + self.dispatch(node.right)
1.399 + self.stream.write("</span>")
1.400 +
1.401 + def _visitUnary(self, node, name, symbol):
1.402 + self.stream.write("<span class='%s'>" % name)
1.403 + self._op(symbol)
1.404 + self.dispatch(node.expr)
1.405 + self.stream.write("</span>")
1.406 +
1.407 + # Expressions.
1.408 +
1.409 + def visitAdd(self, node):
1.410 + self._visitBinary(node, "add", "+")
1.411 +
1.412 + def visitAnd(self, node):
1.413 + self.stream.write("<span class='and'>")
1.414 + first = 1
1.415 + for n in node.nodes:
1.416 + if not first:
1.417 + self._keyword("and", 1)
1.418 + self.dispatch(n)
1.419 + first = 0
1.420 + self.stream.write("</span>")
1.421 +
1.422 + def visitAssAttr(self, node):
1.423 + self.stream.write("<span class='assattr'>")
1.424 + self.dispatch(node.expr)
1.425 + self.stream.write("<span class='attr'>")
1.426 + self.stream.write(".")
1.427 + self._name(node.attrname)
1.428 + self.stream.write("</span>")
1.429 + self.stream.write("</span>")
1.430 +
1.431 + def visitAssList(self, node):
1.432 + self.stream.write("<span class='list'>")
1.433 + self.stream.write("[")
1.434 + self._sequence(node)
1.435 + self.stream.write("]")
1.436 + self.stream.write("</span>")
1.437 +
1.438 + def visitAssName(self, node):
1.439 + self._name(node.name)
1.440 +
1.441 + def visitAssTuple(self, node):
1.442 + self.stream.write("<span class='tuple'>")
1.443 + self.stream.write("(")
1.444 + self._sequence(node)
1.445 + self.stream.write(")")
1.446 + self.stream.write("</span>")
1.447 +
1.448 + def visitBitand(self, node):
1.449 + self._visitBitBinary(node, "bitand", "&")
1.450 +
1.451 + def visitCallFunc(self, node):
1.452 + self.stream.write("<span class='callfunc'>")
1.453 + self.dispatch(node.node)
1.454 + self.stream.write("<span class='call'>")
1.455 + self.stream.write("(")
1.456 + first = 1
1.457 + for arg in node.args:
1.458 + if not first:
1.459 + self.stream.write(", ")
1.460 + self.dispatch(arg)
1.461 + first = 0
1.462 + if node.star_args is not None:
1.463 + if not first:
1.464 + self.stream.write(", *")
1.465 + self.dispatch(node.star_args)
1.466 + first = 0
1.467 + if node.dstar_args is not None:
1.468 + if not first:
1.469 + self.stream.write(", **")
1.470 + self.dispatch(node.dstar_args)
1.471 + first = 0
1.472 + self.stream.write(")")
1.473 + self.stream.write("</span>")
1.474 + self.stream.write("</span>")
1.475 +
1.476 + def visitCompare(self, node):
1.477 + self.stream.write("<span class='compare'>")
1.478 + self.dispatch(node.expr)
1.479 + for op_name, expr in node.ops:
1.480 + self._op(op_name, 1)
1.481 + self.dispatch(expr)
1.482 + self.stream.write("</span>")
1.483 +
1.484 + def visitConst(self, node):
1.485 + if isinstance(node.value, (str, unicode)):
1.486 + self.stream.write("<span class='str'>")
1.487 + self.stream.write(self._text(repr(node.value)))
1.488 + if isinstance(node.value, (str, unicode)):
1.489 + self.stream.write("</span>")
1.490 +
1.491 + def visitDict(self, node):
1.492 + self.stream.write("<span class='dict'>")
1.493 + self.stream.write("{")
1.494 + self._mapping(node)
1.495 + self.stream.write("}")
1.496 + self.stream.write("</span>")
1.497 +
1.498 + def visitDiv(self, node):
1.499 + self._visitBinary(node, "div", "/")
1.500 +
1.501 + def visitFloorDiv(self, node):
1.502 + self._visitBinary(node, "floordiv", "//")
1.503 +
1.504 + def visitGetattr(self, node):
1.505 + self.stream.write("<span class='getattr'>")
1.506 + self.dispatch(node.expr)
1.507 + self.stream.write("<span class='attr'>")
1.508 + self.stream.write(".")
1.509 + self._name(node.attrname)
1.510 + self.stream.write("</span>")
1.511 + self.stream.write("</span>")
1.512 +
1.513 + def visitKeyword(self, node):
1.514 + self.stream.write("<span class='keyword-arg'>")
1.515 + self.stream.write(node.name)
1.516 + self.stream.write("=")
1.517 + self.dispatch(node.expr)
1.518 + self.stream.write("</span>")
1.519 +
1.520 + def visitLambda(self, node):
1.521 + if hasattr(node, "_def"):
1.522 + fn = node._def
1.523 + else:
1.524 + print "Warning: function %s not recognised!" % node.name
1.525 + return
1.526 +
1.527 + self.stream.write("<span class='lambda'>")
1.528 + self._keyword("lambda")
1.529 + self._parameters(fn)
1.530 + self.stream.write(": <span class='code'>")
1.531 + self.dispatch(node.code)
1.532 + self.stream.write("</span>")
1.533 + self.stream.write("</span>")
1.534 +
1.535 + visitList = visitAssList
1.536 +
1.537 + def visitListComp(self, node):
1.538 + self.stream.write("<span class='listcomp'>")
1.539 + self.stream.write("[")
1.540 + self.dispatch(node.expr)
1.541 + for qual in node.quals:
1.542 + self.dispatch(qual)
1.543 + self.stream.write("]")
1.544 + self.stream.write("</span>")
1.545 +
1.546 + def visitListCompFor(self, node):
1.547 + self.stream.write("<span class='listcompfor'>")
1.548 + self._keyword("for")
1.549 + self.stream.write("<span class='iterator'>")
1.550 + self.dispatch(node.assign)
1.551 + self.stream.write("</span>")
1.552 + self._keyword("in", 1)
1.553 + self.stream.write("<span class='collection'>")
1.554 + self.dispatch(node.list)
1.555 + self.stream.write("</span>")
1.556 + for if_ in node.ifs:
1.557 + self.dispatch(if_)
1.558 + self.stream.write("</span>")
1.559 +
1.560 + def visitListCompIf(self, node):
1.561 + self.stream.write("<span class='listcompif'>")
1.562 + self.stream.write("<span class='conditional'>")
1.563 + self._keyword("if", 1)
1.564 + self.dispatch(node.test)
1.565 + self.stream.write("</span>")
1.566 + self.stream.write("</span>")
1.567 +
1.568 + def visitMod(self, node):
1.569 + self._visitBinary(node, "mod", "%")
1.570 +
1.571 + def visitMul(self, node):
1.572 + self._visitBinary(node, "mul", "*")
1.573 +
1.574 + def visitName(self, node):
1.575 + if hasattr(node, "_scope"):
1.576 + scope = node._scope
1.577 + self._name_start()
1.578 + self.stream.write(node.name)
1.579 + self._popup_start()
1.580 + self._scope(scope)
1.581 + self._popup_end()
1.582 + self._name_end()
1.583 + else:
1.584 + self._name(node.name)
1.585 +
1.586 # Output preparation methods.
1.587
1.588 def _sequence(self, node):
1.589 @@ -480,4 +883,12 @@
1.590 finally:
1.591 stream.close()
1.592
1.593 +def report(importer, directory):
1.594 + if not exists(directory):
1.595 + os.mkdir(directory)
1.596 +
1.597 + for module in importer.get_modules():
1.598 + annotate(module, join(directory, "%s%sxhtml" % (module.full_name(), extsep)))
1.599 + summarise(module, join(directory, "%s-summary%sxhtml" % (module.full_name(), extsep)))
1.600 +
1.601 # vim: tabstop=4 expandtab shiftwidth=4