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