1.1 --- a/annotate.py Mon Oct 16 00:36:34 2006 +0200
1.2 +++ b/annotate.py Mon Oct 16 00:39:44 2006 +0200
1.3 @@ -69,17 +69,16 @@
1.4
1.5 # Exceptions.
1.6
1.7 -class AnnotationError(Exception):
1.8 - def __init__(self, exc, node, *args):
1.9 - Exception.__init__(self, *args)
1.10 - self.nodes = [node]
1.11 - self.exc = exc
1.12 - def add(self, node):
1.13 - self.nodes.append(node)
1.14 - def __str__(self):
1.15 - return "%s, %s" % (self.exc, self.nodes)
1.16 +class AnnotationError(SimplifiedError):
1.17 +
1.18 + "An error in the annotation process."
1.19 +
1.20 + pass
1.21
1.22 class AnnotationMessage(Exception):
1.23 +
1.24 + "A lesser annotation error."
1.25 +
1.26 pass
1.27
1.28 # Annotation.
1.29 @@ -197,11 +196,14 @@
1.30
1.31 return result
1.32
1.33 - def annotate(self, node):
1.34 + def annotate(self, node, types=None):
1.35
1.36 - "Annotate the given 'node' in the system."
1.37 + """
1.38 + Annotate the given 'node' in the system, using either the optional
1.39 + 'types' or the namespace's current type information.
1.40 + """
1.41
1.42 - self.system.annotate(node, self.namespace.types)
1.43 + self.system.annotate(node, types or self.namespace.types)
1.44
1.45 # Visitor methods.
1.46
1.47 @@ -288,12 +290,14 @@
1.48 types.append(attribute)
1.49 if not accesses.has_key(attr.type):
1.50 accesses[attr.type] = []
1.51 - accesses[attr.type].append((attribute, accessor))
1.52 + if not (attribute, accessor) in accesses[attr.type]:
1.53 + accesses[attr.type].append((attribute, accessor))
1.54 else:
1.55 print "Empty attribute", loadattr.name, "via accessor", accessor
1.56 if not non_accesses.has_key(attr.type):
1.57 non_accesses[attr.type] = []
1.58 - non_accesses[attr.type].append((attribute, accessor))
1.59 + if not (attribute, accessor) in non_accesses[attr.type]:
1.60 + non_accesses[attr.type].append((attribute, accessor))
1.61 self.namespace.set_types(types)
1.62 loadattr.accesses = accesses
1.63 loadattr.non_accesses = non_accesses
1.64 @@ -347,9 +351,15 @@
1.65 return return_
1.66
1.67 def visitInvoke(self, invoke):
1.68 +
1.69 + # First find the callables.
1.70 +
1.71 invoke.expr = self.dispatch(invoke.expr)
1.72 invocation_types = self.namespace.types
1.73
1.74 + # Invocation processing starts with making sure that the arguments have
1.75 + # been processed.
1.76 +
1.77 if isinstance(invoke, InvokeFunction):
1.78 self.process_args(invoke)
1.79
1.80 @@ -424,6 +434,9 @@
1.81 self.namespace.set_types([Attribute(None, instance)])
1.82 self.annotate(invoke)
1.83
1.84 + # Remember the invocations that were found, along with the return type
1.85 + # information.
1.86 +
1.87 invoke.invocations = invocations
1.88 self.namespace.set_types(getattr(invoke, "types", []))
1.89 return invoke
1.90 @@ -494,7 +507,9 @@
1.91 for locals in self.returned_locals:
1.92 self.namespace.merge_namespace(locals)
1.93
1.94 - def process_args(self, invoke):
1.95 + def process_args(self, invocation):
1.96 +
1.97 + "Process the arguments associated with an 'invocation'."
1.98
1.99 # NOTE: Consider initialiser invocation for classes.
1.100
1.101 @@ -503,25 +518,25 @@
1.102
1.103 # Get type information for regular arguments.
1.104
1.105 - for arg in invoke.args:
1.106 + for arg in invocation.args:
1.107 args.append(self.dispatch(arg))
1.108 types.append(self.namespace.types)
1.109
1.110 # Get type information for star and dstar arguments.
1.111
1.112 - if invoke.star is not None:
1.113 - param, default = invoke.star
1.114 + if invocation.star is not None:
1.115 + param, default = invocation.star
1.116 default = self.dispatch(default)
1.117 - invoke.star = param, default
1.118 + invocation.star = param, default
1.119 types.append(default.types)
1.120
1.121 - if invoke.dstar is not None:
1.122 - param, default = invoke.dstar
1.123 + if invocation.dstar is not None:
1.124 + param, default = invocation.dstar
1.125 default = self.dispatch(default)
1.126 - invoke.dstar = param, default
1.127 + invocation.dstar = param, default
1.128 types.append(default.types)
1.129
1.130 - invoke.args = args
1.131 + invocation.args = args
1.132
1.133 def make_items(self, invocation, subprogram, context):
1.134
1.135 @@ -587,13 +602,12 @@
1.136 if star_args:
1.137 star_invocation = self.make_star_args(invocation, subprogram, star_args)
1.138 self.dispatch(star_invocation)
1.139 - star_invocation.pprint()
1.140 star_types = star_invocation.types
1.141 else:
1.142 star_types = None
1.143
1.144 if dstar_args:
1.145 - dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args)
1.146 + dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args) # NOTE: To be written!
1.147 self.dispatch(dstar_invocation)
1.148 dstar_types = dstar_invocation.types
1.149 else:
1.150 @@ -628,6 +642,12 @@
1.151 arg = self.dispatch(default) # NOTE: Review reprocessing.
1.152 items.append((param, arg.types))
1.153
1.154 + # Record the parameter types.
1.155 +
1.156 + subprogram.paramtypes = {}
1.157 + for param, types in items:
1.158 + subprogram.paramtypes[param] = types
1.159 +
1.160 return items
1.161
1.162 def make_star_args(self, invocation, subprogram, star_args):
2.1 --- a/simplified.py Mon Oct 16 00:36:34 2006 +0200
2.2 +++ b/simplified.py Mon Oct 16 00:39:44 2006 +0200
2.3 @@ -24,6 +24,35 @@
2.4 from compiler.visitor import ASTVisitor
2.5 import sys
2.6
2.7 +# Exceptions.
2.8 +
2.9 +class SimplifiedError(Exception):
2.10 +
2.11 + "An error in the annotation process."
2.12 +
2.13 + def __init__(self, exc, node, *args):
2.14 +
2.15 + """
2.16 + Initialise the error with an existing exception 'exc', the 'node' at
2.17 + which this error occurs, along with additional optional arguments.
2.18 + """
2.19 +
2.20 + Exception.__init__(self, *args)
2.21 + self.nodes = [node]
2.22 + self.exc = exc
2.23 +
2.24 + def add(self, node):
2.25 +
2.26 + "Add the given 'node' to the path of nodes leading from the exception."
2.27 +
2.28 + self.nodes.append(node)
2.29 +
2.30 + def __str__(self):
2.31 +
2.32 + "Return a string showing the principal exception details."
2.33 +
2.34 + return "%s, %s" % (self.exc, self.nodes)
2.35 +
2.36 # Unique name registration.
2.37
2.38 class Naming:
3.1 --- a/viewer.py Mon Oct 16 00:36:34 2006 +0200
3.2 +++ b/viewer.py Mon Oct 16 00:39:44 2006 +0200
3.3 @@ -22,8 +22,19 @@
3.4 """
3.5
3.6 from compiler.visitor import ASTVisitor
3.7 +from simplified import *
3.8 import sys
3.9
3.10 +# Exceptions.
3.11 +
3.12 +class ViewerError(SimplifiedError):
3.13 +
3.14 + "An error in viewing."
3.15 +
3.16 + pass
3.17 +
3.18 +# Classes.
3.19 +
3.20 class Viewer(ASTVisitor):
3.21
3.22 """
3.23 @@ -100,16 +111,14 @@
3.24 .body { padding-left: 2em; }
3.25 .keyword { color: yellow; }
3.26 .comment { color: blue; }
3.27 + .str { color: #FF00FF; }
3.28 + .doc { color: #FF00FF; margin-bottom: 1em; }
3.29 .ref { color: cyan; }
3.30 .ref a { color: cyan; text-decoration: none; }
3.31
3.32 - .name {
3.33 - position: relative;
3.34 - }
3.35 -
3.36 .types {
3.37 display: none; z-index: 2;
3.38 - position: absolute; top: 1em; left: 6.5em;
3.39 + position: absolute; top: 1em; left: 7.5em;
3.40 padding: 0.5em; background-color: #0000FF;
3.41 }
3.42
3.43 @@ -119,8 +128,16 @@
3.44 padding: 0.5em; background-color: #007700;
3.45 }
3.46
3.47 + .name,
3.48 + .attr
3.49 + {
3.50 + position: relative;
3.51 + }
3.52 +
3.53 .name:hover > .types,
3.54 - .name:hover > .scopes
3.55 + .name:hover > .scopes,
3.56 + .attr:hover > .types,
3.57 + .attr:hover > .scopes
3.58 {
3.59 display: block;
3.60 }
3.61 @@ -150,6 +167,15 @@
3.62 self.dispatch(module)
3.63 self.stream.write(html_footer)
3.64
3.65 + def dispatch(self, node):
3.66 + try:
3.67 + ASTVisitor.dispatch(self, node)
3.68 + except ViewerError, exc:
3.69 + exc.add(node)
3.70 + raise
3.71 + except Exception, exc:
3.72 + raise ViewerError(exc, node)
3.73 +
3.74 def visitModule(self, node):
3.75 self.default(node)
3.76
3.77 @@ -160,11 +186,11 @@
3.78
3.79 def visitClass(self, node):
3.80 definition = node._node
3.81 - structure = definition.expr.types[0].type
3.82 + structure = definition.expr.ref
3.83 self.stream.write("<div class='class' id='%s'>\n" % self._url(structure.full_name()))
3.84 self.stream.write("<p>\n")
3.85 self._keyword("class")
3.86 - self._name_start(structure)
3.87 + self._name_start(structure.name)
3.88 self._scopes(definition)
3.89 self._name_end()
3.90 bases = structure.bases
3.91 @@ -174,7 +200,7 @@
3.92 for base in bases:
3.93 if not first:
3.94 self.stream.write(",\n")
3.95 - self._name_start(base)
3.96 + self._name_start(base.name)
3.97 self._types(base)
3.98 self._scopes(base)
3.99 self._name_end()
3.100 @@ -190,6 +216,41 @@
3.101 self.stream.write("</div>\n")
3.102 self.stream.write("</div>\n")
3.103
3.104 + def visitFunction(self, node):
3.105 + definition = node._node
3.106 + subprogram = definition.expr.ref
3.107 + self.stream.write("<div class='def' id='%s'>\n" % self._url(subprogram.full_name()))
3.108 + self.stream.write("<p>\n")
3.109 + self._keyword("def")
3.110 + self._name_start(subprogram.name)
3.111 + self._scopes(definition)
3.112 + self._name_end()
3.113 + self.stream.write("(")
3.114 + first = 1
3.115 + for param, default in subprogram.params:
3.116 + if not first:
3.117 + self.stream.write(",\n")
3.118 + self._name_start(param)
3.119 + if hasattr(subprogram, "paramtypes"):
3.120 + self._types_list(subprogram.paramtypes[param])
3.121 + self._name_end()
3.122 + first = 0
3.123 + self.stream.write(")")
3.124 + self.stream.write(":\n")
3.125 + self._comment(self._text(subprogram.full_name()))
3.126 + self.stream.write("</p>\n")
3.127 +
3.128 + self.stream.write("<div class='body'>\n")
3.129 + self._doc(node)
3.130 + self.dispatch(node.code)
3.131 + self.stream.write("</div>\n")
3.132 + self.stream.write("</div>\n")
3.133 +
3.134 + def visitStmt(self, node):
3.135 + self.stream.write("<div class='stmt'>\n")
3.136 + self.default(node)
3.137 + self.stream.write("</div>\n")
3.138 +
3.139 def visitAssign(self, node):
3.140 self.stream.write("<div class='assign'>\n")
3.141 for lvalue in node.nodes:
3.142 @@ -219,13 +280,13 @@
3.143 visitAssList = visitList
3.144
3.145 def visitName(self, node):
3.146 - self._name_start(node._node)
3.147 + self._name_start(node._node.name)
3.148 self._types(node._node)
3.149 self._scopes(node._node)
3.150 self._name_end()
3.151
3.152 def visitAssName(self, node):
3.153 - self._name_start(node._node)
3.154 + self._name_start(node._node.name)
3.155 self._types(node._node.expr)
3.156 self._scopes(node._node)
3.157 self._name_end()
3.158 @@ -233,6 +294,26 @@
3.159 def visitConst(self, node):
3.160 self.stream.write(repr(node.value))
3.161
3.162 + def visitGetattr(self, node):
3.163 + self.stream.write("<span class='getattr'>\n")
3.164 + self.dispatch(node.expr)
3.165 + self.stream.write("<span class='attr'>\n")
3.166 + self.stream.write(".%s\n" % self._text(node.attrname))
3.167 + self._types(node._node)
3.168 + self._scopes(node._node)
3.169 + self.stream.write("</span>\n")
3.170 + self.stream.write("</span>\n")
3.171 +
3.172 + def visitAssAttr(self, node):
3.173 + self.stream.write("<span class='assattr'>\n")
3.174 + self.dispatch(node.expr)
3.175 + self.stream.write("<span class='attr'>\n")
3.176 + self.stream.write(".%s\n" % self._text(node.attrname))
3.177 + self._types(node._node)
3.178 + self._scopes(node._node)
3.179 + self.stream.write("</span>\n")
3.180 + self.stream.write("</span>\n")
3.181 +
3.182 # Output preparation methods.
3.183
3.184 def _text(self, text):
3.185 @@ -252,7 +333,7 @@
3.186
3.187 def _doc(self, node):
3.188 if node.doc is not None:
3.189 - self.stream.write("<div class='doc'>%s</div>\n" % self._text(node.doc))
3.190 + self.stream.write("<div class='doc'>%s</div>\n" % self._text(repr(node.doc)))
3.191
3.192 def _sequence(self, node):
3.193 first = 1
3.194 @@ -262,18 +343,26 @@
3.195 self.dispatch(n)
3.196 first = 0
3.197
3.198 - def _name(self, node):
3.199 - self.stream.write("<span class='name'>%s</span>\n" % node.name)
3.200 + def _name(self, name):
3.201 + self.stream.write("<span class='name'>%s</span>\n" % name)
3.202
3.203 - def _name_start(self, node):
3.204 - self.stream.write("<span class='name'>%s\n" % node.name)
3.205 + def _name_start(self, name):
3.206 + self.stream.write("<span class='name'>%s\n" % name)
3.207
3.208 def _name_end(self):
3.209 self.stream.write("</span>\n")
3.210
3.211 def _types(self, node):
3.212 + if not hasattr(node, "types"):
3.213 + self.stream.write("<div class='types'>\n")
3.214 + self.stream.write("No types!\n")
3.215 + self.stream.write("</div>\n")
3.216 + else:
3.217 + self._types_list(node.types)
3.218 +
3.219 + def _types_list(self, types):
3.220 self.stream.write("<div class='types'>\n")
3.221 - for type in node.types:
3.222 + for type in types:
3.223 fn = type.type.full_name()
3.224 self.stream.write("<div class='type'>")
3.225 self.stream.write(self._text(fn))
3.226 @@ -281,15 +370,17 @@
3.227 self.stream.write("</div>\n")
3.228
3.229 def _scopes(self, node):
3.230 - self.stream.write("<div class='scopes'>\n")
3.231 - if not hasattr(node, "writes") and not hasattr(node, "accesses"):
3.232 - raise AttributeError, node
3.233 - for ref in getattr(node, "writes", getattr(node, "accesses", {})).keys():
3.234 - fn = ref.full_name()
3.235 - self.stream.write("<div class='scope'>")
3.236 - self.stream.write(self._text(fn))
3.237 + if not isinstance(node, LoadName):
3.238 + self.stream.write("<div class='scopes'>\n")
3.239 + if not hasattr(node, "writes") and not hasattr(node, "accesses"):
3.240 + self.stream.write("No scopes!\n")
3.241 + else:
3.242 + for ref in getattr(node, "writes", getattr(node, "accesses", {})).keys():
3.243 + fn = ref.full_name()
3.244 + self.stream.write("<div class='scope'>")
3.245 + self.stream.write(self._text(fn))
3.246 + self.stream.write("</div>\n")
3.247 self.stream.write("</div>\n")
3.248 - self.stream.write("</div>\n")
3.249
3.250 # Convenience functions.
3.251