1.1 --- a/micropython/data.py Tue Nov 06 00:12:46 2012 +0100
1.2 +++ b/micropython/data.py Tue Nov 06 00:16:26 2012 +0100
1.3 @@ -52,12 +52,9 @@
1.4 where each such object is defined.
1.5 """
1.6
1.7 -from compiler.ast import AttributeUser
1.8 from micropython.program import ReplaceableContext, PlaceholderContext
1.9 from micropython.basicdata import *
1.10 -from micropython.errors import *
1.11 -from micropython.objectset import *
1.12 -from micropython.types import *
1.13 +from micropython.branch import BranchTracking
1.14 import sys
1.15
1.16 try:
1.17 @@ -65,45 +62,19 @@
1.18 except NameError:
1.19 from sets import Set as set
1.20
1.21 -class NamespaceDict(Namespace):
1.22 +class NamespaceDict(Namespace, BranchTracking):
1.23
1.24 "A mix-in providing dictionary methods."
1.25
1.26 def __init__(self, module=None):
1.27 + BranchTracking.__init__(self)
1.28 +
1.29 self.module = module
1.30 self.namespace = {}
1.31 self.globals = set()
1.32 self.lambdas = {} # only really useful for functions
1.33 self.finalised = False
1.34
1.35 - # Attributes accessed on objects, potentially narrowing their types.
1.36 - # Specific namespaces should define known names during initialisation.
1.37 - # For example, functions can define names belonging to parameters.
1.38 -
1.39 - # Attribute users, defining names which use attributes.
1.40 -
1.41 - self.attribute_users = [{}] # stack of assignments and branches
1.42 - self.attribute_user_shelves = []
1.43 -
1.44 - # Suspended user details plus loop details.
1.45 -
1.46 - self.suspended_broken_users = [] # stack of lists of user dicts
1.47 - self.suspended_continuing_users = [] # stack of lists of user dicts
1.48 -
1.49 - # Scope usage, indicating the origin of names.
1.50 -
1.51 - self.scope_usage = [{}] # stack of scope usage
1.52 - self.scope_shelves = []
1.53 -
1.54 - # Abandoned usage, useful for reviving usage for exception handlers.
1.55 -
1.56 - self.abandoned_users = [[]] # stack of lists of users
1.57 -
1.58 - # Define attribute usage to identify active program sections.
1.59 - # Attribute users are AST nodes defining names.
1.60 -
1.61 - self.all_attribute_users = set()
1.62 -
1.63 # Attribute/name definition and access.
1.64
1.65 def __delitem__(self, name):
1.66 @@ -127,6 +98,16 @@
1.67 def get(self, name, default=None):
1.68 return self.namespace.get(name, default)
1.69
1.70 + # Introspection methods.
1.71 +
1.72 + def is_method(self):
1.73 +
1.74 + """
1.75 + Return whether this function is a method explicitly defined in a class.
1.76 + """
1.77 +
1.78 + return False
1.79 +
1.80 # Administrative methods.
1.81
1.82 def finalise(self, objtable):
1.83 @@ -356,680 +337,6 @@
1.84
1.85 self.finalised = False
1.86
1.87 - # Attribute usage methods.
1.88 -
1.89 - def finalise_attribute_usage(self):
1.90 -
1.91 - "Propagate attribute usage for the namespace to the importer."
1.92 -
1.93 - module = self.module
1.94 - importer = module and module.importer
1.95 -
1.96 - if importer is not None:
1.97 -
1.98 - # Visit each user and examine the attribute usage for each name.
1.99 -
1.100 - for user in self.all_attribute_users:
1.101 -
1.102 - # First, visit the contributors and combine their attribute
1.103 - # usage with the usage recorded directly on the user.
1.104 -
1.105 - self.get_usage_from_contributors(user)
1.106 -
1.107 - # Record the defining user on each contributor.
1.108 -
1.109 - for contributor in user._attrcontributors:
1.110 - contributor._attrdefs.append(user)
1.111 -
1.112 - # Then, tell the importer about the usage.
1.113 -
1.114 - for name in user._attrnames.keys():
1.115 -
1.116 - # Only provide information about names defined by this user.
1.117 -
1.118 - usage = user._attrcombined.get(name, [])
1.119 -
1.120 - # Skip reporting where no actual usage occurs.
1.121 -
1.122 - if usage is None:
1.123 - continue
1.124 -
1.125 - # Eliminate non-usage.
1.126 -
1.127 - importer.use_names(user, name, tuple([attrnames for attrnames in usage if attrnames]), self.full_name())
1.128 -
1.129 - def finalise_users(self, objtable):
1.130 -
1.131 - "Record the object types for generating guards."
1.132 -
1.133 - # Visit each user and examine the attribute usage for each name.
1.134 -
1.135 - for user in self.all_attribute_users:
1.136 - user._attrtypes = self._deduce_types(user._attrcombined, objtable)
1.137 - self._finalise_contributor(user, objtable)
1.138 -
1.139 - def _finalise_contributors(self, node, objtable):
1.140 -
1.141 - """
1.142 - Visit the contributing branches of 'node', finalising them using the
1.143 - given 'objtable'.
1.144 - """
1.145 -
1.146 - for contributor in node._attrbranches:
1.147 - self._finalise_contributor(contributor, objtable)
1.148 -
1.149 - def _finalise_contributor(self, node, objtable):
1.150 -
1.151 - """
1.152 - Record the specific object types being used in various regions of a
1.153 - program unit.
1.154 - """
1.155 -
1.156 - if node._attrspecifictypes is None:
1.157 - merged = {}
1.158 -
1.159 - # Get the combined usage information from the user definitions.
1.160 -
1.161 - for user in node._attrdefs or [node]:
1.162 -
1.163 - # Filter the usage for each name using the local usage
1.164 - # information.
1.165 -
1.166 - for name, usage in user._attrcombined.items():
1.167 - localusage = node._attrnames.get(name)
1.168 -
1.169 - if usage and localusage:
1.170 - if not merged.has_key(name):
1.171 - merged[name] = ObjectSet()
1.172 -
1.173 - for attrnames, value in usage.items():
1.174 - if attrnames and localusage.issubset(attrnames):
1.175 - merged[name][attrnames] = value
1.176 -
1.177 - node._attrmerged = merged
1.178 - node._attrspecifictypes = self._deduce_types(node._attrmerged, objtable)
1.179 -
1.180 - self._finalise_contributors(node, objtable)
1.181 -
1.182 - def _deduce_types(self, usage, objtable):
1.183 -
1.184 - """
1.185 - Deduce the types for names from the given attribute 'usage' and using
1.186 - the given 'objtable'.
1.187 - """
1.188 -
1.189 - attrtypes = {}
1.190 - for name, combined_usage in usage.items():
1.191 - if combined_usage is not None:
1.192 - objtypes = get_object_types_for_usage(combined_usage, objtable, name, self.full_name(), True, self.module.importer)
1.193 - if objtypes:
1.194 - if isinstance(self, Function) and self.is_method() and name == "self":
1.195 - objtypes = filter_using_self(objtypes, self.parent)
1.196 - attrtypes[name] = objtypes
1.197 - return attrtypes
1.198 -
1.199 - def get_usage_from_contributors(self, node):
1.200 -
1.201 - """
1.202 - Obtain usage information from the given 'node', combined with usage
1.203 - details from its contributors, returning a tuple containing a set of all
1.204 - contributors employed along with a dictionary mapping names to lists of
1.205 - usage possibilities (each a collection of attribute names).
1.206 - """
1.207 -
1.208 - unfinished = {}
1.209 -
1.210 - # Process any unprocessed contributors, indicating the unfinished state
1.211 - # of the associated data.
1.212 -
1.213 - if node._attrcombined is None:
1.214 - node._attrcombined = Unset
1.215 -
1.216 - for contributor in node._attrbranches:
1.217 -
1.218 - # Get contributor details.
1.219 -
1.220 - unfinished_contributors = self.get_usage_from_contributors(contributor)
1.221 -
1.222 - # Collect unfinished contributors and affected nodes.
1.223 -
1.224 - # Where the contributor is already set to Unset, a loop has
1.225 - # occurred and this node will need to have its usage
1.226 - # recalculated later for the unfinished contributor.
1.227 -
1.228 - if contributor._attrcombined is Unset:
1.229 - if not unfinished.has_key(contributor):
1.230 - unfinished[contributor] = []
1.231 - unfinished[contributor].append(node)
1.232 - continue
1.233 -
1.234 - # Where the contributor provides usage details, it may also
1.235 - # communicate unfinished contributor information. As a
1.236 - # consequence, this node is also affected.
1.237 -
1.238 - for unfinished_contributor, nodes in unfinished_contributors.items():
1.239 - if not unfinished.has_key(unfinished_contributor):
1.240 - unfinished[unfinished_contributor] = nodes
1.241 - else:
1.242 - unfinished[unfinished_contributor] += nodes
1.243 -
1.244 - if node not in unfinished[unfinished_contributor]:
1.245 - unfinished[unfinished_contributor].append(node)
1.246 -
1.247 - # Set the current state of the usage on this node.
1.248 -
1.249 - node._attrcombined, node._attrcontributors = \
1.250 - self.get_usage_from_contributors_for_node(node)
1.251 -
1.252 - # Complete unfinished contributors relying on this node.
1.253 -
1.254 - if unfinished.has_key(node):
1.255 - processed = set()
1.256 - for contributor in unfinished[node]:
1.257 - if not contributor in processed:
1.258 - processed.add(contributor)
1.259 -
1.260 - contributor._attrcombined, contributor._attrcontributors = \
1.261 - self.get_usage_from_contributors_for_node(contributor)
1.262 -
1.263 - del unfinished[node]
1.264 -
1.265 - return unfinished
1.266 -
1.267 - def get_usage_from_contributors_for_node(self, node):
1.268 -
1.269 - # Visit each contributor, gathering usage for each name.
1.270 -
1.271 - contributor_usage = {}
1.272 - all_contributions = []
1.273 - all_contributors = set()
1.274 -
1.275 - for contributor in node._attrbranches:
1.276 - usage = contributor._attrcombined
1.277 - if usage is not Unset:
1.278 - all_contributions.append(usage)
1.279 -
1.280 - all_contributors.add(contributor)
1.281 - contributors = contributor._attrcontributors
1.282 - if contributors is not None:
1.283 - all_contributors.update(contributors)
1.284 -
1.285 - # Get contributed usage for each contributor.
1.286 - # This gathers usage for each name such as {(a, b), (c, d)} and
1.287 - # {(a, b), (e, f)} into a single set {(a, b), (c, d), (e, f)}.
1.288 -
1.289 - update_mapping_dict(contributor_usage, all_contributions)
1.290 -
1.291 - # Then get the resulting usage.
1.292 - # First, make the current usage compatible with the contributed
1.293 - # usage: this makes the attribute usage for each name merely one
1.294 - # member in a list of many possibilities.
1.295 - # Then, combine the current usage with the contributed usage.
1.296 - # Thus, usage of {(f, g)} combined with {(a, b), (c, d)} would give
1.297 - # {(f, g, a, b), (f, g, c, d)}.
1.298 -
1.299 - return combine_mapping_dicts(deepen_mapping_dict(node._attrnames), contributor_usage), all_contributors
1.300 -
1.301 - def use_attribute(self, name, attrname, value=None):
1.302 -
1.303 - """
1.304 - Note usage on the attribute user 'name' of the attribute 'attrname',
1.305 - noting an assignment if 'value' is specified.
1.306 - """
1.307 -
1.308 - return self._use_attribute(name, attrname, value)
1.309 -
1.310 - def use_specific_attribute(self, objname, attrname):
1.311 -
1.312 - "Declare the usage on 'objname' of the given 'attrname'."
1.313 -
1.314 - self._use_specific_attribute(objname, attrname)
1.315 -
1.316 - # These shadow various methods in the InspectedModule class, and provide
1.317 - # implementations generally.
1.318 -
1.319 - def _use_specific_attribute(self, objname, attrname, from_name=None):
1.320 -
1.321 - """
1.322 - Note attribute usage specifically on 'objname' - an object which is
1.323 - known at inspection time - or in the current unit if 'objname' is None,
1.324 - nominating a specific attribute 'attrname'.
1.325 -
1.326 - This bypasses attribute user mechanisms.
1.327 - """
1.328 -
1.329 - from_name = from_name or self.full_name()
1.330 - objname = objname or from_name
1.331 - module = self.module
1.332 - importer = module and module.importer
1.333 -
1.334 - if importer is not None:
1.335 - importer.use_specific_name(objname, attrname, from_name)
1.336 -
1.337 - def _use_attribute(self, name, attrname, value=None):
1.338 -
1.339 - """
1.340 - Indicate the use of the given 'name' in this namespace of an attribute
1.341 - with the given 'attrname'. If the optional 'value' is specified, an
1.342 - assignment using the given 'value' is recorded.
1.343 - """
1.344 -
1.345 - users = self.attribute_users[-1]
1.346 -
1.347 - # If no users are defined for the name, it cannot be handled.
1.348 -
1.349 - if not users.has_key(name):
1.350 - return []
1.351 -
1.352 - # Add the usage to all current users.
1.353 -
1.354 - for user in users[name]:
1.355 - values = user._attrnames[name]
1.356 - if values is None:
1.357 - values = user._attrnames[name] = ObjectSet()
1.358 -
1.359 - # Add an entry for the attribute, optionally with an assigned
1.360 - # value.
1.361 -
1.362 - values.add(attrname)
1.363 - if value is not None:
1.364 - values[attrname].add(value)
1.365 -
1.366 - return users[name]
1.367 -
1.368 - def _define_attribute_user(self, node):
1.369 -
1.370 - """
1.371 - Define 'node' as the user of attributes, indicating the point where the
1.372 - user is defined.
1.373 - """
1.374 -
1.375 - name = node.name
1.376 - self._define_attribute_user_for_name(node, name)
1.377 -
1.378 - def _define_attribute_user_for_name(self, node, name):
1.379 -
1.380 - "Define 'node' as the user of attributes for the given 'name'."
1.381 -
1.382 - users = self.attribute_users[-1]
1.383 -
1.384 - # This node overrides previous definitions.
1.385 -
1.386 - users[name] = set([node])
1.387 -
1.388 - # Record the attribute combinations for the name.
1.389 -
1.390 - self._init_attribute_user_for_name(node, name)
1.391 -
1.392 - # Remember this user.
1.393 -
1.394 - self.all_attribute_users.add(node)
1.395 -
1.396 - def _init_attribute_user_for_name(self, node, name):
1.397 -
1.398 - "Make sure that 'node' is initialised for 'name'."
1.399 -
1.400 - self._init_attribute_user(node)
1.401 - node._attrnames[name] = None
1.402 -
1.403 - def _init_attribute_user(self, node):
1.404 -
1.405 - # Attribute usage for names.
1.406 -
1.407 - if node._attrnames is None:
1.408 - node._attrnames = {}
1.409 - node._attrmerged = {}
1.410 -
1.411 - # Branches contributing usage to this node.
1.412 -
1.413 - if node._attrbranches is None:
1.414 - node._attrbranches = []
1.415 -
1.416 - # Definitions receiving usage from this node.
1.417 -
1.418 - if node._attrdefs is None:
1.419 - node._attrdefs = []
1.420 -
1.421 - def _define_attribute_accessor(self, name, attrname, node, value):
1.422 -
1.423 - # NOTE: Revisiting of nodes may occur for loops.
1.424 -
1.425 - if node._attrusers is None:
1.426 - node._attrusers = set()
1.427 -
1.428 - node._attrusers.update(self.use_attribute(name, attrname, value))
1.429 - node._username = name
1.430 -
1.431 - # Branch management methods.
1.432 -
1.433 - def _new_branchpoint(self, loop_node=None):
1.434 -
1.435 - """
1.436 - Establish a new branchpoint where several control-flow branches diverge
1.437 - and subsequently converge.
1.438 - """
1.439 -
1.440 - self.attribute_user_shelves.append([])
1.441 - self.scope_shelves.append([])
1.442 -
1.443 - if loop_node is not None:
1.444 - self.suspended_broken_users.append([])
1.445 - self.suspended_continuing_users.append((loop_node, []))
1.446 -
1.447 - def _new_branch(self, node):
1.448 -
1.449 - """
1.450 - Establish a new control-flow branch, transferring attribute usage to
1.451 - the new branch so that it may be augmented for each name locally.
1.452 -
1.453 - Add the given 'node' as an active user to be informed of attribute
1.454 - usage.
1.455 - """
1.456 -
1.457 - attribute_users = self.attribute_users[-1]
1.458 -
1.459 - # Define this node as the active attribute user for all currently
1.460 - # defined names.
1.461 -
1.462 - new_users = {}
1.463 -
1.464 - for name in attribute_users.keys():
1.465 - new_users[name] = [node]
1.466 - self._init_attribute_user_for_name(node, name)
1.467 -
1.468 - self._init_attribute_user(node)
1.469 - self.attribute_users.append(new_users)
1.470 -
1.471 - # Add this user as a contributor to the previously active users.
1.472 -
1.473 - self._connect_users_to_branch(attribute_users, node)
1.474 -
1.475 - # Retain a record of scope usage.
1.476 -
1.477 - scope_usage = {}
1.478 - scope_usage.update(self.scope_usage[-1])
1.479 - self.scope_usage.append(scope_usage)
1.480 -
1.481 - # Retain a record of abandoned branch users.
1.482 -
1.483 - self.abandoned_users.append([])
1.484 -
1.485 - def _connect_users_to_branch(self, attribute_users, node):
1.486 -
1.487 - """
1.488 - Given the 'attribute_users' mapping, connect the users referenced in the
1.489 - mapping to the given branch 'node'.
1.490 - """
1.491 -
1.492 - all_users = set()
1.493 -
1.494 - for users in attribute_users.values():
1.495 - all_users.update(users)
1.496 -
1.497 - for user in all_users:
1.498 - self._init_attribute_user(user)
1.499 - user._attrbranches.append(node)
1.500 -
1.501 - def _abandon_branch(self, retain_branch=True):
1.502 -
1.503 - """
1.504 - Abandon scope usage, permitting locally different scopes for names,
1.505 - provided these cannot "escape" from the branch.
1.506 - """
1.507 -
1.508 - attribute_users = self.attribute_users[-1]
1.509 -
1.510 - self.attribute_users[-1] = {}
1.511 - self.scope_usage[-1] = abandoned_branch_scope
1.512 -
1.513 - if retain_branch:
1.514 - self.abandoned_users[-1].append(attribute_users)
1.515 -
1.516 - def _suspend_broken_branch(self):
1.517 -
1.518 - """
1.519 - Suspend a branch for resumption after the current loop.
1.520 - """
1.521 -
1.522 - attribute_users = self.attribute_users[-1]
1.523 -
1.524 - users = self.suspended_broken_users[-1]
1.525 - users.append(attribute_users)
1.526 - self._abandon_branch(False)
1.527 -
1.528 - def _suspend_continuing_branch(self):
1.529 -
1.530 - """
1.531 - Suspend a branch for resumption after the current iteration.
1.532 - """
1.533 -
1.534 - attribute_users = self.attribute_users[-1]
1.535 -
1.536 - loop_node, users = self.suspended_continuing_users[-1]
1.537 - users.append(attribute_users)
1.538 - self._abandon_branch(False)
1.539 -
1.540 - def _shelve_branch(self):
1.541 -
1.542 - """
1.543 - Shelve the current control-flow branch, recording the attribute usage
1.544 - for subsequent merging. If this branch should be abandoned, the usage
1.545 - observations are still recorded but will not contribute to subsequent
1.546 - observations after a merge.
1.547 - """
1.548 -
1.549 - users = self.attribute_users.pop()
1.550 - self.attribute_user_shelves[-1].append(users)
1.551 -
1.552 - scope_usage = self.scope_usage.pop()
1.553 - self.scope_shelves[-1].append(scope_usage)
1.554 -
1.555 - def _merge_branches(self):
1.556 -
1.557 - """
1.558 - Merge control-flow branches. This should find the users active within
1.559 - each branch, which have been "shelved", and update the active users
1.560 - dictionary with these contributions.
1.561 - """
1.562 -
1.563 - # Combine the attribute users. This ensures that a list of users
1.564 - # affected by attribute usage is maintained for the current branch.
1.565 -
1.566 - all_shelved_users = self.attribute_user_shelves.pop()
1.567 - new_users = merge_mapping_dicts(all_shelved_users)
1.568 - self.attribute_users[-1] = new_users
1.569 -
1.570 - # Abandoned users are retained for exception handling purposes.
1.571 -
1.572 - all_abandoned_users = self.abandoned_users.pop()
1.573 - new_abandoned_users = merge_mapping_dicts(all_abandoned_users)
1.574 - self.abandoned_users[-1].append(new_abandoned_users)
1.575 -
1.576 - # Combine the scope usage.
1.577 -
1.578 - scope_usage = self.scope_usage[-1]
1.579 - new_scope_usage = {}
1.580 -
1.581 - all_scope_usage = self.scope_shelves.pop()
1.582 - all_scope_names = set()
1.583 -
1.584 - # Find all the names for whom scope information has been defined.
1.585 -
1.586 - for shelved_usage in all_scope_usage:
1.587 - all_scope_names.update(shelved_usage.keys())
1.588 -
1.589 - for shelved_usage in all_scope_usage:
1.590 - for name in all_scope_names:
1.591 -
1.592 - # Find the recorded scope for the name.
1.593 -
1.594 - if shelved_usage.has_key(name):
1.595 - scope = shelved_usage[name]
1.596 - elif scope_usage.has_key(name):
1.597 - scope = scope_usage[name]
1.598 -
1.599 - # For abandoned branches, no scope is asserted for a name.
1.600 -
1.601 - elif isinstance(shelved_usage, AbandonedBranchScope):
1.602 - scope = None
1.603 -
1.604 - # If no scope is recorded, find a suitable external source.
1.605 -
1.606 - else:
1.607 - attr, scope, full_name = self._get_with_scope(name, external=1)
1.608 -
1.609 - # Attempt to record the scope, testing for conflicts.
1.610 -
1.611 - if scope:
1.612 - if not new_scope_usage.has_key(name):
1.613 - new_scope_usage[name] = scope
1.614 - else:
1.615 - new_scope = new_scope_usage[name]
1.616 - if new_scope != scope:
1.617 - if isinstance(new_scope, ScopeConflict):
1.618 - if isinstance(scope, ScopeConflict):
1.619 - scopes = scope.scopes.union(new_scope.scopes)
1.620 - else:
1.621 - scopes = new_scope.scopes.union(set([scope]))
1.622 - elif isinstance(scope, ScopeConflict):
1.623 - scopes = scope.scopes.union(set([new_scope]))
1.624 - else:
1.625 - scopes = set([scope, new_scope])
1.626 - new_scope_usage[name] = ScopeConflict(scopes)
1.627 -
1.628 - self.scope_usage[-1] = new_scope_usage
1.629 -
1.630 - def _resume_broken_branches(self):
1.631 -
1.632 - """
1.633 - Incorporate users from suspended broken branches into the current set of
1.634 - active users.
1.635 - """
1.636 -
1.637 - suspended_users = self.suspended_broken_users.pop()
1.638 - current_users = self.attribute_users[-1]
1.639 - new_users = merge_mapping_dicts(suspended_users + [current_users])
1.640 - self.attribute_users[-1] = new_users
1.641 -
1.642 - def _resume_continuing_branches(self):
1.643 -
1.644 - """
1.645 - Incorporate users from suspended continuing branches into the current
1.646 - set of active users, merging usage from the latter with the former.
1.647 - """
1.648 -
1.649 - loop_node, suspended_users = self.suspended_continuing_users.pop()
1.650 - current_users = self.attribute_users[-1]
1.651 -
1.652 - # Connect the suspended users to the loop node.
1.653 -
1.654 - for users in suspended_users:
1.655 - self._connect_users_to_branch(users, loop_node)
1.656 -
1.657 - # Merge suspended branches with the current branch.
1.658 -
1.659 - new_users = merge_mapping_dicts(suspended_users + [current_users])
1.660 - self.attribute_users[-1] = new_users
1.661 -
1.662 - def _resume_abandoned_branches(self):
1.663 -
1.664 - """
1.665 - Incorporate users from abandoned branches into the current set of active
1.666 - users. The abandoned branches are taken from the containing branch.
1.667 - """
1.668 -
1.669 - current_users = self.attribute_users[-1]
1.670 - abandoned_users = self.abandoned_users[-2]
1.671 - new_users = merge_mapping_dicts(abandoned_users + [current_users])
1.672 - self.attribute_users[-1] = new_users
1.673 -
1.674 - # Scope usage methods.
1.675 -
1.676 - def define_scope(self, name, scope):
1.677 -
1.678 - """
1.679 - Define 'name' as being from the given 'scope' in the current namespace.
1.680 - """
1.681 -
1.682 - self.scope_usage[-1][name] = scope
1.683 -
1.684 - def note_scope(self, name, scope):
1.685 -
1.686 - """
1.687 - Note usage of 'name' from the given 'scope' in the current namespace.
1.688 - If a conflict has been recorded previously, raise an exception.
1.689 - """
1.690 -
1.691 - scope_usage = self.scope_usage[-1]
1.692 -
1.693 - if scope_usage.has_key(name):
1.694 - found_scope = scope_usage[name]
1.695 - if isinstance(found_scope, ScopeConflict):
1.696 - raise InspectError("Scope conflict for %r: defined as %s." % (
1.697 - name, ", ".join(found_scope.scopes)))
1.698 -
1.699 - scope_usage[name] = scope
1.700 -
1.701 - def used_in_scope(self, name, scope):
1.702 -
1.703 - """
1.704 - Return whether 'name' is used from the given 'scope' in the current
1.705 - namespace.
1.706 - """
1.707 -
1.708 - scope_usage = self.scope_usage[-1]
1.709 - return scope_usage.get(name) == scope
1.710 -
1.711 -# Special helper classes for usage and scope resolution.
1.712 -
1.713 -class EmptyDict:
1.714 -
1.715 - "A class providing dictionaries which retain no information."
1.716 -
1.717 - def has_key(self, name):
1.718 - return False
1.719 -
1.720 - def __setitem__(self, name, value):
1.721 - pass
1.722 -
1.723 - def __getitem__(self, name):
1.724 - raise KeyError, name
1.725 -
1.726 - def get(self, name, default=None):
1.727 - return default
1.728 -
1.729 - def keys(self):
1.730 - return []
1.731 -
1.732 - values = items = keys
1.733 -
1.734 -class AbandonedBranchScope(EmptyDict):
1.735 -
1.736 - """
1.737 - A class providing a value or state for an abandoned branch distinct from an
1.738 - empty scope dictionary.
1.739 - """
1.740 -
1.741 - pass
1.742 -
1.743 -abandoned_branch_scope = AbandonedBranchScope()
1.744 -
1.745 -class ScopeConflict:
1.746 -
1.747 - """
1.748 - A scope conflict caused when different code branches contribute different
1.749 - sources of names.
1.750 - """
1.751 -
1.752 - def __init__(self, scopes):
1.753 - self.scopes = scopes
1.754 -
1.755 -class NullBranch(AttributeUser):
1.756 -
1.757 - "A class representing an attribute user for a non-existent branch."
1.758 -
1.759 - pass
1.760 -
1.761 # Program data structures.
1.762
1.763 class Attr:
1.764 @@ -2227,13 +1534,4 @@
1.765 def __repr__(self):
1.766 return "AtLeast(%r)" % self.count
1.767
1.768 -class UnsetType:
1.769 -
1.770 - "A None-like value."
1.771 -
1.772 - def __nonzero__(self):
1.773 - return False
1.774 -
1.775 -Unset = UnsetType()
1.776 -
1.777 # vim: tabstop=4 expandtab shiftwidth=4