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 for attrnames in usage: 408 if attrnames: 409 break 410 else: 411 continue 412 413 # Eliminate non-usage. 414 415 importer.use_names(user, name, tuple([attrnames for attrnames in usage if attrnames]), self.full_name()) 416 417 def get_usage_from_contributors(self, node): 418 419 """ 420 Obtain usage information from the given 'node', combined with usage 421 details from its contributors, returning a tuple containing a set of all 422 contributors employed along with a dictionary mapping names to lists of 423 usage possibilities (each a collection of attribute names). 424 """ 425 426 if not hasattr(node, "_attrcombined"): 427 428 node._attrcontributors = set() 429 node._attrcombined = {} 430 431 contributor_usage = {} 432 all_contributors = set() 433 434 # Visit each contributor, gathering usage for each name. 435 436 for contributor in node._attrbranches: 437 438 # Get contributed usage for each contributor. 439 # This gathers usage for each name such as {(a, b), (c, d)} and 440 # {(a, b), (e, f)} into a single set {(a, b), (c, d), (e, f)}. 441 442 contributors, contributed_usage = self.get_usage_from_contributors(contributor) 443 update_mapping_dict(contributor_usage, [contributed_usage]) 444 445 # Record all contributors. 446 447 all_contributors.add(contributor) 448 all_contributors.update(contributors) 449 450 # Then get the resulting usage. 451 # First, make the current usage compatible with the contributed 452 # usage: this makes the attribute usage for each name merely one 453 # member in a list of many possibilities. 454 # Then, combine the current usage with the contributed usage. 455 # Thus, usage of {(f, g)} combined with {(a, b), (c, d)} would give 456 # {(f, g, a, b), (f, g, c, d)}. 457 458 usage = combine_mapping_dicts(deepen_mapping_dict(node._attrnames), contributor_usage) 459 460 node._attrcontributors = all_contributors 461 node._attrcombined = usage 462 463 return node._attrcontributors, node._attrcombined 464 465 def use_attribute(self, name, attrname, value=None): 466 467 """ 468 Note usage on the attribute user 'name' of the attribute 'attrname', 469 noting an assignment if 'value' is specified. 470 """ 471 472 return self._use_attribute(name, attrname, value) 473 474 def use_specific_attribute(self, objname, attrname): 475 476 "Declare the usage on 'objname' of the given 'attrname'." 477 478 self._use_specific_attribute(objname, attrname) 479 480 # These shadow various methods in the InspectedModule class, and provide 481 # implementations generally. 482 483 def _use_specific_attribute(self, objname, attrname, from_name=None): 484 485 """ 486 Note attribute usage specifically on 'objname' - an object which is 487 known at inspection time - or in the current unit if 'objname' is None, 488 nominating a specific attribute 'attrname'. 489 490 This bypasses attribute user mechanisms. 491 """ 492 493 from_name = from_name or self.full_name() 494 objname = objname or from_name 495 module = self.module 496 importer = module and module.importer 497 498 if importer is not None: 499 importer.use_specific_name(objname, attrname, from_name) 500 501 def _use_attribute(self, name, attrname, value=None): 502 503 """ 504 Indicate the use of the given 'name' in this namespace of an attribute 505 with the given 'attrname'. If the optional 'value' is specified, an 506 assignment using the given 'value' is recorded. 507 """ 508 509 users = self.attribute_users[-1] 510 511 # Add the usage to all current users. 512 513 if users.has_key(name): 514 for user in users[name]: 515 values = user._attrnames[name] 516 517 # Add an entry for the attribute, optionally with an assigned 518 # value. 519 520 values.add(attrname) 521 if value is not None: 522 values[attrname].append(value) 523 524 return users[name] 525 else: 526 return [] 527 528 def _define_attribute_user(self, node): 529 530 """ 531 Define 'node' as the user of attributes, indicating the point where the 532 user is defined. 533 """ 534 535 name = node.name 536 self._define_attribute_user_for_name(node, name) 537 538 def _define_attribute_user_for_name(self, node, name): 539 540 "Define 'node' as the user of attributes for the given 'name'." 541 542 users = self.attribute_users[-1] 543 544 # This node overrides previous definitions. 545 546 users[name] = set([node]) 547 548 # Record the attribute combinations for the name. 549 550 self._init_attribute_user_for_name(node, name) 551 552 # Remember this user. 553 554 self.all_attribute_users.add(node) 555 556 def _init_attribute_user_for_name(self, node, name): 557 558 "Make sure that 'node' is initialised for 'name'." 559 560 self._init_attribute_user(node) 561 node._attrnames[name] = ObjectSet() 562 563 def _init_attribute_user(self, node): 564 565 # Attribute usage for names. 566 567 if not hasattr(node, "_attrnames"): 568 node._attrnames = {} 569 570 # Branches contributing usage to this node. 571 572 if not hasattr(node, "_attrbranches"): 573 node._attrbranches = [] 574 575 # Definitions receiving usage from this node. 576 577 if not hasattr(node, "_attrdefs"): 578 node._attrdefs = [] 579 580 # Eventual type information. 581 582 if not hasattr(node, "_attrtypes"): 583 node._attrtypes = {} 584 585 # Branch management methods. 586 587 def _new_branchpoint(self, loop_node=None): 588 589 """ 590 Establish a new branchpoint where several control-flow branches diverge 591 and subsequently converge. 592 """ 593 594 self.attribute_user_shelves.append([]) 595 self.scope_shelves.append([]) 596 597 if loop_node is not None: 598 self.suspended_broken_users.append([]) 599 self.suspended_continuing_users.append((loop_node, [])) 600 601 def _new_branch(self, node): 602 603 """ 604 Establish a new control-flow branch, transferring attribute usage to 605 the new branch so that it may be augmented for each name locally. 606 607 Add the given 'node' as an active user to be informed of attribute 608 usage. 609 """ 610 611 attribute_users = self.attribute_users[-1] 612 613 # Define this node as the active attribute user for all currently 614 # defined names. 615 616 new_users = {} 617 618 for name in attribute_users.keys(): 619 new_users[name] = [node] 620 self._init_attribute_user_for_name(node, name) 621 622 self._init_attribute_user(node) 623 self.attribute_users.append(new_users) 624 625 # Add this user as a contributor to the previously active users. 626 627 self._connect_users_to_branch(attribute_users, node) 628 629 # Retain a record of scope usage. 630 631 scope_usage = {} 632 scope_usage.update(self.scope_usage[-1]) 633 self.scope_usage.append(scope_usage) 634 635 def _connect_users_to_branch(self, attribute_users, node): 636 637 """ 638 Given the 'attribute_users' mapping, connect the users referenced in the 639 mapping to the given branch 'node'. 640 """ 641 642 all_users = set() 643 644 for users in attribute_users.values(): 645 all_users.update(users) 646 647 for user in all_users: 648 self._init_attribute_user(user) 649 user._attrbranches.append(node) 650 651 def _abandon_branch(self): 652 653 """ 654 Abandon scope usage, permitting locally different scopes for names, 655 provided these cannot "escape" from the branch. 656 """ 657 658 self.attribute_users[-1] = abandoned_branch_users 659 self.scope_usage[-1] = abandoned_branch_scope 660 661 def _suspend_broken_branch(self): 662 663 """ 664 Suspend a branch for resumption after the current loop. 665 """ 666 667 attribute_users = self.attribute_users[-1] 668 669 if not isinstance(attribute_users, AbandonedBranchUsers): 670 users = self.suspended_broken_users[-1] 671 users.append(attribute_users) 672 self._abandon_branch() 673 674 def _suspend_continuing_branch(self): 675 676 """ 677 Suspend a branch for resumption after the current iteration. 678 """ 679 680 attribute_users = self.attribute_users[-1] 681 682 if not isinstance(attribute_users, AbandonedBranchUsers): 683 loop_node, users = self.suspended_continuing_users[-1] 684 users.append(attribute_users) 685 self._abandon_branch() 686 687 def _shelve_branch(self): 688 689 """ 690 Shelve the current control-flow branch, recording the attribute usage 691 for subsequent merging. If this branch should be abandoned, the usage 692 observations are still recorded but will not contribute to subsequent 693 observations after a merge. 694 """ 695 696 users = self.attribute_users.pop() 697 self.attribute_user_shelves[-1].append(users) 698 699 scope_usage = self.scope_usage.pop() 700 self.scope_shelves[-1].append(scope_usage) 701 702 def _merge_branches(self): 703 704 """ 705 Merge control-flow branches. This should find the users active within 706 each branch, which have been "shelved", and update the active users 707 dictionary with these contributions. 708 """ 709 710 # Combine the attribute users. This ensures that a list of users 711 # affected by attribute usage is maintained for the current branch. 712 713 all_shelved_users = self.attribute_user_shelves.pop() 714 new_users = merge_mapping_dicts(all_shelved_users) 715 self.attribute_users[-1] = new_users 716 717 # Combine the scope usage. 718 719 scope_usage = self.scope_usage[-1] 720 new_scope_usage = {} 721 722 all_scope_usage = self.scope_shelves.pop() 723 all_scope_names = set() 724 725 # Find all the names for whom scope information has been defined. 726 727 for shelved_usage in all_scope_usage: 728 all_scope_names.update(shelved_usage.keys()) 729 730 for shelved_usage in all_scope_usage: 731 for name in all_scope_names: 732 733 # Find the recorded scope for the name. 734 735 if shelved_usage.has_key(name): 736 scope = shelved_usage[name] 737 elif scope_usage.has_key(name): 738 scope = scope_usage[name] 739 740 # For abandoned branches, no scope is asserted for a name. 741 742 elif isinstance(shelved_usage, AbandonedBranchScope): 743 scope = None 744 745 # If no scope is recorded, find a suitable external source. 746 747 else: 748 attr, scope, full_name = self._get_with_scope(name, external=1) 749 750 # Attempt to record the scope, testing for conflicts. 751 752 if scope: 753 if not new_scope_usage.has_key(name): 754 new_scope_usage[name] = scope 755 elif new_scope_usage[name] != scope: 756 new_scope_usage[name] = ScopeConflict(scope, new_scope_usage[name]) 757 758 self.scope_usage[-1] = new_scope_usage 759 760 def _resume_broken_branches(self): 761 762 """ 763 Incorporate users from suspended broken branches into the current set of 764 active users. 765 """ 766 767 suspended_users = self.suspended_broken_users.pop() 768 current_users = self.attribute_users[-1] 769 new_users = merge_mapping_dicts(suspended_users + [current_users]) 770 self.attribute_users[-1] = new_users 771 772 def _resume_continuing_branches(self): 773 774 """ 775 Incorporate users from suspended continuing branches into the current 776 set of active users, merging usage from the latter with the former. 777 """ 778 779 loop_node, suspended_users = self.suspended_continuing_users.pop() 780 current_users = self.attribute_users[-1] 781 782 # Connect the suspended users to the loop node. 783 784 for users in suspended_users: 785 self._connect_users_to_branch(users, loop_node) 786 787 # Merge suspended branches with the current branch. 788 789 new_users = merge_mapping_dicts(suspended_users + [current_users]) 790 self.attribute_users[-1] = new_users 791 792 # Scope usage methods. 793 794 def define_scope(self, name, scope): 795 796 """ 797 Define 'name' as being from the given 'scope' in the current namespace. 798 """ 799 800 self.scope_usage[-1][name] = scope 801 802 def note_scope(self, name, scope): 803 804 """ 805 Note usage of 'name' from the given 'scope' in the current namespace. 806 If a conflict has been recorded previously, raise an exception. 807 """ 808 809 scope_usage = self.scope_usage[-1] 810 811 if scope_usage.has_key(name): 812 found_scope = scope_usage[name] 813 if isinstance(found_scope, ScopeConflict): 814 raise InspectError("Scope conflict for %r: defined as both %s and %s." % ( 815 name, found_scope.old_scope, found_scope.new_scope)) 816 817 scope_usage[name] = scope 818 819 def used_in_scope(self, name, scope): 820 821 """ 822 Return whether 'name' is used from the given 'scope' in the current 823 namespace. 824 """ 825 826 scope_usage = self.scope_usage[-1] 827 return scope_usage.get(name) == scope 828 829 # Special helper classes for usage and scope resolution. 830 831 class EmptyDict: 832 833 "A class providing dictionaries which retain no information." 834 835 def has_key(self, name): 836 return 0 837 838 def __setitem__(self, name, value): 839 pass 840 841 def __getitem__(self, name): 842 raise KeyError, name 843 844 def get(self, name, default=None): 845 return default 846 847 def keys(self): 848 return [] 849 850 values = items = keys 851 852 class AbandonedBranchUsers(EmptyDict): 853 854 """ 855 A class providing a value or state for an abandoned branch distinct from an 856 empty usage dictionary. 857 """ 858 859 pass 860 861 class AbandonedBranchScope(EmptyDict): 862 863 """ 864 A class providing a value or state for an abandoned branch distinct from an 865 empty scope dictionary. 866 """ 867 868 pass 869 870 abandoned_branch_users = AbandonedBranchUsers() 871 abandoned_branch_scope = AbandonedBranchScope() 872 873 class ScopeConflict: 874 875 """ 876 A scope conflict caused when different code branches contribute different 877 sources of names. 878 """ 879 880 def __init__(self, old_scope, new_scope): 881 self.old_scope = old_scope 882 self.new_scope = new_scope 883 884 class NullBranch: 885 886 "A class representing an attribute user for a non-existent branch." 887 888 pass 889 890 # Program data structures. 891 892 class Attr: 893 894 "An attribute entry having a context." 895 896 def __init__(self, position, parent, name): 897 898 """ 899 Initialise the attribute with the given 'position' within the collection 900 of attributes of its 'parent', indicating its 'name'. 901 """ 902 903 self.position = position 904 self.parent = parent 905 self.name = name 906 907 # Possible values. 908 909 self.context_values = set() 910 911 # Number of assignments per name. 912 913 self.assignments = None 914 915 # Value-related methods. 916 917 def get_contexts(self): 918 return [c for (c, v) in self.context_values] 919 920 def get_values(self): 921 return [v for (c, v) in self.context_values] 922 923 def get_context(self): 924 if len(self.context_values) == 1: 925 return self.get_contexts()[0] 926 else: 927 return None 928 929 def get_value(self): 930 if len(self.context_values) == 1: 931 return self.get_values()[0] 932 else: 933 return None 934 935 def update(self, context_values, single_assignment): 936 937 """ 938 Update the attribute, adding the 'context_values' provided to the 939 known details associated with the attribute, changing the number of 940 assignments according to the 'single_assignment' status of the 941 operation, where a true value indicates that only one assignment is 942 associated with the update, and a false value indicates that potentially 943 many assignments may be involved. 944 """ 945 946 if self.context_values.issuperset(context_values) and \ 947 not (make_instance(), make_instance()) in context_values: 948 return 949 950 if self.assignments is None: 951 if single_assignment: 952 self.assignments = len(set(context_values)) 953 else: 954 self.assignments = AtLeast(len(set(context_values))) 955 else: 956 if single_assignment: 957 self.assignments += 1 958 else: 959 self.assignments += AtLeast(1) 960 961 self.context_values.update(context_values) 962 963 def is_constant(self): 964 965 """ 966 Return whether this attribute references something that can be regarded 967 as being constant within a particular scope. 968 """ 969 970 return self.assignments == 1 971 972 def is_strict_constant(self): 973 974 """ 975 Return whether this attribute references something that can be regarded 976 as being constant. 977 """ 978 979 value = self.get_value() 980 return not (value is None or (isinstance(value, Instance) and not isinstance(value, Constant))) 981 982 def is_static_attribute(self): 983 984 """ 985 Return whether this attribute is defined on a fixed/static object such 986 as a class or a module. 987 """ 988 989 return isinstance(self.parent, (Class, Module)) 990 991 def defines_ambiguous_class(self): 992 993 "Return whether this attribute defines more than one class." 994 995 if self.assignments > 1: 996 have_class = 0 997 for obj in self.get_values(): 998 if isinstance(obj, Class): 999 if have_class: 1000 return 1 1001 have_class = 1 1002 1003 return 0 1004 1005 def defined_within_hierarchy(self): 1006 1007 """ 1008 Return whether the parent and context of the attribute belong to the 1009 same class hierarchy. 1010 """ 1011 1012 # Must be defined within a class. 1013 1014 if isinstance(self.parent, Class): 1015 1016 # To be sure, all contexts must be classes and be the same as the 1017 # parent, or be a superclass of the parent, or be a subclass of the 1018 # parent. 1019 1020 for context in self.get_contexts(): 1021 if not ( 1022 isinstance(context, Class) and ( 1023 context is self.parent or 1024 context.has_subclass(self.parent) or 1025 self.parent.has_subclass(context)) 1026 ): 1027 return 0 1028 1029 return 1 1030 1031 # Instance attributes are not defined within a hierarchy. 1032 1033 else: 1034 return 0 1035 1036 def defined_outside_hierarchy(self): 1037 1038 """ 1039 Return whether the parent and context of the attribute never belong to 1040 the same class hierarchy. 1041 """ 1042 1043 # Must be defined within a class. 1044 1045 if isinstance(self.parent, Class): 1046 1047 # To be sure, all contexts must be classes and be the same as the 1048 # parent, or be a superclass of the parent, or be a subclass of the 1049 # parent. 1050 1051 for context in self.get_contexts(): 1052 if not ( 1053 isinstance(context, Class) and not ( 1054 context is self.parent or 1055 context.has_subclass(self.parent) or 1056 self.parent.has_subclass(context)) 1057 ): 1058 return 0 1059 1060 return 1 1061 1062 # Instance attributes are not defined within a hierarchy. 1063 1064 else: 1065 return 0 1066 1067 def __repr__(self): 1068 return "Attr(%r, %s, %r) # {[%s] (%r)}" % ( 1069 self.position, shortrepr(self.parent), self.name, 1070 self._context_values_str(), self.assignments 1071 ) 1072 1073 def __shortrepr__(self): 1074 return "Attr(%r, %s, %r)" % ( 1075 self.position, shortrepr(self.parent), self.name 1076 ) 1077 1078 def _context_values_str(self): 1079 l = [] 1080 for (c, v) in self.context_values: 1081 l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) 1082 return ", ".join(l) 1083 1084 # Instances are special in that they need to be wrapped together with context in 1085 # a running program, but they are not generally constant. 1086 1087 class Instance: 1088 1089 "A placeholder indicating the involvement of an instance." 1090 1091 def __init__(self): 1092 self.parent = None 1093 1094 # Image generation details. 1095 1096 self.location = None 1097 1098 def __repr__(self): 1099 return "Instance()" 1100 1101 def __eq__(self, other): 1102 return other.__class__ is Instance 1103 1104 def __ne__(self, other): 1105 return not self.__eq__(other) 1106 1107 def __hash__(self): 1108 return 0 1109 1110 __shortrepr__ = __repr__ 1111 1112 common_instance = Instance() 1113 1114 def make_instance(): 1115 return common_instance 1116 1117 class Constant: 1118 1119 "A superclass for all constant or context-free structures." 1120 1121 pass 1122 1123 # Data objects appearing in programs before run-time. 1124 1125 class Const(Constant, Instance): 1126 1127 "A constant object with no context." 1128 1129 def __init__(self, value): 1130 Instance.__init__(self) 1131 self.value = value 1132 1133 def get_value(self): 1134 return self.value 1135 1136 def __repr__(self): 1137 if self.location is not None: 1138 return "Const(%r, location=%r)" % (self.value, self.location) 1139 else: 1140 return "Const(%r)" % self.value 1141 1142 __shortrepr__ = __repr__ 1143 1144 # Support constants as dictionary keys in order to build constant tables. 1145 1146 def __eq__(self, other): 1147 return other is not None and isinstance(other, Const) and \ 1148 self.value == other.value and self.value.__class__ is other.value.__class__ 1149 1150 def __ne__(self, other): 1151 return not self.__eq__(other) 1152 1153 def __hash__(self): 1154 return hash(self.value) 1155 1156 # Constants are instances of various built-in types. 1157 1158 def value_type_name(self): 1159 return ".".join(self.value_type_name_parts()) 1160 1161 def value_type_name_parts(self): 1162 return "__builtins__", self.value.__class__.__name__ 1163 1164 class Class(NamespaceDict, Naming, Constant): 1165 1166 "A base class for common/normal classes and the type class." 1167 1168 def __init__(self, name, parent=None, module=None, node=None): 1169 1170 """ 1171 Initialise the class with the given 'name', optional 'parent' object, 1172 'module' and AST 'node'. The optional information must be set at a later 1173 point using the 'set_context' method if omitted. 1174 """ 1175 1176 NamespaceDict.__init__(self, module) 1177 self.name = name 1178 self.parent = parent 1179 self.astnode = node 1180 1181 # Superclasses, descendants and attributes. 1182 1183 self.bases = [] 1184 self.descendants = set() 1185 self.instattr = set() # instance attributes 1186 self.relocated = set() # attributes which do not have the same 1187 # position as those of the same name in 1188 # some superclasses 1189 1190 # Caches. 1191 1192 self.reset_caches() 1193 1194 # Image generation details. 1195 1196 self.location = None 1197 self.code_location = None 1198 self.code_body_location = None # corresponds to the instantiator 1199 1200 self.instantiator = None 1201 self.instance_template_location = None # for creating instances at run-time 1202 1203 # Program-related details. 1204 1205 self.blocks = None 1206 self.temp_usage = 0 1207 self.local_usage = 0 1208 self.all_local_usage = 0 1209 1210 # Add an attribute to this class for use by instances. 1211 1212 self.set("__class__", self) 1213 1214 def set_context(self, parent, module, node): 1215 1216 "Set the 'parent', 'module' and 'node' of a class created in advance." 1217 1218 self.parent = parent 1219 self.module = module 1220 self.astnode = node 1221 1222 def reset_caches(self): 1223 1224 "Reset the caches." 1225 1226 self.all_instattr = None # cache for instance_attributes 1227 self.all_instattr_names = None # from all_instattr 1228 self.all_classattr = None # cache for all_class_attributes 1229 self.all_classattr_names = None # from all_classattr 1230 self.allattr = None # cache for all_attributes 1231 self.allattr_names = None # from allattr 1232 1233 def __repr__(self): 1234 if self.location is not None: 1235 return "Class(%r, %s, location=%r)" % (self.name, shortrepr(self.parent), self.location) 1236 else: 1237 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 1238 1239 def __shortrepr__(self): 1240 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 1241 1242 def get_body_block(self): 1243 return self.get_instantiator().blocks[0] 1244 1245 # Namespace-related methods. 1246 1247 def get_updated_context_values(self, context_values): 1248 1249 """ 1250 Adapt the contexts found in the given 'context_values', returning a new 1251 set. 1252 See: docs/assignment.txt 1253 """ 1254 1255 results = set() 1256 1257 for context, value in context_values: 1258 1259 # Change the ownership of functions. 1260 1261 if context is ReplaceableContext and value is not None and isinstance(value, Function): 1262 results.add((self, value)) 1263 else: 1264 results.add((context, value)) 1265 1266 return NamespaceDict.get_updated_context_values(self, results) 1267 1268 # Administrative methods. 1269 1270 def items_for_vacuum(self): 1271 1272 "Consider both class and instance attributes for vacuuming." 1273 1274 items = [] 1275 for name in self.instattr: 1276 items.append((name, None)) 1277 return NamespaceDict.items_for_vacuum(self) + items 1278 1279 def vacuum_item(self, name): 1280 1281 "Vacuum 'name' from the class or instance attribute collections." 1282 1283 # NOTE: Hack to prevent damage to exceptions. 1284 1285 if name == "_pc": 1286 return 0 1287 1288 if not NamespaceDict.vacuum_item(self, name): 1289 self.instattr.remove(name) 1290 return 1 1291 1292 def finalise_attributes(self): 1293 1294 "Make sure that all attributes are fully defined." 1295 1296 if self.finalised: 1297 return 1298 1299 self.finalise_class_attributes() 1300 self.finalise_instance_attributes() 1301 self.finalised = 1 1302 1303 def unfinalise_attributes(self): 1304 1305 "Open attribute definitions to editing and subsequent finalisation." 1306 1307 self.reset_caches() 1308 self.finalised = 0 1309 1310 # Convenience methods for accessing functions and methods. 1311 1312 def get_instantiator(self): 1313 1314 "Return a function which can be used to instantiate the class." 1315 1316 if self.instantiator is None: 1317 self.instantiator = self.get_init_method().as_instantiator() 1318 return self.instantiator 1319 1320 def get_init_method(self): 1321 return self.all_class_attributes()["__init__"].get_value() 1322 1323 # Class-specific methods. 1324 1325 def add_base(self, base): 1326 self.bases.append(base) 1327 base.add_descendant(self) 1328 1329 def add_instance_attribute(self, name): 1330 self.instattr.add(name) 1331 1332 def add_descendant(self, cls): 1333 self.descendants.add(cls) 1334 for base in self.bases: 1335 base.add_descendant(cls) 1336 1337 def has_subclass(self, other): 1338 return other in self.descendants 1339 1340 def all_descendants(self): 1341 d = {} 1342 for cls in self.descendants: 1343 d[cls.full_name()] = cls 1344 return d 1345 1346 "Return the attribute names provided by this class only." 1347 1348 class_attribute_names = NamespaceDict.keys 1349 1350 def class_attributes(self): 1351 1352 "Return class attributes provided by this class only." 1353 1354 return dict(self) 1355 1356 def all_class_attribute_names(self): 1357 1358 "Return the attribute names provided by classes in this hierarchy." 1359 1360 if self.all_classattr_names is None: 1361 self.all_class_attributes() 1362 self.all_classattr_names = self.all_classattr.keys() 1363 return self.all_classattr_names 1364 1365 def all_class_attributes(self): 1366 1367 "Return all class attributes, indicating the class which provides them." 1368 1369 self.finalise_class_attributes() 1370 return self.all_classattr 1371 1372 def finalise_class_attributes(self): 1373 1374 "Make sure that the class attributes are fully defined." 1375 1376 if self.all_classattr is None: 1377 self.all_classattr = {} 1378 clsattr = {} 1379 1380 # Record provisional position information for attributes of this 1381 # class. 1382 1383 for name in self.class_attributes().keys(): 1384 1385 # Special case: __class__ has to be at position 0. 1386 1387 if name == "__class__": 1388 clsattr[name] = set([0]) 1389 else: 1390 clsattr[name] = set() # position not yet defined 1391 1392 reversed_bases = self.bases[:] 1393 reversed_bases.reverse() 1394 1395 # For the bases in reverse order, acquire class attribute details. 1396 1397 for cls in reversed_bases: 1398 for name, attr in cls.all_class_attributes().items(): 1399 self.all_classattr[name] = attr 1400 1401 # Record previous attribute information. 1402 1403 if clsattr.has_key(name): 1404 clsattr[name].add(attr.position) 1405 1406 # Record class attributes provided by this class and its bases, 1407 # along with their positions. 1408 1409 self.all_classattr.update(self.class_attributes()) 1410 1411 if clsattr: 1412 for i, name in enumerate(self._get_position_list(clsattr)): 1413 self.all_classattr[name].position = i 1414 1415 return self.all_classattr 1416 1417 def instance_attribute_names(self): 1418 1419 "Return the instance attribute names provided by the class." 1420 1421 if self.all_instattr_names is None: 1422 self.instance_attributes() 1423 return self.all_instattr_names 1424 1425 def instance_attributes(self): 1426 1427 "Return instance-only attributes for instances of this class." 1428 1429 self.finalise_instance_attributes() 1430 return self.all_instattr 1431 1432 def finalise_instance_attributes(self): 1433 1434 "Make sure that the instance attributes are fully defined." 1435 1436 # Cache the attributes by converting the positioned attributes into a 1437 # dictionary. 1438 1439 if self.all_instattr is None: 1440 self.all_instattr = self._get_attributes() 1441 self.all_instattr_names = self.all_instattr.keys() 1442 1443 return self.all_instattr 1444 1445 def _get_attributes(self): 1446 1447 """ 1448 Return a dictionary mapping names to Attr instances incorporating 1449 information about their positions in the final instance structure. 1450 """ 1451 1452 instattr = {} 1453 1454 # Record provisional position information for attributes of this 1455 # instance. 1456 1457 for name in self.instattr: 1458 instattr[name] = set() # position not yet defined 1459 1460 reversed_bases = self.bases[:] 1461 reversed_bases.reverse() 1462 1463 # For the bases in reverse order, acquire instance attribute 1464 # details. 1465 1466 for cls in reversed_bases: 1467 for name, attr in cls.instance_attributes().items(): 1468 1469 # Record previous attribute information. 1470 1471 if instattr.has_key(name): 1472 instattr[name].add(attr.position) 1473 else: 1474 instattr[name] = set([attr.position]) 1475 1476 # Build the dictionary of attributes using the existing positions known 1477 # for each name. 1478 1479 d = {} 1480 for i, name in enumerate(self._get_position_list(instattr)): 1481 d[name] = Attr(i, make_instance(), name) 1482 return d 1483 1484 def _get_position_list(self, positions): 1485 1486 """ 1487 Return a list of attribute names for the given 'positions' mapping from 1488 names to positions, indicating the positions of the attributes in the 1489 final instance structure. 1490 """ 1491 1492 position_items = positions.items() 1493 namearray = [None] * len(position_items) 1494 1495 # Get the positions in ascending order of list size, with lists 1496 # of the same size ordered according to their smallest position 1497 # value. 1498 1499 position_items.sort(self._cmp_positions) 1500 1501 # Get the names in position order. 1502 1503 held = [] 1504 1505 for name, pos in position_items: 1506 pos = list(pos) 1507 pos.sort() 1508 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 1509 namearray[pos[0]] = name 1510 else: 1511 if pos: 1512 self.relocated.add(name) 1513 held.append((name, pos)) 1514 1515 for i, attr in enumerate(namearray): 1516 if attr is None: 1517 name, pos = held.pop() 1518 namearray[i] = name 1519 1520 return namearray 1521 1522 def _cmp_positions(self, a, b): 1523 1524 "Compare name plus position list operands 'a' and 'b'." 1525 1526 name_a, list_a = a 1527 name_b, list_b = b 1528 if len(list_a) < len(list_b): 1529 return -1 1530 elif len(list_a) > len(list_b): 1531 return 1 1532 elif not list_a: 1533 return 0 1534 else: 1535 return cmp(min(list_a), min(list_b)) 1536 1537 def all_attribute_names(self): 1538 1539 """ 1540 Return the names of all attributes provided by instances of this class. 1541 """ 1542 1543 self.allattr_names = self.allattr_names or self.all_attributes().keys() 1544 return self.allattr_names 1545 1546 def all_attributes(self): 1547 1548 """ 1549 Return all attributes for an instance, indicating either the class which 1550 provides them or that the instance itself provides them. 1551 1552 Note that __class__ acts like a class attribute for both instances and 1553 classes, and must be able to convey distinct values. 1554 """ 1555 1556 if self.allattr is None: 1557 self.allattr = {} 1558 self.allattr.update(self.all_class_attributes()) 1559 for name, attr in self.instance_attributes().items(): 1560 if self.allattr.has_key(name) and name != "__class__": 1561 print "Warning: instance attribute %r in %r overrides class attribute." % (name, self) 1562 self.allattr[name] = attr 1563 return self.allattr 1564 1565 class TypeClass(Class): 1566 1567 "A special class for the type class." 1568 1569 pass 1570 1571 class CommonClass(Class): 1572 1573 "An inspected class." 1574 1575 pass 1576 1577 class Function(NamespaceDict, Naming, Constant): 1578 1579 "An inspected function." 1580 1581 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, 1582 dynamic_def=0, module=None, node=None): 1583 1584 """ 1585 Initialise the function with the given 'name', 'parent', list of 1586 'argnames', list of 'defaults', the 'has_star' flag (indicating the 1587 presence of a * parameter), the 'has_dstar' flag (indicating the 1588 presence of a ** parameter), optional 'dynamic_def' (indicating that the 1589 function must be handled dynamically), optional 'module', and optional 1590 AST 'node'. 1591 """ 1592 1593 NamespaceDict.__init__(self, module) 1594 1595 if name is None: 1596 self.name = "lambda#%d" % new_lambda() 1597 self._is_lambda = 1 1598 else: 1599 self.name = name 1600 self._is_lambda = 0 1601 1602 self.parent = parent 1603 self.argnames = argnames 1604 self.defaults = defaults 1605 self.has_star = has_star 1606 self.has_dstar = has_dstar 1607 self.dynamic_def = dynamic_def 1608 self.astnode = node 1609 1610 # Initialise the positional names. 1611 1612 self.positional_names = self.argnames[:] 1613 if has_dstar: 1614 self.dstar_name = self.positional_names[-1] 1615 del self.positional_names[-1] 1616 if has_star: 1617 self.star_name = self.positional_names[-1] 1618 del self.positional_names[-1] 1619 1620 # Initialise default storage. 1621 # NOTE: This must be initialised separately due to the reliance on node 1622 # NOTE: visiting. 1623 1624 self.default_attrs = [] 1625 1626 # Initialise attribute usage. 1627 1628 if node is not None: 1629 for arg in argnames: 1630 1631 # Define attribute users. 1632 1633 self._define_attribute_user_for_name(node, arg) 1634 1635 # Caches. 1636 1637 self.localnames = None # cache for locals 1638 1639 # Add parameters to the namespace. 1640 1641 self._add_parameters(argnames) 1642 1643 # Image generation details. 1644 1645 self.dynamic = None 1646 self.location = None 1647 self.code_location = None 1648 self.code_body_location = None 1649 1650 # Program-related details. 1651 1652 self.blocks = None 1653 self.body_block = None 1654 1655 self.temp_usage = 0 1656 self.local_usage = 0 1657 self.all_local_usage = 0 1658 1659 def _add_parameters(self, argnames): 1660 1661 "Add 'argnames' to the namespace." 1662 1663 for name in argnames: 1664 self.set(name, make_instance()) 1665 1666 for name, top_level in self._flattened_parameters(argnames): 1667 if not top_level: 1668 self.set(name, make_instance()) 1669 1670 def _flattened_parameters(self, argnames, top_level=1): 1671 l = [] 1672 for name in argnames: 1673 if isinstance(name, tuple): 1674 l += self._flattened_parameters(name, 0) 1675 else: 1676 l.append((name, top_level)) 1677 return l 1678 1679 def __repr__(self): 1680 if self.location is not None: 1681 return "Function(%r, %s, %r, location=%r, code_location=%r)" % ( 1682 self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location 1683 ) 1684 else: 1685 return "Function(%r, %s, %r)" % ( 1686 self.name, shortrepr(self.parent), self.argnames 1687 ) 1688 1689 def __shortrepr__(self): 1690 return "Function(%r, %s)" % ( 1691 self.name, shortrepr(self.parent) 1692 ) 1693 1694 def get_body_block(self): 1695 return self.body_block 1696 1697 def is_lambda(self): 1698 return self._is_lambda 1699 1700 # Defaults-related methods. 1701 1702 def store_default(self, attr_or_value): 1703 1704 """ 1705 Reserve space for defaults, set outside the function, potentially on a 1706 dynamic basis, using the 'attr_or_value'. 1707 """ 1708 1709 attr = Attr(None, self, None) 1710 self._set_using_attr(attr, attr_or_value) 1711 self.default_attrs.append(attr) 1712 1713 def make_dynamic(self): 1714 1715 "Return whether this function must be handled using a dynamic object." 1716 1717 if self.dynamic is None: 1718 for attr in self.default_attrs: 1719 if not attr.is_strict_constant() and self.dynamic_def: 1720 self.dynamic = 1 1721 self._make_dynamic() 1722 break 1723 else: 1724 self.dynamic = 0 1725 1726 return self.dynamic 1727 1728 is_dynamic = make_dynamic 1729 1730 def _make_dynamic(self): 1731 1732 "Where functions have dynamic defaults, add a context argument." 1733 1734 name = "<context>" 1735 self.argnames.insert(0, name) 1736 self.positional_names.insert(0, name) 1737 self.set(name, make_instance()) 1738 1739 # Namespace-related methods. 1740 1741 def make_global(self, name): 1742 1743 "Declare 'name' as a global in the current namespace." 1744 1745 if name not in self.argnames and not self.has_key(name): 1746 self.globals.add(name) 1747 return 1 1748 else: 1749 return 0 1750 1751 def parameters(self): 1752 1753 """ 1754 Return a dictionary mapping parameter names to their position in the 1755 parameter list. 1756 """ 1757 1758 parameters = {} 1759 for i, name in enumerate(self.argnames): 1760 parameters[name] = i 1761 return parameters 1762 1763 def tuple_parameters(self, argnames=None): 1764 1765 """ 1766 Return a list of (position, parameter) entries corresponding to tuple 1767 parameters, where each parameter may either be a string or another such 1768 list of entries. 1769 """ 1770 1771 names = argnames or self.argnames 1772 1773 l = [] 1774 for i, name in enumerate(names): 1775 if isinstance(name, tuple): 1776 l.append((i, self.tuple_parameters(name))) 1777 elif argnames: 1778 l.append((i, name)) 1779 return l 1780 1781 def all_locals(self): 1782 1783 "Return a dictionary mapping names to local and parameter details." 1784 1785 return dict(self) 1786 1787 def locals(self): 1788 1789 "Return a dictionary mapping names to local details." 1790 1791 if self.localnames is None: 1792 self.localnames = {} 1793 self.localnames.update(self.all_locals()) 1794 for name in self.argnames: 1795 del self.localnames[name] 1796 return self.localnames 1797 1798 def is_method(self): 1799 1800 """ 1801 Return whether this function is a method explicitly defined in a class. 1802 """ 1803 1804 return isinstance(self.parent, Class) 1805 1806 def is_relocated(self, name): 1807 1808 """ 1809 Determine whether the given attribute 'name' is relocated for instances 1810 having this function as a method. 1811 """ 1812 1813 for cls in self.parent.descendants: 1814 if name in cls.relocated: 1815 return 1 1816 return 0 1817 1818 # Administrative methods. 1819 1820 def finalise(self, objtable): 1821 self.finalise_attributes() 1822 self.finalise_users(objtable) 1823 1824 def items_for_vacuum(self): 1825 return self.lambdas.items() 1826 1827 def vacuum_item(self, name): 1828 del self.lambdas[name] 1829 return 1 1830 1831 def finalise_attributes(self): 1832 1833 """ 1834 Make sure all attributes (locals) are fully defined. Note that locals 1835 are not attributes in the sense of class, module or instance attributes. 1836 Defaults are also finalised by this method. 1837 """ 1838 1839 if self.finalised: 1840 return 1841 1842 # Defaults. 1843 1844 for i, default in enumerate(self.default_attrs): 1845 default.position = i 1846 1847 # Parameters. 1848 1849 i = self._finalise_parameters() 1850 1851 if i is not None: 1852 nparams = i + 1 1853 else: 1854 nparams = 0 1855 1856 # Locals (and tuple parameter names). 1857 1858 i = None 1859 for i, attr in enumerate(self.locals().values()): 1860 attr.position = i + nparams 1861 1862 if i is not None: 1863 nothers = i + 1 1864 else: 1865 nothers = 0 1866 1867 self.local_usage = nothers 1868 self.all_local_usage = nparams + nothers 1869 self.finalised = 1 1870 1871 def _finalise_parameters(self): 1872 if not self.argnames: 1873 return None 1874 1875 for i, name in enumerate(self.argnames): 1876 self[name].position = i 1877 1878 return i 1879 1880 def finalise_users(self, objtable): 1881 1882 "Record the object types for generating guards." 1883 1884 # Visit each user and examine the attribute usage for each name. 1885 1886 for user in self.all_attribute_users: 1887 user._attrtypes = {} 1888 for name, usage in user._attrcombined.items(): 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