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 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 DataObject, DataValue, ReplaceableContext, PlaceholderContext 56 57 def shortrepr(obj): 58 if obj is None: 59 return repr(None) 60 else: 61 return obj.__shortrepr__() 62 63 # Special representations. 64 65 class AtLeast: 66 67 "A special representation for numbers of a given value or greater." 68 69 def __init__(self, count): 70 self.count = count 71 72 def __eq__(self, other): 73 return 0 74 75 __lt__ = __le__ = __eq__ 76 77 def __ne__(self, other): 78 return 1 79 80 def __gt__(self, other): 81 if isinstance(other, AtLeast): 82 return 0 83 else: 84 return self.count > other 85 86 def __ge__(self, other): 87 if isinstance(other, AtLeast): 88 return 0 89 else: 90 return self.count >= other 91 92 def __iadd__(self, other): 93 if isinstance(other, AtLeast): 94 self.count += other.count 95 else: 96 self.count += other 97 return self 98 99 def __radd__(self, other): 100 if isinstance(other, AtLeast): 101 return AtLeast(self.count + other.count) 102 else: 103 return AtLeast(self.count + other) 104 105 def __repr__(self): 106 return "AtLeast(%r)" % self.count 107 108 # Mix-ins and abstract classes. 109 110 class Naming: 111 112 "A mix-in providing naming conveniences." 113 114 def full_name(self): 115 if self.name is not None: 116 return self.parent.full_name() + "." + self.name 117 else: 118 return self.parent.full_name() 119 120 class NamespaceDict: 121 122 "A mix-in providing dictionary methods." 123 124 def __init__(self, module=None): 125 self.namespace = {} 126 self.globals = set() 127 self.scope_usage = {} 128 self.module = module 129 self.finalised = 0 130 131 # Attributes accessed on objects, potentially narrowing their types. 132 # Specific namespaces should define known names during initialisation. 133 # For example, functions can define names belonging to parameters. 134 135 # Attribute users, defining names which use attributes. 136 137 self.attribute_users = [{}] # stack of assignments 138 self.user_shelves = [] 139 self.loop_users = [{}] # stack of loop nodes 140 141 # Define attribute usage to identify active program sections. 142 143 self.all_attribute_users = set() 144 145 # Attribute/name definition and access. 146 147 def __delitem__(self, name): 148 del self.namespace[name] 149 150 def has_key(self, name): 151 return self.namespace.has_key(name) 152 153 def keys(self): 154 return self.namespace.keys() 155 156 def values(self): 157 return self.namespace.values() 158 159 def items(self): 160 return self.namespace.items() 161 162 def __getitem__(self, name): 163 return self.namespace[name] 164 165 def get(self, name, default=None): 166 return self.namespace.get(name, default) 167 168 def __setitem__(self, name, value): 169 self.set(name, value) 170 171 def set(self, name, value, single_assignment=1): 172 173 """ 174 A more powerful set operation, making 'name' refer to 'value' whilst 175 indicating whether a 'single_assignment' (true by default) occurs in 176 this operation (or whether the operation covers potentially many 177 assignments in the lifetime of a program). 178 """ 179 180 if name in self.globals: 181 self.module.set(name, value, 0) 182 else: 183 self._set(name, value, single_assignment) 184 185 def set_module(self, name, value): 186 187 """ 188 A specialised set operation, making 'name' refer to 'value' in the 189 context of making a module reference available in association with 190 'name' as part of the import of that module or a submodule of that 191 module. 192 """ 193 194 self._set(name, value, 1) 195 196 def _set(self, name, attr_or_value, single_assignment=1): 197 198 """ 199 The underlying set operation associating 'name' with the given 200 'attr_or_value'. 201 See: docs/assignment.txt 202 """ 203 204 # Add and/or obtain the namespace entry. 205 206 if not self.namespace.has_key(name): 207 self.namespace[name] = Attr(None, self, name) 208 209 attr = self.namespace[name] 210 self._set_using_attr(attr, attr_or_value, single_assignment) 211 212 def _set_using_attr(self, attr, attr_or_value, single_assignment=1): 213 214 # Handle attribute assignment as well as assignment of basic objects. 215 # Attempt to fix the context if not explicitly defined. 216 217 if isinstance(attr_or_value, Attr): 218 context_values = self.get_updated_context_values(attr_or_value.context_values) 219 else: 220 context_values = self.get_updated_context_values([self.get_context_and_value(attr_or_value)]) 221 222 attr.update(context_values, single_assignment) 223 224 def get_context_and_value(self, value): 225 226 "Return a context, value tuple for the given 'value'." 227 228 # Functions have a replaceable context. 229 230 if isinstance(value, Function): 231 return (ReplaceableContext, value) 232 233 # Classes use placeholder contexts which cannot be replaced but which 234 # do not communicate useful contextual information. 235 236 elif isinstance(value, Class): 237 return (PlaceholderContext, value) 238 239 # Other values employ themselves as the context. 240 241 else: 242 return (value, value) 243 244 def get_updated_context_values(self, context_values): 245 246 """ 247 Adapt the contexts found in the given 'context_values', returning a new 248 set. 249 See: docs/assignment.txt 250 """ 251 252 results = set() 253 254 for context, value in context_values: 255 256 # Set the context of instances to themselves. 257 258 if isinstance(value, Instance): 259 results.add((value, value)) 260 else: 261 results.add((context, value)) 262 263 return results 264 265 def make_global(self, name): 266 267 "Declare 'name' as a global in the current namespace." 268 269 if not self.namespace.has_key(name): 270 self.globals.add(name) 271 return 1 272 else: 273 return 0 274 275 def note_scope(self, name, scope): 276 277 "Note usage of 'name' from the given 'scope' in the current namespace." 278 279 if not self.scope_usage.has_key(name): 280 self.scope_usage[name] = scope 281 return 1 282 elif self.scope_usage[name] == scope: 283 return 1 284 else: 285 return 0 286 287 def used_in_scope(self, name, scope): 288 289 """ 290 Return whether 'name' is used from the given 'scope' in the current 291 namespace. 292 """ 293 294 return self.scope_usage.get(name) == scope 295 296 # Attribute positioning. 297 298 def attributes_as_list(self): 299 300 "Return the attributes in a list." 301 302 self.finalise_attributes() 303 l = [None] * len(self.keys()) 304 for attr in self.values(): 305 l[attr.position] = attr 306 return l 307 308 def finalise_attributes(self): 309 310 "Make sure all attributes are fully defined." 311 312 if self.finalised: 313 return 314 315 # The default action is to assign attribute positions sequentially. 316 317 for i, attr in enumerate(self.values()): 318 attr.position = i 319 320 self.finalised = 1 321 322 def unfinalise_attributes(self): 323 324 "Open attribute definitions to editing and subsequent finalisation." 325 326 self.finalised = 0 327 328 # Attribute usage methods. 329 330 def get_all_attribute_usage(self): 331 332 """ 333 Return a set of all usage tuples for attributes used with the different 334 local names. 335 """ 336 337 usage = set() 338 for user in self.all_attribute_users: 339 for name, attrnames in user._attrnames.items(): 340 usage.add(tuple(attrnames)) 341 return usage 342 343 def use_attribute(self, name, attrname): 344 345 "Declare the usage on 'name' of the given 'attrname'." 346 347 return self._use_attribute(name, attrname) 348 349 # These shadow various methods in the InspectedModule class, and provide 350 # implementations generally. 351 352 def _use_attribute(self, name, attrname): 353 354 """ 355 Indicate the use of the given 'name' in this namespace of an attribute 356 with the given 'attrname'. 357 """ 358 359 for users in (self.attribute_users[-1], self.loop_users[-1]): 360 361 # Add the usage to all current users. 362 363 if users.has_key(name): 364 for user in users[name]: 365 user._attrnames[name].add(attrname) 366 367 users = self.attribute_users[-1] 368 369 if users.has_key(name): 370 return users[name] 371 else: 372 return [] 373 374 def _define_attribute_user(self, node): 375 376 """ 377 Define 'node' as the user of attributes, indicating the point where the 378 user is defined. 379 """ 380 381 name = node.name 382 self._define_attribute_user_for_name(node, name) 383 384 def _define_attribute_user_for_name(self, node, name): 385 386 "Define 'node' as the user of attributes for the given 'name'." 387 388 users = self.attribute_users[-1] 389 390 # This node overrides previous definitions. 391 392 users[name] = set([node]) 393 394 # Record the attribute combinations for the name. 395 396 self._init_attribute_user_for_name(node, name) 397 398 # Propagate any loop usage forward to any redefinition of a name. 399 400 loop_users = self.loop_users[-1] 401 402 if loop_users.has_key(name): 403 for loop_user in loop_users[name]: 404 node._attrnames[name].update(loop_user._attrnames[name]) 405 del loop_users[name] 406 407 # Remember this user. 408 409 self.all_attribute_users.add(node) 410 411 def _init_attribute_user_for_name(self, node, name): 412 413 "Make sure that 'node' is initialised for 'name'." 414 415 if not hasattr(node, "_attrnames"): 416 node._attrnames = {} 417 418 node._attrnames[name] = set() 419 420 def _new_branchpoint(self): 421 422 """ 423 Establish a new branchpoint where several control-flow branches diverge 424 and subsequently converge. 425 """ 426 427 self.user_shelves.append([]) 428 429 def _new_branch(self, loop_node=None): 430 431 """ 432 Establish a new control-flow branch, transferring attribute usage to 433 the new branch so that it may be augmented for each name locally. 434 435 If the optional 'loop_node' is given, add it as an active user to be 436 informed of attribute usage. 437 """ 438 439 # Retain a record of active users. 440 441 d = {} 442 d.update(self.attribute_users[-1]) 443 self.attribute_users.append(d) 444 445 new_users = self.attribute_users[-1] 446 447 d = {} 448 d.update(self.loop_users[-1]) 449 450 if loop_node is not None: 451 for name in new_users.keys(): 452 if not d.has_key(name): 453 d[name] = set([loop_node]) 454 else: 455 d[name] = d[name].union([loop_node]) 456 self._init_attribute_user_for_name(loop_node, name) 457 458 self.loop_users.append(d) 459 460 def _abandon_branch(self): 461 pass 462 463 def _shelve_branch(self): 464 465 """ 466 Shelve the current control-flow branch, recording the attribute usage 467 for subsequent merging. If this branch should be abandoned, the usage 468 observations are still recorded but will not contribute to subsequent 469 observations after a merge. 470 """ 471 472 users = self.attribute_users.pop() 473 self.user_shelves[-1].append(users) 474 475 def _merge_branches(self): 476 477 """ 478 Merge control-flow branches. This should find the users active within 479 each branch, which have been "shelved", and update the active users 480 dictionary with these contributions. 481 """ 482 483 # Combine the attribute users. This ensures that a list of users 484 # affected by attribute usage is maintained for the current branch. 485 486 users = self.attribute_users[-1] 487 new_users = {} 488 489 all_shelved_users = self.user_shelves.pop() 490 all_user_names = set() 491 492 # Find all the names defined by the branches. 493 494 for shelved_users in all_shelved_users: 495 all_user_names.update(shelved_users.keys()) 496 497 # Copy all definitions from the branches for the names, maintaining 498 # the existing users where a branch does not redefine a name. 499 500 for shelved_users in all_shelved_users: 501 for name in all_user_names: 502 503 if shelved_users.has_key(name): 504 nodes = shelved_users[name] 505 else: 506 nodes = users.get(name, set()) 507 508 if nodes: 509 if not new_users.has_key(name): 510 new_users[name] = set(nodes) 511 else: 512 new_users[name].update(nodes) 513 514 self.attribute_users[-1] = new_users 515 516 # Program data structures. 517 518 class Attr: 519 520 "An attribute entry having a context." 521 522 def __init__(self, position, parent, name): 523 524 """ 525 Initialise the attribute with the given 'position' within the collection 526 of attributes of its 'parent', indicating its 'name'. 527 """ 528 529 self.position = position 530 self.parent = parent 531 self.name = name 532 533 # Possible values. 534 535 self.context_values = set() 536 537 # Number of assignments per name. 538 539 self.assignments = None 540 541 # Value-related methods. 542 543 def get_contexts(self): 544 return [c for (c, v) in self.context_values] 545 546 def get_values(self): 547 return [v for (c, v) in self.context_values] 548 549 def get_context(self): 550 if len(self.context_values) == 1: 551 return self.get_contexts()[0] 552 else: 553 return None 554 555 def get_value(self): 556 if len(self.context_values) == 1: 557 return self.get_values()[0] 558 else: 559 return None 560 561 def update(self, context_values, single_assignment): 562 563 """ 564 Update the attribute, adding the 'context_values' provided to the 565 known details associated with the attribute, changing the number of 566 assignments according to the 'single_assignment' status of the 567 operation, where a true value indicates that only one assignment is 568 associated with the update, and a false value indicates that potentially 569 many assignments may be involved. 570 """ 571 572 if self.assignments is None: 573 if single_assignment: 574 self.assignments = 1 575 else: 576 self.assignments = AtLeast(1) 577 else: 578 if single_assignment: 579 self.assignments += 1 580 else: 581 self.assignments += AtLeast(1) 582 583 self.context_values.update(context_values) 584 585 def is_constant(self): 586 587 """ 588 Return whether this attribute references something that can be regarded 589 as being constant within a particular scope. 590 """ 591 592 return self.assignments == 1 593 594 def is_strict_constant(self): 595 596 """ 597 Return whether this attribute references something that can be regarded 598 as being constant. 599 """ 600 601 value = self.get_value() 602 return not (value is None or isinstance(value, Instance)) 603 604 def is_static_attribute(self): 605 606 """ 607 Return whether this attribute is defined on a fixed/static object such 608 as a class or a module. 609 """ 610 611 return isinstance(self.parent, (Class, Module)) 612 613 def defines_ambiguous_class(self): 614 615 "Return whether this attribute defines more than one class." 616 617 if self.assignments > 1: 618 have_class = 0 619 for obj in self.get_values(): 620 if isinstance(obj, Class): 621 if have_class: 622 return 1 623 have_class = 1 624 625 return 0 626 627 def defined_within_hierarchy(self): 628 629 """ 630 Return whether the parent and context of the attribute belong to the 631 same class hierarchy. 632 """ 633 634 # Must be defined within a class. 635 636 if isinstance(self.parent, Class): 637 638 # To be sure, all contexts must be classes and be the same as the 639 # parent, or be a superclass of the parent, or be a subclass of the 640 # parent. 641 642 for context in self.get_contexts(): 643 if not ( 644 isinstance(context, Class) and ( 645 context is self.parent or 646 context.has_subclass(self.parent) or 647 self.parent.has_subclass(context)) 648 ): 649 return 0 650 651 return 1 652 653 # Instance attributes are not defined within a hierarchy. 654 655 else: 656 return 0 657 658 def defined_outside_hierarchy(self): 659 660 """ 661 Return whether the parent and context of the attribute never belong to 662 the same class hierarchy. 663 """ 664 665 # Must be defined within a class. 666 667 if isinstance(self.parent, Class): 668 669 # To be sure, all contexts must be classes and be the same as the 670 # parent, or be a superclass of the parent, or be a subclass of the 671 # parent. 672 673 for context in self.get_contexts(): 674 if not ( 675 isinstance(context, Class) and not ( 676 context is self.parent or 677 context.has_subclass(self.parent) or 678 self.parent.has_subclass(context)) 679 ): 680 return 0 681 682 return 1 683 684 # Instance attributes are not defined within a hierarchy. 685 686 else: 687 return 0 688 689 def __repr__(self): 690 return "Attr(%r, %s, %r) # {[%s] (%r)}" % ( 691 self.position, shortrepr(self.parent), self.name, 692 self._context_values_str(), self.assignments 693 ) 694 695 def __shortrepr__(self): 696 return "Attr(%r, %s, %r)" % ( 697 self.position, shortrepr(self.parent), self.name 698 ) 699 700 def _context_values_str(self): 701 l = [] 702 for (c, v) in self.context_values: 703 l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) 704 return ", ".join(l) 705 706 # Instances are special in that they need to be wrapped together with context in 707 # a running program, but they are not generally constant. 708 709 class Instance: 710 711 "A placeholder indicating the involvement of an instance." 712 713 def __init__(self): 714 self.parent = None 715 716 # Image generation details. 717 718 self.location = None 719 720 def __repr__(self): 721 return "Instance()" 722 723 __shortrepr__ = __repr__ 724 725 class Constant: 726 727 "A superclass for all constant or context-free structures." 728 729 pass 730 731 # Data objects appearing in programs before run-time. 732 733 class Const(Constant, Instance): 734 735 "A constant object with no context." 736 737 def __init__(self, value): 738 Instance.__init__(self) 739 self.value = value 740 741 def get_value(self): 742 return self.value 743 744 def __repr__(self): 745 if self.location is not None: 746 return "Const(%r, location=%r)" % (self.value, self.location) 747 else: 748 return "Const(%r)" % self.value 749 750 __shortrepr__ = __repr__ 751 752 # Support constants as dictionary keys in order to build constant tables. 753 754 def __eq__(self, other): 755 return other is not None and self.value == other.value and self.value.__class__ is other.value.__class__ 756 757 def __hash__(self): 758 return hash(self.value) 759 760 def value_type_name(self): 761 return "__builtins__." + self.value.__class__.__name__ 762 763 class Class(NamespaceDict, Naming, Constant): 764 765 "An inspected class." 766 767 def __init__(self, name, parent, module=None, node=None): 768 769 """ 770 Initialise the class with the given 'name', 'parent' object, optional 771 'module' and optional AST 'node'. 772 """ 773 774 NamespaceDict.__init__(self, module) 775 self.name = name 776 self.parent = parent 777 self.astnode = node 778 node._def = self 779 780 # Superclasses, descendants and attributes. 781 782 self.bases = [] 783 self.descendants = set() 784 self.instattr = set() # instance attributes 785 self.relocated = set() # attributes which do not have the same 786 # position as those of the same name in 787 # some superclasses 788 789 # Caches. 790 791 self.reset_caches() 792 793 # Image generation details. 794 795 self.location = None 796 self.code_location = None 797 self.code_body_location = None # corresponds to the instantiator 798 799 self.instantiator = None 800 self.instance_template_location = None # for creating instances at run-time 801 802 # Program-related details. 803 804 self.blocks = None 805 self.temp_usage = 0 806 self.local_usage = 0 807 self.all_local_usage = 0 808 809 # Add this class to its attributes. 810 811 self.set("__class__", self) 812 813 def reset_caches(self): 814 815 "Reset the caches." 816 817 self.all_instattr = None # cache for instance_attributes 818 self.all_instattr_names = None # from all_instattr 819 self.all_classattr = None # cache for all_class_attributes 820 self.all_classattr_names = None # from all_classattr 821 self.allattr = None # cache for all_attributes 822 self.allattr_names = None # from allattr 823 824 def __repr__(self): 825 if self.location is not None: 826 return "Class(%r, %s, location=%r)" % (self.name, shortrepr(self.parent), self.location) 827 else: 828 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 829 830 def __shortrepr__(self): 831 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 832 833 def get_body_block(self): 834 return self.get_instantiator().blocks[0] 835 836 # Namespace-related methods. 837 838 def get_updated_context_values(self, context_values): 839 840 """ 841 Adapt the contexts found in the given 'context_values', returning a new 842 set. 843 See: docs/assignment.txt 844 """ 845 846 results = set() 847 848 for context, value in context_values: 849 850 # Change the ownership of functions. 851 852 if context is ReplaceableContext and value is not None and isinstance(value, Function): 853 results.add((self, value)) 854 else: 855 results.add((context, value)) 856 857 return NamespaceDict.get_updated_context_values(self, results) 858 859 def finalise_attributes(self): 860 861 "Make sure that all attributes are fully defined." 862 863 if self.finalised: 864 return 865 866 self.finalise_class_attributes() 867 self.finalise_instance_attributes() 868 self.finalised = 1 869 870 def unfinalise_attributes(self): 871 872 "Open attribute definitions to editing and subsequent finalisation." 873 874 self.reset_caches() 875 self.finalised = 0 876 877 # Convenience methods for accessing functions and methods. 878 879 def get_instantiator(self): 880 881 "Return a function which can be used to instantiate the class." 882 883 if self.instantiator is None: 884 self.instantiator = self.get_init_method().as_instantiator() 885 return self.instantiator 886 887 def get_init_method(self): 888 return self.all_class_attributes()["__init__"].get_value() 889 890 # Class-specific methods. 891 892 def add_base(self, base): 893 self.bases.append(base) 894 base.add_descendant(self) 895 896 def add_instance_attribute(self, name): 897 self.instattr.add(name) 898 899 def add_descendant(self, cls): 900 self.descendants.add(cls) 901 for base in self.bases: 902 base.add_descendant(cls) 903 904 def has_subclass(self, other): 905 return other in self.descendants 906 907 def all_descendants(self): 908 d = {} 909 for cls in self.descendants: 910 d[cls.full_name()] = cls 911 return d 912 913 "Return the attribute names provided by this class only." 914 915 class_attribute_names = NamespaceDict.keys 916 917 def class_attributes(self): 918 919 "Return class attributes provided by this class only." 920 921 return dict(self) 922 923 def all_class_attribute_names(self): 924 925 "Return the attribute names provided by classes in this hierarchy." 926 927 if self.all_classattr_names is None: 928 self.all_class_attributes() 929 self.all_classattr_names = self.all_classattr.keys() 930 return self.all_classattr_names 931 932 def all_class_attributes(self): 933 934 "Return all class attributes, indicating the class which provides them." 935 936 self.finalise_class_attributes() 937 return self.all_classattr 938 939 def finalise_class_attributes(self): 940 941 "Make sure that the class attributes are fully defined." 942 943 if self.all_classattr is None: 944 self.all_classattr = {} 945 clsattr = {} 946 947 # Record provisional position information for attributes of this 948 # class. 949 950 for name in self.class_attributes().keys(): 951 clsattr[name] = set() # position not yet defined 952 953 reversed_bases = self.bases[:] 954 reversed_bases.reverse() 955 956 # For the bases in reverse order, acquire class attribute details. 957 958 for cls in reversed_bases: 959 for name, attr in cls.all_class_attributes().items(): 960 self.all_classattr[name] = attr 961 962 # Record previous attribute information. 963 964 if clsattr.has_key(name): 965 clsattr[name].add(attr.position) 966 967 # Record class attributes provided by this class and its bases, 968 # along with their positions. 969 970 self.all_classattr.update(self.class_attributes()) 971 972 if clsattr: 973 for i, name in enumerate(self._get_position_list(clsattr)): 974 self.all_classattr[name].position = i 975 976 return self.all_classattr 977 978 def instance_attribute_names(self): 979 980 "Return the instance attribute names provided by the class." 981 982 if self.all_instattr_names is None: 983 self.instance_attributes() 984 return self.all_instattr_names 985 986 def instance_attributes(self): 987 988 "Return instance-only attributes for instances of this class." 989 990 self.finalise_instance_attributes() 991 return self.all_instattr 992 993 def finalise_instance_attributes(self): 994 995 "Make sure that the instance attributes are fully defined." 996 997 # Cache the attributes by converting the positioned attributes into a 998 # dictionary. 999 1000 if self.all_instattr is None: 1001 self.all_instattr = self._get_attributes() 1002 self.all_instattr_names = self.all_instattr.keys() 1003 1004 return self.all_instattr 1005 1006 def _get_attributes(self): 1007 1008 """ 1009 Return a dictionary mapping names to Attr instances incorporating 1010 information about their positions in the final instance structure. 1011 """ 1012 1013 instattr = {} 1014 1015 # Record provisional position information for attributes of this 1016 # instance. 1017 1018 for name in self.instattr: 1019 instattr[name] = set() # position not yet defined 1020 1021 reversed_bases = self.bases[:] 1022 reversed_bases.reverse() 1023 1024 # For the bases in reverse order, acquire instance attribute 1025 # details. 1026 1027 for cls in reversed_bases: 1028 for name, attr in cls.instance_attributes().items(): 1029 1030 # Record previous attribute information. 1031 1032 if instattr.has_key(name): 1033 instattr[name].add(attr.position) 1034 else: 1035 instattr[name] = set([attr.position]) 1036 1037 # Build the dictionary of attributes using the existing positions known 1038 # for each name. 1039 1040 d = {} 1041 for i, name in enumerate(self._get_position_list(instattr)): 1042 d[name] = Attr(i, Instance(), name) 1043 return d 1044 1045 def _get_position_list(self, positions): 1046 1047 """ 1048 Return a list of attribute names for the given 'positions' mapping from 1049 names to positions, indicating the positions of the attributes in the 1050 final instance structure. 1051 """ 1052 1053 position_items = positions.items() 1054 namearray = [None] * len(position_items) 1055 1056 # Get the positions in ascending order of list size, with lists 1057 # of the same size ordered according to their smallest position 1058 # value. 1059 1060 position_items.sort(self._cmp_positions) 1061 1062 # Get the names in position order. 1063 1064 held = [] 1065 1066 for name, pos in position_items: 1067 pos = list(pos) 1068 pos.sort() 1069 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 1070 namearray[pos[0]] = name 1071 else: 1072 if pos: 1073 self.relocated.add(name) 1074 held.append((name, pos)) 1075 1076 for i, attr in enumerate(namearray): 1077 if attr is None: 1078 name, pos = held.pop() 1079 namearray[i] = name 1080 1081 return namearray 1082 1083 def _cmp_positions(self, a, b): 1084 1085 "Compare name plus position list operands 'a' and 'b'." 1086 1087 name_a, list_a = a 1088 name_b, list_b = b 1089 if len(list_a) < len(list_b): 1090 return -1 1091 elif len(list_a) > len(list_b): 1092 return 1 1093 elif not list_a: 1094 return 0 1095 else: 1096 return cmp(min(list_a), min(list_b)) 1097 1098 def all_attribute_names(self): 1099 1100 """ 1101 Return the names of all attributes provided by instances of this class. 1102 """ 1103 1104 self.allattr_names = self.allattr_names or self.all_attributes().keys() 1105 return self.allattr_names 1106 1107 def all_attributes(self): 1108 1109 """ 1110 Return all attributes for an instance, indicating either the class which 1111 provides them or that the instance itself provides them. 1112 """ 1113 1114 if self.allattr is None: 1115 self.allattr = {} 1116 self.allattr.update(self.all_class_attributes()) 1117 for name, attr in self.instance_attributes().items(): 1118 if self.allattr.has_key(name): 1119 print "Instance attribute %r in %r overrides class attribute." % (name, self) 1120 self.allattr[name] = attr 1121 return self.allattr 1122 1123 class Function(NamespaceDict, Naming, Constant): 1124 1125 "An inspected function." 1126 1127 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, 1128 dynamic_def=0, module=None, node=None): 1129 1130 """ 1131 Initialise the function with the given 'name', 'parent', list of 1132 'argnames', list of 'defaults', the 'has_star' flag (indicating the 1133 presence of a * parameter), the 'has_dstar' flag (indicating the 1134 presence of a ** parameter), optional 'module', and optional AST 'node'. 1135 """ 1136 1137 NamespaceDict.__init__(self, module) 1138 self.name = name 1139 self.parent = parent 1140 self.argnames = argnames 1141 self.defaults = defaults 1142 self.has_star = has_star 1143 self.has_dstar = has_dstar 1144 self.dynamic_def = dynamic_def 1145 self.astnode = node 1146 node._def = self 1147 1148 # Initialise the positional names. 1149 1150 self.positional_names = self.argnames[:] 1151 if has_dstar: 1152 self.dstar_name = self.positional_names[-1] 1153 del self.positional_names[-1] 1154 if has_star: 1155 self.star_name = self.positional_names[-1] 1156 del self.positional_names[-1] 1157 1158 # Initialise default storage. 1159 # NOTE: This must be initialised separately due to the reliance on node 1160 # NOTE: visiting. 1161 1162 self.default_attrs = [] 1163 1164 # Initialise attribute usage. 1165 1166 for arg in argnames: 1167 1168 # Define attribute users. 1169 1170 if node is not None: 1171 self._define_attribute_user_for_name(node, arg) 1172 1173 # Or just record the usage. 1174 1175 else: 1176 self.attributes_used[-1][arg] = set() 1177 1178 # Caches. 1179 1180 self.localnames = None # cache for locals 1181 1182 # Add parameters to the namespace. 1183 1184 self._add_parameters(argnames) 1185 1186 # Image generation details. 1187 1188 self.dynamic = None 1189 self.location = None 1190 self.code_location = None 1191 self.code_body_location = None 1192 1193 # Program-related details. 1194 1195 self.blocks = None 1196 self.body_block = None 1197 1198 self.temp_usage = 0 1199 self.local_usage = 0 1200 self.all_local_usage = 0 1201 1202 def _add_parameters(self, argnames): 1203 for name in argnames: 1204 if isinstance(name, tuple): 1205 self._add_parameters(name) 1206 else: 1207 self.set(name, Instance()) 1208 1209 def __repr__(self): 1210 if self.location is not None: 1211 return "Function(%r, %s, %r, location=%r, code_location=%r)" % ( 1212 self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location 1213 ) 1214 else: 1215 return "Function(%r, %s, %r)" % ( 1216 self.name, shortrepr(self.parent), self.argnames 1217 ) 1218 1219 def __shortrepr__(self): 1220 return "Function(%r, %s)" % ( 1221 self.name, shortrepr(self.parent) 1222 ) 1223 1224 def get_body_block(self): 1225 return self.body_block 1226 1227 # Defaults-related methods. 1228 1229 def store_default(self, attr_or_value): 1230 1231 """ 1232 Reserve space for defaults, set outside the function, potentially on a 1233 dynamic basis, using the 'attr_or_value'. 1234 """ 1235 1236 attr = Attr(None, self, None) 1237 self._set_using_attr(attr, attr_or_value) 1238 self.default_attrs.append(attr) 1239 1240 def make_dynamic(self): 1241 1242 "Return whether this function must be handled using a dynamic object." 1243 1244 if self.dynamic is None: 1245 for attr in self.default_attrs: 1246 if not attr.is_strict_constant() and self.dynamic_def: 1247 self.dynamic = 1 1248 self._make_dynamic() 1249 break 1250 else: 1251 self.dynamic = 0 1252 1253 return self.dynamic 1254 1255 is_dynamic = make_dynamic 1256 1257 def _make_dynamic(self): 1258 1259 "Where functions have dynamic defaults, add a context argument." 1260 1261 name = "<context>" 1262 self.argnames.insert(0, name) 1263 self.positional_names.insert(0, name) 1264 self.set(name, Instance()) 1265 1266 # Namespace-related methods. 1267 1268 def make_global(self, name): 1269 1270 "Declare 'name' as a global in the current namespace." 1271 1272 if name not in self.argnames and not self.has_key(name): 1273 self.globals.add(name) 1274 return 1 1275 else: 1276 return 0 1277 1278 def parameters(self): 1279 1280 """ 1281 Return a dictionary mapping parameter names to their position in the 1282 parameter list. 1283 """ 1284 1285 parameters = {} 1286 for i, name in enumerate(self.argnames): 1287 parameters[name] = i 1288 return parameters 1289 1290 def all_locals(self): 1291 1292 "Return a dictionary mapping names to local and parameter details." 1293 1294 return dict(self) 1295 1296 def locals(self): 1297 1298 "Return a dictionary mapping names to local details." 1299 1300 if self.localnames is None: 1301 self.localnames = {} 1302 self.localnames.update(self.all_locals()) 1303 for name in self.argnames: 1304 del self.localnames[name] 1305 return self.localnames 1306 1307 def is_method(self): 1308 1309 """ 1310 Return whether this function is a method explicitly defined in a class. 1311 """ 1312 1313 return isinstance(self.parent, Class) 1314 1315 def is_relocated(self, name): 1316 1317 """ 1318 Determine whether the given attribute 'name' is relocated for instances 1319 having this function as a method. 1320 """ 1321 1322 for cls in self.parent.descendants: 1323 if name in cls.relocated: 1324 return 1 1325 return 0 1326 1327 def finalise_attributes(self): 1328 1329 """ 1330 Make sure all attributes (locals) are fully defined. Note that locals 1331 are not attributes in the sense of class, module or instance attributes. 1332 Defaults are also finalised by this method. 1333 """ 1334 1335 if self.finalised: 1336 return 1337 1338 # Defaults. 1339 1340 for i, default in enumerate(self.default_attrs): 1341 default.position = i 1342 1343 # Locals. 1344 1345 i = None 1346 for i, name in enumerate(self.argnames): 1347 self[name].position = i 1348 1349 if i is not None: 1350 nparams = i + 1 1351 else: 1352 nparams = 0 1353 1354 i = None 1355 for i, attr in enumerate(self.locals().values()): 1356 attr.position = i + nparams 1357 1358 if i is not None: 1359 nothers = i + 1 1360 else: 1361 nothers = 0 1362 1363 self.local_usage = nothers 1364 self.all_local_usage = nparams + nothers 1365 self.finalised = 1 1366 1367 def as_instantiator(self): 1368 1369 "Make an instantiator function from a method, keeping all arguments." 1370 1371 function = Function(self.parent.name, self.parent.parent, self.argnames, self.defaults, 1372 self.has_star, self.has_dstar, self.dynamic_def, self.module, self.astnode) 1373 function.default_attrs = self.default_attrs 1374 return function 1375 1376 class UnresolvedName(NamespaceDict, Constant): 1377 1378 "A module, class or function which was mentioned but could not be imported." 1379 1380 def __init__(self, name, parent_name, module=None): 1381 NamespaceDict.__init__(self, module) 1382 self.name = name 1383 self.parent_name = parent_name 1384 self.parent = None 1385 1386 self.descendants = set() 1387 1388 def add_descendant(self, cls): 1389 self.descendants.add(cls) 1390 1391 def all_class_attributes(self): 1392 return {} 1393 1394 def instance_attributes(self): 1395 return {} 1396 1397 def __repr__(self): 1398 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 1399 1400 __shortrepr__ = __repr__ 1401 1402 def full_name(self): 1403 if self.name is not None: 1404 return self.parent_name + "." + self.name 1405 else: 1406 return self.parent_name 1407 1408 class Module(NamespaceDict, Constant): 1409 1410 "An inspected module's core details." 1411 1412 def __init__(self, name): 1413 NamespaceDict.__init__(self, self) 1414 self.name = name 1415 self.parent = None 1416 1417 # Original location details. 1418 1419 self.astnode = None 1420 1421 # Complete lists of classes and functions. 1422 1423 self.all_objects = set() 1424 1425 # Keyword records. 1426 1427 self.keyword_names = set() 1428 1429 # Image generation details. 1430 1431 self.location = None 1432 self.code_location = None 1433 1434 # Program-related details. 1435 1436 self.blocks = None 1437 self.temp_usage = 0 1438 self.local_usage = 0 1439 self.all_local_usage = 0 1440 1441 def full_name(self): 1442 return self.name 1443 1444 def __repr__(self): 1445 if self.location is not None: 1446 return "Module(%r, location=%r)" % (self.name, self.location) 1447 else: 1448 return "Module(%r)" % self.name 1449 1450 def __shortrepr__(self): 1451 return "Module(%r)" % self.name 1452 1453 # Attribute methods. 1454 1455 "Return the module attribute names provided by the module." 1456 1457 module_attribute_names = NamespaceDict.keys 1458 1459 def module_attributes(self): 1460 1461 "Return a dictionary mapping names to module attributes." 1462 1463 return dict(self) 1464 1465 # vim: tabstop=4 expandtab shiftwidth=4