1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/micropython/data.py Sun May 11 18:20:27 2008 +0200
1.3 @@ -0,0 +1,775 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +"""
1.7 +Data classes.
1.8 +
1.9 +Copyright (C) 2007, 2008 Paul Boddie <paul@boddie.org.uk>
1.10 +
1.11 +This program is free software; you can redistribute it and/or modify it under
1.12 +the terms of the GNU General Public License as published by the Free Software
1.13 +Foundation; either version 3 of the License, or (at your option) any later
1.14 +version.
1.15 +
1.16 +This program is distributed in the hope that it will be useful, but WITHOUT
1.17 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.18 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.19 +details.
1.20 +
1.21 +You should have received a copy of the GNU General Public License along with
1.22 +this program. If not, see <http://www.gnu.org/licenses/>.
1.23 +
1.24 +--------
1.25 +
1.26 +The central classes in this module are the following:
1.27 +
1.28 + * Class
1.29 + * Function
1.30 + * Module
1.31 + * InspectedModule (derived from Module)
1.32 +
1.33 +All of the above support the Naming interface either explicitly or through
1.34 +general conformance, meaning that all can be asked to provide their 'full_name'
1.35 +using the method of that name.
1.36 +
1.37 +Additionally, all of the above also support a dictionary interface in order to
1.38 +access names within their defined scopes. Specific methods also exist in order
1.39 +to distinguish between certain kinds of attributes:
1.40 +
1.41 + * Class: (class|all_class|instance|all)_attributes
1.42 + * Function: parameters, locals, all_locals
1.43 + * Module: module_attributes
1.44 +
1.45 +These specific methods are useful in certain situations.
1.46 +
1.47 +The above classes also provide a 'node' attribute, indicating the AST node where
1.48 +each such object is defined.
1.49 +"""
1.50 +
1.51 +from micropython.common import *
1.52 +
1.53 +# Mix-ins and abstract classes.
1.54 +
1.55 +class NamespaceDict:
1.56 +
1.57 + "A mix-in providing dictionary methods."
1.58 +
1.59 + def __init__(self, global_namespace=None):
1.60 + self.namespace = {}
1.61 + self.globals = set()
1.62 + self.global_namespace = global_namespace
1.63 +
1.64 + def __getitem__(self, name):
1.65 + return self.namespace[name]
1.66 +
1.67 + def get(self, name, default=None):
1.68 + return self.namespace.get(name, default)
1.69 +
1.70 + def __setitem__(self, name, value):
1.71 + self.set(name, value)
1.72 +
1.73 + def set(self, name, value, single_assignment=1):
1.74 +
1.75 + """
1.76 + A more powerful set operation, making 'name' refer to 'value' whilst
1.77 + indicating whether a 'single_assignment' (true by default) occurs in
1.78 + this operation (or whether the operation covers potentially many
1.79 + assignments in the lifetime of a program).
1.80 + """
1.81 +
1.82 + if name in self.globals:
1.83 + self.global_namespace.set(name, value, 0)
1.84 + else:
1.85 + attr = self._set(name, value)
1.86 +
1.87 + # NOTE: Insist on assignments with known values.
1.88 +
1.89 + if value is not None:
1.90 + attr.update(value, single_assignment)
1.91 +
1.92 + def set_module(self, name, value):
1.93 +
1.94 + """
1.95 + A specialised set operation, making 'name' refer to 'value' in the
1.96 + context of making a module reference available in association with
1.97 + 'name' as part of the import of that module or a submodule of that
1.98 + module.
1.99 + """
1.100 +
1.101 + attr = self._set(name, value)
1.102 + if attr.assignments is None:
1.103 + attr.assignments = 1
1.104 + attr.assignment_values.add(value)
1.105 +
1.106 + def _set(self, name, value):
1.107 +
1.108 + "The underlying set operation associating 'name' with 'value'."
1.109 +
1.110 + if not self.namespace.has_key(name):
1.111 + self.namespace[name] = Attr(None, self, name, value)
1.112 + return self.namespace[name]
1.113 +
1.114 + def __delitem__(self, name):
1.115 + del self.namespace[name]
1.116 +
1.117 + def has_key(self, name):
1.118 + return self.namespace.has_key(name)
1.119 +
1.120 + def keys(self):
1.121 + return self.namespace.keys()
1.122 +
1.123 + def values(self):
1.124 + return self.namespace.values()
1.125 +
1.126 + def items(self):
1.127 + return self.namespace.items()
1.128 +
1.129 + def make_global(self, name):
1.130 + if not self.namespace.has_key(name):
1.131 + self.globals.add(name)
1.132 + else:
1.133 + raise InspectError(self.full_name(), self.node, "Name %r is both global and local in %r" % (name, self.full_name()))
1.134 +
1.135 + def get_assignments(self, name):
1.136 + if self.assignments.has_key(name):
1.137 + return max(self.assignments[name], len(self.assignment_values[name]))
1.138 + else:
1.139 + return None
1.140 +
1.141 + def attributes_as_list(self):
1.142 + self.finalise_attributes()
1.143 + l = [None] * len(self.keys())
1.144 + for attr in self.values():
1.145 + l[attr.position] = attr
1.146 + return l
1.147 +
1.148 + def finalise_attributes(self):
1.149 +
1.150 + "Make sure all attributes are fully defined."
1.151 +
1.152 + # The default action is to assign attribute positions sequentially.
1.153 +
1.154 + for i, attr in enumerate(self.values()):
1.155 + attr.position = i
1.156 +
1.157 +# Program data structures.
1.158 +
1.159 +class Attr:
1.160 +
1.161 + "An attribute entry having a parent as context."
1.162 +
1.163 + def __init__(self, position, parent, name, value=None, assignments=None):
1.164 + self.position = position
1.165 + self.parent = parent
1.166 + self.name = name
1.167 + self.value = value
1.168 +
1.169 + # Number of assignments per name.
1.170 +
1.171 + self.assignments = assignments
1.172 + self.assignment_values = set()
1.173 +
1.174 + def update(self, value, single_assignment):
1.175 +
1.176 + """
1.177 + Update the attribute, adding the 'value' provided to the known values
1.178 + associated with the attribute, changing the number of assignments
1.179 + according to the 'single_assignment' status of the operation, where
1.180 + a true value indicates that only one assignment is associated with the
1.181 + update, and a false value indicates that potentially many assignments
1.182 + may be involved.
1.183 + """
1.184 +
1.185 + if self.assignments is None:
1.186 + if single_assignment:
1.187 + self.assignments = 1
1.188 + else:
1.189 + self.assignments = AtLeast(1)
1.190 + else:
1.191 + if single_assignment:
1.192 + self.assignments += 1
1.193 + else:
1.194 + self.assignments += AtLeast(1)
1.195 + self.assignment_values.add(value)
1.196 +
1.197 + def __repr__(self):
1.198 + return "Attr(%r, %r, %r, %r, %r)" % (self.position, self.parent, self.name, self.value, self.assignments)
1.199 +
1.200 +class Const:
1.201 +
1.202 + "A constant object with no context."
1.203 +
1.204 + def __init__(self, value):
1.205 + self.value = value
1.206 +
1.207 + # Image generation details.
1.208 +
1.209 + self.location = None
1.210 +
1.211 + def __repr__(self):
1.212 + if self.location is not None:
1.213 + return "Const(%r, location=%r)" % (self.value, self.location)
1.214 + else:
1.215 + return "Const(%r)" % self.value
1.216 +
1.217 + # Support constants as dictionary keys in order to build constant tables.
1.218 +
1.219 + def __eq__(self, other):
1.220 + return self.value == other.value
1.221 +
1.222 + def __hash__(self):
1.223 + return hash(self.value)
1.224 +
1.225 + def value_type_name(self):
1.226 + return "__builtins__." + self.value.__class__.__name__
1.227 +
1.228 +class Class(NamespaceDict, Naming):
1.229 +
1.230 + "An inspected class."
1.231 +
1.232 + def __init__(self, name, parent, global_namespace=None, node=None):
1.233 +
1.234 + """
1.235 + Initialise the class with the given 'name', 'parent' object, optional
1.236 + 'global_namespace' and optional AST 'node'.
1.237 + """
1.238 +
1.239 + NamespaceDict.__init__(self, global_namespace)
1.240 + self.name = name
1.241 + self.parent = parent
1.242 + self.node = node
1.243 +
1.244 + # Superclasses, descendants and attributes.
1.245 +
1.246 + self.bases = []
1.247 + self.descendants = set()
1.248 + self.instattr = set() # instance attributes
1.249 + self.relocated = set() # attributes which do not have the same
1.250 + # position as those of the same name in
1.251 + # some superclasses
1.252 +
1.253 + # Caches.
1.254 +
1.255 + self.all_instattr = None # cache for instance_attributes
1.256 + self.all_instattr_names = None # from all_instattr
1.257 + self.all_classattr = None # cache for all_class_attributes
1.258 + self.all_classattr_names = None # from all_classattr
1.259 + self.allattr = None # cache for all_attributes
1.260 + self.allattr_names = None # from allattr
1.261 +
1.262 + # Add this class to its attributes.
1.263 +
1.264 + self.set("__class__", self)
1.265 +
1.266 + # Image generation details.
1.267 +
1.268 + self.location = None
1.269 + self.code_location = None
1.270 + self.instantiator = None
1.271 +
1.272 + # Program-related details.
1.273 +
1.274 + self.stack_usage = 0
1.275 + self.stack_temp_usage = 0
1.276 + self.stack_local_usage = 0
1.277 +
1.278 + def __repr__(self):
1.279 + if self.location is not None:
1.280 + return "Class(%r, %r, location=%r)" % (self.name, self.parent, self.location)
1.281 + else:
1.282 + return "Class(%r, %r)" % (self.name, self.parent)
1.283 +
1.284 + def finalise_attributes(self):
1.285 +
1.286 + "Make sure that all attributes are fully defined."
1.287 +
1.288 + self.finalise_class_attributes()
1.289 + self.finalise_instance_attributes()
1.290 +
1.291 + def get_instantiator(self):
1.292 +
1.293 + "Return a function which can be used to instantiate the class."
1.294 +
1.295 + if self.instantiator is None:
1.296 + init_method = self.all_class_attributes()["__init__"].value
1.297 + self.instantiator = init_method.function_from_method()
1.298 + return self.instantiator
1.299 +
1.300 + # Class-specific methods.
1.301 +
1.302 + def add_base(self, base):
1.303 + self.bases.append(base)
1.304 + base.add_descendant(self)
1.305 +
1.306 + def add_instance_attribute(self, name):
1.307 + self.instattr.add(name)
1.308 +
1.309 + def add_descendant(self, cls):
1.310 + self.descendants.add(cls)
1.311 + for base in self.bases:
1.312 + base.add_descendant(cls)
1.313 +
1.314 + "Return the attribute names provided by this class only."
1.315 +
1.316 + class_attribute_names = NamespaceDict.keys
1.317 +
1.318 + def class_attributes(self):
1.319 +
1.320 + "Return class attributes provided by this class only."
1.321 +
1.322 + self.finalise_class_attributes()
1.323 + return dict(self)
1.324 +
1.325 + def all_class_attribute_names(self):
1.326 +
1.327 + "Return the attribute names provided by classes in this hierarchy."
1.328 +
1.329 + if self.all_classattr_names is None:
1.330 + self.all_class_attributes()
1.331 + return self.all_classattr_names
1.332 +
1.333 + def all_class_attributes(self):
1.334 +
1.335 + "Return all class attributes, indicating the class which provides them."
1.336 +
1.337 + self.finalise_class_attributes()
1.338 + return self.all_classattr
1.339 +
1.340 + def finalise_class_attributes(self):
1.341 +
1.342 + "Make sure that the class attributes are fully defined."
1.343 +
1.344 + if self.all_classattr is None:
1.345 + self.all_classattr = {}
1.346 + clsattr = {}
1.347 +
1.348 + # Record provisional position information for attributes of this
1.349 + # class.
1.350 +
1.351 + for name in self.class_attributes().keys():
1.352 + clsattr[name] = set() # position not yet defined
1.353 +
1.354 + reversed_bases = self.bases[:]
1.355 + reversed_bases.reverse()
1.356 +
1.357 + # For the bases in reverse order, acquire class attribute details.
1.358 +
1.359 + for cls in reversed_bases:
1.360 + for name, attr in cls.all_class_attributes().items():
1.361 + self.all_classattr[name] = attr
1.362 +
1.363 + # Record previous attribute information.
1.364 +
1.365 + if clsattr.has_key(name):
1.366 + clsattr[name].add(attr.position)
1.367 +
1.368 + # Record class attributes provided by this class and its bases,
1.369 + # along with their positions.
1.370 +
1.371 + self.all_classattr.update(self.class_attributes())
1.372 +
1.373 + if clsattr:
1.374 + for i, name in enumerate(self._get_position_list(clsattr)):
1.375 + self.all_classattr[name].position = i
1.376 +
1.377 + return self.all_classattr
1.378 +
1.379 + def instance_attribute_names(self):
1.380 +
1.381 + "Return the instance attribute names provided by the class."
1.382 +
1.383 + if self.all_instattr_names is None:
1.384 + self.instance_attributes()
1.385 + return self.all_instattr_names
1.386 +
1.387 + def instance_attributes(self):
1.388 +
1.389 + "Return instance-only attributes for instances of this class."
1.390 +
1.391 + self.finalise_instance_attributes()
1.392 + return self.all_instattr
1.393 +
1.394 + def finalise_instance_attributes(self):
1.395 +
1.396 + "Make sure that the instance attributes are fully defined."
1.397 +
1.398 + if self.all_instattr is None:
1.399 + self.all_instattr = {}
1.400 + instattr = {}
1.401 +
1.402 + # Record provisional position information for attributes of this
1.403 + # instance.
1.404 +
1.405 + for name in self.instattr:
1.406 + instattr[name] = set() # position not yet defined
1.407 +
1.408 + reversed_bases = self.bases[:]
1.409 + reversed_bases.reverse()
1.410 +
1.411 + # For the bases in reverse order, acquire instance attribute
1.412 + # details.
1.413 +
1.414 + for cls in reversed_bases:
1.415 + for name, attr in cls.instance_attributes().items():
1.416 +
1.417 + # Record previous attribute information.
1.418 +
1.419 + if instattr.has_key(name):
1.420 + instattr[name].add(attr.position)
1.421 +
1.422 + # Cache the attributes by converting the positioned attributes into
1.423 + # a dictionary.
1.424 +
1.425 + if not instattr:
1.426 + self.all_instattr = {}
1.427 + else:
1.428 + self.all_instattr = self._get_attributes(instattr)
1.429 +
1.430 + self.all_instattr_names = self.all_instattr.keys()
1.431 +
1.432 + return self.all_instattr
1.433 +
1.434 + def _get_position_list(self, positions):
1.435 +
1.436 + """
1.437 + Return a list of attribute names for the given 'positions' mapping from
1.438 + names to positions, indicating the positions of the attributes in the
1.439 + final instance structure.
1.440 + """
1.441 +
1.442 + position_items = positions.items()
1.443 + namearray = [None] * len(position_items)
1.444 +
1.445 + # Get the positions in ascending order of list size, with lists
1.446 + # of the same size ordered according to their smallest position
1.447 + # value.
1.448 +
1.449 + position_items.sort(self._cmp_positions)
1.450 +
1.451 + # Get the names in position order.
1.452 +
1.453 + held = []
1.454 +
1.455 + for name, pos in position_items:
1.456 + pos = list(pos)
1.457 + pos.sort()
1.458 + if pos and pos[0] < len(namearray) and namearray[pos[0]] is None:
1.459 + namearray[pos[0]] = name
1.460 + else:
1.461 + if pos:
1.462 + self.relocated.add(name)
1.463 + held.append((name, pos))
1.464 +
1.465 + for i, attr in enumerate(namearray):
1.466 + if attr is None:
1.467 + name, pos = held.pop()
1.468 + namearray[i] = name
1.469 +
1.470 + #print self.name, positions
1.471 + #print "->", namearray
1.472 + return namearray
1.473 +
1.474 + def _get_attributes(self, positions):
1.475 +
1.476 + """
1.477 + For the given 'positions' mapping from names to positions, return a
1.478 + dictionary mapping names to Attr instances incorporating information
1.479 + about their positions in the final instance structure.
1.480 + """
1.481 +
1.482 + d = {}
1.483 + for i, name in enumerate(self._get_position_list(positions)):
1.484 + d[name] = Attr(i, Instance(), name, None)
1.485 + return d
1.486 +
1.487 + def _cmp_positions(self, a, b):
1.488 +
1.489 + "Compare name plus position list operands 'a' and 'b'."
1.490 +
1.491 + name_a, list_a = a
1.492 + name_b, list_b = b
1.493 + if len(list_a) < len(list_b):
1.494 + return -1
1.495 + elif len(list_a) > len(list_b):
1.496 + return 1
1.497 + elif not list_a:
1.498 + return 0
1.499 + else:
1.500 + return cmp(min(list_a), min(list_b))
1.501 +
1.502 + def all_attribute_names(self):
1.503 +
1.504 + """
1.505 + Return the names of all attributes provided by instances of this class.
1.506 + """
1.507 +
1.508 + self.allattr_names = self.allattr_names or self.all_attributes().keys()
1.509 + return self.allattr_names
1.510 +
1.511 + def all_attributes(self):
1.512 +
1.513 + """
1.514 + Return all attributes for an instance, indicating either the class which
1.515 + provides them or that the instance itself provides them.
1.516 + """
1.517 +
1.518 + if self.allattr is None:
1.519 + self.allattr = {}
1.520 + self.allattr.update(self.all_class_attributes())
1.521 + for name, attr in self.instance_attributes().items():
1.522 + if self.allattr.has_key(name):
1.523 + print "Instance attribute %r in %r overrides class attribute." % (name, self)
1.524 + self.allattr[name] = attr
1.525 + return self.allattr
1.526 +
1.527 +class Function(NamespaceDict, Naming):
1.528 +
1.529 + "An inspected function."
1.530 +
1.531 + def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, global_namespace=None, node=None):
1.532 +
1.533 + """
1.534 + Initialise the function with the given 'name', 'parent', list of
1.535 + 'argnames', list of 'defaults', the 'has_star' flag (indicating the
1.536 + presence of a * parameter), the 'has_dstar' flag (indicating the
1.537 + presence of a ** parameter), optional 'global_namespace', and optional
1.538 + AST 'node'.
1.539 + """
1.540 +
1.541 + NamespaceDict.__init__(self, global_namespace)
1.542 + self.name = name
1.543 + self.parent = parent
1.544 + self.argnames = argnames
1.545 + self.defaults = defaults
1.546 + self.has_star = has_star
1.547 + self.has_dstar = has_dstar
1.548 + self.node = node
1.549 +
1.550 + # Initialise the positional names.
1.551 +
1.552 + self.positional_names = self.argnames[:]
1.553 + if has_dstar:
1.554 + self.dstar_name = self.positional_names[-1]
1.555 + del self.positional_names[-1]
1.556 + if has_star:
1.557 + self.star_name = self.positional_names[-1]
1.558 + del self.positional_names[-1]
1.559 +
1.560 + # Initialise default storage.
1.561 + # NOTE: This must be initialised separately due to the reliance on node
1.562 + # NOTE: visiting.
1.563 +
1.564 + self.default_attrs = []
1.565 +
1.566 + # Caches.
1.567 +
1.568 + self.localnames = None # cache for locals
1.569 +
1.570 + # Add parameters to the namespace.
1.571 +
1.572 + self._add_parameters(argnames)
1.573 +
1.574 + # Image generation details.
1.575 +
1.576 + self.location = None
1.577 + self.code_location = None
1.578 +
1.579 + # Program-related details.
1.580 +
1.581 + self.stack_usage = 0
1.582 + self.stack_temp_usage = 0
1.583 + self.stack_local_usage = 0
1.584 +
1.585 + def _add_parameters(self, argnames):
1.586 + for name in argnames:
1.587 + if isinstance(name, tuple):
1.588 + self._add_parameters(name)
1.589 + else:
1.590 + self.set(name, None)
1.591 +
1.592 + def __repr__(self):
1.593 + if self.location is not None:
1.594 + return "Function(%r, %r, %r, %r, %r, %r, location=%r)" % (
1.595 + self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.location
1.596 + )
1.597 + else:
1.598 + return "Function(%r, %r, %r, %r, %r, %r)" % (
1.599 + self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar
1.600 + )
1.601 +
1.602 + def store_default(self, value):
1.603 + attr = Attr(None, self, None, value)
1.604 + attr.update(value, 1)
1.605 + self.default_attrs.append(attr)
1.606 +
1.607 + def make_global(self, name):
1.608 + if name not in self.argnames and not self.has_key(name):
1.609 + self.globals.add(name)
1.610 + else:
1.611 + raise InspectError(self.full_name(), self.node, "Name %r is global and local in %r" % (name, self.full_name()))
1.612 +
1.613 + def parameters(self):
1.614 +
1.615 + """
1.616 + Return a dictionary mapping parameter names to their position in the
1.617 + parameter list.
1.618 + """
1.619 +
1.620 + parameters = {}
1.621 + for i, name in enumerate(self.argnames):
1.622 + parameters[name] = i
1.623 + return parameters
1.624 +
1.625 + def all_locals(self):
1.626 +
1.627 + "Return a dictionary mapping names to local and parameter details."
1.628 +
1.629 + return dict(self)
1.630 +
1.631 + def locals(self):
1.632 +
1.633 + "Return a dictionary mapping names to local details."
1.634 +
1.635 + if self.localnames is None:
1.636 + self.localnames = {}
1.637 + self.localnames.update(self.all_locals())
1.638 + for name in self.argnames:
1.639 + del self.localnames[name]
1.640 + return self.localnames
1.641 +
1.642 + def is_method(self):
1.643 +
1.644 + "Return whether this function is a method."
1.645 +
1.646 + return isinstance(self.parent, Class)
1.647 +
1.648 + def is_relocated(self, name):
1.649 +
1.650 + """
1.651 + Determine whether the given attribute 'name' is relocated for instances
1.652 + having this function as a method.
1.653 + """
1.654 +
1.655 + for cls in self.parent.descendants:
1.656 + if name in cls.relocated:
1.657 + return 1
1.658 + return 0
1.659 +
1.660 + def finalise_attributes(self):
1.661 +
1.662 + """
1.663 + Make sure all attributes (locals) are fully defined. Note that locals
1.664 + are not attributes in the sense of class, module or instance attributes.
1.665 + Defaults are also finalised by this method.
1.666 + """
1.667 +
1.668 + for i, default in enumerate(self.default_attrs):
1.669 + default.position = i
1.670 +
1.671 + i = None
1.672 + for i, name in enumerate(self.argnames):
1.673 + self[name].position = i
1.674 +
1.675 + if i is not None:
1.676 + j = i
1.677 + else:
1.678 + j = 0
1.679 +
1.680 + i = -1
1.681 + for i, attr in enumerate(self.locals().values()):
1.682 + attr.position = i + j
1.683 +
1.684 + self.stack_local_usage = i + 1
1.685 +
1.686 + def function_from_method(self):
1.687 +
1.688 + "Make a function from a method."
1.689 +
1.690 + function = Function(self.name, self.parent, self.argnames[1:], self.defaults,
1.691 + self.has_star, self.has_dstar, self.global_namespace, self.node)
1.692 + function.default_attrs = self.default_attrs
1.693 + return function
1.694 +
1.695 +class UnresolvedName(NamespaceDict):
1.696 +
1.697 + "A module, class or function which was mentioned but could not be imported."
1.698 +
1.699 + def __init__(self, name, parent_name, global_namespace=None):
1.700 + NamespaceDict.__init__(self, global_namespace)
1.701 + self.name = name
1.702 + self.parent_name = parent_name
1.703 +
1.704 + def all_class_attributes(self):
1.705 + return {}
1.706 +
1.707 + def instance_attributes(self):
1.708 + return {}
1.709 +
1.710 + def __repr__(self):
1.711 + return "UnresolvedName(%r, %r)" % (self.name, self.parent_name)
1.712 +
1.713 + def full_name(self):
1.714 + if self.name is not None:
1.715 + return self.parent_name + "." + self.name
1.716 + else:
1.717 + return self.parent_name
1.718 +
1.719 +class Instance:
1.720 +
1.721 + "A placeholder indicating the involvement of an instance."
1.722 +
1.723 + def __repr__(self):
1.724 + return "Instance()"
1.725 +
1.726 +class Module(NamespaceDict):
1.727 +
1.728 + "An inspected module's core details."
1.729 +
1.730 + def __init__(self, name):
1.731 + NamespaceDict.__init__(self, self)
1.732 + self.name = name
1.733 +
1.734 + # Original location details.
1.735 +
1.736 + self.node = None
1.737 +
1.738 + # Complete lists of classes and functions.
1.739 +
1.740 + self.all_objects = set()
1.741 +
1.742 + # Keyword records.
1.743 +
1.744 + self.keyword_names = set()
1.745 +
1.746 + # Image generation details.
1.747 +
1.748 + self.location = None
1.749 + self.code_location = None
1.750 +
1.751 + # Program-related details.
1.752 +
1.753 + self.stack_usage = 0
1.754 + self.stack_temp_usage = 0
1.755 + self.stack_local_usage = 0
1.756 +
1.757 + def full_name(self):
1.758 + return self.name
1.759 +
1.760 + def __repr__(self):
1.761 + if self.location is not None:
1.762 + return "Module(%r, location=%r)" % (self.name, self.location)
1.763 + else:
1.764 + return "Module(%r)" % self.name
1.765 +
1.766 + # Attribute methods.
1.767 +
1.768 + "Return the module attribute names provided by the module."
1.769 +
1.770 + module_attribute_names = NamespaceDict.keys
1.771 +
1.772 + def module_attributes(self):
1.773 +
1.774 + "Return a dictionary mapping names to module attributes."
1.775 +
1.776 + return dict(self)
1.777 +
1.778 +# vim: tabstop=4 expandtab shiftwidth=4