1.1 --- a/annotate.py Sun Nov 26 15:45:53 2006 +0100
1.2 +++ b/annotate.py Sun Nov 26 21:28:11 2006 +0100
1.3 @@ -234,27 +234,52 @@
1.4 # With Return nodes inside the body/else sections, the changes are
1.5 # communicated to the caller.
1.6
1.7 - conditional.test = self.dispatch(conditional.test)
1.8 - saved_namespace = self.namespace
1.9 - is_global = self.namespace is self.global_namespace
1.10 + is_module = self.namespace is self.module.namespace
1.11 +
1.12 + # Where the test is closely associated with the body, save the namespace
1.13 + # before entering the test.
1.14 +
1.15 + if conditional.isolate_test:
1.16 + saved_namespace = self.namespace
1.17 + self.namespace = Namespace()
1.18 + if is_module:
1.19 + self.module.namespace = self.namespace
1.20 + self.namespace.merge_namespace(saved_namespace)
1.21
1.22 - self.namespace = Namespace()
1.23 - if is_global:
1.24 - self.module.namespace = self.global_namespace = self.namespace
1.25 - self.namespace.merge_namespace(saved_namespace)
1.26 + conditional.test = self.dispatch(conditional.test)
1.27 +
1.28 + # Where the test may affect the body and the else clause, save the
1.29 + # namespace after processing the test.
1.30 +
1.31 + if not conditional.isolate_test:
1.32 + saved_namespace = self.namespace
1.33 + self.namespace = Namespace()
1.34 + if is_module:
1.35 + self.module.namespace = self.namespace
1.36 + self.namespace.merge_namespace(saved_namespace)
1.37 +
1.38 + # Process the body clause.
1.39 +
1.40 conditional.body = self.dispatches(conditional.body)
1.41 body_namespace = self.namespace
1.42
1.43 + # Use the saved namespace as a template for the else clause.
1.44 +
1.45 self.namespace = Namespace()
1.46 - if is_global:
1.47 - self.module.namespace = self.global_namespace = self.namespace
1.48 + if is_module:
1.49 + self.module.namespace = self.namespace
1.50 self.namespace.merge_namespace(saved_namespace)
1.51 +
1.52 + # Process the else clause.
1.53 +
1.54 conditional.else_ = self.dispatches(conditional.else_)
1.55 else_namespace = self.namespace
1.56
1.57 + # Merge the body and else namespaces.
1.58 +
1.59 self.namespace = Namespace()
1.60 - if is_global:
1.61 - self.module.namespace = self.global_namespace = self.namespace
1.62 + if is_module:
1.63 + self.module.namespace = self.namespace
1.64 self.namespace.merge_namespace(body_namespace)
1.65 self.namespace.merge_namespace(else_namespace)
1.66
1.67 @@ -272,21 +297,74 @@
1.68 return subprogram
1.69
1.70 def visitTry(self, try_):
1.71 + is_module = self.namespace is self.module.namespace
1.72 +
1.73 try_.body = self.dispatches(try_.body)
1.74 - try_.handler = self.dispatches(try_.handler)
1.75 +
1.76 + # Save the namespace from the body.
1.77 +
1.78 + body_namespace = Namespace()
1.79 + body_namespace.merge_namespace(self.namespace)
1.80 +
1.81 + # Process the handler.
1.82 +
1.83 + if hasattr(try_, "handler"):
1.84 + try_.handler = self.dispatches(try_.handler)
1.85 +
1.86 + # Save the namespace from the handler.
1.87 +
1.88 + handler_namespace = Namespace()
1.89 + handler_namespace.merge_namespace(self.namespace)
1.90 +
1.91 + # Remember the raised exceptions encountered so far.
1.92 +
1.93 raises = self.namespace.raises
1.94
1.95 - # Empty the raised exceptions for the else clause.
1.96 + # Process the else clause.
1.97 +
1.98 + if hasattr(try_, "else_"):
1.99 +
1.100 + # Restore the body namespace for the else clause.
1.101 +
1.102 + self.namespace = body_namespace
1.103 + if is_module:
1.104 + self.module.namespace = self.namespace
1.105 +
1.106 + # Empty the raised exceptions for the else clause.
1.107
1.108 - self.namespace.raises = []
1.109 - try_.else_ = self.dispatches(try_.else_)
1.110 - self.namespace.raises = raises
1.111 + self.namespace.raises = []
1.112 + try_.else_ = self.dispatches(try_.else_)
1.113 + self.namespace.raises = raises
1.114 +
1.115 + # Merge the namespaces.
1.116 +
1.117 + self.namespace = Namespace()
1.118 + if is_module:
1.119 + self.module.namespace = self.namespace
1.120 + self.namespace.merge_namespace(body_namespace)
1.121 + self.namespace.merge_namespace(handler_namespace)
1.122 +
1.123 + # Process the finally clause, if any.
1.124
1.125 try_.finally_ = self.dispatches(try_.finally_)
1.126 return try_
1.127
1.128 # Namespace operations.
1.129
1.130 + def visitCheckExc(self, checkexc):
1.131 + checkexc.expr = self.dispatch(checkexc.expr)
1.132 + expr_types = self.namespace.types
1.133 + choice_types = []
1.134 + choices = []
1.135 + for choice in checkexc.choices:
1.136 + choices.append(self.dispatch(choice))
1.137 + choice_types += self.namespace.types
1.138 + for expr_type in expr_types:
1.139 + if expr_type.type.get_class() not in choice_types:
1.140 + print "CheckExc", expr_type, "should be revoked!"
1.141 + self._prune_non_accesses(checkexc.expr, expr_type)
1.142 + return checkexc
1.143 +
1.144 def visitLoadAttr(self, loadattr):
1.145 loadattr.expr = self.dispatch(loadattr.expr)
1.146 types = []
1.147 @@ -300,7 +378,7 @@
1.148
1.149 # Revoke this type from any name involved.
1.150
1.151 - self._prune_non_accesses(loadattr, attr)
1.152 + self._prune_non_accesses(loadattr.expr, attr)
1.153
1.154 for attribute, accessor in attributes:
1.155 if attribute is not None:
1.156 @@ -315,7 +393,7 @@
1.157
1.158 # Revoke this type from any name involved.
1.159
1.160 - self._prune_non_accesses(loadattr, attr)
1.161 + self._prune_non_accesses(loadattr.expr, attr)
1.162
1.163 if not types:
1.164 print "No attribute found for", loadattr.name, "given", self.namespace.types
1.165 @@ -325,13 +403,15 @@
1.166 self.annotate(loadattr)
1.167 return loadattr
1.168
1.169 - def _prune_non_accesses(self, loadattr, attr):
1.170 - if isinstance(loadattr.expr, LoadName):
1.171 - self.namespace.revoke(loadattr.expr.name, attr)
1.172 - elif isinstance(loadattr.expr, LoadAttr):
1.173 - for expr_attr in loadattr.expr.expr.types:
1.174 + def _prune_non_accesses(self, expr, attr):
1.175 + if isinstance(expr, LoadName):
1.176 + self.namespace.revoke(expr.name, attr)
1.177 + elif isinstance(expr, LoadAttr):
1.178 + for expr_attr in expr.expr.types:
1.179 if hasattr(expr_attr.type, "namespace"):
1.180 - expr_attr.type.namespace.revoke(loadattr.expr.name, attr)
1.181 + expr_attr.type.namespace.revoke(expr.name, attr)
1.182 + elif isinstance(expr, LoadExc):
1.183 + self.namespace.revoke_exception_type(attr)
1.184
1.185 def visitLoadExc(self, loadexc):
1.186 self.namespace.types = self.namespace.raises[:]
1.187 @@ -887,6 +967,9 @@
1.188 def revoke(self, name, type):
1.189 self.names[name].remove(type)
1.190
1.191 + def revoke_exception_type(self, type):
1.192 + self.raises.remove(type)
1.193 +
1.194 def merge_namespace(self, namespace, no_return_locals=0):
1.195 self.merge_items(namespace.names.items())
1.196 combine(self.returns, namespace.returns)