1.1 --- a/annotate.py Sun May 27 18:19:01 2007 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,1789 +0,0 @@
1.4 -#!/usr/bin/env python
1.5 -
1.6 -"""
1.7 -Annotate program node structures. The code in this module operates upon nodes
1.8 -which are produced when simplifying AST node trees originating from the compiler
1.9 -module.
1.10 -
1.11 -Copyright (C) 2006, 2007 Paul Boddie <paul@boddie.org.uk>
1.12 -
1.13 -This software is free software; you can redistribute it and/or
1.14 -modify it under the terms of the GNU General Public License as
1.15 -published by the Free Software Foundation; either version 2 of
1.16 -the License, or (at your option) any later version.
1.17 -
1.18 -This software is distributed in the hope that it will be useful,
1.19 -but WITHOUT ANY WARRANTY; without even the implied warranty of
1.20 -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.21 -GNU General Public License for more details.
1.22 -
1.23 -You should have received a copy of the GNU General Public
1.24 -License along with this library; see the file LICENCE.txt
1.25 -If not, write to the Free Software Foundation, Inc.,
1.26 -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.27 -
1.28 ---------
1.29 -
1.30 -To use this module, the easiest approach is to use the load function:
1.31 -
1.32 -load(filename, builtins)
1.33 -
1.34 -To control module importing, an importer should be constructed and employed.
1.35 -Here, the standard path for module searching is used:
1.36 -
1.37 -importer = Importer(sys.path)
1.38 -load(filename, builtins, importer)
1.39 -
1.40 -Underneath the load function, the annotate function provides support for
1.41 -annotating modules already processed by simplify and fixnames:
1.42 -
1.43 -annotate(module, builtins)
1.44 -
1.45 -And at the most basic level, the most intricate approach involves obtaining an
1.46 -Annotator object:
1.47 -
1.48 -annotator = Annotator()
1.49 -
1.50 -Then, processing an existing module with it:
1.51 -
1.52 -annotator.process(module)
1.53 -
1.54 -If a module containing built-in classes and functions has already been
1.55 -annotated, such a module should be passed in as an additional argument:
1.56 -
1.57 -annotator.process(module, builtins)
1.58 -"""
1.59 -
1.60 -from simplified import *
1.61 -import simplify, fixnames # for the load function
1.62 -import compiler
1.63 -import os
1.64 -
1.65 -class System:
1.66 -
1.67 - """
1.68 - A class maintaining the state of the annotation system. When the system
1.69 - counter can no longer be incremented by any annotation operation, the
1.70 - system may be considered stable and fully annotated.
1.71 - """
1.72 -
1.73 - def __init__(self):
1.74 - self.count = 0
1.75 -
1.76 - def init(self, node, attr="types"):
1.77 -
1.78 - "Initialise a 'node' for annotation."
1.79 -
1.80 - if not hasattr(node, attr):
1.81 - setattr(node, attr, set())
1.82 -
1.83 - def annotate(self, node, types, attr="types"):
1.84 -
1.85 - "Annotate the given 'node' with the given 'types'."
1.86 -
1.87 - self.init(node, attr)
1.88 - self.combine(getattr(node, attr), types)
1.89 -
1.90 - def combine(self, target, types):
1.91 -
1.92 - """
1.93 - Combine the 'target' list with the given 'types', counting new members.
1.94 - """
1.95 -
1.96 - for type in types:
1.97 - if type not in target:
1.98 - target.add(type)
1.99 - self.count += 1
1.100 -
1.101 -system = System()
1.102 -
1.103 -# Exceptions.
1.104 -
1.105 -class AnnotationError(SimplifiedError):
1.106 -
1.107 - "An error in the annotation process."
1.108 -
1.109 - pass
1.110 -
1.111 -class AnnotationMessage(Exception):
1.112 -
1.113 - "A lesser annotation error."
1.114 -
1.115 - pass
1.116 -
1.117 -# Annotation.
1.118 -
1.119 -class Annotator(Visitor):
1.120 -
1.121 - """
1.122 - The type annotator which traverses the program nodes, typically depth-first,
1.123 - and maintains a record of the current set of types applying to the currently
1.124 - considered operation. Such types are also recorded on the nodes, and a
1.125 - special "system" record is maintained to monitor the level of annotation
1.126 - activity with a view to recognising when no more annotations are possible.
1.127 -
1.128 - Throughout the annotation activity, type information consists of lists of
1.129 - Attribute objects where such objects retain information about the context of
1.130 - the type (since a value in the program may be associated with an object or
1.131 - class) and the actual type of the value being manipulated. Upon accessing
1.132 - attribute information on namespaces, additional accessor information is also
1.133 - exchanged - this provides a means of distinguishing between the different
1.134 - types possible when the means of constructing the namespace may depend on
1.135 - run-time behaviour.
1.136 -
1.137 - Covered: Assign, CheckType, Conditional, Global, Import, InvokeRef,
1.138 - InvokeFunction, LoadAttr, LoadExc, LoadName, LoadRef, LoadTemp,
1.139 - Module, Not, Pass, Raise, ReleaseTemp, ReturnFromBlock,
1.140 - ReturnFromFunction, StoreAttr, StoreName, StoreTemp, Subprogram,
1.141 - Try.
1.142 - """
1.143 -
1.144 - def __init__(self, importer=None):
1.145 -
1.146 - "Initialise the visitor with an optional 'importer'."
1.147 -
1.148 - Visitor.__init__(self)
1.149 - self.system = system
1.150 - self.importer = importer or Importer()
1.151 -
1.152 - # Satisfy visitor issues.
1.153 -
1.154 - self.visitor = self
1.155 -
1.156 - def process(self, module, builtins=None):
1.157 -
1.158 - """
1.159 - Process the given 'module', using the optional 'builtins' to access
1.160 - built-in classes and functions.
1.161 - """
1.162 -
1.163 - self.subprograms = []
1.164 - self.current_subprograms = []
1.165 - self.current_namespaces = []
1.166 - self.rerun_subprograms = {}
1.167 - self.namespace = None
1.168 - self.module = module
1.169 -
1.170 - # Process the module, supplying builtins if possible.
1.171 -
1.172 - self.builtins = builtins
1.173 - self.global_namespace = Namespace()
1.174 -
1.175 - if builtins is not None:
1.176 - self.builtins_namespace = builtins.namespace
1.177 - else:
1.178 - self.builtins_namespace = self.global_namespace
1.179 -
1.180 - # NOTE: Not declaring module namespace usage, even though it is used.
1.181 -
1.182 - self.process_node(module, self.global_namespace, 0)
1.183 -
1.184 - def process_node(self, node, locals, using_module_namespace):
1.185 -
1.186 - """
1.187 - Process a subprogram or module 'node', indicating the initial 'locals'.
1.188 - Note that this method may mutate nodes in the original program.
1.189 - """
1.190 -
1.191 - # Recursion test.
1.192 -
1.193 - if node in self.current_subprograms:
1.194 - if not self.rerun_subprograms.has_key(node):
1.195 - self.rerun_subprograms[node] = []
1.196 - self.rerun_subprograms[node].append(locals)
1.197 - return
1.198 -
1.199 - # Record the current subprogram and namespace.
1.200 -
1.201 - self.current_subprograms.append(node)
1.202 -
1.203 - # Determine the namespace.
1.204 -
1.205 - self.current_namespaces.append(self.namespace)
1.206 - self.namespace = locals
1.207 -
1.208 - # Add namespace details to any structure involved.
1.209 -
1.210 - if getattr(node, "structure", None) is not None:
1.211 - node.structure.namespace = Namespace()
1.212 -
1.213 - # Initialise bases where appropriate.
1.214 -
1.215 - if hasattr(node.structure, "bases"):
1.216 - base_refs = []
1.217 - for base in node.structure.bases:
1.218 - self.dispatch(base)
1.219 - base_refs.append(self.namespace.types)
1.220 - node.structure.base_refs = base_refs
1.221 -
1.222 - # Dispatch to the code itself.
1.223 -
1.224 - node.namespace = self.namespace
1.225 - self.set_module_namespace(using_module_namespace)
1.226 -
1.227 - self.dispatch(node)
1.228 - self.extract_results(node)
1.229 -
1.230 - while self.rerun_subprograms.has_key(node):
1.231 - all_rerun_locals = self.rerun_subprograms[node]
1.232 - del self.rerun_subprograms[node]
1.233 - for rerun_locals in all_rerun_locals:
1.234 - #print "Re-running", node, "with", rerun_locals
1.235 -
1.236 - self.namespace = rerun_locals
1.237 - node.namespace = rerun_locals
1.238 - self.set_module_namespace(using_module_namespace)
1.239 -
1.240 - self.dispatch(node)
1.241 - self.extract_results(node)
1.242 -
1.243 - # Restore the previous subprogram and namespace.
1.244 -
1.245 - self.namespace = self.current_namespaces.pop()
1.246 - self.current_subprograms.pop()
1.247 - self.reset_module_namespace(using_module_namespace)
1.248 -
1.249 - def set_module_namespace(self, using_module_namespace):
1.250 -
1.251 - """
1.252 - In order to keep global accesses working, the module namespace must be
1.253 - adjusted.
1.254 - """
1.255 -
1.256 - if using_module_namespace:
1.257 - self.module.namespace = self.namespace
1.258 -
1.259 - def reset_module_namespace(self, using_module_namespace):
1.260 -
1.261 - """
1.262 - In order to keep global accesses working, the module namespace must be
1.263 - reset.
1.264 - """
1.265 -
1.266 - if using_module_namespace:
1.267 - self.module.namespace = self.namespace
1.268 -
1.269 - def extract_results(self, node):
1.270 -
1.271 - "Extract results from the namespace."
1.272 -
1.273 - node.namespace = self.namespace
1.274 - self.system.annotate(node, self.namespace.raises, "raises")
1.275 - self.system.annotate(node, self.namespace.returns, "returns")
1.276 - if hasattr(node, "return_locals"):
1.277 - node.return_locals.update(self.namespace.return_locals)
1.278 -
1.279 - def annotate(self, node, types=None):
1.280 -
1.281 - """
1.282 - Annotate the given 'node' in the system, using either the optional
1.283 - 'types' or the namespace's current type information.
1.284 - """
1.285 -
1.286 - if types is None:
1.287 - self.system.annotate(node, self.namespace.types)
1.288 - else:
1.289 - self.system.annotate(node, types)
1.290 -
1.291 - def annotate_parameters(self, node, items):
1.292 -
1.293 - """
1.294 - Annotate the given 'node' using the given 'items' and updating the
1.295 - system's annotation counter.
1.296 - """
1.297 -
1.298 - if not hasattr(node, "paramtypes"):
1.299 - node.paramtypes = {}
1.300 -
1.301 - for param, types in items:
1.302 - if not node.paramtypes.has_key(param):
1.303 - node.paramtypes[param] = set()
1.304 - self.system.combine(node.paramtypes[param], types)
1.305 -
1.306 - # Visitor methods.
1.307 -
1.308 - def default(self, node):
1.309 -
1.310 - """
1.311 - Process the given 'node', given that it does not have a specific
1.312 - handler.
1.313 - """
1.314 -
1.315 - raise AnnotationMessage, "Node '%s' not supported." % node
1.316 -
1.317 - def dispatch(self, node, *args):
1.318 - try:
1.319 - Visitor.dispatch(self, node, *args)
1.320 - except AnnotationError, exc:
1.321 - exc.add(node)
1.322 - raise
1.323 - except AnnotationMessage, exc:
1.324 - raise AnnotationError(exc, node)
1.325 -
1.326 - # Specific node methods.
1.327 -
1.328 - def visitAssign(self, assign):
1.329 -
1.330 - """
1.331 - Process the 'assign' node and its contents.
1.332 - """
1.333 -
1.334 - self.dispatches(assign.code)
1.335 -
1.336 - def visitCheckType(self, checktype):
1.337 -
1.338 - """
1.339 - Process the 'checktype' node, finding the possible types of the
1.340 - exception, and processing each choice to build a list of checked types
1.341 - for the exception.
1.342 - """
1.343 -
1.344 - inverted = getattr(checktype, "inverted", 0)
1.345 - self.dispatch(checktype.expr)
1.346 -
1.347 - expr_types = self.namespace.types
1.348 - choice_types = set()
1.349 - choices = []
1.350 -
1.351 - for choice in checktype.choices:
1.352 - choices.append(self.dispatch(choice))
1.353 - choice_types.update(self.namespace.types)
1.354 -
1.355 - for expr_type in expr_types:
1.356 - in_choices = expr_type.type.get_class() in choice_types
1.357 -
1.358 - # Filter out types not in the choices list unless the operation is
1.359 - # inverted; in which case, filter out types in the choices list.
1.360 -
1.361 - if not inverted and not in_choices or inverted and in_choices:
1.362 - self._prune_non_accesses(checktype.expr, expr_type)
1.363 -
1.364 - def visitConditional(self, conditional):
1.365 -
1.366 - """
1.367 - Process the 'conditional' node, processing the test, body and else
1.368 - clauses and recording their processed forms. The body and else clauses
1.369 - are processed within their own namespaces, and the test is also
1.370 - processed in its own namespace if 'isolate_test' is set on the
1.371 - 'conditional' node.
1.372 - """
1.373 -
1.374 - # Conditionals keep local namespace changes isolated.
1.375 - # With Return nodes inside the body/else sections, the changes are
1.376 - # communicated to the caller.
1.377 -
1.378 - is_module = self.namespace is self.module.namespace
1.379 -
1.380 - # Where the test is closely associated with the body, save the namespace
1.381 - # before entering the test.
1.382 -
1.383 - if conditional.isolate_test:
1.384 - saved_namespace = self.namespace
1.385 - self.namespace = Namespace()
1.386 - if is_module:
1.387 - self.module.namespace = self.namespace
1.388 - self.namespace.merge_namespace(saved_namespace)
1.389 -
1.390 - self.dispatch(conditional.test)
1.391 -
1.392 - # Where the test may affect the body and the else clause, save the
1.393 - # namespace after processing the test.
1.394 -
1.395 - if not conditional.isolate_test:
1.396 - saved_namespace = self.namespace
1.397 - self.namespace = Namespace()
1.398 - if is_module:
1.399 - self.module.namespace = self.namespace
1.400 - self.namespace.merge_namespace(saved_namespace)
1.401 -
1.402 - # NOTE: Exception recording.
1.403 -
1.404 - else:
1.405 - test_raises = set()
1.406 - test_raises.update(self.namespace.raises)
1.407 -
1.408 - # Process the body clause.
1.409 -
1.410 - self.dispatches(conditional.body)
1.411 - body_namespace = self.namespace
1.412 -
1.413 - # Use the saved namespace as a template for the else clause.
1.414 -
1.415 - self.namespace = Namespace()
1.416 - if is_module:
1.417 - self.module.namespace = self.namespace
1.418 - self.namespace.merge_namespace(saved_namespace)
1.419 -
1.420 - # Process the else clause.
1.421 -
1.422 - self.dispatches(conditional.else_)
1.423 - else_namespace = self.namespace
1.424 -
1.425 - # Merge the body and else namespaces.
1.426 -
1.427 - self.namespace = Namespace()
1.428 - if is_module:
1.429 - self.module.namespace = self.namespace
1.430 - self.namespace.merge_namespace(body_namespace)
1.431 - self.namespace.merge_namespace(else_namespace)
1.432 -
1.433 - # NOTE: Test of exception type pruning based on the test/body.
1.434 - # Note that the checked exceptions are tested for re-raising.
1.435 -
1.436 - if conditional.isolate_test:
1.437 - for exc_type in test_raises:
1.438 - if exc_type not in body_namespace.raises:
1.439 - self.namespace.revoke_exception_type(exc_type)
1.440 -
1.441 - def visitGlobal(self, global_):
1.442 -
1.443 - """
1.444 - Leave the 'global_' node unprocessed since namespaces should have
1.445 - already been altered to take global names into consideration.
1.446 - """
1.447 -
1.448 - pass
1.449 -
1.450 - def visitImport(self, import_):
1.451 -
1.452 - """
1.453 - Process the 'import_' node, importing the module with the stated name
1.454 - and storing details on the node.
1.455 - """
1.456 -
1.457 - module = self.importer.load(import_.name, self.builtins, getattr(import_, "alias", None))
1.458 - if module is not None:
1.459 - self.namespace.set_types(set([module]))
1.460 - else:
1.461 - self.namespace.set_types(set())
1.462 - self.annotate(import_) # mainly for viewing purposes
1.463 -
1.464 - def _visitInvoke(self, invoke, invocation_types, have_args):
1.465 -
1.466 - """
1.467 - Process the 'invoke' node, using the given 'invocation_types' as the
1.468 - list of callables to be investigated for instantiation or for the
1.469 - invocation of functions or blocks. If 'have_args' is a true value, any
1.470 - invocation or instantiation will involve arguments.
1.471 - """
1.472 -
1.473 - # Now locate and invoke the subprogram. This can be complicated because
1.474 - # the target may be a class or object, and there may be many different
1.475 - # related subprograms.
1.476 -
1.477 - invocations = []
1.478 -
1.479 - # Visit each callable in turn, finding subprograms.
1.480 -
1.481 - for attr in invocation_types:
1.482 -
1.483 - # Deal with class invocations by providing instance objects.
1.484 - # Here, each class is queried for the __init__ method, which may
1.485 - # exist for some combinations of classes in a hierarchy but not for
1.486 - # others.
1.487 -
1.488 - if isinstance(attr.type, Class):
1.489 - attributes = get_attributes(attr.type, "__init__")
1.490 -
1.491 - # Deal with object invocations by using __call__ methods.
1.492 -
1.493 - elif isinstance(attr.type, Instance):
1.494 - attributes = get_attributes(attr.type, "__call__")
1.495 -
1.496 - # Normal functions or methods are more straightforward.
1.497 - # Here, we model them using an attribute with no context and with
1.498 - # no associated accessor.
1.499 -
1.500 - else:
1.501 - attributes = [(attr, None)]
1.502 -
1.503 - # Inspect each attribute and extract the subprogram.
1.504 -
1.505 - for attribute, accessor in attributes:
1.506 -
1.507 - # If a class is involved, presume that it must create a new
1.508 - # object.
1.509 -
1.510 - if isinstance(attr.type, Class):
1.511 -
1.512 - # Instantiate the class.
1.513 -
1.514 - instance = self.new_instance(invoke, attr.type)
1.515 -
1.516 - # For instantiations, switch the context.
1.517 -
1.518 - if attribute is not None:
1.519 - attribute = Attribute(instance, attribute.type)
1.520 -
1.521 - # Request an instance-specific initialiser.
1.522 -
1.523 - attribute = attr.type.get_attribute_for_instance(attribute, instance)
1.524 -
1.525 - # Skip cases where no callable is found.
1.526 -
1.527 - if attribute is not None:
1.528 -
1.529 - # If a subprogram is defined, invoke it.
1.530 -
1.531 - self.invoke_subprogram(invoke, attribute)
1.532 - if attribute.type not in invocations:
1.533 - invocations.append(attribute.type)
1.534 -
1.535 - elif not isinstance(attr.type, Class):
1.536 - print "Invocation type is None for", accessor
1.537 -
1.538 - else:
1.539 -
1.540 - # Test to see if no arguments were supplied in cases where no
1.541 - # initialiser was found.
1.542 -
1.543 - if have_args:
1.544 - raise AnnotationMessage, "No initialiser found for '%s' with arguments." % attr.type
1.545 -
1.546 - # Special case: initialisation.
1.547 -
1.548 - if isinstance(attr.type, Class):
1.549 -
1.550 - # Associate the instance with the result of this invocation.
1.551 -
1.552 - self.namespace.set_types(set([Attribute(None, instance)]))
1.553 - self.annotate(invoke)
1.554 -
1.555 - # Remember the invocations that were found, along with the return type
1.556 - # information.
1.557 -
1.558 - invoke.invocations = invocations
1.559 - self.namespace.set_types(getattr(invoke, "types", set()))
1.560 -
1.561 - def visitInvokeRef(self, invoke):
1.562 -
1.563 - """
1.564 - Process the 'invoke' node, first finding the callables indicated by the
1.565 - reference.
1.566 - """
1.567 -
1.568 - # Where the invocation belongs to an instance but the invoked subprogram
1.569 - # does not, request a special copy.
1.570 -
1.571 - instance = getattr(invoke, "instance", None)
1.572 - if instance is not None and getattr(invoke.ref, "instance", None) is None:
1.573 - if invoke.ref.copies.has_key(instance):
1.574 - invoke.ref = invoke.ref.copies[instance]
1.575 - else:
1.576 - invoke.ref = invoke.ref.copy(instance)
1.577 - #print "Created", invoke.ref, "for", getattr(invoke.ref, "instance", None)
1.578 - invoke.ref.module.simplifier.subnames[invoke.ref.full_name()] = invoke.ref
1.579 - invocation_types = [Attribute(None, invoke.ref)]
1.580 - self._visitInvoke(invoke, invocation_types, have_args=0)
1.581 -
1.582 - def visitInvokeFunction(self, invoke):
1.583 -
1.584 - """
1.585 - Process the 'invoke' node, first finding the callables indicated by the
1.586 - expression.
1.587 - """
1.588 -
1.589 - self.dispatch(invoke.expr)
1.590 - invocation_types = self.namespace.types
1.591 -
1.592 - # Invocation processing starts with making sure that the arguments have
1.593 - # been processed.
1.594 -
1.595 - self._visitInvoke(invoke, invocation_types, have_args=self.process_args(invoke))
1.596 -
1.597 - def visitLoadAttr(self, loadattr):
1.598 -
1.599 - """
1.600 - Process the 'loadattr' node, processing and storing the expression, and
1.601 - using the expression's types to construct records of accesses and
1.602 - non-accesses using the stated attribute name.
1.603 - """
1.604 -
1.605 - self.dispatch(loadattr.expr)
1.606 - types = set()
1.607 - raises = set()
1.608 - non_accesses = []
1.609 - accesses = {}
1.610 -
1.611 - # For each expression type...
1.612 -
1.613 - for attr in self.namespace.types:
1.614 -
1.615 - # Find types for the named attribute.
1.616 -
1.617 - attributes = get_attributes(attr.type, loadattr.name)
1.618 -
1.619 - # Where no attributes exist...
1.620 -
1.621 - if not attributes:
1.622 -
1.623 - # Register new invalid accesses and mark a possible exception.
1.624 -
1.625 - if not attr in non_accesses:
1.626 - non_accesses.append(attr)
1.627 - exc = self.get_builtin_instances(loadattr, "AttributeError")
1.628 - raises.update(exc)
1.629 - self.namespace.raises.update(exc)
1.630 -
1.631 - # Revoke this type from any name involved.
1.632 -
1.633 - self._prune_non_accesses(loadattr.expr, attr)
1.634 -
1.635 - # For each type found...
1.636 -
1.637 - for attribute, accessor in attributes:
1.638 -
1.639 - # For actual attributes, register the type and remember the
1.640 - # access.
1.641 -
1.642 - if attribute is not None:
1.643 - types.add(attribute)
1.644 - if not accesses.has_key(attr.type):
1.645 - accesses[attr.type] = []
1.646 - if not (attribute, accessor) in accesses[attr.type]:
1.647 - accesses[attr.type].append((attribute, accessor))
1.648 -
1.649 - # Otherwise, register new invalid accesses and note a possible
1.650 - # exception.
1.651 -
1.652 - else:
1.653 - if not attr in non_accesses:
1.654 - non_accesses.append(attr)
1.655 - exc = self.get_builtin_instances(loadattr, "AttributeError")
1.656 - raises.update(exc)
1.657 - self.namespace.raises.update(exc)
1.658 -
1.659 - # Revoke this type from any name involved.
1.660 -
1.661 - self._prune_non_accesses(loadattr.expr, attr)
1.662 -
1.663 - if not types:
1.664 - print "No attribute found for", loadattr.name, "given", self.namespace.types
1.665 -
1.666 - # Remember the result types.
1.667 -
1.668 - self.namespace.set_types(types)
1.669 - loadattr.non_accesses = non_accesses
1.670 - loadattr.accesses = accesses
1.671 - loadattr.raises = raises
1.672 - self.annotate(loadattr)
1.673 -
1.674 - def _prune_non_accesses(self, expr, attr):
1.675 -
1.676 - """
1.677 - Prune type information from 'expr' where the given 'attr' has been
1.678 - shown to be a non-access.
1.679 - """
1.680 -
1.681 - if isinstance(expr, LoadName):
1.682 - self.namespace.revoke(expr.name, attr)
1.683 - elif isinstance(expr, LoadExc):
1.684 - self.namespace.revoke_exception_type(attr)
1.685 - elif isinstance(expr, LoadTemp):
1.686 - self.namespace.revoke_temp_type(getattr(expr, "index", None), attr)
1.687 -
1.688 - # LoadAttr cannot be pruned since this might unintentionally prune
1.689 - # legitimate types from other applications of the referenced type, it
1.690 - # almost certainly doesn't take "concurrent" mutation into
1.691 - # consideration (where in a running program, the pruned type is actually
1.692 - # reintroduced, making the pruning invalid), and there is no easy way of
1.693 - # preserving the meaning of a namespace without either creating lots of
1.694 - # specialised instances, and even then...
1.695 -
1.696 - #elif isinstance(expr, LoadAttr):
1.697 - # for expr_attr in expr.expr.types:
1.698 - # if hasattr(expr_attr.type, "namespace"):
1.699 - # expr_attr.type.namespace.revoke(expr.name, attr)
1.700 -
1.701 - def visitLoadExc(self, loadexc):
1.702 -
1.703 - """
1.704 - Process the 'loadexc' node, discovering the possible exception types
1.705 - raised.
1.706 - """
1.707 -
1.708 - self.namespace.set_types(self.namespace.raises)
1.709 - self.annotate(loadexc)
1.710 -
1.711 - def visitLoadName(self, loadname):
1.712 -
1.713 - """
1.714 - Process the 'loadname' node, processing the name information on the node
1.715 - to determine which types are involved with the name.
1.716 - """
1.717 -
1.718 - self.namespace.set_types(self.namespace.load(loadname.name))
1.719 - self.annotate(loadname)
1.720 -
1.721 - def visitLoadRef(self, loadref):
1.722 -
1.723 - """
1.724 - Process the 'loadref' node, obtaining type information about the
1.725 - reference stated on the node.
1.726 - """
1.727 -
1.728 - self.namespace.set_types(set([Attribute(None, loadref.ref)]))
1.729 - self.annotate(loadref)
1.730 -
1.731 - def visitLoadTemp(self, loadtemp):
1.732 -
1.733 - """
1.734 - Process the 'loadtemp' node, obtaining type information about the
1.735 - temporary variable accessed, and removing variable information where the
1.736 - 'release' attribute has been set on the node.
1.737 - """
1.738 -
1.739 - index = getattr(loadtemp, "index", None)
1.740 - try:
1.741 - if getattr(loadtemp, "release", 0):
1.742 - self.namespace.set_types(self.namespace.temp[index].pop())
1.743 - else:
1.744 - self.namespace.set_types(self.namespace.temp[index][-1])
1.745 - except KeyError:
1.746 - raise AnnotationMessage, "Temporary store index '%s' not defined." % index
1.747 - self.annotate(loadtemp)
1.748 -
1.749 - def visitMakeTuple(self, maketuple):
1.750 -
1.751 - """
1.752 - Process the 'maketuple' node and its contents.
1.753 - """
1.754 -
1.755 - # Get a tuple and populate it with type information for the contents.
1.756 -
1.757 - tuples = self.get_builtin_instances(maketuple, "tuple")
1.758 -
1.759 - # NOTE: This is dependent on the tuple definition in the builtins.
1.760 -
1.761 - for node in maketuple.nodes:
1.762 - self.dispatch(node)
1.763 - for t in tuples:
1.764 - t.type.namespace.add("value", self.namespace.types)
1.765 -
1.766 - self.namespace.set_types(tuples)
1.767 - self.annotate(maketuple)
1.768 -
1.769 - def visitModule(self, module):
1.770 -
1.771 - """
1.772 - Process the 'module' and its contents.
1.773 - """
1.774 -
1.775 - self.dispatches(module.code)
1.776 -
1.777 - def visitNot(self, not_):
1.778 -
1.779 - "Process the 'not_' node and its expression."
1.780 -
1.781 - self.dispatch(not_.expr)
1.782 -
1.783 - def visitPass(self, pass_):
1.784 -
1.785 - "Leave the 'pass_' node unprocessed."
1.786 -
1.787 - pass
1.788 -
1.789 - def visitRaise(self, raise_):
1.790 -
1.791 - """
1.792 - Process the 'raise_' node, processing any traceback information along
1.793 - with the raised exception expression, converting the node into a kind of
1.794 - invocation where the expression is found not to be an invocation itself.
1.795 - This node affects the namespace, adding exception types to the list of
1.796 - those raised in the namespace.
1.797 - """
1.798 -
1.799 - if getattr(raise_, "traceback", None) is not None:
1.800 - self.dispatch(raise_.traceback)
1.801 - self.dispatch(raise_.expr)
1.802 -
1.803 - # Handle bare name exceptions by converting any classes to instances.
1.804 -
1.805 - if not isinstance(raise_.expr, InvokeFunction):
1.806 - raise_.pos_args = []
1.807 - raise_.kw_args = {}
1.808 - raise_.star = None
1.809 - raise_.dstar = None
1.810 - types = set()
1.811 - for attr in self.namespace.types:
1.812 - if isinstance(attr.type, Class):
1.813 - self._visitInvoke(raise_, [attr], have_args=0)
1.814 - types.update(self.namespace.types)
1.815 - else:
1.816 - types = self.namespace.types
1.817 -
1.818 - self.namespace.raises.update(types)
1.819 -
1.820 - def visitReleaseTemp(self, releasetemp):
1.821 -
1.822 - """
1.823 - Process the 'releasetemp' node, removing temporary variable information
1.824 - from the current namespace.
1.825 - """
1.826 -
1.827 - index = getattr(releasetemp, "index", None)
1.828 - try:
1.829 - self.namespace.temp[index].pop()
1.830 - except KeyError:
1.831 - raise AnnotationMessage, "Temporary store index '%s' not defined." % index
1.832 - except IndexError:
1.833 - pass #raise AnnotationMessage, "Temporary store index '%s' is empty." % index
1.834 -
1.835 - def visitResetExc(self, resetexc):
1.836 - self.namespace.raises = set()
1.837 -
1.838 - def visitReturn(self, return_):
1.839 -
1.840 - """
1.841 - Process the 'return_' node, processing any expression and obtaining type
1.842 - information to be accumulated in the current namespace's list of return
1.843 - types. A snapshot of the namespace is taken for the purposes of
1.844 - reconciling or merging namespaces where subprograms actually share
1.845 - locals with their callers.
1.846 - """
1.847 -
1.848 - if hasattr(return_, "expr"):
1.849 - self.dispatch(return_.expr)
1.850 - self.namespace.returns.update(self.namespace.types)
1.851 - self.annotate(return_)
1.852 - self.namespace.snapshot()
1.853 -
1.854 - visitReturnFromBlock = visitReturn
1.855 - visitReturnFromFunction = visitReturn
1.856 -
1.857 - def visitStoreAttr(self, storeattr):
1.858 -
1.859 - """
1.860 - Process the 'storeattr' node, processing the expression and target, and
1.861 - using the type information obtained to build records of legitimate
1.862 - writes to the stated attribute, along with "impossible" non-writes to
1.863 - the attribute.
1.864 - """
1.865 -
1.866 - self.dispatch(storeattr.expr)
1.867 - expr = self.namespace.types
1.868 - self.dispatch(storeattr.lvalue)
1.869 - writes = {}
1.870 - non_writes = []
1.871 - for attr in self.namespace.types:
1.872 - # NOTE: Impose "atomic" constraints on certain types.
1.873 - if attr is None:
1.874 - if not attr in non_writes:
1.875 - non_writes.append(attr)
1.876 - continue
1.877 - attr.type.namespace.add(storeattr.name, expr)
1.878 - writes[attr.type] = attr.type.namespace.load(storeattr.name)
1.879 - if not writes:
1.880 - print "Unable to store attribute", storeattr.name, "given", self.namespace.types
1.881 - storeattr.writes = writes
1.882 - storeattr.non_writes = non_writes
1.883 -
1.884 - def visitStoreName(self, storename):
1.885 -
1.886 - """
1.887 - Process the 'storename' node, processing the expression on the node and
1.888 - associating the type information obtained with the stated name in the
1.889 - current namespace.
1.890 - """
1.891 -
1.892 - self.dispatch(storename.expr)
1.893 - self.namespace.store(storename.name, self.namespace.types)
1.894 - self.annotate(storename)
1.895 -
1.896 - def visitStoreTemp(self, storetemp):
1.897 -
1.898 - """
1.899 - Process the 'storetemp' node, processing the expression on the node and
1.900 - associating the type information obtained with a temporary variable in
1.901 - the current namespace.
1.902 - """
1.903 -
1.904 - self.dispatch(storetemp.expr)
1.905 - index = getattr(storetemp, "index", None)
1.906 - if not self.namespace.temp.has_key(index):
1.907 - self.namespace.temp[index] = []
1.908 - self.namespace.temp[index].append(self.namespace.types)
1.909 -
1.910 - def visitSubprogram(self, subprogram):
1.911 -
1.912 - """
1.913 - Process the 'subprogram' node, processing its contents (a group of nodes
1.914 - comprising the subprogram).
1.915 - """
1.916 -
1.917 - self.dispatches(subprogram.code)
1.918 -
1.919 - def visitTry(self, try_):
1.920 -
1.921 - """
1.922 - Process the 'try_' node, processing the body clause in its own namespace
1.923 - derived from the current namespace, processing any handler clause using
1.924 - the namespace information accumulated in the body, and processing any
1.925 - else and finally clauses, attempting to supply each with appropriate
1.926 - namespace information.
1.927 - """
1.928 -
1.929 - is_module = self.namespace is self.module.namespace
1.930 -
1.931 - self.dispatches(try_.body)
1.932 -
1.933 - # Save the namespace from the body.
1.934 -
1.935 - body_namespace = Namespace()
1.936 - body_namespace.merge_namespace(self.namespace)
1.937 -
1.938 - # Process the handler.
1.939 -
1.940 - if hasattr(try_, "handler"):
1.941 - self.dispatches(try_.handler)
1.942 -
1.943 - # Save the namespace from the handler.
1.944 -
1.945 - handler_namespace = Namespace()
1.946 - handler_namespace.merge_namespace(self.namespace)
1.947 -
1.948 - # Remember the raised exceptions encountered so far.
1.949 -
1.950 - raises = self.namespace.raises
1.951 -
1.952 - # Process the else clause.
1.953 -
1.954 - if hasattr(try_, "else_"):
1.955 -
1.956 - # Restore the body namespace for the else clause.
1.957 -
1.958 - self.namespace = body_namespace
1.959 - if is_module:
1.960 - self.module.namespace = self.namespace
1.961 -
1.962 - # Empty the raised exceptions for the else clause.
1.963 -
1.964 - self.namespace.raises = set()
1.965 - self.dispatches(try_.else_)
1.966 - self.namespace.raises = raises
1.967 -
1.968 - # Merge the namespaces.
1.969 -
1.970 - self.namespace = Namespace()
1.971 - if is_module:
1.972 - self.module.namespace = self.namespace
1.973 - self.namespace.merge_namespace(body_namespace)
1.974 - self.namespace.merge_namespace(handler_namespace)
1.975 -
1.976 - # Process the finally clause, if any.
1.977 -
1.978 - self.dispatches(try_.finally_)
1.979 -
1.980 - def visitYield(self, yield_):
1.981 - raise NotImplementedError, "The yield statement is not currently supported."
1.982 -
1.983 - # Utility methods.
1.984 -
1.985 - def get_builtin_instances(self, node, name):
1.986 - return set([Attribute(None, self.new_instance(node, attr.type)) for attr in self.builtins.namespace[name]])
1.987 -
1.988 - def new_instance(self, node, type):
1.989 -
1.990 - "For the given 'node', obtain an instance from the given 'type'."
1.991 -
1.992 - if not type.has_instance(node):
1.993 - instance = Instance()
1.994 - instance.namespace = Namespace()
1.995 - instance.namespace.store("__class__", set([Attribute(None, type)]))
1.996 - type.add_instance(node, instance)
1.997 - else:
1.998 - instance = type.get_instance(node)
1.999 -
1.1000 - return instance
1.1001 -
1.1002 - def invoke_subprogram(self, invoke, attribute):
1.1003 -
1.1004 - """
1.1005 - Invoke using the given 'invoke' node the subprogram represented by the
1.1006 - given 'attribute'.
1.1007 - """
1.1008 -
1.1009 - # Test for context information, making it into a real attribute.
1.1010 -
1.1011 - if attribute.context is not None:
1.1012 - context = Attribute(None, attribute.context)
1.1013 - target = attribute.type
1.1014 - else:
1.1015 - context = None
1.1016 - target = attribute.type
1.1017 -
1.1018 - # Test to see if anything has changed.
1.1019 -
1.1020 - if hasattr(invoke, "syscount") and invoke.syscount.has_key(target) and invoke.syscount[target] == self.system.count:
1.1021 - return
1.1022 -
1.1023 - # Remember the state of the system.
1.1024 -
1.1025 - else:
1.1026 - if not hasattr(invoke, "syscount"):
1.1027 - invoke.syscount = {}
1.1028 - invoke.syscount[target] = self.system.count
1.1029 -
1.1030 - # Provide the correct namespace for the invocation.
1.1031 - # This may be a "shared" namespace...
1.1032 -
1.1033 - if getattr(invoke, "share_locals", 0):
1.1034 - namespace = Namespace()
1.1035 - namespace.merge_namespace(self.namespace, everything=0)
1.1036 - using_module_namespace = self.namespace is self.module.namespace
1.1037 -
1.1038 - # Or it may be a structure...
1.1039 -
1.1040 - elif getattr(target, "structure", None):
1.1041 - namespace = Namespace()
1.1042 - using_module_namespace = 0
1.1043 -
1.1044 - # Or it may be a new namespace populated with the supplied parameters.
1.1045 -
1.1046 - else:
1.1047 - items = self.make_items(invoke, target, context)
1.1048 - namespace = Namespace()
1.1049 - namespace.merge_items(items)
1.1050 - using_module_namespace = 0
1.1051 -
1.1052 - # NOTE: Avoid PEP 227 (nested scopes) whilst permitting references to a
1.1053 - # NOTE: subprogram within itself. Do not define the name of the function
1.1054 - # NOTE: within a method definition.
1.1055 -
1.1056 - if getattr(target, "name", None) is not None and not getattr(target, "is_method", 0):
1.1057 - namespace.store(target.name, set([Attribute(None, target)]))
1.1058 -
1.1059 - # Process the subprogram.
1.1060 -
1.1061 - self.process_node(target, namespace, using_module_namespace)
1.1062 -
1.1063 - # NOTE: Improve and verify this.
1.1064 - # If the invocation returns a value, acquire the return types.
1.1065 -
1.1066 - if getattr(target, "returns_value", 0):
1.1067 - self.namespace.set_types(target.returns)
1.1068 - self.annotate(invoke)
1.1069 -
1.1070 - # If it is a normal block, merge the locals.
1.1071 - # This can happen in addition to the above because for things like
1.1072 - # logical expressions, the namespace can be modified whilst values are
1.1073 - # returned as results.
1.1074 -
1.1075 - if getattr(invoke, "share_locals", 0):
1.1076 - self.namespace.reset()
1.1077 -
1.1078 - # Merge the locals snapshots.
1.1079 -
1.1080 - for locals in target.return_locals:
1.1081 -
1.1082 - # For blocks returning values (such as operations), do not merge
1.1083 - # snapshots or results.
1.1084 -
1.1085 - if getattr(target, "returns_value", 0):
1.1086 - self.namespace.merge_namespace(locals, everything=0)
1.1087 -
1.1088 - # For blocks not returning values (such as loops), merge
1.1089 - # snapshots and results since they contain details of genuine
1.1090 - # returns.
1.1091 -
1.1092 - else:
1.1093 - self.namespace.merge_namespace(locals)
1.1094 -
1.1095 - # Incorporate any raised exceptions.
1.1096 -
1.1097 - if not hasattr(invoke, "raises"):
1.1098 - invoke.raises = set()
1.1099 - invoke.raises.update(target.raises)
1.1100 - self.namespace.raises.update(target.raises)
1.1101 -
1.1102 - def process_args(self, invocation):
1.1103 -
1.1104 - """
1.1105 - Process the arguments associated with an 'invocation'. Return whether
1.1106 - any arguments were processed.
1.1107 - """
1.1108 -
1.1109 - self.dispatches(invocation.pos_args)
1.1110 - self.dispatch_dict(invocation.kw_args)
1.1111 -
1.1112 - # Get type information for star and dstar arguments.
1.1113 -
1.1114 - if invocation.star is not None:
1.1115 - param, default = invocation.star
1.1116 - self.dispatch(default)
1.1117 - invocation.star = param, default
1.1118 -
1.1119 - if invocation.dstar is not None:
1.1120 - param, default = invocation.dstar
1.1121 - self.dispatch(default)
1.1122 - invocation.dstar = param, default
1.1123 -
1.1124 - if invocation.pos_args or invocation.kw_args or invocation.star or invocation.dstar:
1.1125 - return 1
1.1126 - else:
1.1127 - return 0
1.1128 -
1.1129 - def make_items(self, invocation, subprogram, context):
1.1130 -
1.1131 - """
1.1132 - Make an items mapping for the 'invocation' of the 'subprogram' using the
1.1133 - given 'context' (which may be None).
1.1134 - """
1.1135 -
1.1136 - # NOTE: Support class methods!
1.1137 -
1.1138 - if context is not None and isinstance(context.type, Instance):
1.1139 - pos_args = [Self(context)] + invocation.pos_args
1.1140 - else:
1.1141 - pos_args = invocation.pos_args
1.1142 -
1.1143 - # Duplicate the keyword arguments - we remove them in processing below.
1.1144 -
1.1145 - kw_args = {}
1.1146 - kw_args.update(invocation.kw_args)
1.1147 -
1.1148 - # Sort the arguments into positional and keyword arguments.
1.1149 -
1.1150 - params = subprogram.params
1.1151 - items = []
1.1152 - star_args = []
1.1153 -
1.1154 - # Match each positional argument, taking excess arguments as star args.
1.1155 -
1.1156 - for arg in pos_args:
1.1157 - if params:
1.1158 - param, default = params[0]
1.1159 - if arg is None:
1.1160 - arg = default
1.1161 - if hasattr(arg, "types"):
1.1162 - items.append((param, arg.types))
1.1163 - else:
1.1164 - items.append((param, set())) # Annotation has not succeeded.
1.1165 - params = params[1:]
1.1166 - else:
1.1167 - star_args.append(arg)
1.1168 -
1.1169 - # Collect the remaining defaults.
1.1170 -
1.1171 - while params:
1.1172 - param, default = params[0]
1.1173 - if kw_args.has_key(param):
1.1174 - arg = kw_args[param]
1.1175 - del kw_args[param]
1.1176 - elif default is not None:
1.1177 - self.dispatch(default)
1.1178 - arg = default
1.1179 - else:
1.1180 - raise AnnotationMessage, "No argument supplied in '%s' for parameter '%s'." % (subprogram, param)
1.1181 - if hasattr(arg, "types"):
1.1182 - items.append((param, arg.types))
1.1183 - else:
1.1184 - items.append((param, set())) # Annotation has not succeeded.
1.1185 - params = params[1:]
1.1186 -
1.1187 - dstar_args = kw_args.items()
1.1188 -
1.1189 - # Construct temporary objects.
1.1190 -
1.1191 - if star_args:
1.1192 - star_invocation = self.make_star_args(invocation, subprogram, star_args)
1.1193 - self.dispatch(star_invocation)
1.1194 - star_types = star_invocation.types
1.1195 - else:
1.1196 - star_types = None
1.1197 -
1.1198 - if dstar_args:
1.1199 - dstar_invocation = self.make_dstar_args(invocation, subprogram, dstar_args)
1.1200 - self.dispatch(dstar_invocation)
1.1201 - dstar_types = dstar_invocation.types
1.1202 - else:
1.1203 - dstar_types = None
1.1204 -
1.1205 - # NOTE: Merge the objects properly.
1.1206 -
1.1207 - star_types = star_types or invocation.star and invocation.star.types
1.1208 - dstar_types = dstar_types or invocation.dstar and invocation.dstar.types
1.1209 -
1.1210 - # Add star and dstar.
1.1211 -
1.1212 - if star_types is not None:
1.1213 - if subprogram.star is not None:
1.1214 - param, default = subprogram.star
1.1215 - items.append((param, star_types))
1.1216 - else:
1.1217 - raise AnnotationMessage, "Invocation provides unwanted *args."
1.1218 - elif subprogram.star is not None:
1.1219 - param, default = subprogram.star
1.1220 - if not hasattr(default, "types"):
1.1221 - subprogram.star = param, self.dispatch(default) # NOTE: Review reprocessing.
1.1222 - items.append((param, default.types))
1.1223 -
1.1224 - if dstar_types is not None:
1.1225 - if subprogram.dstar is not None:
1.1226 - param, default = subprogram.dstar
1.1227 - items.append((param, dstar_types))
1.1228 - else:
1.1229 - raise AnnotationMessage, "Invocation provides unwanted **args."
1.1230 - elif subprogram.dstar is not None:
1.1231 - param, default = subprogram.dstar
1.1232 - if not hasattr(default, "types"):
1.1233 - subprogram.dstar = param, self.dispatch(default) # NOTE: Review reprocessing.
1.1234 - items.append((param, default.types))
1.1235 -
1.1236 - # Record the parameter types.
1.1237 -
1.1238 - self.annotate_parameters(subprogram, items)
1.1239 - return subprogram.paramtypes.items()
1.1240 -
1.1241 - def make_star_args(self, invocation, subprogram, star_args):
1.1242 -
1.1243 - "Make a subprogram which initialises a list containing 'star_args'."
1.1244 -
1.1245 - if not hasattr(invocation, "stars"):
1.1246 - invocation.stars = {}
1.1247 -
1.1248 - if not invocation.stars.has_key(subprogram.full_name()):
1.1249 - instance = getattr(invocation, "instance", None)
1.1250 -
1.1251 - code = [
1.1252 - Return(
1.1253 - instance=instance,
1.1254 - expr=MakeTuple(
1.1255 - instance=instance,
1.1256 - nodes=star_args
1.1257 - )
1.1258 - )
1.1259 - ]
1.1260 -
1.1261 - new_subprogram = Subprogram(
1.1262 - instance=instance,
1.1263 - name=None,
1.1264 - returns_value=1,
1.1265 - params=[],
1.1266 - star=None,
1.1267 - dstar=None,
1.1268 - code=code
1.1269 - )
1.1270 -
1.1271 - subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram
1.1272 -
1.1273 - invocation.stars[subprogram.full_name()] = InvokeRef(
1.1274 - invocation.original,
1.1275 - instance=instance,
1.1276 - produces_result=1,
1.1277 - ref=new_subprogram
1.1278 - )
1.1279 -
1.1280 - return invocation.stars[subprogram.full_name()]
1.1281 -
1.1282 - def make_dstar_args(self, invocation, subprogram, dstar_args):
1.1283 -
1.1284 - """
1.1285 - Make a subprogram which initialises a dictionary built from the given
1.1286 - 'dstar_args'.
1.1287 - """
1.1288 -
1.1289 - if not hasattr(invocation, "dstars"):
1.1290 - invocation.dstars = {}
1.1291 -
1.1292 - if not invocation.dstars.has_key(subprogram.full_name()):
1.1293 - instance = getattr(invocation, "instance", None)
1.1294 -
1.1295 - code=[
1.1296 - StoreTemp(
1.1297 - instance=instance,
1.1298 - expr=InvokeFunction(
1.1299 - invocation.original,
1.1300 - instance=instance,
1.1301 - expr=LoadAttr(
1.1302 - instance=instance,
1.1303 - expr=LoadRef(
1.1304 - instance=instance,
1.1305 - ref=self.builtins
1.1306 - ),
1.1307 - name="dict",
1.1308 - nstype="module",
1.1309 - )
1.1310 - )
1.1311 - )
1.1312 - ]
1.1313 -
1.1314 - for arg, value in dstar_args:
1.1315 -
1.1316 - # NOTE: Constant not added to table.
1.1317 -
1.1318 - constant = Constant(name=repr(arg), value=arg)
1.1319 - code += [
1.1320 - StoreTemp(
1.1321 - instance=instance,
1.1322 - expr=InvokeFunction(
1.1323 - instance=instance,
1.1324 - expr=LoadName(
1.1325 - instance=instance,
1.1326 - name=constant.typename
1.1327 - )
1.1328 - ),
1.1329 - index="const"
1.1330 - ),
1.1331 - InvokeFunction(
1.1332 - invocation.original,
1.1333 - instance=instance,
1.1334 - expr=LoadAttr(
1.1335 - instance=instance,
1.1336 - expr=LoadTemp(
1.1337 - instance=instance
1.1338 - ),
1.1339 - name="__setitem__"
1.1340 - ),
1.1341 - args=[
1.1342 - LoadTemp(
1.1343 - instance=instance,
1.1344 - index="const",
1.1345 - release=1
1.1346 - ),
1.1347 - value
1.1348 - ]
1.1349 - )
1.1350 - ]
1.1351 -
1.1352 - code += [
1.1353 - Return(
1.1354 - instance=instance,
1.1355 - expr=LoadTemp(
1.1356 - instance=instance,
1.1357 - release=1
1.1358 - )
1.1359 - )
1.1360 - ]
1.1361 -
1.1362 - new_subprogram = Subprogram(
1.1363 - instance=instance,
1.1364 - name=None,
1.1365 - returns_value=1,
1.1366 - params=[],
1.1367 - star=None,
1.1368 - dstar=None,
1.1369 - code=code
1.1370 - )
1.1371 - subprogram.module.simplifier.subnames[new_subprogram.full_name()] = new_subprogram
1.1372 -
1.1373 - invocation.dstars[subprogram.full_name()] = InvokeRef(
1.1374 - invocation.original,
1.1375 - instance=instance,
1.1376 - produces_result=1,
1.1377 - ref=new_subprogram
1.1378 - )
1.1379 -
1.1380 - return invocation.dstars[subprogram.full_name()]
1.1381 -
1.1382 -# Namespace-related abstractions.
1.1383 -
1.1384 -class Namespace:
1.1385 -
1.1386 - """
1.1387 - A local namespace which may either relate to a genuine set of function
1.1388 - locals or the initialisation of a structure or module.
1.1389 - """
1.1390 -
1.1391 - def __init__(self):
1.1392 -
1.1393 - """
1.1394 - Initialise the namespace with a mapping of local names to possible
1.1395 - types, a list of return values and of possible returned local
1.1396 - namespaces. The namespace also tracks the "current" types and a mapping
1.1397 - of temporary value names to types.
1.1398 - """
1.1399 -
1.1400 - self.names = {}
1.1401 - self.returns = set()
1.1402 - self.return_locals = set()
1.1403 - self.raises = set()
1.1404 - self.temp = {}
1.1405 - self.types = set()
1.1406 -
1.1407 - def set_types(self, types):
1.1408 -
1.1409 - "Set the current collection of 'types'."
1.1410 -
1.1411 - self.types = types.copy()
1.1412 -
1.1413 - def add(self, name, types):
1.1414 -
1.1415 - "Add to the entry with the given 'name' the specified 'types'."
1.1416 -
1.1417 - if self.names.has_key(name):
1.1418 - self.names[name].update(types)
1.1419 - else:
1.1420 - self.store(name, types)
1.1421 -
1.1422 - def store(self, name, types):
1.1423 -
1.1424 - "Store in (or associate with) the given 'name' the specified 'types'."
1.1425 -
1.1426 - self.names[name] = types.copy()
1.1427 -
1.1428 - __setitem__ = store
1.1429 -
1.1430 - def load(self, name):
1.1431 -
1.1432 - "Load the types associated with the given 'name'."
1.1433 -
1.1434 - return self.names[name]
1.1435 -
1.1436 - __getitem__ = load
1.1437 -
1.1438 - def has_key(self, name):
1.1439 - return self.names.has_key(name)
1.1440 -
1.1441 - def revoke(self, name, type):
1.1442 -
1.1443 - "Revoke from the entry for the given 'name' the specified 'type'."
1.1444 -
1.1445 - new_types = self.names[name].copy()
1.1446 - new_types.remove(type)
1.1447 - self.names[name] = new_types
1.1448 -
1.1449 - def revoke_exception_type(self, type):
1.1450 -
1.1451 - "Revoke the given 'type' from the collection of exception types."
1.1452 -
1.1453 - self.raises.remove(type)
1.1454 -
1.1455 - def revoke_temp_type(self, index, type):
1.1456 -
1.1457 - "Revoke from the temporary variable 'index' the given 'type'."
1.1458 -
1.1459 - new_types = self.temp[index][-1].copy()
1.1460 - new_types.remove(type)
1.1461 - self.temp[index][-1] = new_types
1.1462 -
1.1463 - def merge_namespace(self, namespace, everything=1):
1.1464 -
1.1465 - """
1.1466 - Merge items from the given 'namespace' with this namespace. When the
1.1467 - optional 'everything' parameter is set to a false value (unlike the
1.1468 - default), return values and locals snapshots will not be copied to this
1.1469 - namespace.
1.1470 - """
1.1471 -
1.1472 - self.merge_items(namespace.names.items())
1.1473 - self.raises.update(namespace.raises)
1.1474 - if everything:
1.1475 - self.returns.update(namespace.returns)
1.1476 - self.return_locals.update(namespace.return_locals)
1.1477 - for name, values in namespace.temp.items():
1.1478 - if values:
1.1479 - if not self.temp.has_key(name) or not self.temp[name]:
1.1480 - self.temp[name] = [set()]
1.1481 - self.temp[name][-1].update(values[-1])
1.1482 -
1.1483 - def merge_items(self, items):
1.1484 -
1.1485 - "Merge the given 'items' with this namespace."
1.1486 -
1.1487 - for name, types in items:
1.1488 - self.merge(name, types)
1.1489 -
1.1490 - def merge(self, name, types):
1.1491 -
1.1492 - "Merge the entry for the given 'name' and 'types' with this namespace."
1.1493 -
1.1494 - if not self.names.has_key(name):
1.1495 - self.names[name] = types.copy()
1.1496 - else:
1.1497 - existing = self.names[name]
1.1498 - existing.update(types)
1.1499 -
1.1500 - def snapshot(self):
1.1501 -
1.1502 - "Make a snapshot of the locals and remember them."
1.1503 -
1.1504 - namespace = Namespace()
1.1505 - namespace.merge_namespace(self)
1.1506 - self.return_locals.add(namespace)
1.1507 -
1.1508 - def reset(self):
1.1509 -
1.1510 - "Reset a namespace in preparation for merging with returned locals."
1.1511 -
1.1512 - self.names = {}
1.1513 -
1.1514 - def __repr__(self):
1.1515 - return repr(self.names) + " (temp) " + repr(self.temp)
1.1516 -
1.1517 -class Importer:
1.1518 -
1.1519 - "An import machine, searching for and loading modules."
1.1520 -
1.1521 - def __init__(self, path=None):
1.1522 -
1.1523 - """
1.1524 - Initialise the importer with the given search 'path' - a list of
1.1525 - directories to search for Python modules.
1.1526 - """
1.1527 -
1.1528 - self.path = path or [os.getcwd()]
1.1529 - self.path.append(libdir)
1.1530 - self.modules = {}
1.1531 -
1.1532 - def find_in_path(self, name):
1.1533 -
1.1534 - """
1.1535 - Find the given module 'name' in the search path, returning None where no
1.1536 - such module could be found, or a 2-tuple from the 'find' method
1.1537 - otherwise.
1.1538 - """
1.1539 -
1.1540 - for d in self.path:
1.1541 - m = self.find(d, name)
1.1542 - if m: return m
1.1543 - return None
1.1544 -
1.1545 - def find(self, d, name):
1.1546 -
1.1547 - """
1.1548 - In the directory 'd', find the given module 'name', where 'name' can
1.1549 - either refer to a single file module or to a package. Return None if the
1.1550 - 'name' cannot be associated with either a file or a package directory,
1.1551 - or a 2-tuple from '_find_package' or '_find_module' otherwise.
1.1552 - """
1.1553 -
1.1554 - m = self._find_package(d, name)
1.1555 - if m: return m
1.1556 - m = self._find_module(d, name)
1.1557 - if m: return m
1.1558 - return None
1.1559 -
1.1560 - def _find_module(self, d, name):
1.1561 -
1.1562 - """
1.1563 - In the directory 'd', find the given module 'name', returning None where
1.1564 - no suitable file exists in the directory, or a 2-tuple consisting of
1.1565 - None (indicating that no package directory is involved) and a filename
1.1566 - indicating the location of the module.
1.1567 - """
1.1568 -
1.1569 - name_py = name + os.extsep + "py"
1.1570 - filename = self._find_file(d, name_py)
1.1571 - if filename:
1.1572 - return None, filename
1.1573 - return None
1.1574 -
1.1575 - def _find_package(self, d, name):
1.1576 -
1.1577 - """
1.1578 - In the directory 'd', find the given package 'name', returning None
1.1579 - where no suitable package directory exists, or a 2-tuple consisting of
1.1580 - a directory (indicating the location of the package directory itself)
1.1581 - and a filename indicating the location of the __init__.py module which
1.1582 - declares the package's top-level contents.
1.1583 - """
1.1584 -
1.1585 - filename = self._find_file(d, name)
1.1586 - if filename:
1.1587 - init_py = "__init__" + os.path.extsep + "py"
1.1588 - init_py_filename = self._find_file(filename, init_py)
1.1589 - if init_py_filename:
1.1590 - return filename, init_py_filename
1.1591 - return None
1.1592 -
1.1593 - def _find_file(self, d, filename):
1.1594 -
1.1595 - """
1.1596 - Return the filename obtained when searching the directory 'd' for the
1.1597 - given 'filename', or None if no actual file exists for the filename.
1.1598 - """
1.1599 -
1.1600 - filename = os.path.join(d, filename)
1.1601 - if os.path.exists(filename):
1.1602 - return filename
1.1603 - else:
1.1604 - return None
1.1605 -
1.1606 - def load(self, name, builtins, alias=None):
1.1607 -
1.1608 - """
1.1609 - Load the module or package with the given 'name' and using the specified
1.1610 - 'builtins'. Return an Attribute object referencing the loaded module or
1.1611 - package, or None if no such module or package exists.
1.1612 - """
1.1613 -
1.1614 - if self.modules.has_key(name):
1.1615 - return Attribute(None, self.modules[name])
1.1616 -
1.1617 - path = name.split(".")
1.1618 - m = self.find_in_path(path[0])
1.1619 - if not m:
1.1620 - return None # NOTE: Import error.
1.1621 - d, filename = m
1.1622 -
1.1623 - if self.modules.has_key(path[0]):
1.1624 - top = module = self.modules[path[0]]
1.1625 - else:
1.1626 - top = module = self.modules[path[0]] = load(filename, builtins, path[0], self, no_annotate=1)
1.1627 - annotate(module, builtins, self)
1.1628 -
1.1629 - if len(path) > 1:
1.1630 - path_so_far = path[:1]
1.1631 - for p in path[1:]:
1.1632 - path_so_far.append(p)
1.1633 - m = self.find(d, p)
1.1634 - if not m:
1.1635 - return None # NOTE: Import error.
1.1636 - d, filename = m
1.1637 - module_name = ".".join(path_so_far)
1.1638 -
1.1639 - if self.modules.has_key(module_name):
1.1640 - submodule = self.modules[module_name]
1.1641 - else:
1.1642 - submodule = self.modules[module_name] = load(filename, builtins, module_name, self, no_annotate=1)
1.1643 - annotate(submodule, builtins, self)
1.1644 -
1.1645 - # Store the submodule within its parent module.
1.1646 -
1.1647 - module.namespace[p] = [Attribute(None, submodule)]
1.1648 - module = submodule
1.1649 -
1.1650 - if alias:
1.1651 - return Attribute(None, module)
1.1652 - else:
1.1653 - return Attribute(None, top)
1.1654 -
1.1655 -def combine(target, additions):
1.1656 -
1.1657 - """
1.1658 - Merge into the 'target' sequence the given 'additions', preventing duplicate
1.1659 - items.
1.1660 - """
1.1661 -
1.1662 - for addition in additions:
1.1663 - if addition not in target:
1.1664 - target.append(addition)
1.1665 -
1.1666 -def find_attributes(structure, name):
1.1667 -
1.1668 - """
1.1669 - Find for the given 'structure' all attributes for the given 'name', visiting
1.1670 - base classes where appropriate and returning the attributes in order of
1.1671 - descending precedence for all possible base classes.
1.1672 -
1.1673 - The elements in the result list are 2-tuples which contain the attribute and
1.1674 - the structure involved in accessing the attribute.
1.1675 - """
1.1676 -
1.1677 - # First attempt to search the instance/class namespace.
1.1678 -
1.1679 - try:
1.1680 - l = structure.namespace.load(name)
1.1681 - attributes = []
1.1682 - for attribute in l:
1.1683 - attributes.append((attribute, structure))
1.1684 -
1.1685 - # If that does not work, attempt to investigate any class or base classes.
1.1686 -
1.1687 - except KeyError:
1.1688 - attributes = []
1.1689 -
1.1690 - # Investigate any instance's implementing class.
1.1691 -
1.1692 - if isinstance(structure, Instance):
1.1693 - for attr in structure.namespace.load("__class__"):
1.1694 - cls = attr.type
1.1695 - l = get_attributes(cls, name)
1.1696 - combine(attributes, l)
1.1697 -
1.1698 - # Investigate any class's base classes.
1.1699 -
1.1700 - elif isinstance(structure, Class):
1.1701 -
1.1702 - # If no base classes exist, return an indicator that no attribute
1.1703 - # exists.
1.1704 -
1.1705 - if not structure.base_refs:
1.1706 - return [(None, structure)]
1.1707 -
1.1708 - # Otherwise, find all possible base classes.
1.1709 -
1.1710 - for base_refs in structure.base_refs:
1.1711 - base_attributes = []
1.1712 -
1.1713 - # For each base class, find attributes either in the base
1.1714 - # class or its own base classes.
1.1715 -
1.1716 - for base_ref in base_refs:
1.1717 - l = get_attributes(base_ref, name)
1.1718 - combine(base_attributes, l)
1.1719 -
1.1720 - combine(attributes, base_attributes)
1.1721 -
1.1722 - return attributes
1.1723 -
1.1724 -def get_attributes(structure, name):
1.1725 -
1.1726 - """
1.1727 - Return all possible attributes for the given 'structure' having the given
1.1728 - 'name', wrapping each attribute in an Attribute object which includes
1.1729 - context information for the attribute access.
1.1730 -
1.1731 - The elements in the result list are 2-tuples which contain the attribute and
1.1732 - the structure involved in accessing the attribute.
1.1733 - """
1.1734 -
1.1735 - if isinstance(structure, Attribute):
1.1736 - structure = structure.type
1.1737 - results = []
1.1738 - for attribute, accessor in find_attributes(structure, name):
1.1739 -
1.1740 - # Detect class attribute access via instances.
1.1741 -
1.1742 - if attribute is not None and isinstance(structure, Instance) and isinstance(accessor, Class):
1.1743 - attribute = accessor.get_attribute_for_instance(attribute, structure)
1.1744 -
1.1745 - # Produce an attribute with the appropriate context.
1.1746 -
1.1747 - if attribute is not None and isinstance(structure, Structure):
1.1748 - results.append((Attribute(structure, attribute.type), accessor))
1.1749 - else:
1.1750 - results.append((attribute, accessor))
1.1751 -
1.1752 - return results
1.1753 -
1.1754 -def prompt(vars):
1.1755 - try:
1.1756 - while 1:
1.1757 - s = raw_input("> ")
1.1758 - print eval(s, vars)
1.1759 - except EOFError:
1.1760 - pass
1.1761 -
1.1762 -# Convenience functions.
1.1763 -
1.1764 -def load(name, builtins=None, module_name=None, importer=None, no_annotate=0):
1.1765 -
1.1766 - """
1.1767 - Load the module with the given 'name' (which may be a full module path),
1.1768 - using the optional 'builtins' to resolve built-in names, and using the
1.1769 - optional 'importer' to provide a means of finding and loading modules.
1.1770 - """
1.1771 -
1.1772 - module = simplify.simplify(name, builtins is None, module_name)
1.1773 - fixnames.fix(module, builtins)
1.1774 - if not no_annotate:
1.1775 - annotate(module, builtins, importer)
1.1776 - return module
1.1777 -
1.1778 -def annotate(module, builtins=None, importer=None):
1.1779 -
1.1780 - """
1.1781 - Annotate the given 'module', also employing the optional 'builtins' module,
1.1782 - if specified. If the optional 'importer' is given, use that to find and load
1.1783 - modules.
1.1784 - """
1.1785 -
1.1786 - annotator = Annotator(importer)
1.1787 - if builtins is not None:
1.1788 - annotator.process(module, builtins)
1.1789 - else:
1.1790 - annotator.process(module)
1.1791 -
1.1792 -# vim: tabstop=4 expandtab shiftwidth=4