1 #!/usr/bin/env python 2 3 """ 4 Program data structures. There are two separate kinds of structures: those with 5 context, which are the values manipulated by programs, and those without 6 context, which are typically constant things which are stored alongside the 7 program but which are wrapped in context-dependent structures in the running 8 program. 9 10 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Paul Boddie <paul@boddie.org.uk> 11 12 This program is free software; you can redistribute it and/or modify it under 13 the terms of the GNU General Public License as published by the Free Software 14 Foundation; either version 3 of the License, or (at your option) any later 15 version. 16 17 This program is distributed in the hope that it will be useful, but WITHOUT 18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 20 details. 21 22 You should have received a copy of the GNU General Public License along with 23 this program. If not, see <http://www.gnu.org/licenses/>. 24 25 -------- 26 27 The principal value structure class in this module is the Attr class which 28 represents attributes of objects and retains the context of each reference to an 29 attribute. This class models program behaviour at run-time. 30 31 The central data structure classes in this module are the following: 32 33 * Class 34 * Function 35 * Module 36 37 All of the above support the Naming interface either explicitly or through 38 general conformance, meaning that all can be asked to provide their 'full_name' 39 using the method of that name. 40 41 Additionally, all of the above also support a dictionary interface in order to 42 access names within their defined scopes. Specific methods also exist in order 43 to distinguish between certain kinds of attributes: 44 45 * Class: class_attributes, all_class_attributes, instance_attributes, all_attributes 46 * Function: parameters, locals, all_locals 47 * Module: module_attributes 48 49 These specific methods are useful in certain situations. 50 51 The above classes also provide an 'astnode' attribute, indicating the AST node 52 where each such object is defined. 53 """ 54 55 from compiler.ast import AttributeUser 56 from micropython.program import ReplaceableContext, PlaceholderContext 57 from micropython.basicdata import * 58 from micropython.errors import * 59 from micropython.objectset import * 60 from micropython.types import * 61 import sys 62 63 try: 64 set 65 except NameError: 66 from sets import Set as set 67 68 class NamespaceDict(Namespace): 69 70 "A mix-in providing dictionary methods." 71 72 def __init__(self, module=None): 73 self.module = module 74 self.namespace = {} 75 self.globals = set() 76 self.lambdas = {} # only really useful for functions 77 self.finalised = False 78 79 # Attributes accessed on objects, potentially narrowing their types. 80 # Specific namespaces should define known names during initialisation. 81 # For example, functions can define names belonging to parameters. 82 83 # Attribute users, defining names which use attributes. 84 85 self.attribute_users = [{}] # stack of assignments and branches 86 self.attribute_user_shelves = [] 87 88 # Suspended user details plus loop details. 89 90 self.suspended_broken_users = [] # stack of lists of user dicts 91 self.suspended_continuing_users = [] # stack of lists of user dicts 92 93 # Scope usage, indicating the origin of names. 94 95 self.scope_usage = [{}] # stack of scope usage 96 self.scope_shelves = [] 97 98 # Abandoned usage, useful for reviving usage for exception handlers. 99 100 self.abandoned_users = [[]] # stack of lists of users 101 102 # Define attribute usage to identify active program sections. 103 # Attribute users are AST nodes defining names. 104 105 self.all_attribute_users = set() 106 107 # Attribute/name definition and access. 108 109 def __delitem__(self, name): 110 del self.namespace[name] 111 112 def has_key(self, name): 113 return self.namespace.has_key(name) 114 115 def keys(self): 116 return self.namespace.keys() 117 118 def values(self): 119 return self.namespace.values() 120 121 def items(self): 122 return self.namespace.items() 123 124 def __getitem__(self, name): 125 return self.namespace[name] 126 127 def get(self, name, default=None): 128 return self.namespace.get(name, default) 129 130 # Administrative methods. 131 132 def finalise(self, objtable): 133 self.finalise_attributes() 134 self.finalise_users(objtable) 135 136 def items_for_vacuum(self): 137 return self.items() + self.lambdas.items() 138 139 def vacuum_item(self, name): 140 if self.has_key(name): 141 del self[name] 142 return True 143 else: 144 return False 145 146 def add_lambda(self, obj): 147 attr = Attr(None, self, obj.name) 148 attr.update([self.get_context_and_value(obj)], single_assignment=1) 149 self.lambdas[obj.name] = attr 150 151 # Specialised access methods. 152 153 def get_using_node(self, name, node): 154 155 """ 156 Access the given 'name' through this namespace, making use of the module 157 and builtins namespaces if necessary, annotating the given 'node' with 158 the scope involved. 159 """ 160 161 attr, scope, full_name = self._get_with_scope(name) 162 163 if scope is not None: 164 node._scope = scope 165 self.note_scope(name, scope) 166 167 if full_name is not None and (scope != "local" or isinstance(self, (Class, Module))): 168 self.use_specific_attribute(full_name, name) 169 170 return attr 171 172 def _get_with_scope(self, name, external=0): 173 174 """ 175 Find the source of the given 'name', returning the attribute object, 176 scope (constant, local, global or builtins), and the full name of the 177 source namespace (or None for constants). 178 179 If the optional 'external' flag is set to a true value, only external 180 (non-local) namespaces will be involved in the search. 181 """ 182 183 module = self.module 184 builtins = module and module.builtins or None 185 importer = module and module.importer or None 186 187 # Constants. 188 189 if importer is not None and importer.predefined_constants.has_key(name): 190 return importer.get_predefined_constant(name), "constant", None 191 192 # Locals. 193 194 elif not external and self.has_key(name): 195 return self[name], "local", self.full_name() 196 197 # Globals. 198 199 elif module is not None and module is not self and module.has_key(name): 200 return module[name], "global", module.full_name() 201 202 # Builtins. 203 204 elif builtins is not None and builtins.has_key(name): 205 return builtins[name], "builtins", builtins.full_name() 206 207 # Unknown. 208 209 else: 210 return None, None, None 211 212 # Attribute definition methods. 213 214 def __setitem__(self, name, value): 215 self.set(name, value) 216 217 def set(self, name, value, single_assignment=1): 218 219 """ 220 A more powerful set operation, making 'name' refer to 'value' whilst 221 indicating whether a 'single_assignment' (true by default) occurs in 222 this operation (or whether the operation covers potentially many 223 assignments in the lifetime of a program). 224 """ 225 226 if value is None: 227 print >>sys.stderr, "Warning: name %r in namespace %r has an unknown value (evaluated to None)." % (name, self.full_name()) 228 value = make_instance() 229 230 if name in self.globals: 231 self.module.set(name, value, 0) 232 else: 233 self._set(name, value, single_assignment) 234 self.define_scope(name, "local") 235 236 def set_module(self, name, value): 237 238 """ 239 A specialised set operation, making 'name' refer to 'value' in the 240 context of making a module reference available in association with 241 'name' as part of the import of that module or a submodule of that 242 module. 243 """ 244 245 self._set(name, value, 1) 246 247 def _set(self, name, attr_or_value, single_assignment=1): 248 249 """ 250 The underlying set operation associating 'name' with the given 251 'attr_or_value'. 252 See: docs/assignment.txt 253 """ 254 255 # Add and/or obtain the namespace entry. 256 257 if not self.namespace.has_key(name): 258 self.namespace[name] = Attr(None, self, name) 259 260 attr = self.namespace[name] 261 self._set_using_attr(attr, attr_or_value, single_assignment) 262 263 def _set_using_attr(self, attr, attr_or_value, single_assignment=1): 264 265 # Handle attribute assignment as well as assignment of basic objects. 266 # Attempt to fix the context if not explicitly defined. 267 268 if isinstance(attr_or_value, Attr): 269 context_values = self.get_updated_context_values(attr_or_value.context_values) 270 else: 271 context_values = self.get_updated_context_values([self.get_context_and_value(attr_or_value)]) 272 273 attr.update(context_values, single_assignment) 274 275 def get_context_and_value(self, value): 276 277 "Return a context, value tuple for the given 'value'." 278 279 # Functions have a replaceable context. 280 281 if isinstance(value, Function): 282 return (ReplaceableContext, value) 283 284 # Classes use placeholder contexts which cannot be replaced but which 285 # do not communicate useful contextual information. 286 287 elif isinstance(value, Class): 288 return (PlaceholderContext, value) 289 290 # Other values employ themselves as the context. 291 292 else: 293 return (value, value) 294 295 def get_updated_context_values(self, context_values): 296 297 """ 298 Adapt the contexts found in the given 'context_values', returning a new 299 set. 300 See: docs/assignment.txt 301 """ 302 303 results = set() 304 305 for context, value in context_values: 306 307 # Set the context of instances to themselves. 308 309 if isinstance(value, Instance): 310 results.add((value, value)) 311 else: 312 results.add((context, value)) 313 314 return results 315 316 def make_global(self, name): 317 318 "Declare 'name' as a global in the current namespace." 319 320 if not self.namespace.has_key(name): 321 self.globals.add(name) 322 self.define_scope(name, "global") 323 return True 324 else: 325 return False 326 327 # Attribute positioning. 328 329 def attributes_as_list(self): 330 331 "Return the attributes in a list." 332 333 self.finalise_attributes() 334 l = [None] * len(self.keys()) 335 for attr in self.values(): 336 l[attr.position] = attr 337 return l 338 339 def finalise_attributes(self): 340 341 "Make sure all attributes are fully defined." 342 343 if self.finalised: 344 return 345 346 # The default action is to assign attribute positions sequentially. 347 348 for i, attr in enumerate(self.values()): 349 attr.position = i 350 351 self.finalised = True 352 353 def unfinalise_attributes(self): 354 355 "Open attribute definitions to editing and subsequent finalisation." 356 357 self.finalised = False 358 359 # Attribute usage methods. 360 361 def finalise_attribute_usage(self): 362 363 "Propagate attribute usage for the namespace to the importer." 364 365 module = self.module 366 importer = module and module.importer 367 368 if importer is not None: 369 370 # Visit each user and examine the attribute usage for each name. 371 372 for user in self.all_attribute_users: 373 374 # First, visit the contributors and combine their attribute 375 # usage with the usage recorded directly on the user. 376 377 self.get_usage_from_contributors(user) 378 379 # Record the defining user on each contributor. 380 381 for contributor in user._attrcontributors: 382 contributor._attrdefs.append(user) 383 384 # Then, tell the importer about the usage. 385 386 for name in user._attrnames.keys(): 387 388 # Only provide information about names defined by this user. 389 390 usage = user._attrcombined.get(name, []) 391 392 # Skip reporting where no actual usage occurs. 393 394 if usage is None: 395 continue 396 397 # Eliminate non-usage. 398 399 importer.use_names(user, name, tuple([attrnames for attrnames in usage if attrnames]), self.full_name()) 400 401 def finalise_users(self, objtable): 402 403 "Record the object types for generating guards." 404 405 # Visit each user and examine the attribute usage for each name. 406 407 for user in self.all_attribute_users: 408 user._attrtypes = self._deduce_types(user._attrcombined, objtable) 409 self._finalise_contributor(user, objtable) 410 411 def _finalise_contributors(self, node, objtable): 412 413 """ 414 Visit the contributing branches of 'node', finalising them using the 415 given 'objtable'. 416 """ 417 418 for contributor in node._attrbranches: 419 self._finalise_contributor(contributor, objtable) 420 421 def _finalise_contributor(self, node, objtable): 422 423 """ 424 Record the specific object types being used in various regions of a 425 program unit. 426 """ 427 428 if node._attrspecifictypes is None: 429 merged = {} 430 431 # Get the combined usage information from the user definitions. 432 433 for user in node._attrdefs or [node]: 434 435 # Filter the usage for each name using the local usage 436 # information. 437 438 for name, usage in user._attrcombined.items(): 439 localusage = node._attrnames.get(name) 440 441 if usage and localusage: 442 if not merged.has_key(name): 443 merged[name] = ObjectSet() 444 445 for attrnames, value in usage.items(): 446 if attrnames and localusage.issubset(attrnames): 447 merged[name][attrnames] = value 448 449 node._attrmerged = merged 450 node._attrspecifictypes = self._deduce_types(node._attrmerged, objtable) 451 452 self._finalise_contributors(node, objtable) 453 454 def _deduce_types(self, usage, objtable): 455 456 """ 457 Deduce the types for names from the given attribute 'usage' and using 458 the given 'objtable'. 459 """ 460 461 attrtypes = {} 462 for name, combined_usage in usage.items(): 463 if combined_usage is not None: 464 objtypes = get_object_types_for_usage(combined_usage, objtable, name, self.full_name(), True, self.module.importer) 465 if objtypes: 466 if isinstance(self, Function) and self.is_method() and name == "self": 467 objtypes = filter_using_self(objtypes, self.parent) 468 attrtypes[name] = objtypes 469 return attrtypes 470 471 def get_usage_from_contributors(self, node): 472 473 """ 474 Obtain usage information from the given 'node', combined with usage 475 details from its contributors, returning a tuple containing a set of all 476 contributors employed along with a dictionary mapping names to lists of 477 usage possibilities (each a collection of attribute names). 478 """ 479 480 unfinished = {} 481 482 # Process any unprocessed contributors, indicating the unfinished state 483 # of the associated data. 484 485 if node._attrcombined is None: 486 node._attrcombined = Unset 487 488 for contributor in node._attrbranches: 489 490 # Get contributor details. 491 492 unfinished_contributors = self.get_usage_from_contributors(contributor) 493 494 # Collect unfinished contributors and affected nodes. 495 496 # Where the contributor is already set to Unset, a loop has 497 # occurred and this node will need to have its usage 498 # recalculated later for the unfinished contributor. 499 500 if contributor._attrcombined is Unset: 501 if not unfinished.has_key(contributor): 502 unfinished[contributor] = [] 503 unfinished[contributor].append(node) 504 continue 505 506 # Where the contributor provides usage details, it may also 507 # communicate unfinished contributor information. As a 508 # consequence, this node is also affected. 509 510 for unfinished_contributor, nodes in unfinished_contributors.items(): 511 if not unfinished.has_key(unfinished_contributor): 512 unfinished[unfinished_contributor] = nodes 513 else: 514 unfinished[unfinished_contributor] += nodes 515 516 if node not in unfinished[unfinished_contributor]: 517 unfinished[unfinished_contributor].append(node) 518 519 # Set the current state of the usage on this node. 520 521 node._attrcombined, node._attrcontributors = \ 522 self.get_usage_from_contributors_for_node(node) 523 524 # Complete unfinished contributors relying on this node. 525 526 if unfinished.has_key(node): 527 processed = set() 528 for contributor in unfinished[node]: 529 if not contributor in processed: 530 processed.add(contributor) 531 532 contributor._attrcombined, contributor._attrcontributors = \ 533 self.get_usage_from_contributors_for_node(contributor) 534 535 del unfinished[node] 536 537 return unfinished 538 539 def get_usage_from_contributors_for_node(self, node): 540 541 # Visit each contributor, gathering usage for each name. 542 543 contributor_usage = {} 544 all_contributions = [] 545 all_contributors = set() 546 547 for contributor in node._attrbranches: 548 usage = contributor._attrcombined 549 if usage is not Unset: 550 all_contributions.append(usage) 551 552 all_contributors.add(contributor) 553 contributors = contributor._attrcontributors 554 if contributors is not None: 555 all_contributors.update(contributors) 556 557 # Get contributed usage for each contributor. 558 # This gathers usage for each name such as {(a, b), (c, d)} and 559 # {(a, b), (e, f)} into a single set {(a, b), (c, d), (e, f)}. 560 561 update_mapping_dict(contributor_usage, all_contributions) 562 563 # Then get the resulting usage. 564 # First, make the current usage compatible with the contributed 565 # usage: this makes the attribute usage for each name merely one 566 # member in a list of many possibilities. 567 # Then, combine the current usage with the contributed usage. 568 # Thus, usage of {(f, g)} combined with {(a, b), (c, d)} would give 569 # {(f, g, a, b), (f, g, c, d)}. 570 571 return combine_mapping_dicts(deepen_mapping_dict(node._attrnames), contributor_usage), all_contributors 572 573 def use_attribute(self, name, attrname, value=None): 574 575 """ 576 Note usage on the attribute user 'name' of the attribute 'attrname', 577 noting an assignment if 'value' is specified. 578 """ 579 580 return self._use_attribute(name, attrname, value) 581 582 def use_specific_attribute(self, objname, attrname): 583 584 "Declare the usage on 'objname' of the given 'attrname'." 585 586 self._use_specific_attribute(objname, attrname) 587 588 # These shadow various methods in the InspectedModule class, and provide 589 # implementations generally. 590 591 def _use_specific_attribute(self, objname, attrname, from_name=None): 592 593 """ 594 Note attribute usage specifically on 'objname' - an object which is 595 known at inspection time - or in the current unit if 'objname' is None, 596 nominating a specific attribute 'attrname'. 597 598 This bypasses attribute user mechanisms. 599 """ 600 601 from_name = from_name or self.full_name() 602 objname = objname or from_name 603 module = self.module 604 importer = module and module.importer 605 606 if importer is not None: 607 importer.use_specific_name(objname, attrname, from_name) 608 609 def _use_attribute(self, name, attrname, value=None): 610 611 """ 612 Indicate the use of the given 'name' in this namespace of an attribute 613 with the given 'attrname'. If the optional 'value' is specified, an 614 assignment using the given 'value' is recorded. 615 """ 616 617 users = self.attribute_users[-1] 618 619 # If no users are defined for the name, it cannot be handled. 620 621 if not users.has_key(name): 622 return [] 623 624 # Add the usage to all current users. 625 626 for user in users[name]: 627 values = user._attrnames[name] 628 if values is None: 629 values = user._attrnames[name] = ObjectSet() 630 631 # Add an entry for the attribute, optionally with an assigned 632 # value. 633 634 values.add(attrname) 635 if value is not None: 636 values[attrname].add(value) 637 638 return users[name] 639 640 def _define_attribute_user(self, node): 641 642 """ 643 Define 'node' as the user of attributes, indicating the point where the 644 user is defined. 645 """ 646 647 name = node.name 648 self._define_attribute_user_for_name(node, name) 649 650 def _define_attribute_user_for_name(self, node, name): 651 652 "Define 'node' as the user of attributes for the given 'name'." 653 654 users = self.attribute_users[-1] 655 656 # This node overrides previous definitions. 657 658 users[name] = set([node]) 659 660 # Record the attribute combinations for the name. 661 662 self._init_attribute_user_for_name(node, name) 663 664 # Remember this user. 665 666 self.all_attribute_users.add(node) 667 668 def _init_attribute_user_for_name(self, node, name): 669 670 "Make sure that 'node' is initialised for 'name'." 671 672 self._init_attribute_user(node) 673 node._attrnames[name] = None 674 675 def _init_attribute_user(self, node): 676 677 # Attribute usage for names. 678 679 if node._attrnames is None: 680 node._attrnames = {} 681 node._attrmerged = {} 682 683 # Branches contributing usage to this node. 684 685 if node._attrbranches is None: 686 node._attrbranches = [] 687 688 # Definitions receiving usage from this node. 689 690 if node._attrdefs is None: 691 node._attrdefs = [] 692 693 def _define_attribute_accessor(self, name, attrname, node, value): 694 695 # NOTE: Revisiting of nodes may occur for loops. 696 697 if node._attrusers is None: 698 node._attrusers = set() 699 700 node._attrusers.update(self.use_attribute(name, attrname, value)) 701 node._username = name 702 703 # Branch management methods. 704 705 def _new_branchpoint(self, loop_node=None): 706 707 """ 708 Establish a new branchpoint where several control-flow branches diverge 709 and subsequently converge. 710 """ 711 712 self.attribute_user_shelves.append([]) 713 self.scope_shelves.append([]) 714 715 if loop_node is not None: 716 self.suspended_broken_users.append([]) 717 self.suspended_continuing_users.append((loop_node, [])) 718 719 def _new_branch(self, node): 720 721 """ 722 Establish a new control-flow branch, transferring attribute usage to 723 the new branch so that it may be augmented for each name locally. 724 725 Add the given 'node' as an active user to be informed of attribute 726 usage. 727 """ 728 729 attribute_users = self.attribute_users[-1] 730 731 # Define this node as the active attribute user for all currently 732 # defined names. 733 734 new_users = {} 735 736 for name in attribute_users.keys(): 737 new_users[name] = [node] 738 self._init_attribute_user_for_name(node, name) 739 740 self._init_attribute_user(node) 741 self.attribute_users.append(new_users) 742 743 # Add this user as a contributor to the previously active users. 744 745 self._connect_users_to_branch(attribute_users, node) 746 747 # Retain a record of scope usage. 748 749 scope_usage = {} 750 scope_usage.update(self.scope_usage[-1]) 751 self.scope_usage.append(scope_usage) 752 753 # Retain a record of abandoned branch users. 754 755 self.abandoned_users.append([]) 756 757 def _connect_users_to_branch(self, attribute_users, node): 758 759 """ 760 Given the 'attribute_users' mapping, connect the users referenced in the 761 mapping to the given branch 'node'. 762 """ 763 764 all_users = set() 765 766 for users in attribute_users.values(): 767 all_users.update(users) 768 769 for user in all_users: 770 self._init_attribute_user(user) 771 user._attrbranches.append(node) 772 773 def _abandon_branch(self, retain_branch=True): 774 775 """ 776 Abandon scope usage, permitting locally different scopes for names, 777 provided these cannot "escape" from the branch. 778 """ 779 780 attribute_users = self.attribute_users[-1] 781 782 self.attribute_users[-1] = {} 783 self.scope_usage[-1] = abandoned_branch_scope 784 785 if retain_branch: 786 self.abandoned_users[-1].append(attribute_users) 787 788 def _suspend_broken_branch(self): 789 790 """ 791 Suspend a branch for resumption after the current loop. 792 """ 793 794 attribute_users = self.attribute_users[-1] 795 796 users = self.suspended_broken_users[-1] 797 users.append(attribute_users) 798 self._abandon_branch(False) 799 800 def _suspend_continuing_branch(self): 801 802 """ 803 Suspend a branch for resumption after the current iteration. 804 """ 805 806 attribute_users = self.attribute_users[-1] 807 808 loop_node, users = self.suspended_continuing_users[-1] 809 users.append(attribute_users) 810 self._abandon_branch(False) 811 812 def _shelve_branch(self): 813 814 """ 815 Shelve the current control-flow branch, recording the attribute usage 816 for subsequent merging. If this branch should be abandoned, the usage 817 observations are still recorded but will not contribute to subsequent 818 observations after a merge. 819 """ 820 821 users = self.attribute_users.pop() 822 self.attribute_user_shelves[-1].append(users) 823 824 scope_usage = self.scope_usage.pop() 825 self.scope_shelves[-1].append(scope_usage) 826 827 def _merge_branches(self): 828 829 """ 830 Merge control-flow branches. This should find the users active within 831 each branch, which have been "shelved", and update the active users 832 dictionary with these contributions. 833 """ 834 835 # Combine the attribute users. This ensures that a list of users 836 # affected by attribute usage is maintained for the current branch. 837 838 all_shelved_users = self.attribute_user_shelves.pop() 839 new_users = merge_mapping_dicts(all_shelved_users) 840 self.attribute_users[-1] = new_users 841 842 # Abandoned users are retained for exception handling purposes. 843 844 all_abandoned_users = self.abandoned_users.pop() 845 new_abandoned_users = merge_mapping_dicts(all_abandoned_users) 846 self.abandoned_users[-1].append(new_abandoned_users) 847 848 # Combine the scope usage. 849 850 scope_usage = self.scope_usage[-1] 851 new_scope_usage = {} 852 853 all_scope_usage = self.scope_shelves.pop() 854 all_scope_names = set() 855 856 # Find all the names for whom scope information has been defined. 857 858 for shelved_usage in all_scope_usage: 859 all_scope_names.update(shelved_usage.keys()) 860 861 for shelved_usage in all_scope_usage: 862 for name in all_scope_names: 863 864 # Find the recorded scope for the name. 865 866 if shelved_usage.has_key(name): 867 scope = shelved_usage[name] 868 elif scope_usage.has_key(name): 869 scope = scope_usage[name] 870 871 # For abandoned branches, no scope is asserted for a name. 872 873 elif isinstance(shelved_usage, AbandonedBranchScope): 874 scope = None 875 876 # If no scope is recorded, find a suitable external source. 877 878 else: 879 attr, scope, full_name = self._get_with_scope(name, external=1) 880 881 # Attempt to record the scope, testing for conflicts. 882 883 if scope: 884 if not new_scope_usage.has_key(name): 885 new_scope_usage[name] = scope 886 else: 887 new_scope = new_scope_usage[name] 888 if new_scope != scope: 889 if isinstance(new_scope, ScopeConflict): 890 if isinstance(scope, ScopeConflict): 891 scopes = scope.scopes.union(new_scope.scopes) 892 else: 893 scopes = new_scope.scopes.union(set([scope])) 894 elif isinstance(scope, ScopeConflict): 895 scopes = scope.scopes.union(set([new_scope])) 896 else: 897 scopes = set([scope, new_scope]) 898 new_scope_usage[name] = ScopeConflict(scopes) 899 900 self.scope_usage[-1] = new_scope_usage 901 902 def _resume_broken_branches(self): 903 904 """ 905 Incorporate users from suspended broken branches into the current set of 906 active users. 907 """ 908 909 suspended_users = self.suspended_broken_users.pop() 910 current_users = self.attribute_users[-1] 911 new_users = merge_mapping_dicts(suspended_users + [current_users]) 912 self.attribute_users[-1] = new_users 913 914 def _resume_continuing_branches(self): 915 916 """ 917 Incorporate users from suspended continuing branches into the current 918 set of active users, merging usage from the latter with the former. 919 """ 920 921 loop_node, suspended_users = self.suspended_continuing_users.pop() 922 current_users = self.attribute_users[-1] 923 924 # Connect the suspended users to the loop node. 925 926 for users in suspended_users: 927 self._connect_users_to_branch(users, loop_node) 928 929 # Merge suspended branches with the current branch. 930 931 new_users = merge_mapping_dicts(suspended_users + [current_users]) 932 self.attribute_users[-1] = new_users 933 934 def _resume_abandoned_branches(self): 935 936 """ 937 Incorporate users from abandoned branches into the current set of active 938 users. The abandoned branches are taken from the containing branch. 939 """ 940 941 current_users = self.attribute_users[-1] 942 abandoned_users = self.abandoned_users[-2] 943 new_users = merge_mapping_dicts(abandoned_users + [current_users]) 944 self.attribute_users[-1] = new_users 945 946 # Scope usage methods. 947 948 def define_scope(self, name, scope): 949 950 """ 951 Define 'name' as being from the given 'scope' in the current namespace. 952 """ 953 954 self.scope_usage[-1][name] = scope 955 956 def note_scope(self, name, scope): 957 958 """ 959 Note usage of 'name' from the given 'scope' in the current namespace. 960 If a conflict has been recorded previously, raise an exception. 961 """ 962 963 scope_usage = self.scope_usage[-1] 964 965 if scope_usage.has_key(name): 966 found_scope = scope_usage[name] 967 if isinstance(found_scope, ScopeConflict): 968 raise InspectError("Scope conflict for %r: defined as %s." % ( 969 name, ", ".join(found_scope.scopes))) 970 971 scope_usage[name] = scope 972 973 def used_in_scope(self, name, scope): 974 975 """ 976 Return whether 'name' is used from the given 'scope' in the current 977 namespace. 978 """ 979 980 scope_usage = self.scope_usage[-1] 981 return scope_usage.get(name) == scope 982 983 # Special helper classes for usage and scope resolution. 984 985 class EmptyDict: 986 987 "A class providing dictionaries which retain no information." 988 989 def has_key(self, name): 990 return False 991 992 def __setitem__(self, name, value): 993 pass 994 995 def __getitem__(self, name): 996 raise KeyError, name 997 998 def get(self, name, default=None): 999 return default 1000 1001 def keys(self): 1002 return [] 1003 1004 values = items = keys 1005 1006 class AbandonedBranchScope(EmptyDict): 1007 1008 """ 1009 A class providing a value or state for an abandoned branch distinct from an 1010 empty scope dictionary. 1011 """ 1012 1013 pass 1014 1015 abandoned_branch_scope = AbandonedBranchScope() 1016 1017 class ScopeConflict: 1018 1019 """ 1020 A scope conflict caused when different code branches contribute different 1021 sources of names. 1022 """ 1023 1024 def __init__(self, scopes): 1025 self.scopes = scopes 1026 1027 class NullBranch(AttributeUser): 1028 1029 "A class representing an attribute user for a non-existent branch." 1030 1031 pass 1032 1033 # Program data structures. 1034 1035 class Attr: 1036 1037 "An attribute entry having a context." 1038 1039 def __init__(self, position, parent, name): 1040 1041 """ 1042 Initialise the attribute with the given 'position' within the collection 1043 of attributes of its 'parent', indicating its 'name'. 1044 """ 1045 1046 self.position = position 1047 self.parent = parent 1048 self.name = name 1049 1050 # Possible values. 1051 1052 self.context_values = set() 1053 1054 # Number of assignments per name. 1055 1056 self.assignments = None 1057 1058 # Value-related methods. 1059 1060 def get_contexts(self): 1061 return [c for (c, v) in self.context_values] 1062 1063 def get_values(self): 1064 return [v for (c, v) in self.context_values] 1065 1066 def get_context(self): 1067 1068 "Get the context referenced by the attribute." 1069 1070 if self.assignments == 1 and len(self.context_values) == 1: 1071 return self.get_contexts()[0] 1072 else: 1073 return None 1074 1075 def get_value(self): 1076 1077 "Get the value referenced by the attribute." 1078 1079 if self.assignments == 1 and len(self.context_values) == 1: 1080 return self.get_values()[0] 1081 else: 1082 return None 1083 1084 __call__ = get_value # convenient access to any single value 1085 1086 def update(self, context_values, single_assignment): 1087 1088 """ 1089 Update the attribute, adding the 'context_values' provided to the 1090 known details associated with the attribute, changing the number of 1091 assignments according to the 'single_assignment' status of the 1092 operation, where a true value indicates that only one assignment is 1093 associated with the update, and a false value indicates that potentially 1094 many assignments may be involved. 1095 """ 1096 1097 if self.context_values.issuperset(context_values) and \ 1098 not (make_instance(), make_instance()) in context_values: 1099 return 1100 1101 self.update_assignments(len(set(context_values)), single_assignment) 1102 self.context_values.update(context_values) 1103 1104 def update_assignments(self, n, single_assignment): 1105 if self.assignments is None: 1106 if single_assignment: 1107 self.assignments = n 1108 else: 1109 self.assignments = AtLeast(n) 1110 else: 1111 if single_assignment: 1112 self.assignments += n 1113 else: 1114 self.assignments += AtLeast(n) 1115 1116 def is_constant(self): 1117 1118 """ 1119 Return whether this attribute references something that can be regarded 1120 as being constant within a particular scope. 1121 """ 1122 1123 return self.assignments == 1 1124 1125 def is_strict_constant(self): 1126 1127 """ 1128 Return whether this attribute references something that can be regarded 1129 as being constant. 1130 """ 1131 1132 value = self.get_value() 1133 return not (value is None or (isinstance(value, Instance) and not isinstance(value, Constant))) 1134 1135 def is_static_attribute(self): 1136 1137 """ 1138 Return whether this attribute is defined on a fixed/static object such 1139 as a class or a module. 1140 """ 1141 1142 return isinstance(self.parent, (Class, Module)) 1143 1144 def defines_ambiguous_class(self): 1145 1146 "Return whether this attribute defines more than one class." 1147 1148 if self.assignments > 1: 1149 have_class = False 1150 for obj in self.get_values(): 1151 if isinstance(obj, Class): 1152 if have_class: 1153 return True 1154 have_class = True 1155 1156 return False 1157 1158 def defined_within_hierarchy(self): 1159 1160 """ 1161 Return whether the parent and context of the attribute belong to the 1162 same class hierarchy. 1163 """ 1164 1165 # Must be defined within a class. 1166 1167 if isinstance(self.parent, Class): 1168 1169 # To be sure, all contexts must be classes and be the same as the 1170 # parent, or be a superclass of the parent, or be a subclass of the 1171 # parent. 1172 1173 for context in self.get_contexts(): 1174 if not ( 1175 isinstance(context, Class) and ( 1176 context is self.parent or 1177 context.has_subclass(self.parent) or 1178 self.parent.has_subclass(context)) 1179 ): 1180 return False 1181 1182 return True 1183 1184 # Instance attributes are not defined within a hierarchy. 1185 1186 else: 1187 return False 1188 1189 def defined_outside_hierarchy(self): 1190 1191 """ 1192 Return whether the parent and context of the attribute never belong to 1193 the same class hierarchy. 1194 """ 1195 1196 # Must be defined within a class. 1197 1198 if isinstance(self.parent, Class): 1199 1200 # To be sure, all contexts must be classes and be the same as the 1201 # parent, or be a superclass of the parent, or be a subclass of the 1202 # parent. 1203 1204 for context in self.get_contexts(): 1205 if not ( 1206 isinstance(context, Class) and not ( 1207 context is self.parent or 1208 context.has_subclass(self.parent) or 1209 self.parent.has_subclass(context)) 1210 ): 1211 return False 1212 1213 return True 1214 1215 # Instance attributes are not defined within a hierarchy. 1216 1217 else: 1218 return False 1219 1220 def __repr__(self): 1221 if self.position is not None: 1222 position = "at %r, " % self.position 1223 else: 1224 position = "" 1225 return "<attribute %s.%s (%sassigned %r)>" % ( 1226 shortrepr(self.parent), self.name, 1227 position, self.assignments 1228 ) 1229 1230 def __shortrepr__(self): 1231 return "%s.%s (at %r)" % (shortrepr(self.parent), self.name, self.position) 1232 1233 def _context_values_str(self): 1234 l = [] 1235 for (c, v) in self.context_values: 1236 l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) 1237 return ", ".join(l) 1238 1239 class Class(NamespaceDict, Naming, Constant): 1240 1241 "A base class for common/normal classes and the type class." 1242 1243 def __init__(self, name, parent=None, module=None, node=None): 1244 1245 """ 1246 Initialise the class with the given 'name', optional 'parent' object, 1247 'module' and AST 'node'. The optional information must be set at a later 1248 point using the 'set_context' method if omitted. 1249 """ 1250 1251 NamespaceDict.__init__(self, module) 1252 self.name = name 1253 self.parent = parent 1254 self.astnode = node 1255 1256 # Superclasses, descendants and attributes. 1257 1258 self.bases = [] 1259 self.descendants = set() 1260 self.instattr = set() # instance attributes 1261 self.instattr_tentative = set() # tentative/suspected instance attributes 1262 self.relocated = set() # attributes which do not have the same 1263 # position as those of the same name in 1264 # some superclasses 1265 1266 # Caches. 1267 1268 self.reset_caches() 1269 1270 # Image generation details. 1271 1272 self.location = None 1273 self.code_location = None 1274 self.code_body_location = None # corresponds to the instantiator 1275 1276 self.instantiator = None 1277 self.instance_template_location = None # for creating instances at run-time 1278 1279 # Program-related details. 1280 1281 self.blocks = None 1282 self.temp_usage = 0 1283 self.local_usage = 0 1284 self.all_local_usage = 0 1285 1286 # Add an attribute to this class for use by instances. 1287 1288 self.set("__class__", self) 1289 1290 def set_context(self, parent, module, node): 1291 1292 "Set the 'parent', 'module' and 'node' of a class created in advance." 1293 1294 self.parent = parent 1295 self.module = module 1296 self.astnode = node 1297 1298 def reset_caches(self): 1299 1300 "Reset the caches." 1301 1302 self.all_instattr = None # cache for instance_attributes 1303 self.all_instattr_names = None # from all_instattr 1304 self.all_classattr = None # cache for all_class_attributes 1305 self.all_classattr_names = None # from all_classattr 1306 self.allattr = None # cache for all_attributes 1307 self.allattr_names = None # from allattr 1308 1309 def __repr__(self): 1310 if self.location is not None: 1311 return "<class %s (at %r)>" % (shortrepr(self), self.location) 1312 else: 1313 return "<class %s>" % shortrepr(self) 1314 1315 def __shortrepr__(self): 1316 return "%s.%s" % (shortrepr(self.parent), self.name) 1317 1318 def get_body_block(self): 1319 return self.get_instantiator().blocks[0] 1320 1321 # Namespace-related methods. 1322 1323 def get_updated_context_values(self, context_values): 1324 1325 """ 1326 Adapt the contexts found in the given 'context_values', returning a new 1327 set. 1328 See: docs/assignment.txt 1329 """ 1330 1331 results = set() 1332 1333 for context, value in context_values: 1334 1335 # Change the ownership of functions. 1336 1337 if context is ReplaceableContext and value is not None and isinstance(value, Function): 1338 results.add((self, value)) 1339 else: 1340 results.add((context, value)) 1341 1342 return NamespaceDict.get_updated_context_values(self, results) 1343 1344 # Administrative methods. 1345 1346 def items_for_vacuum(self): 1347 1348 "Consider both class and instance attributes for vacuuming." 1349 1350 items = [] 1351 for name in self.instattr: 1352 items.append((name, None)) 1353 return NamespaceDict.items_for_vacuum(self) + items 1354 1355 def vacuum_item(self, name): 1356 1357 "Vacuum 'name' from the class or instance attribute collections." 1358 1359 # NOTE: Hack to prevent damage to exceptions. 1360 1361 if name == "_pc": 1362 return False 1363 1364 if not NamespaceDict.vacuum_item(self, name): 1365 self.instattr.remove(name) 1366 return True 1367 1368 def finalise_attributes(self): 1369 1370 "Make sure that all attributes are fully defined." 1371 1372 if self.finalised: 1373 return 1374 1375 self.finalise_class_attributes() 1376 self.finalise_instance_attributes() 1377 self.finalised = True 1378 1379 def unfinalise_attributes(self): 1380 1381 "Open attribute definitions to editing and subsequent finalisation." 1382 1383 self.reset_caches() 1384 self.finalised = False 1385 1386 # Convenience methods for accessing functions and methods. 1387 1388 def get_instantiator(self): 1389 1390 "Return a function which can be used to instantiate the class." 1391 1392 if self.instantiator is None: 1393 self.instantiator = self.get_init_method().as_instantiator() 1394 return self.instantiator 1395 1396 def get_init_method(self): 1397 return self.all_class_attributes()["__init__"].get_value() 1398 1399 # Class-specific methods. 1400 1401 def add_base(self, base): 1402 self.bases.append(base) 1403 base.add_descendant(self) 1404 1405 def add_instance_attribute(self, name, tentative=False): 1406 if tentative: 1407 self.instattr_tentative.add(name) 1408 else: 1409 self.instattr.add(name) 1410 1411 def add_descendant(self, cls): 1412 self.descendants.add(cls) 1413 for base in self.bases: 1414 base.add_descendant(cls) 1415 1416 def has_subclass(self, other): 1417 return other in self.descendants 1418 1419 def all_descendants(self): 1420 d = {} 1421 for cls in self.descendants: 1422 d[cls.full_name()] = cls 1423 return d 1424 1425 "Return the attribute names provided by this class only." 1426 1427 class_attribute_names = NamespaceDict.keys 1428 1429 def class_attributes(self): 1430 1431 "Return class attributes provided by this class only." 1432 1433 return dict(self) 1434 1435 def all_class_attribute_names(self): 1436 1437 "Return the attribute names provided by classes in this hierarchy." 1438 1439 if self.all_classattr_names is None: 1440 self.all_class_attributes() 1441 self.all_classattr_names = self.all_classattr.keys() 1442 return self.all_classattr_names 1443 1444 def all_class_attributes(self): 1445 1446 "Return all class attributes, indicating the class which provides them." 1447 1448 self.finalise_class_attributes() 1449 return self.all_classattr 1450 1451 def finalise_class_attributes(self): 1452 1453 "Make sure that the class attributes are fully defined." 1454 1455 if self.all_classattr is None: 1456 self.all_classattr = {} 1457 clsattr = {} 1458 1459 # Record provisional position information for attributes of this 1460 # class. 1461 1462 for name in self.class_attributes().keys(): 1463 1464 # Special case: __class__ has to be at position 0. 1465 1466 if name == "__class__": 1467 clsattr[name] = set([0]) 1468 else: 1469 clsattr[name] = set() # position not yet defined 1470 1471 reversed_bases = self.bases[:] 1472 reversed_bases.reverse() 1473 1474 # For the bases in reverse order, acquire class attribute details. 1475 1476 for cls in reversed_bases: 1477 for name, attr in cls.all_class_attributes().items(): 1478 self.all_classattr[name] = attr 1479 1480 # Record previous attribute information. 1481 1482 if clsattr.has_key(name): 1483 clsattr[name].add(attr.position) 1484 1485 # Record class attributes provided by this class and its bases, 1486 # along with their positions. 1487 1488 self.all_classattr.update(self.class_attributes()) 1489 1490 if clsattr: 1491 for i, name in enumerate(self._get_position_list(clsattr)): 1492 self.all_classattr[name].position = i 1493 1494 return self.all_classattr 1495 1496 def instance_attribute_names(self): 1497 1498 "Return the instance attribute names provided by the class." 1499 1500 if self.all_instattr_names is None: 1501 self.instance_attributes() 1502 return self.all_instattr_names 1503 1504 def instance_attributes(self): 1505 1506 "Return instance-only attributes for instances of this class." 1507 1508 self.finalise_instance_attributes() 1509 return self.all_instattr 1510 1511 def finalise_instance_attributes(self): 1512 1513 "Make sure that the instance attributes are fully defined." 1514 1515 # Eliminate tentative instance attributes that are actually class 1516 # attributes. 1517 1518 for attrname in self.all_class_attributes().keys(): 1519 if attrname in self.instattr_tentative: 1520 self.instattr_tentative.remove(attrname) 1521 1522 for cls in self.descendants: 1523 for attrname in cls.class_attribute_names(): 1524 if attrname in self.instattr_tentative: 1525 self.instattr_tentative.remove(attrname) 1526 1527 for attrname in self.instattr_tentative: 1528 self.instattr.add(attrname) 1529 1530 # Cache the attributes by converting the positioned attributes into a 1531 # dictionary. 1532 1533 if self.all_instattr is None: 1534 self.all_instattr = self._get_attributes() 1535 self.all_instattr_names = self.all_instattr.keys() 1536 1537 return self.all_instattr 1538 1539 def _get_attributes(self): 1540 1541 """ 1542 Return a dictionary mapping names to Attr instances incorporating 1543 information about their positions in the final instance structure. 1544 """ 1545 1546 instattr = {} 1547 1548 # Record provisional position information for attributes of this 1549 # instance. 1550 1551 for name in self.instattr: 1552 instattr[name] = set() # position not yet defined 1553 1554 reversed_bases = self.bases[:] 1555 reversed_bases.reverse() 1556 1557 # For the bases in reverse order, acquire instance attribute 1558 # details. 1559 1560 for cls in reversed_bases: 1561 for name, attr in cls.instance_attributes().items(): 1562 1563 # Record previous attribute information. 1564 1565 if instattr.has_key(name): 1566 instattr[name].add(attr.position) 1567 else: 1568 instattr[name] = set([attr.position]) 1569 1570 # Build the dictionary of attributes using the existing positions known 1571 # for each name. 1572 1573 d = {} 1574 for i, name in enumerate(self._get_position_list(instattr)): 1575 d[name] = Attr(i, make_instance(), name) 1576 return d 1577 1578 def _get_position_list(self, positions): 1579 1580 """ 1581 Return a list of attribute names for the given 'positions' mapping from 1582 names to positions, indicating the positions of the attributes in the 1583 final instance structure. 1584 """ 1585 1586 position_items = positions.items() 1587 namearray = [None] * len(position_items) 1588 1589 # Get the positions in ascending order of list size, with lists 1590 # of the same size ordered according to their smallest position 1591 # value. 1592 1593 position_items.sort(self._cmp_positions) 1594 1595 # Get the names in position order. 1596 1597 held = [] 1598 1599 for name, pos in position_items: 1600 pos = list(pos) 1601 pos.sort() 1602 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 1603 namearray[pos[0]] = name 1604 else: 1605 if pos: 1606 self.relocated.add(name) 1607 held.append((name, pos)) 1608 1609 for i, attr in enumerate(namearray): 1610 if attr is None: 1611 name, pos = held.pop() 1612 namearray[i] = name 1613 1614 return namearray 1615 1616 def _cmp_positions(self, a, b): 1617 1618 "Compare name plus position list operands 'a' and 'b'." 1619 1620 name_a, list_a = a 1621 name_b, list_b = b 1622 if len(list_a) < len(list_b): 1623 return -1 1624 elif len(list_a) > len(list_b): 1625 return 1 1626 elif not list_a: 1627 return 0 1628 else: 1629 return cmp(min(list_a), min(list_b)) 1630 1631 def all_attribute_names(self): 1632 1633 """ 1634 Return the names of all attributes provided by instances of this class. 1635 """ 1636 1637 self.allattr_names = self.allattr_names or self.all_attributes().keys() 1638 return self.allattr_names 1639 1640 def all_attributes(self): 1641 1642 """ 1643 Return all attributes for an instance, indicating either the class which 1644 provides them or that the instance itself provides them. 1645 1646 Note that __class__ acts like a class attribute for both instances and 1647 classes, and must be able to convey distinct values. 1648 """ 1649 1650 if self.allattr is None: 1651 self.allattr = {} 1652 self.allattr.update(self.all_class_attributes()) 1653 for name, attr in self.instance_attributes().items(): 1654 if self.allattr.has_key(name) and name != "__class__": 1655 print >>sys.stderr, "Warning: instance attribute %r in %r overrides class attribute." % (name, self) 1656 self.allattr[name] = attr 1657 return self.allattr 1658 1659 class Function(NamespaceDict, Naming, Constant): 1660 1661 "An inspected function." 1662 1663 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, 1664 dynamic_def=0, module=None, node=None): 1665 1666 """ 1667 Initialise the function with the given 'name', 'parent', list of 1668 'argnames', list of 'defaults', the 'has_star' flag (indicating the 1669 presence of a * parameter), the 'has_dstar' flag (indicating the 1670 presence of a ** parameter), optional 'dynamic_def' (indicating that the 1671 function must be handled dynamically), optional 'module', and optional 1672 AST 'node'. 1673 """ 1674 1675 NamespaceDict.__init__(self, module) 1676 1677 if name is None: 1678 self.name = "lambda#%d" % new_lambda() 1679 self._is_lambda = True 1680 else: 1681 self.name = name 1682 self._is_lambda = False 1683 1684 self.parent = parent 1685 self.argnames = argnames 1686 self.defaults = defaults 1687 self.has_star = has_star 1688 self.has_dstar = has_dstar 1689 self.dynamic_def = dynamic_def 1690 self.astnode = node 1691 1692 # Initialise the positional names. 1693 1694 self.positional_names = self.argnames[:] 1695 if has_dstar: 1696 self.dstar_name = self.positional_names[-1] 1697 del self.positional_names[-1] 1698 if has_star: 1699 self.star_name = self.positional_names[-1] 1700 del self.positional_names[-1] 1701 1702 # Initialise default storage. 1703 # NOTE: This must be initialised separately due to the reliance on node 1704 # NOTE: visiting. 1705 1706 self.default_attrs = [] 1707 1708 # Initialise attribute usage. 1709 1710 if node is not None: 1711 for arg in argnames: 1712 1713 # Define attribute users. 1714 1715 self._define_attribute_user_for_name(node, arg) 1716 1717 # Caches. 1718 1719 self.localnames = None # cache for locals 1720 1721 # Add parameters to the namespace. 1722 1723 self._add_parameters(argnames) 1724 1725 # Image generation details. 1726 1727 self.dynamic = None 1728 self.location = None 1729 self.code_location = None 1730 self.code_body_location = None 1731 1732 # Program-related details. 1733 1734 self.blocks = None 1735 self.body_block = None 1736 1737 self.temp_usage = 0 1738 self.local_usage = 0 1739 self.all_local_usage = 0 1740 1741 def _add_parameters(self, argnames): 1742 1743 "Add 'argnames' to the namespace." 1744 1745 for name in argnames: 1746 self.set(name, make_instance()) 1747 1748 for name, top_level in self._flattened_parameters(argnames): 1749 if not top_level: 1750 self.set(name, make_instance()) 1751 1752 def _flattened_parameters(self, argnames, top_level=1): 1753 l = [] 1754 for name in argnames: 1755 if isinstance(name, tuple): 1756 l += self._flattened_parameters(name, 0) 1757 else: 1758 l.append((name, top_level)) 1759 return l 1760 1761 def __repr__(self): 1762 if self.location is not None: 1763 return "<function %s (at %r, code at %r)>" % ( 1764 shortrepr(self), self.location, self.code_location 1765 ) 1766 else: 1767 return "<function %s>" % shortrepr(self) 1768 1769 def __shortrepr__(self): 1770 return "%s.%s(%s)" % (shortrepr(self.parent), self.name, ", ".join(self.argnames)) 1771 1772 def get_body_block(self): 1773 return self.body_block 1774 1775 def is_lambda(self): 1776 return self._is_lambda 1777 1778 # Defaults-related methods. 1779 1780 def store_default(self, attr_or_value): 1781 1782 """ 1783 Reserve space for defaults, set outside the function, potentially on a 1784 dynamic basis, using the 'attr_or_value'. 1785 """ 1786 1787 attr = Attr(None, self, None) 1788 self._set_using_attr(attr, attr_or_value) 1789 self.default_attrs.append(attr) 1790 1791 def make_dynamic(self): 1792 1793 "Return whether this function must be handled using a dynamic object." 1794 1795 if self.dynamic is None: 1796 for attr in self.default_attrs: 1797 if not attr.is_strict_constant() and self.dynamic_def: 1798 self.dynamic = True 1799 self._make_dynamic() 1800 break 1801 else: 1802 self.dynamic = False 1803 1804 return self.dynamic 1805 1806 is_dynamic = make_dynamic 1807 1808 def _make_dynamic(self): 1809 1810 "Where functions have dynamic defaults, add a context argument." 1811 1812 name = "<context>" 1813 self.argnames.insert(0, name) 1814 self.positional_names.insert(0, name) 1815 self.set(name, make_instance()) 1816 1817 # Namespace-related methods. 1818 1819 def make_global(self, name): 1820 1821 "Declare 'name' as a global in the current namespace." 1822 1823 if name not in self.argnames and not self.has_key(name): 1824 self.globals.add(name) 1825 return True 1826 else: 1827 return False 1828 1829 def parameters(self): 1830 1831 """ 1832 Return a dictionary mapping parameter names to their position in the 1833 parameter list. 1834 """ 1835 1836 parameters = {} 1837 for i, name in enumerate(self.argnames): 1838 parameters[name] = i 1839 return parameters 1840 1841 def tuple_parameters(self, argnames=None): 1842 1843 """ 1844 Return a list of (position, parameter) entries corresponding to tuple 1845 parameters, where each parameter may either be a string or another such 1846 list of entries. 1847 """ 1848 1849 names = argnames or self.argnames 1850 1851 l = [] 1852 for i, name in enumerate(names): 1853 if isinstance(name, tuple): 1854 l.append((i, self.tuple_parameters(name))) 1855 elif argnames: 1856 l.append((i, name)) 1857 return l 1858 1859 def all_locals(self): 1860 1861 "Return a dictionary mapping names to local and parameter details." 1862 1863 return dict(self) 1864 1865 def locals(self): 1866 1867 "Return a dictionary mapping names to local details." 1868 1869 if self.localnames is None: 1870 self.localnames = {} 1871 self.localnames.update(self.all_locals()) 1872 for name in self.argnames: 1873 del self.localnames[name] 1874 return self.localnames 1875 1876 def is_method(self): 1877 1878 """ 1879 Return whether this function is a method explicitly defined in a class. 1880 """ 1881 1882 return isinstance(self.parent, Class) 1883 1884 def is_relocated(self, name): 1885 1886 """ 1887 Determine whether the given attribute 'name' is relocated for instances 1888 having this function as a method. 1889 """ 1890 1891 for cls in self.parent.descendants: 1892 if name in cls.relocated: 1893 return True 1894 return False 1895 1896 # Administrative methods. 1897 1898 def items_for_vacuum(self): 1899 return self.lambdas.items() 1900 1901 def vacuum_item(self, name): 1902 del self.lambdas[name] 1903 return True 1904 1905 def finalise_attributes(self): 1906 1907 """ 1908 Make sure all attributes (locals) are fully defined. Note that locals 1909 are not attributes in the sense of class, module or instance attributes. 1910 Defaults are also finalised by this method. 1911 """ 1912 1913 if self.finalised: 1914 return 1915 1916 # Defaults. 1917 1918 for i, default in enumerate(self.default_attrs): 1919 default.position = i 1920 1921 # Parameters. 1922 1923 i = self._finalise_parameters() 1924 1925 if i is not None: 1926 nparams = i + 1 1927 else: 1928 nparams = 0 1929 1930 # Locals (and tuple parameter names). 1931 1932 i = None 1933 for i, attr in enumerate(self.locals().values()): 1934 attr.position = i + nparams 1935 1936 if i is not None: 1937 nothers = i + 1 1938 else: 1939 nothers = 0 1940 1941 self.local_usage = nothers 1942 self.all_local_usage = nparams + nothers 1943 self.finalised = True 1944 1945 def _finalise_parameters(self): 1946 if not self.argnames: 1947 return None 1948 1949 for i, name in enumerate(self.argnames): 1950 self[name].position = i 1951 1952 return i 1953 1954 def as_instantiator(self): 1955 1956 "Make an instantiator function from a method, keeping all arguments." 1957 1958 function = Function(self.parent.name, self.parent.parent, self.argnames, self.defaults, 1959 self.has_star, self.has_dstar, self.dynamic_def, self.module) 1960 function.default_attrs = self.default_attrs 1961 return function 1962 1963 class UnresolvedName(NamespaceDict, Constant): 1964 1965 "A module, class or function which was mentioned but could not be imported." 1966 1967 def __init__(self, name, parent_name, module=None): 1968 NamespaceDict.__init__(self, module) 1969 self.name = name 1970 self.parent_name = parent_name 1971 self.parent = None 1972 1973 self.descendants = set() 1974 1975 def add_descendant(self, cls): 1976 self.descendants.add(cls) 1977 1978 def all_attributes(self): 1979 return {} 1980 1981 def all_attribute_names(self): 1982 return [] 1983 1984 all_class_attributes = class_attributes = instance_attributes = all_attributes 1985 all_class_attribute_names = class_attribute_names = instance_attribute_names = all_attribute_names 1986 1987 def __repr__(self): 1988 return "<unknown %s>" % shortrepr(self) 1989 1990 def __shortrepr__(self): 1991 if self.name is not None: 1992 return "%s.%s" % (self.parent_name, self.name) 1993 else: 1994 return self.parent_name 1995 1996 def full_name(self): 1997 if self.name is not None: 1998 return self.parent_name + "." + self.name 1999 else: 2000 return self.parent_name 2001 2002 class Module(NamespaceDict, Constant): 2003 2004 "An inspected module's core details." 2005 2006 def __init__(self, name, importer): 2007 NamespaceDict.__init__(self, self) 2008 self.name = name 2009 self.importer = importer 2010 self.parent = None 2011 2012 # Original location details. 2013 2014 self.astnode = None 2015 2016 # Complete lists of classes and functions. 2017 2018 self.all_objects = set() 2019 2020 # Whether the module is imported in a circular fashion, exposing the 2021 # unfinished namespace to external modification. 2022 2023 self.circular_import = self in importer.circular_imports 2024 2025 # A set of global names that cannot support combined attribute usage 2026 # observations because they may be modified within functions during 2027 # initialisation. 2028 2029 self.modified_names = set() 2030 2031 # Keyword records. 2032 2033 self.keyword_names = set() 2034 2035 # Image generation details. 2036 2037 self.location = None 2038 self.code_location = None 2039 2040 # Program-related details. 2041 2042 self.blocks = None 2043 self.temp_usage = 0 2044 self.local_usage = 0 2045 self.all_local_usage = 0 2046 2047 def full_name(self): 2048 return self.name 2049 2050 def __repr__(self): 2051 if self.location is not None: 2052 return "<module %s (at %r)>" % (self.name, self.location) 2053 else: 2054 return "<module %s>" % shortrepr(self) 2055 2056 def __shortrepr__(self): 2057 return self.name 2058 2059 # Attribute methods. 2060 2061 "Return the module attribute names provided by the module." 2062 2063 module_attribute_names = NamespaceDict.keys 2064 2065 def module_attributes(self): 2066 2067 "Return a dictionary mapping names to module attributes." 2068 2069 return dict(self) 2070 2071 all_attributes = module_attributes 2072 2073 def get_static_attribute(self, name): 2074 2075 """ 2076 Return a static attribute for the given 'name' or None if no such 2077 attribute exists. 2078 """ 2079 2080 return self.get(name) 2081 2082 def modify_name(self, name): 2083 2084 """ 2085 Modify a global 'name' invalidating various assumptions about its 2086 behaviour based on the module namespace being "safe" and suitable for 2087 attribute usage and constant value observations. 2088 """ 2089 2090 self.modified_names.add(name) 2091 2092 # Establish an attribute directly in the namespace if not present. 2093 2094 if not self.namespace.has_key(name): 2095 self.namespace[name] = Attr(None, self, name) 2096 2097 # Indicate that there is at least one assignment to the name, although 2098 # no actual values are recorded. 2099 2100 attr = self.namespace[name] 2101 attr.update_assignments(1, False) 2102 2103 def set(self, name, value, single_assignment=1): 2104 2105 """ 2106 Set the module attribute with the given 'name', having the given 'value' 2107 that is assigned once if 'single_assignment' is omitted to given as a 2108 true value. 2109 2110 Where the module is imported before it is completely initialised, all 2111 assignments will be regarded as multiple assignments since it is 2112 possible that an external assignment to the name may occur. 2113 """ 2114 2115 NamespaceDict.set(self, name, value, not self.circular_import and single_assignment) 2116 2117 # Attribute usage methods that apply to module globals in certain 2118 # circumstances. 2119 2120 def _use_attribute(self, name, attrname, value=None): 2121 if name not in self.modified_names and not self.circular_import: 2122 return NamespaceDict._use_attribute(self, name, attrname, value) 2123 else: 2124 self.importer.use_name(attrname, self.full_name(), value) 2125 return [] 2126 2127 def _define_attribute_user_for_name(self, node, name): 2128 if name not in self.modified_names and not self.circular_import: 2129 NamespaceDict._define_attribute_user_for_name(self, node, name) 2130 2131 def _init_attribute_user_for_name(self, node, name): 2132 if name not in self.modified_names and not self.circular_import: 2133 NamespaceDict._init_attribute_user_for_name(self, node, name) 2134 2135 def _define_attribute_accessor(self, name, attrname, node, value): 2136 if name not in self.modified_names and not self.circular_import: 2137 NamespaceDict._define_attribute_accessor(self, name, attrname, node, value) 2138 else: 2139 self.importer.use_name(attrname, self.full_name(), value) 2140 2141 # Pre-made class instances. 2142 # For each of these, their details will be filled in later. 2143 2144 premade = { 2145 "bool" : Class("bool"), 2146 "float" : Class("float"), 2147 "int" : Class("int"), 2148 "long" : Class("long"), 2149 "str" : Class("str"), 2150 "unicode" : Class("unicode"), 2151 "type" : Class("type"), 2152 } 2153 2154 # Class construction. 2155 2156 def get_class(name, parent, module, node): 2157 2158 """ 2159 Return a Class instance for the class with the given 'name', 'parent', 2160 'module' and 'node'. 2161 """ 2162 2163 if premade.has_key(name) and module.full_name() == "__builtins__": 2164 cls = premade[name] 2165 cls.set_context(parent, module, node) 2166 return cls 2167 else: 2168 return Class(name, parent, module, node) 2169 2170 # Lambda sequence numbering. 2171 2172 lambda_index = 0 2173 2174 def new_lambda(): 2175 2176 "Return a new sequence number for a lambda definition." 2177 2178 global lambda_index 2179 lambda_index += 1 2180 return lambda_index 2181 2182 # Special representations. 2183 2184 class AtLeast: 2185 2186 "A special representation for numbers of a given value or greater." 2187 2188 def __init__(self, count): 2189 self.count = count 2190 2191 def __eq__(self, other): 2192 return False 2193 2194 __lt__ = __le__ = __eq__ 2195 2196 def __ne__(self, other): 2197 return True 2198 2199 def __gt__(self, other): 2200 if isinstance(other, AtLeast): 2201 return False 2202 else: 2203 return self.count > other 2204 2205 def __ge__(self, other): 2206 if isinstance(other, AtLeast): 2207 return False 2208 else: 2209 return self.count >= other 2210 2211 def __iadd__(self, other): 2212 if isinstance(other, AtLeast): 2213 self.count += other.count 2214 else: 2215 self.count += other 2216 return self 2217 2218 def __radd__(self, other): 2219 if isinstance(other, AtLeast): 2220 return AtLeast(self.count + other.count) 2221 else: 2222 return AtLeast(self.count + other) 2223 2224 def __repr__(self): 2225 return "AtLeast(%r)" % self.count 2226 2227 class UnsetType: 2228 2229 "A None-like value." 2230 2231 def __nonzero__(self): 2232 return False 2233 2234 Unset = UnsetType() 2235 2236 # vim: tabstop=4 expandtab shiftwidth=4