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