1.1 --- a/annotate.py Sat Aug 12 01:42:41 2006 +0200
1.2 +++ b/annotate.py Sat Aug 12 01:46:35 2006 +0200
1.3 @@ -198,7 +198,20 @@
1.4
1.5 self.visitor = self
1.6
1.7 - def process_all(self, visitor, builtins_visitor=None):
1.8 + def process(self, visitor, builtins_visitor=None):
1.9 +
1.10 + """
1.11 + Process the resources of the given 'visitor', using the optional
1.12 + 'builtins_visitor' to access built-in classes and functions.
1.13 + """
1.14 +
1.15 + self.subprograms = []
1.16 + self.current_subprograms = []
1.17 + self.current_namespaces = []
1.18 + self.current_returns = []
1.19 + self.current_return_locals = []
1.20 + self.current_temps = []
1.21 + self.current_types = []
1.22
1.23 # Give constants their own namespace.
1.24
1.25 @@ -207,12 +220,16 @@
1.26
1.27 # Process the module, supplying builtins if possible.
1.28
1.29 + self.global_namespace = Namespace()
1.30 +
1.31 if builtins_visitor is not None:
1.32 - return self.process(visitor.result, builtins=builtins_visitor.result.namespace)
1.33 + self.builtins_namespace = builtins_visitor.result.namespace
1.34 else:
1.35 - return self.process(visitor.result)
1.36 + self.builtins_namespace = self.global_namespace
1.37
1.38 - def process(self, node, locals=None, globals=None, builtins=None):
1.39 + return self.process_node(visitor.result)
1.40 +
1.41 + def process_node(self, node, locals=None):
1.42
1.43 """
1.44 Process a subprogram or module 'node', indicating any initial 'locals'.
1.45 @@ -220,12 +237,19 @@
1.46 mutate nodes in the original program.
1.47 """
1.48
1.49 - # Determine the global namespace.
1.50 - # NOTE: Improve this.
1.51 + if locals:
1.52 + self.namespace = locals
1.53 + else:
1.54 + self.namespace = self.global_namespace
1.55 +
1.56 + # Record the current subprogram and namespace.
1.57
1.58 - self.global_namespace = globals or Namespace()
1.59 - self.builtins_namespace = builtins or self.global_namespace
1.60 - self.namespace = locals or self.global_namespace
1.61 + self.current_subprograms.append(node)
1.62 + self.current_namespaces.append(self.namespace)
1.63 + self.current_returns.append([])
1.64 + self.current_return_locals.append([])
1.65 + self.current_temps.append({})
1.66 + self.current_types.append([])
1.67
1.68 # Record the namespace on the node.
1.69 # NOTE: This may eventually be a specialisation node.
1.70 @@ -234,10 +258,10 @@
1.71
1.72 # Remember return values and locals snapshots.
1.73
1.74 - self.returns = []
1.75 self.return_locals = []
1.76 - self.types = None
1.77 - self.temp = {}
1.78 + self.returns = self.current_returns[-1]
1.79 + self.temp = self.current_temps[-1]
1.80 + self.types = self.current_types[-1]
1.81
1.82 # Add namespace details to any structure involved.
1.83
1.84 @@ -256,6 +280,31 @@
1.85 # Dispatch to the code itself.
1.86
1.87 result = self.dispatch(node)
1.88 +
1.89 + # Restore the previous subprogram and namespace.
1.90 +
1.91 + self.current_namespaces.pop()
1.92 + if self.current_namespaces:
1.93 + self.namespace = self.current_namespaces[-1]
1.94 +
1.95 + self.current_types.pop()
1.96 + if self.current_types:
1.97 + self.types = self.current_types[-1]
1.98 +
1.99 + self.current_temps.pop()
1.100 + if self.current_temps:
1.101 + self.temp = self.current_temps[-1]
1.102 +
1.103 + self.last_returns = self.current_returns.pop()
1.104 + if self.current_returns:
1.105 + self.returns = self.current_returns[-1]
1.106 +
1.107 + self.returned_locals = self.current_return_locals.pop()
1.108 + if self.current_return_locals:
1.109 + self.return_locals = self.current_return_locals[-1]
1.110 +
1.111 + self.current_subprograms.pop()
1.112 +
1.113 return result
1.114
1.115 def annotate(self, node):
1.116 @@ -315,13 +364,15 @@
1.117 return storename
1.118
1.119 def visitLoadGlobal(self, loadglobal):
1.120 - try:
1.121 - self.types = self.global_namespace.load(loadglobal.name)
1.122 - except KeyError:
1.123 - self.types = self.builtins_namespace.load(loadglobal.name)
1.124 + self.types = self.global_namespace.load(loadglobal.name)
1.125 self.annotate(loadglobal)
1.126 return loadglobal
1.127
1.128 + def visitLoadBuiltin(self, loadbuiltin):
1.129 + self.types = self.builtins_namespace.load(loadbuiltin.name)
1.130 + self.annotate(loadbuiltin)
1.131 + return loadbuiltin
1.132 +
1.133 def visitStoreGlobal(self, storeglobal):
1.134 storeglobal.expr = self.dispatch(storeglobal.expr)
1.135 self.global_namespace.merge(storeglobal.name, self.types)
1.136 @@ -520,18 +571,16 @@
1.137
1.138 # Process the subprogram.
1.139
1.140 - annotator = Annotator()
1.141 - annotator.process(subprogram, namespace, self.global_namespace, self.builtins_namespace)
1.142 + self.process_node(subprogram, namespace)
1.143
1.144 - # NOTE: Annotate the node with invocation details.
1.145 - # NOTE: This should really be as part of a table of alternatives.
1.146 + # NOTE: Improve and verify this.
1.147
1.148 if getattr(subprogram, "returns_value", 0):
1.149 - self.types = annotator.returns
1.150 + self.types = self.last_returns
1.151 self.annotate(invoke)
1.152
1.153 if getattr(invoke, "same_frame", 0):
1.154 - for locals in annotator.return_locals:
1.155 + for locals in self.returned_locals:
1.156 self.namespace.merge_namespace(locals)
1.157
1.158 # Remember the state of the system.
2.1 --- a/fixnames.py Sat Aug 12 01:42:41 2006 +0200
2.2 +++ b/fixnames.py Sat Aug 12 01:46:35 2006 +0200
2.3 @@ -24,7 +24,6 @@
2.4 """
2.5
2.6 from simplified import *
2.7 -import compiler
2.8
2.9 # Fixing of name-related operations.
2.10
2.11 @@ -38,41 +37,81 @@
2.12 """
2.13
2.14 def __init__(self):
2.15 +
2.16 + "Initialise the name fixer."
2.17 +
2.18 Visitor.__init__(self)
2.19
2.20 # Satisfy visitor issues.
2.21
2.22 self.visitor = self
2.23
2.24 - def process_all(self, visitor):
2.25 - subprograms = []
2.26 + def process(self, visitor):
2.27 +
2.28 + "Process the resources of the given 'visitor'."
2.29 +
2.30 + self.subprograms = []
2.31 + self.current_subprograms = []
2.32 + self.current_namespaces = []
2.33 +
2.34 + # First, process the top-level code, finding out which names are
2.35 + # defined at that level.
2.36 +
2.37 + self.global_namespace = None
2.38 + visitor.result = self.process_node(visitor.result)
2.39 +
2.40 + # Then, process all functions and methods, providing a global namespace.
2.41 +
2.42 + self.global_namespace = self.namespace
2.43 +
2.44 for subprogram in visitor.subprograms:
2.45 - subprograms.append(self.process(subprogram))
2.46 - visitor.subprograms = subprograms
2.47 - visitor.result = self.process(visitor.result)
2.48 +
2.49 + # Internal subprograms are skipped here and processed specially via
2.50 + # Invoke nodes.
2.51 +
2.52 + if not getattr(subprogram, "acquire_locals", 0):
2.53 + self.subprograms.append(self.process_node(subprogram))
2.54 +
2.55 + visitor.subprograms = self.subprograms
2.56 return visitor
2.57
2.58 - def process(self, node):
2.59 + def process_node(self, node, namespace=None):
2.60
2.61 """
2.62 Process a subprogram or module 'node', discovering from attributes on
2.63 'node' any initial locals. Return a modified subprogram or module.
2.64 """
2.65
2.66 + # Do not process subprograms already being processed.
2.67 +
2.68 + if node in self.current_subprograms:
2.69 + return None
2.70 +
2.71 # Obtain a namespace either based on locals or on a structure.
2.72
2.73 - self.namespace = NameOrganiser(structure=getattr(node, "structure", None))
2.74 + structure = structure=getattr(node, "structure", None)
2.75 + self.namespace = NameOrganiser(structure)
2.76 +
2.77 + # Record the current subprogram and namespace.
2.78 +
2.79 + self.current_subprograms.append(node)
2.80 + self.current_namespaces.append(self.namespace)
2.81 +
2.82 + # If passed some namespace, merge its contents into this namespace.
2.83 +
2.84 + if namespace is not None:
2.85 + self.namespace.merge_namespace(namespace)
2.86
2.87 # NOTE: Check this.
2.88
2.89 if hasattr(node, "params"):
2.90 for param, default in node.params:
2.91 self.namespace.store(param)
2.92 - if hasattr(node, "star"):
2.93 - param = node.star
2.94 + if getattr(node, "star", None):
2.95 + param, default = node.star
2.96 self.namespace.store(param)
2.97 - if hasattr(node, "dstar"):
2.98 - param = node.dstar
2.99 + if getattr(node, "dstar", None):
2.100 + param, default = node.dstar
2.101 self.namespace.store(param)
2.102
2.103 # Add namespace details to any structure involved.
2.104 @@ -90,6 +129,14 @@
2.105 # Dispatch to the code itself.
2.106
2.107 result = self.dispatch(node)
2.108 +
2.109 + # Restore the previous subprogram and namespace.
2.110 +
2.111 + self.current_namespaces.pop()
2.112 + if self.current_namespaces:
2.113 + self.namespace = self.current_namespaces[-1]
2.114 + self.current_subprograms.pop()
2.115 +
2.116 return result
2.117
2.118 # Visitor methods.
2.119 @@ -124,26 +171,107 @@
2.120 return global_
2.121
2.122 def visitLoadName(self, loadname):
2.123 - print "Name", loadname.name, "in", self.namespace
2.124 +
2.125 + "Transform the 'loadname' node to a specific, scope-sensitive node."
2.126 +
2.127 scope = self.namespace.find_for_load(loadname.name)
2.128 +
2.129 + # For structure namespaces, load an attribute.
2.130 +
2.131 if scope == "structure":
2.132 result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.namespace.structure), name=loadname.name))
2.133 +
2.134 + # For global accesses (ie. those outside the local namespace)...
2.135 +
2.136 elif scope == "global":
2.137 - result = self.dispatch(LoadGlobal(name=loadname.name))
2.138 +
2.139 + # Where a distinct global namespace exists, examine it.
2.140 +
2.141 + if self.global_namespace is not None:
2.142 + scope = self.global_namespace.find_for_load(loadname.name)
2.143 +
2.144 + # Where the name is outside the global namespace, it must be a
2.145 + # built-in.
2.146 +
2.147 + if scope == "global":
2.148 + result = self.dispatch(LoadBuiltin(name=loadname.name))
2.149 +
2.150 + # Otherwise, it is within the global namespace and must be a
2.151 + # global.
2.152 +
2.153 + else:
2.154 + result = self.dispatch(LoadGlobal(name=loadname.name))
2.155 +
2.156 + # Where no global namespace exists, we are at the module level and
2.157 + # must be accessing a built-in.
2.158 +
2.159 + else:
2.160 + result = self.dispatch(LoadBuiltin(name=loadname.name))
2.161 +
2.162 + # For local accesses...
2.163 +
2.164 else:
2.165 - result = loadname
2.166 +
2.167 + # Where a distinct global namespace exists, it must be a local.
2.168 +
2.169 + if self.global_namespace is not None:
2.170 + result = loadname
2.171 +
2.172 + # Otherwise, we must be accessing a global (which is local at the
2.173 + # module level).
2.174 +
2.175 + else:
2.176 + result = self.dispatch(LoadGlobal(name=loadname.name))
2.177 +
2.178 return result
2.179
2.180 def visitStoreName(self, storename):
2.181 +
2.182 + "Transform the 'storename' node to a specific, scope-sensitive node."
2.183 +
2.184 scope = self.namespace.find_for_store(storename.name)
2.185 +
2.186 + # For structure namespaces, store an attribute.
2.187 +
2.188 if scope == "structure":
2.189 return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.namespace.structure), name=storename.name, expr=storename.expr))
2.190 +
2.191 + # Where the name is outside the local namespace, disallow any built-in
2.192 + # assignment and store the name globally.
2.193 +
2.194 elif scope == "global":
2.195 return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr))
2.196 +
2.197 + # For local namespace accesses...
2.198 +
2.199 else:
2.200 - storename.expr = self.dispatch(storename.expr)
2.201 self.namespace.store(storename.name)
2.202 - return storename
2.203 +
2.204 + # If a distinct global namespace exists, it must be a local access.
2.205 +
2.206 + if self.global_namespace is not None:
2.207 + return storename
2.208 +
2.209 + # Otherwise, the name is being set at the module level and is
2.210 + # considered global.
2.211 +
2.212 + else:
2.213 + return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr))
2.214 +
2.215 + def visitInvoke(self, invoke):
2.216 +
2.217 + "Transform the 'invoke' node, performing processing on subprograms."
2.218 +
2.219 + # The special case of internal subprogram invocation is addressed by
2.220 + # propagating namespace information to the subprogram and processing it.
2.221 +
2.222 + if getattr(invoke, "same_frame", 0):
2.223 + subprogram = self.process_node(invoke.expr.ref, self.namespace)
2.224 + if subprogram is not None:
2.225 + self.subprograms.append(subprogram)
2.226 + return invoke
2.227 + else:
2.228 + return self.default(invoke)
2.229
2.230 class NameOrganiser:
2.231
2.232 @@ -177,9 +305,9 @@
2.233 else:
2.234 return "global"
2.235
2.236 - def store(self, name, types=None):
2.237 + def store(self, name):
2.238 if name not in self.not_local:
2.239 - self.names[name] = types
2.240 + self.names[name] = None
2.241 else:
2.242 raise KeyError, name
2.243
2.244 @@ -189,6 +317,17 @@
2.245 else:
2.246 return self.names[name]
2.247
2.248 + def merge(self, name):
2.249 + if not self.names.has_key(name):
2.250 + self.names[name] = None
2.251 +
2.252 + def merge_namespace(self, namespace):
2.253 + self.merge_names(namespace.names.keys())
2.254 +
2.255 + def merge_names(self, names):
2.256 + for name in names:
2.257 + self.merge(name)
2.258 +
2.259 def __repr__(self):
2.260 return repr(self.names)
2.261