1.1 --- a/fixnames.py Sun May 27 18:19:01 2007 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,489 +0,0 @@
1.4 -#!/usr/bin/env python
1.5 -
1.6 -"""
1.7 -Fix name-related operations. The code in this module operates upon simplified
1.8 -program node trees.
1.9 -
1.10 -Copyright (C) 2006 Paul Boddie <paul@boddie.org.uk>
1.11 -
1.12 -This software is free software; you can redistribute it and/or
1.13 -modify it under the terms of the GNU General Public License as
1.14 -published by the Free Software Foundation; either version 2 of
1.15 -the License, or (at your option) any later version.
1.16 -
1.17 -This software is distributed in the hope that it will be useful,
1.18 -but WITHOUT ANY WARRANTY; without even the implied warranty of
1.19 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.20 -GNU General Public License for more details.
1.21 -
1.22 -You should have received a copy of the GNU General Public
1.23 -License along with this library; see the file LICENCE.txt
1.24 -If not, write to the Free Software Foundation, Inc.,
1.25 -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.26 -
1.27 ---------
1.28 -
1.29 -To use this module, the easiest approach is to use the fix function:
1.30 -
1.31 -fix(module)
1.32 -
1.33 -The more complicated approach involves instantiating a Fixer object:
1.34 -
1.35 -fixer = Fixer()
1.36 -
1.37 -Then, applying the fixer to an existing module:
1.38 -
1.39 -fixer.process(module)
1.40 -
1.41 -If a module containing built-in classes and functions exists, apply the fixer as
1.42 -follows:
1.43 -
1.44 -fixer.process(module, builtins)
1.45 -"""
1.46 -
1.47 -from simplified import *
1.48 -
1.49 -# Fixing of name-related operations.
1.50 -
1.51 -class Fixer(Visitor):
1.52 -
1.53 - """
1.54 - The name fixer which traverses the program nodes in a module, typically
1.55 - depth-first, and maintains a record of name usage in the different
1.56 - namespaces. As a consequence of various observations, some parts of the
1.57 - program node tree are modified with different operations employed to those
1.58 - originally defined.
1.59 -
1.60 - There are two kinds of subprograms in modules: functions/methods and
1.61 - internal subprograms which support things like loops. The latter kind of
1.62 - subprogram may acquire the locals from their callers and must therefore be
1.63 - traversed with information from such callers. Thus, we choose the top-level
1.64 - code and all functions/methods as roots for processing, following
1.65 - invocations of internal subprograms in order to reach all subprograms that
1.66 - are defined in each module.
1.67 -
1.68 - top-level
1.69 - ...
1.70 - invoke function
1.71 - ...
1.72 - invoke loop -> subprogram (internal)
1.73 - ...
1.74 -
1.75 - subprogram (function)
1.76 - ...
1.77 - invoke loop -> subprogram (internal)
1.78 - ...
1.79 -
1.80 - ...
1.81 -
1.82 - The above approach should guarantee that all subprograms are traversed and
1.83 - that all name lookups are correctly categorised.
1.84 - """
1.85 -
1.86 - def __init__(self):
1.87 -
1.88 - "Initialise the name fixer."
1.89 -
1.90 - Visitor.__init__(self)
1.91 -
1.92 - # Satisfy visitor issues.
1.93 -
1.94 - self.visitor = self
1.95 -
1.96 - def process(self, module, builtins=None):
1.97 -
1.98 - """
1.99 - Process the given 'module' optionally using some 'builtins' to reference
1.100 - built-in objects.
1.101 - """
1.102 -
1.103 - # The fixer maintains a list of transformed subprograms (added for each
1.104 - # of the processing "roots" and also for each invoked internal
1.105 - # subprogram), along with a list of current subprograms (used to avoid
1.106 - # recursion issues) and a list of current namespaces (used to recall
1.107 - # namespaces upon invoking internal subprograms).
1.108 -
1.109 - self.subprograms = []
1.110 - self.current_subprograms = []
1.111 - self.current_namespaces = []
1.112 -
1.113 - # First, process the top-level code, finding out which names are
1.114 - # defined at that level.
1.115 -
1.116 - self.global_namespace = None
1.117 - self.module = module
1.118 - self.builtins = builtins or module
1.119 -
1.120 - self.process_node(self.module)
1.121 -
1.122 - # Then, process all functions and methods, providing a global namespace.
1.123 - # By setting a global namespace, we influence the resolution of names:
1.124 - # those which are global to the top-level module (processed above) are
1.125 - # considered as built-in names, whereas those which are global to a
1.126 - # function or method are searched for in the global namespace.
1.127 -
1.128 - self.global_namespace = self.namespace
1.129 -
1.130 - for subprogram in self.module.simplifier.subprograms:
1.131 -
1.132 - # Internal subprograms are skipped here and processed specially via
1.133 - # Invoke nodes.
1.134 -
1.135 - if not getattr(subprogram, "internal", 0):
1.136 - self.subprograms.append(self.process_node(subprogram))
1.137 -
1.138 - # Ultimately, we redefine the list of subprograms on the visitor.
1.139 -
1.140 - self.module.simplifier.subprograms = self.subprograms
1.141 - return self.module
1.142 -
1.143 - def process_node(self, node, namespace=None):
1.144 -
1.145 - """
1.146 - Process a subprogram or module 'node', discovering from attributes on
1.147 - 'node' any initial locals. Return a modified subprogram or module.
1.148 - """
1.149 -
1.150 - # Do not process subprograms already being processed.
1.151 -
1.152 - if node in self.current_subprograms:
1.153 - return None
1.154 -
1.155 - # Obtain a namespace either based on locals or on a structure.
1.156 -
1.157 - structure = structure=getattr(node, "structure", None)
1.158 -
1.159 - # If passed some namespace, use that as the current namespace.
1.160 -
1.161 - if namespace is not None:
1.162 - self.namespace.merge_namespace(namespace)
1.163 - else:
1.164 - self.namespace = NameOrganiser(structure)
1.165 -
1.166 - # Record the current subprogram and namespace.
1.167 -
1.168 - self.current_subprograms.append(node)
1.169 - self.current_namespaces.append(self.namespace)
1.170 -
1.171 - # NOTE: Avoid PEP 227 (nested scopes) whilst permitting references to a
1.172 - # NOTE: subprogram within itself. Do not define the name of the function
1.173 - # NOTE: within a method definition.
1.174 -
1.175 - if isinstance(node, Subprogram) and getattr(node, "name", None) is not None and not getattr(node, "is_method", 0):
1.176 - self.namespace.store(node.name)
1.177 -
1.178 - # Register the names of parameters in the namespace.
1.179 -
1.180 - if hasattr(node, "params"):
1.181 - new_params = []
1.182 - for param, default in node.params:
1.183 - new_params.append((param, self.dispatch(default)))
1.184 - self.namespace.store(param)
1.185 - node.params = new_params
1.186 - if getattr(node, "star", None):
1.187 - param, default = node.star
1.188 - self.namespace.store(param)
1.189 - node.star = param, self.dispatch(default)
1.190 - if getattr(node, "dstar", None):
1.191 - param, default = node.dstar
1.192 - self.namespace.store(param)
1.193 - node.dstar = param, self.dispatch(default)
1.194 -
1.195 - # Add namespace details to any structure involved.
1.196 -
1.197 - if hasattr(node, "structure") and node.structure is not None:
1.198 -
1.199 - # Initialise bases where appropriate.
1.200 -
1.201 - if hasattr(node.structure, "bases"):
1.202 - bases = []
1.203 - for base in node.structure.bases:
1.204 - bases.append(self.dispatch(base))
1.205 - node.structure.bases = bases
1.206 -
1.207 - # Dispatch to the code itself.
1.208 -
1.209 - result = self.dispatch(node)
1.210 - result.organiser = self.namespace
1.211 -
1.212 - # Restore the previous subprogram and namespace.
1.213 -
1.214 - self.current_namespaces.pop()
1.215 - if self.current_namespaces:
1.216 - self.namespace = self.current_namespaces[-1]
1.217 - self.current_subprograms.pop()
1.218 -
1.219 - return result
1.220 -
1.221 - # Visitor methods.
1.222 -
1.223 - def default(self, node):
1.224 -
1.225 - """
1.226 - Process the given 'node', given that it does not have a specific
1.227 - handler.
1.228 - """
1.229 -
1.230 - for attr in ("pos_args",):
1.231 - value = getattr(node, attr, None)
1.232 - if value is not None:
1.233 - setattr(node, attr, self.dispatches(value))
1.234 - for attr in ("kw_args",):
1.235 - value = getattr(node, attr, None)
1.236 - if value is not None:
1.237 - setattr(node, attr, self.dispatch_dict(value))
1.238 - for attr in ("expr", "lvalue", "test", "star", "dstar"):
1.239 - value = getattr(node, attr, None)
1.240 - if value is not None:
1.241 - setattr(node, attr, self.dispatch(value))
1.242 - for attr in ("body", "else_", "handler", "finally_", "code", "choices", "nodes"):
1.243 - value = getattr(node, attr, None)
1.244 - if value is not None:
1.245 - setattr(node, attr, self.dispatches(value))
1.246 - return node
1.247 -
1.248 - def dispatch(self, node, *args):
1.249 - return Visitor.dispatch(self, node, *args)
1.250 -
1.251 - def visitGlobal(self, global_):
1.252 - for name in global_.names:
1.253 - self.namespace.make_global(name)
1.254 - return global_
1.255 -
1.256 - def visitLoadName(self, loadname):
1.257 -
1.258 - "Transform the 'loadname' node to a specific, scope-sensitive node."
1.259 -
1.260 - scope = self.namespace.find_for_load(loadname.name)
1.261 -
1.262 - # For structure namespaces, load an attribute.
1.263 -
1.264 - if scope == "structure":
1.265 - result = self.dispatch(
1.266 - LoadAttr(loadname.original, loadname.defining,
1.267 - expr=LoadRef(loadname.original,
1.268 - ref=self.namespace.structure),
1.269 - name=loadname.name,
1.270 - nstype="structure")
1.271 - )
1.272 -
1.273 - # For global accesses (ie. those outside the local namespace)...
1.274 -
1.275 - elif scope == "global":
1.276 -
1.277 - # Where a distinct global namespace exists, examine it.
1.278 -
1.279 - if self.global_namespace is not None:
1.280 - scope = self.global_namespace.find_for_load(loadname.name)
1.281 -
1.282 - # Where the name is outside the global namespace, it must be a
1.283 - # built-in.
1.284 -
1.285 - if scope == "global":
1.286 - result = self.dispatch(
1.287 - LoadAttr(loadname.original, loadname.defining,
1.288 - expr=LoadRef(loadname.original,
1.289 - ref=self.builtins),
1.290 - name=loadname.name,
1.291 - nstype="module")
1.292 - )
1.293 -
1.294 - # Otherwise, it is within the global namespace and must be a
1.295 - # global.
1.296 -
1.297 - else:
1.298 - result = self.dispatch(
1.299 - LoadAttr(loadname.original, loadname.defining,
1.300 - expr=LoadRef(loadname.original,
1.301 - ref=self.module),
1.302 - name=loadname.name,
1.303 - nstype="module")
1.304 - )
1.305 -
1.306 - # Where no global namespace exists, we are at the module level and
1.307 - # must be accessing a built-in.
1.308 -
1.309 - else:
1.310 - result = self.dispatch(
1.311 - LoadAttr(loadname.original, loadname.defining,
1.312 - expr=LoadRef(loadname.original,
1.313 - ref=self.builtins),
1.314 - name=loadname.name,
1.315 - nstype="module")
1.316 - )
1.317 -
1.318 - # For local accesses...
1.319 -
1.320 - else:
1.321 -
1.322 - # Where a distinct global namespace exists, it must be a local.
1.323 -
1.324 - if self.global_namespace is not None:
1.325 - result = loadname
1.326 -
1.327 - # Otherwise, we must be accessing a global (which is local at the
1.328 - # module level).
1.329 -
1.330 - else:
1.331 - result = self.dispatch(
1.332 - LoadAttr(loadname.original, loadname.defining,
1.333 - expr=LoadRef(loadname.original,
1.334 - ref=self.module),
1.335 - name=loadname.name,
1.336 - nstype="module")
1.337 - )
1.338 -
1.339 - return result
1.340 -
1.341 - def visitStoreName(self, storename):
1.342 -
1.343 - "Transform the 'storename' node to a specific, scope-sensitive node."
1.344 -
1.345 - scope = self.namespace.find_for_store(storename.name)
1.346 -
1.347 - # For structure namespaces, store an attribute.
1.348 -
1.349 - if scope == "structure":
1.350 - self.namespace.store(storename.name)
1.351 -
1.352 - return self.dispatch(
1.353 - StoreAttr(storename.original, storename.defining,
1.354 - lvalue=LoadRef(storename.original,
1.355 - ref=self.namespace.structure),
1.356 - name=storename.name,
1.357 - expr=storename.expr,
1.358 - nstype="structure")
1.359 - )
1.360 -
1.361 - # Where the name is outside the local namespace, disallow any built-in
1.362 - # assignment and store the name globally.
1.363 -
1.364 - elif scope == "global":
1.365 - return self.dispatch(
1.366 - StoreAttr(storename.original, storename.defining,
1.367 - lvalue=LoadRef(storename.original,
1.368 - ref=self.module),
1.369 - name=storename.name,
1.370 - expr=storename.expr,
1.371 - nstype="module")
1.372 - )
1.373 -
1.374 - # For local namespace accesses...
1.375 -
1.376 - else:
1.377 - self.namespace.store(storename.name)
1.378 -
1.379 - # If a distinct global namespace exists, it must be a local access.
1.380 -
1.381 - if self.global_namespace is not None:
1.382 - return storename
1.383 -
1.384 - # Otherwise, the name is being set at the module level and is
1.385 - # considered global.
1.386 -
1.387 - else:
1.388 - return self.dispatch(
1.389 - StoreAttr(storename.original, storename.defining,
1.390 - lvalue=LoadRef(storename.original,
1.391 - ref=self.module),
1.392 - name=storename.name,
1.393 - expr=storename.expr,
1.394 - nstype="module")
1.395 - )
1.396 -
1.397 - def visitInvokeFunction(self, invoke):
1.398 -
1.399 - "Transform the 'invoke' node, performing processing on subprograms."
1.400 -
1.401 - return self.default(invoke)
1.402 -
1.403 - def visitInvokeRef(self, invoke):
1.404 -
1.405 - "Transform the 'invoke' node, performing processing on subprograms."
1.406 -
1.407 - # The special case of internal subprogram invocation is addressed by
1.408 - # propagating namespace information to the subprogram and processing it.
1.409 -
1.410 - if invoke.share_locals:
1.411 - subprogram = self.process_node(invoke.ref, self.namespace)
1.412 - else:
1.413 - subprogram = self.process_node(invoke.ref)
1.414 -
1.415 - if subprogram is not None:
1.416 - self.subprograms.append(subprogram)
1.417 - return invoke
1.418 -
1.419 -class ScopeMismatch(Exception):
1.420 - pass
1.421 -
1.422 -class NameOrganiser:
1.423 -
1.424 - """
1.425 - A local namespace which may either relate to a genuine set of function
1.426 - locals or the initialisation of a structure.
1.427 - """
1.428 -
1.429 - def __init__(self, structure=None):
1.430 -
1.431 - "Initialise the namespace with an optional 'structure'."
1.432 -
1.433 - self.structure = structure
1.434 - if structure is not None:
1.435 - self.local = "structure"
1.436 - else:
1.437 - self.local = "local"
1.438 -
1.439 - # Names may be self.local or "global".
1.440 -
1.441 - self.names = {}
1.442 -
1.443 - def make_global(self, name):
1.444 - if not self.names.has_key(name):
1.445 - self.names[name] = "global"
1.446 - elif self.names[name] == self.local:
1.447 - raise ScopeMismatch, "Name '%s' already considered as %s." % (name, self.local)
1.448 -
1.449 - def find_for_load(self, name):
1.450 - return self.names.get(name, "global")
1.451 -
1.452 - def find_for_store(self, name):
1.453 - return self.names.get(name, self.local)
1.454 -
1.455 - def store(self, name):
1.456 - if self.names.get(name) != "global":
1.457 - self.names[name] = self.local
1.458 - else:
1.459 - raise ScopeMismatch, "Name '%s' already considered as global." % name
1.460 -
1.461 - def merge(self, name, scope):
1.462 - if self.names.get(name) in (None, scope):
1.463 - self.names[name] = scope
1.464 - else:
1.465 - raise ScopeMismatch, "Name '%s' already considered as %s." % (name, self.names[name])
1.466 -
1.467 - def merge_namespace(self, namespace):
1.468 - self.merge_items(namespace.names.items())
1.469 -
1.470 - def merge_items(self, items):
1.471 - for name, scope in items:
1.472 - self.merge(name, scope)
1.473 -
1.474 - def __repr__(self):
1.475 - return repr(self.names)
1.476 -
1.477 -# Convenience functions.
1.478 -
1.479 -def fix(module, builtins=None):
1.480 -
1.481 - """
1.482 - Fix the names in the given 'module', also employing the optional 'builtins'
1.483 - module, if specified.
1.484 - """
1.485 -
1.486 - fixer = Fixer()
1.487 - if builtins is not None:
1.488 - fixer.process(module, builtins)
1.489 - else:
1.490 - fixer.process(module)
1.491 -
1.492 -# vim: tabstop=4 expandtab shiftwidth=4