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