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