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