1.1 --- a/fixnames.py Sat Aug 12 01:42:41 2006 +0200
1.2 +++ b/fixnames.py Sat Aug 12 01:46:35 2006 +0200
1.3 @@ -24,7 +24,6 @@
1.4 """
1.5
1.6 from simplified import *
1.7 -import compiler
1.8
1.9 # Fixing of name-related operations.
1.10
1.11 @@ -38,41 +37,81 @@
1.12 """
1.13
1.14 def __init__(self):
1.15 +
1.16 + "Initialise the name fixer."
1.17 +
1.18 Visitor.__init__(self)
1.19
1.20 # Satisfy visitor issues.
1.21
1.22 self.visitor = self
1.23
1.24 - def process_all(self, visitor):
1.25 - subprograms = []
1.26 + def process(self, visitor):
1.27 +
1.28 + "Process the resources of the given 'visitor'."
1.29 +
1.30 + self.subprograms = []
1.31 + self.current_subprograms = []
1.32 + self.current_namespaces = []
1.33 +
1.34 + # First, process the top-level code, finding out which names are
1.35 + # defined at that level.
1.36 +
1.37 + self.global_namespace = None
1.38 + visitor.result = self.process_node(visitor.result)
1.39 +
1.40 + # Then, process all functions and methods, providing a global namespace.
1.41 +
1.42 + self.global_namespace = self.namespace
1.43 +
1.44 for subprogram in visitor.subprograms:
1.45 - subprograms.append(self.process(subprogram))
1.46 - visitor.subprograms = subprograms
1.47 - visitor.result = self.process(visitor.result)
1.48 +
1.49 + # Internal subprograms are skipped here and processed specially via
1.50 + # Invoke nodes.
1.51 +
1.52 + if not getattr(subprogram, "acquire_locals", 0):
1.53 + self.subprograms.append(self.process_node(subprogram))
1.54 +
1.55 + visitor.subprograms = self.subprograms
1.56 return visitor
1.57
1.58 - def process(self, node):
1.59 + def process_node(self, node, namespace=None):
1.60
1.61 """
1.62 Process a subprogram or module 'node', discovering from attributes on
1.63 'node' any initial locals. Return a modified subprogram or module.
1.64 """
1.65
1.66 + # Do not process subprograms already being processed.
1.67 +
1.68 + if node in self.current_subprograms:
1.69 + return None
1.70 +
1.71 # Obtain a namespace either based on locals or on a structure.
1.72
1.73 - self.namespace = NameOrganiser(structure=getattr(node, "structure", None))
1.74 + structure = structure=getattr(node, "structure", None)
1.75 + self.namespace = NameOrganiser(structure)
1.76 +
1.77 + # Record the current subprogram and namespace.
1.78 +
1.79 + self.current_subprograms.append(node)
1.80 + self.current_namespaces.append(self.namespace)
1.81 +
1.82 + # If passed some namespace, merge its contents into this namespace.
1.83 +
1.84 + if namespace is not None:
1.85 + self.namespace.merge_namespace(namespace)
1.86
1.87 # NOTE: Check this.
1.88
1.89 if hasattr(node, "params"):
1.90 for param, default in node.params:
1.91 self.namespace.store(param)
1.92 - if hasattr(node, "star"):
1.93 - param = node.star
1.94 + if getattr(node, "star", None):
1.95 + param, default = node.star
1.96 self.namespace.store(param)
1.97 - if hasattr(node, "dstar"):
1.98 - param = node.dstar
1.99 + if getattr(node, "dstar", None):
1.100 + param, default = node.dstar
1.101 self.namespace.store(param)
1.102
1.103 # Add namespace details to any structure involved.
1.104 @@ -90,6 +129,14 @@
1.105 # Dispatch to the code itself.
1.106
1.107 result = self.dispatch(node)
1.108 +
1.109 + # Restore the previous subprogram and namespace.
1.110 +
1.111 + self.current_namespaces.pop()
1.112 + if self.current_namespaces:
1.113 + self.namespace = self.current_namespaces[-1]
1.114 + self.current_subprograms.pop()
1.115 +
1.116 return result
1.117
1.118 # Visitor methods.
1.119 @@ -124,26 +171,107 @@
1.120 return global_
1.121
1.122 def visitLoadName(self, loadname):
1.123 - print "Name", loadname.name, "in", self.namespace
1.124 +
1.125 + "Transform the 'loadname' node to a specific, scope-sensitive node."
1.126 +
1.127 scope = self.namespace.find_for_load(loadname.name)
1.128 +
1.129 + # For structure namespaces, load an attribute.
1.130 +
1.131 if scope == "structure":
1.132 result = self.dispatch(LoadAttr(expr=LoadRef(ref=self.namespace.structure), name=loadname.name))
1.133 +
1.134 + # For global accesses (ie. those outside the local namespace)...
1.135 +
1.136 elif scope == "global":
1.137 - result = self.dispatch(LoadGlobal(name=loadname.name))
1.138 +
1.139 + # Where a distinct global namespace exists, examine it.
1.140 +
1.141 + if self.global_namespace is not None:
1.142 + scope = self.global_namespace.find_for_load(loadname.name)
1.143 +
1.144 + # Where the name is outside the global namespace, it must be a
1.145 + # built-in.
1.146 +
1.147 + if scope == "global":
1.148 + result = self.dispatch(LoadBuiltin(name=loadname.name))
1.149 +
1.150 + # Otherwise, it is within the global namespace and must be a
1.151 + # global.
1.152 +
1.153 + else:
1.154 + result = self.dispatch(LoadGlobal(name=loadname.name))
1.155 +
1.156 + # Where no global namespace exists, we are at the module level and
1.157 + # must be accessing a built-in.
1.158 +
1.159 + else:
1.160 + result = self.dispatch(LoadBuiltin(name=loadname.name))
1.161 +
1.162 + # For local accesses...
1.163 +
1.164 else:
1.165 - result = loadname
1.166 +
1.167 + # Where a distinct global namespace exists, it must be a local.
1.168 +
1.169 + if self.global_namespace is not None:
1.170 + result = loadname
1.171 +
1.172 + # Otherwise, we must be accessing a global (which is local at the
1.173 + # module level).
1.174 +
1.175 + else:
1.176 + result = self.dispatch(LoadGlobal(name=loadname.name))
1.177 +
1.178 return result
1.179
1.180 def visitStoreName(self, storename):
1.181 +
1.182 + "Transform the 'storename' node to a specific, scope-sensitive node."
1.183 +
1.184 scope = self.namespace.find_for_store(storename.name)
1.185 +
1.186 + # For structure namespaces, store an attribute.
1.187 +
1.188 if scope == "structure":
1.189 return self.dispatch(StoreAttr(lvalue=LoadRef(ref=self.namespace.structure), name=storename.name, expr=storename.expr))
1.190 +
1.191 + # Where the name is outside the local namespace, disallow any built-in
1.192 + # assignment and store the name globally.
1.193 +
1.194 elif scope == "global":
1.195 return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr))
1.196 +
1.197 + # For local namespace accesses...
1.198 +
1.199 else:
1.200 - storename.expr = self.dispatch(storename.expr)
1.201 self.namespace.store(storename.name)
1.202 - return storename
1.203 +
1.204 + # If a distinct global namespace exists, it must be a local access.
1.205 +
1.206 + if self.global_namespace is not None:
1.207 + return storename
1.208 +
1.209 + # Otherwise, the name is being set at the module level and is
1.210 + # considered global.
1.211 +
1.212 + else:
1.213 + return self.dispatch(StoreGlobal(name=storename.name, expr=storename.expr))
1.214 +
1.215 + def visitInvoke(self, invoke):
1.216 +
1.217 + "Transform the 'invoke' node, performing processing on subprograms."
1.218 +
1.219 + # The special case of internal subprogram invocation is addressed by
1.220 + # propagating namespace information to the subprogram and processing it.
1.221 +
1.222 + if getattr(invoke, "same_frame", 0):
1.223 + subprogram = self.process_node(invoke.expr.ref, self.namespace)
1.224 + if subprogram is not None:
1.225 + self.subprograms.append(subprogram)
1.226 + return invoke
1.227 + else:
1.228 + return self.default(invoke)
1.229
1.230 class NameOrganiser:
1.231
1.232 @@ -177,9 +305,9 @@
1.233 else:
1.234 return "global"
1.235
1.236 - def store(self, name, types=None):
1.237 + def store(self, name):
1.238 if name not in self.not_local:
1.239 - self.names[name] = types
1.240 + self.names[name] = None
1.241 else:
1.242 raise KeyError, name
1.243
1.244 @@ -189,6 +317,17 @@
1.245 else:
1.246 return self.names[name]
1.247
1.248 + def merge(self, name):
1.249 + if not self.names.has_key(name):
1.250 + self.names[name] = None
1.251 +
1.252 + def merge_namespace(self, namespace):
1.253 + self.merge_names(namespace.names.keys())
1.254 +
1.255 + def merge_names(self, names):
1.256 + for name in names:
1.257 + self.merge(name)
1.258 +
1.259 def __repr__(self):
1.260 return repr(self.names)
1.261