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