1.1 --- a/micropython/report.py Sun Apr 18 21:28:56 2010 +0200
1.2 +++ b/micropython/report.py Mon Apr 19 01:14:59 2010 +0200
1.3 @@ -158,9 +158,6 @@
1.4 def _url(self, url):
1.5 return self._attr(url).replace("#", "%23").replace("-", "%2d")
1.6
1.7 - def _summary_link(self, module_name, name):
1.8 - return "<a href='%s-summary%sxhtml#%s'>%s</a>" % (module_name, os.path.extsep, self._attr(name), self._text(name))
1.9 -
1.10 # Methods which write to the stream.
1.11
1.12 def _comment(self, comment):
1.13 @@ -181,9 +178,25 @@
1.14 def _name(self, name):
1.15 self.stream.write("<span class='name'>%s</span>\n" % name)
1.16
1.17 + def _name_link(self, module_name, full_name, name):
1.18 + self.stream.write("<a class='name' href='%s%sxhtml#%s'>%s</a>" % (
1.19 + module_name, os.path.extsep, self._attr(full_name), self._text(name)))
1.20 +
1.21 + def _summary_link(self, module_name, full_name, name):
1.22 + self.stream.write("<a class='name' href='%s-summary%sxhtml#%s'>%s</a>" % (
1.23 + module_name, os.path.extsep, self._attr(full_name), self._text(name)))
1.24 +
1.25 + def _object_name_def(self, module, obj):
1.26 +
1.27 + """
1.28 + Link to the summary for 'module' using 'obj'.
1.29 + """
1.30 +
1.31 + self._summary_link(module.full_name(), obj.full_name(), obj.name)
1.32 +
1.33 # Summary classes.
1.34
1.35 -class Summariser(Writer):
1.36 +class Summary(Writer):
1.37
1.38 "Summarise classes and attributes in modules."
1.39
1.40 @@ -253,13 +266,277 @@
1.41 self.attribute_names = list(names)
1.42 self.attribute_names.sort()
1.43
1.44 +# Source code classes.
1.45 +
1.46 +class AnnotatedSource(ASTVisitor, Writer):
1.47 +
1.48 + "A module source code browser."
1.49 +
1.50 + def __init__(self, module):
1.51 + ASTVisitor.__init__(self)
1.52 + self.visitor = self
1.53 + self.module = module
1.54 +
1.55 + def to_stream(self, stream):
1.56 +
1.57 + "Write the annotated code to the given 'stream'."
1.58 +
1.59 + self.stream = stream
1.60 + self.stream.write(html_header)
1.61 + self.dispatch(self.module.module)
1.62 + self.stream.write(html_footer)
1.63 +
1.64 + def visitModule(self, node):
1.65 + self.default(node)
1.66 +
1.67 + # Statements.
1.68 +
1.69 + def visitAssert(self, node):
1.70 + self.stream.write("<div class='assert nowrap'>\n")
1.71 + self._keyword("assert")
1.72 + self.dispatch(node.test)
1.73 + if node.fail:
1.74 + self.stream.write(", ")
1.75 + self.dispatch(node.fail)
1.76 + self.stream.write("</div>\n")
1.77 +
1.78 + def visitAssign(self, node):
1.79 + self.stream.write("<div class='assign nowrap'>\n")
1.80 + for lvalue in node.nodes:
1.81 + self.dispatch(lvalue)
1.82 + self.stream.write("= ")
1.83 + self.dispatch(node.expr)
1.84 + self.stream.write("</div>\n")
1.85 +
1.86 + def visitAugAssign(self, node):
1.87 + self.stream.write("<div class='augassign nowrap'>\n")
1.88 + self.dispatch(node.node)
1.89 + self.stream.write("%s " % node.op)
1.90 + self.dispatch(node.expr)
1.91 + self.stream.write("</div>\n")
1.92 +
1.93 + def visitBreak(self, node):
1.94 + self.stream.write("<div class='break nowrap'>\n")
1.95 + self._keyword("break")
1.96 + self.stream.write("</div>\n")
1.97 +
1.98 + def visitClass(self, node):
1.99 +
1.100 + # Use inspected details where possible.
1.101 +
1.102 + if hasattr(node, "_def"):
1.103 + cls = node._def
1.104 + bases = cls.bases
1.105 + self.stream.write("<div class='class nowrap' id='%s'>\n" % cls.full_name())
1.106 + else:
1.107 + print "Warning: class %s not recognised!" % node.name
1.108 + return
1.109 +
1.110 + # Write the declaration line.
1.111 +
1.112 + self.stream.write("<div>\n")
1.113 + self._keyword("class")
1.114 + self._object_name_def(self.module, cls)
1.115 +
1.116 + # Suppress the "object" class appearing alone.
1.117 +
1.118 + if bases and not (len(bases) == 1 and bases[0].name == "object"):
1.119 + self.stream.write("(")
1.120 + first = 1
1.121 + for base in bases:
1.122 + if not first:
1.123 + self.stream.write(",\n")
1.124 +
1.125 + self._object_name_def(base.module, base)
1.126 +
1.127 + first = 0
1.128 + self.stream.write(")")
1.129 +
1.130 + self.stream.write(":\n")
1.131 + self.stream.write("</div>\n")
1.132 +
1.133 + # Write the docstring and class body.
1.134 +
1.135 + self.stream.write("<div class='body nowrap'>\n")
1.136 + self._doc(node)
1.137 + self.dispatch(node.code)
1.138 + self.stream.write("</div>\n")
1.139 + self.stream.write("</div>\n")
1.140 +
1.141 + def visitContinue(self, node):
1.142 + self.stream.write("<div class='continue nowrap'>\n")
1.143 + self._keyword("continue")
1.144 + self.stream.write("</div>\n")
1.145 +
1.146 + def visitDiscard(self, node):
1.147 + self.stream.write("<div class='discard nowrap'>\n")
1.148 + self.default(node)
1.149 + self.stream.write("</div>\n")
1.150 +
1.151 + def visitFor(self, node):
1.152 + self.stream.write("<div class='if nowrap'>\n")
1.153 + self.stream.write("<div>\n")
1.154 + self._keyword("for")
1.155 + self.dispatch(node.assign)
1.156 + self._keyword("in")
1.157 + self.dispatch(node.list)
1.158 + self.stream.write(":\n")
1.159 + self.stream.write("</div>\n")
1.160 + self.stream.write("<div class='body nowrap'>\n")
1.161 + self.dispatch(node.body)
1.162 + self.stream.write("</div>\n")
1.163 + if node.else_ is not None:
1.164 + self.stream.write("<div>\n")
1.165 + self._keyword("else")
1.166 + self.stream.write(":\n")
1.167 + self.stream.write("</div>\n")
1.168 + self.stream.write("<div class='body nowrap'>\n")
1.169 + self.dispatch(node.else_)
1.170 + self.stream.write("</div>\n")
1.171 + self.stream.write("</div>\n")
1.172 +
1.173 + def visitFrom(self, node):
1.174 + self.stream.write("<div class='from nowrap'>\n")
1.175 + self._keyword("from")
1.176 + self._name(node.modname)
1.177 + self._keyword("import")
1.178 + first = 1
1.179 + for (name, alias), _name in map(None, node.names, node._names):
1.180 + if not first:
1.181 + self.stream.write(",\n")
1.182 + if alias:
1.183 + self.stream.write(name + " ")
1.184 + self._keyword("as")
1.185 + self._name(alias or name)
1.186 + first = 0
1.187 + self.stream.write("</div>\n")
1.188 +
1.189 + def visitFunction(self, node):
1.190 + if hasattr(node, "_def"):
1.191 + fn = node._def
1.192 + self.stream.write("<div class='function nowrap' id='%s'>\n" % fn.full_name())
1.193 + else:
1.194 + print "Warning: function %s not recognised!" % node.name
1.195 + return
1.196 +
1.197 + # Write the declaration line.
1.198 +
1.199 + self.stream.write("<div>\n")
1.200 + self._keyword("def")
1.201 + self._object_name_def(self.module, fn)
1.202 +
1.203 + self.stream.write("(")
1.204 + self._parameters(fn)
1.205 + self.stream.write(")")
1.206 + self.stream.write(":\n")
1.207 + self.stream.write("</div>\n")
1.208 +
1.209 + self.stream.write("<div class='body nowrap'>\n")
1.210 + self._doc(node)
1.211 + self.dispatch(node.code)
1.212 + self.stream.write("</div>\n")
1.213 + self.stream.write("</div>\n")
1.214 +
1.215 + def visitGlobal(self, node):
1.216 + self.stream.write("<div class='global nowrap'>\n")
1.217 + self._keyword("global")
1.218 + first = 1
1.219 + for name in node.names:
1.220 + if not first:
1.221 + self.stream.write(",\n")
1.222 + self.stream.write(name)
1.223 + first = 0
1.224 + self.stream.write("</div>\n")
1.225 +
1.226 + def visitIf(self, node):
1.227 + self.stream.write("<div class='if nowrap'>\n")
1.228 + first = 1
1.229 + for compare, stmt in node.tests:
1.230 + self.stream.write("<div>\n")
1.231 + if first:
1.232 + self._keyword("if")
1.233 + else:
1.234 + self._keyword("elif")
1.235 + self.dispatch(compare)
1.236 + self.stream.write(":\n")
1.237 + self.stream.write("</div>\n")
1.238 + self.stream.write("<div class='body nowrap'>\n")
1.239 + self.dispatch(stmt)
1.240 + self.stream.write("</div>\n")
1.241 + first = 0
1.242 + if node.else_ is not None:
1.243 + self.stream.write("<div>\n")
1.244 + self._keyword("else")
1.245 + self.stream.write(":\n")
1.246 + self.stream.write("</div>\n")
1.247 + self.stream.write("<div class='body nowrap'>\n")
1.248 + self.dispatch(node.else_)
1.249 + self.stream.write("</div>\n")
1.250 + self.stream.write("</div>\n")
1.251 +
1.252 + # Output preparation methods.
1.253 +
1.254 + def _sequence(self, node):
1.255 + first = 1
1.256 + for n in node.nodes:
1.257 + if not first:
1.258 + self.stream.write(",\n")
1.259 + self.dispatch(n)
1.260 + first = 0
1.261 +
1.262 + def _mapping(self, node):
1.263 + first = 1
1.264 + for k, v in node.items:
1.265 + if not first:
1.266 + self.stream.write(",\n")
1.267 + self.dispatch(k)
1.268 + self.stream.write(":\n")
1.269 + self.dispatch(v)
1.270 + first = 0
1.271 +
1.272 + def _parameters(self, fn):
1.273 + first = 1
1.274 + nparams = len(fn.positional_names)
1.275 + ndefaults = len(fn.defaults)
1.276 + first_with_default = nparams - ndefaults
1.277 +
1.278 + for n, param in enumerate(fn.positional_names):
1.279 + if not first:
1.280 + self.stream.write(",\n")
1.281 + self._name(param)
1.282 + n_default = n - first_with_default
1.283 + if n_default >= 0:
1.284 + self._default(fn.defaults[n_default])
1.285 +
1.286 + if fn.has_star:
1.287 + if not first:
1.288 + self.stream.write(", *\n")
1.289 + self._name(fn.star_name)
1.290 +
1.291 + if fn.has_dstar:
1.292 + if not first:
1.293 + self.stream.write(", **\n")
1.294 + self._name(fn.dstar_name)
1.295 +
1.296 + def _default(self, default):
1.297 + self.stream.write("=\n")
1.298 + self.dispatch(default)
1.299 +
1.300 # Convenience functions.
1.301
1.302 -def summary(module, filename):
1.303 +def summarise(module, filename):
1.304 stream = open(filename, "wb")
1.305 try:
1.306 - summariser = Summariser(module)
1.307 - summariser.to_stream(stream)
1.308 + summary = Summary(module)
1.309 + summary.to_stream(stream)
1.310 + finally:
1.311 + stream.close()
1.312 +
1.313 +def annotate(module, filename):
1.314 + stream = open(filename, "wb")
1.315 + try:
1.316 + source = AnnotatedSource(module)
1.317 + source.to_stream(stream)
1.318 finally:
1.319 stream.close()
1.320