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 # Include 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 514 # Template instance... 515 516 DataObject( 517 classcode, attrcode, call_method_code_location, 518 ( 519 call_method_value and len(call_method_value.positional_names), 520 call_method_value and len(call_method_value.defaults) 521 ), 522 1, 523 self.full_name() 524 ), 525 526 # Class... 527 528 DataObject( 529 classcode, attrcode, instantiator_code_location, 530 ( 531 len(self.get_instantiator().positional_names), 532 len(self.get_instantiator().defaults) 533 ), 534 0, 535 self.full_name() 536 ) 537 ] 538 539 # Namespace-related methods. 540 541 def get_updated_context_values(self, context_values): 542 543 """ 544 Adapt the contexts found in the given 'context_values', returning a new 545 set. 546 See: docs/assignment.txt 547 """ 548 549 results = set() 550 551 for context, value in context_values: 552 553 # Change the ownership of functions. 554 555 if context is None and value is not None and isinstance(value, Function): 556 results.add((self, value)) 557 else: 558 results.add((context, value)) 559 560 return NamespaceDict.get_updated_context_values(self, results) 561 562 def finalise_attributes(self): 563 564 "Make sure that all attributes are fully defined." 565 566 if self.finalised: 567 return 568 569 self.finalise_class_attributes() 570 self.finalise_instance_attributes() 571 self.finalised = 1 572 573 # Convenience methods for accessing functions and methods. 574 575 def get_instantiator(self): 576 577 "Return a function which can be used to instantiate the class." 578 579 if self.instantiator is None: 580 self.instantiator = self.get_init_method().function_from_method() 581 return self.instantiator 582 583 def get_init_method(self): 584 return self.all_class_attributes()["__init__"].get_value() 585 586 # Class-specific methods. 587 588 def add_base(self, base): 589 self.bases.append(base) 590 base.add_descendant(self) 591 592 def add_instance_attribute(self, name): 593 self.instattr.add(name) 594 595 def add_descendant(self, cls): 596 self.descendants.add(cls) 597 for base in self.bases: 598 base.add_descendant(cls) 599 600 def has_subclass(self, other): 601 return other in self.descendants 602 603 def all_descendants(self): 604 d = {} 605 for cls in self.descendants: 606 d[cls.full_name()] = cls 607 return d 608 609 "Return the attribute names provided by this class only." 610 611 class_attribute_names = NamespaceDict.keys 612 613 def class_attributes(self): 614 615 "Return class attributes provided by this class only." 616 617 return dict(self) 618 619 def all_class_attribute_names(self): 620 621 "Return the attribute names provided by classes in this hierarchy." 622 623 if self.all_classattr_names is None: 624 self.all_class_attributes() 625 return self.all_classattr_names 626 627 def all_class_attributes(self): 628 629 "Return all class attributes, indicating the class which provides them." 630 631 self.finalise_class_attributes() 632 return self.all_classattr 633 634 def finalise_class_attributes(self): 635 636 "Make sure that the class attributes are fully defined." 637 638 if self.all_classattr is None: 639 self.all_classattr = {} 640 clsattr = {} 641 642 # Record provisional position information for attributes of this 643 # class. 644 645 for name in self.class_attributes().keys(): 646 clsattr[name] = set() # position not yet defined 647 648 reversed_bases = self.bases[:] 649 reversed_bases.reverse() 650 651 # For the bases in reverse order, acquire class attribute details. 652 653 for cls in reversed_bases: 654 for name, attr in cls.all_class_attributes().items(): 655 self.all_classattr[name] = attr 656 657 # Record previous attribute information. 658 659 if clsattr.has_key(name): 660 clsattr[name].add(attr.position) 661 662 # Record class attributes provided by this class and its bases, 663 # along with their positions. 664 665 self.all_classattr.update(self.class_attributes()) 666 667 if clsattr: 668 for i, name in enumerate(self._get_position_list(clsattr)): 669 self.all_classattr[name].position = i 670 671 return self.all_classattr 672 673 def instance_attribute_names(self): 674 675 "Return the instance attribute names provided by the class." 676 677 if self.all_instattr_names is None: 678 self.instance_attributes() 679 return self.all_instattr_names 680 681 def instance_attributes(self): 682 683 "Return instance-only attributes for instances of this class." 684 685 self.finalise_instance_attributes() 686 return self.all_instattr 687 688 def finalise_instance_attributes(self): 689 690 "Make sure that the instance attributes are fully defined." 691 692 if self.all_instattr is None: 693 self.all_instattr = {} 694 instattr = {} 695 696 # Record provisional position information for attributes of this 697 # instance. 698 699 for name in self.instattr: 700 instattr[name] = set() # position not yet defined 701 702 reversed_bases = self.bases[:] 703 reversed_bases.reverse() 704 705 # For the bases in reverse order, acquire instance attribute 706 # details. 707 708 for cls in reversed_bases: 709 for name, attr in cls.instance_attributes().items(): 710 711 # Record previous attribute information. 712 713 if instattr.has_key(name): 714 instattr[name].add(attr.position) 715 716 # Cache the attributes by converting the positioned attributes into 717 # a dictionary. 718 719 if not instattr: 720 self.all_instattr = {} 721 else: 722 self.all_instattr = self._get_attributes(instattr) 723 724 self.all_instattr_names = self.all_instattr.keys() 725 726 return self.all_instattr 727 728 def _get_position_list(self, positions): 729 730 """ 731 Return a list of attribute names for the given 'positions' mapping from 732 names to positions, indicating the positions of the attributes in the 733 final instance structure. 734 """ 735 736 position_items = positions.items() 737 namearray = [None] * len(position_items) 738 739 # Get the positions in ascending order of list size, with lists 740 # of the same size ordered according to their smallest position 741 # value. 742 743 position_items.sort(self._cmp_positions) 744 745 # Get the names in position order. 746 747 held = [] 748 749 for name, pos in position_items: 750 pos = list(pos) 751 pos.sort() 752 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 753 namearray[pos[0]] = name 754 else: 755 if pos: 756 self.relocated.add(name) 757 held.append((name, pos)) 758 759 for i, attr in enumerate(namearray): 760 if attr is None: 761 name, pos = held.pop() 762 namearray[i] = name 763 764 #print self.name, positions 765 #print "->", namearray 766 return namearray 767 768 def _get_attributes(self, positions): 769 770 """ 771 For the given 'positions' mapping from names to positions, return a 772 dictionary mapping names to Attr instances incorporating information 773 about their positions in the final instance structure. 774 """ 775 776 d = {} 777 for i, name in enumerate(self._get_position_list(positions)): 778 d[name] = Attr(i, Instance(), name) 779 return d 780 781 def _cmp_positions(self, a, b): 782 783 "Compare name plus position list operands 'a' and 'b'." 784 785 name_a, list_a = a 786 name_b, list_b = b 787 if len(list_a) < len(list_b): 788 return -1 789 elif len(list_a) > len(list_b): 790 return 1 791 elif not list_a: 792 return 0 793 else: 794 return cmp(min(list_a), min(list_b)) 795 796 def all_attribute_names(self): 797 798 """ 799 Return the names of all attributes provided by instances of this class. 800 """ 801 802 self.allattr_names = self.allattr_names or self.all_attributes().keys() 803 return self.allattr_names 804 805 def all_attributes(self): 806 807 """ 808 Return all attributes for an instance, indicating either the class which 809 provides them or that the instance itself provides them. 810 """ 811 812 if self.allattr is None: 813 self.allattr = {} 814 self.allattr.update(self.all_class_attributes()) 815 for name, attr in self.instance_attributes().items(): 816 if self.allattr.has_key(name): 817 print "Instance attribute %r in %r overrides class attribute." % (name, self) 818 self.allattr[name] = attr 819 return self.allattr 820 821 class Function(NamespaceDict, Naming, Constant): 822 823 "An inspected function." 824 825 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, module=None, node=None): 826 827 """ 828 Initialise the function with the given 'name', 'parent', list of 829 'argnames', list of 'defaults', the 'has_star' flag (indicating the 830 presence of a * parameter), the 'has_dstar' flag (indicating the 831 presence of a ** parameter), optional 'module', and optional AST 'node'. 832 """ 833 834 NamespaceDict.__init__(self, module) 835 self.name = name 836 self.parent = parent 837 self.argnames = argnames 838 self.defaults = defaults 839 self.has_star = has_star 840 self.has_dstar = has_dstar 841 self.astnode = node 842 self.referenced = 0 843 844 # Initialise the positional names. 845 846 self.positional_names = self.argnames[:] 847 if has_dstar: 848 self.dstar_name = self.positional_names[-1] 849 del self.positional_names[-1] 850 if has_star: 851 self.star_name = self.positional_names[-1] 852 del self.positional_names[-1] 853 854 # Initialise default storage. 855 # NOTE: This must be initialised separately due to the reliance on node 856 # NOTE: visiting. 857 858 self.default_attrs = [] 859 860 # Caches. 861 862 self.localnames = None # cache for locals 863 864 # Add parameters to the namespace. 865 866 self._add_parameters(argnames) 867 868 # Image generation details. 869 870 self.location = None 871 self.code_location = None 872 873 # Program-related details. 874 875 self.blocks = None 876 self.temp_usage = 0 877 self.local_usage = 0 878 self.all_local_usage = 0 879 880 def set_referenced(self): 881 self.referenced = 1 882 883 def _add_parameters(self, argnames): 884 for name in argnames: 885 if isinstance(name, tuple): 886 self._add_parameters(name) 887 else: 888 self.set(name, None) 889 890 def __repr__(self): 891 if self.location is not None: 892 return "Function(%r, %s, %r, location=%r, code_location=%r)" % ( 893 self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location 894 ) 895 else: 896 return "Function(%r, %s, %r)" % ( 897 self.name, shortrepr(self.parent), self.argnames 898 ) 899 900 def __shortrepr__(self): 901 return "Function(%r, %s)" % ( 902 self.name, shortrepr(self.parent) 903 ) 904 905 def as_raw(self, objtable, paramtable): 906 # NOTE: Need class and parameter details! Should arguably be types.FunctionType. 907 return [ 908 DataObject( 909 objtable.as_list().get_code("__builtins__.function"), 910 objtable.get_index("__builtins__.function"), 911 self.code_location, 912 ( 913 len(self.positional_names), 914 len(self.defaults) 915 ), 916 0, 917 "__builtins__.function", 918 paramtable.as_list().get_code(self.full_name()) 919 ) 920 ] 921 922 # Namespace-related methods. 923 924 def store_default(self, value): 925 attr = Attr(None, self, None) 926 attr.update([(None, value)], 1) 927 self.default_attrs.append(attr) 928 929 def make_global(self, name): 930 if name not in self.argnames and not self.has_key(name): 931 self.globals.add(name) 932 return 1 933 else: 934 return 0 935 936 def parameters(self): 937 938 """ 939 Return a dictionary mapping parameter names to their position in the 940 parameter list. 941 """ 942 943 parameters = {} 944 for i, name in enumerate(self.argnames): 945 parameters[name] = i 946 return parameters 947 948 def all_locals(self): 949 950 "Return a dictionary mapping names to local and parameter details." 951 952 return dict(self) 953 954 def locals(self): 955 956 "Return a dictionary mapping names to local details." 957 958 if self.localnames is None: 959 self.localnames = {} 960 self.localnames.update(self.all_locals()) 961 for name in self.argnames: 962 del self.localnames[name] 963 return self.localnames 964 965 def is_method(self): 966 967 "Return whether this function is a method." 968 969 return isinstance(self.parent, Class) 970 971 def is_relocated(self, name): 972 973 """ 974 Determine whether the given attribute 'name' is relocated for instances 975 having this function as a method. 976 """ 977 978 for cls in self.parent.descendants: 979 if name in cls.relocated: 980 return 1 981 return 0 982 983 def finalise_attributes(self): 984 985 """ 986 Make sure all attributes (locals) are fully defined. Note that locals 987 are not attributes in the sense of class, module or instance attributes. 988 Defaults are also finalised by this method. 989 """ 990 991 for i, default in enumerate(self.default_attrs): 992 default.position = i 993 994 i = None 995 for i, name in enumerate(self.argnames): 996 self[name].position = i 997 998 if i is not None: 999 nparams = i + 1 1000 else: 1001 nparams = 0 1002 1003 i = None 1004 for i, attr in enumerate(self.locals().values()): 1005 attr.position = i + nparams 1006 1007 if i is not None: 1008 nothers = i + 1 1009 else: 1010 nothers = 0 1011 1012 self.local_usage = nothers 1013 self.all_local_usage = nparams + nothers 1014 self.finalised = 1 1015 1016 def function_from_method(self): 1017 1018 "Make a function from a method." 1019 1020 function = Function(self.name, self.parent, self.argnames[1:], self.defaults, 1021 self.has_star, self.has_dstar, self.module, self.astnode) 1022 function.default_attrs = self.default_attrs 1023 return function 1024 1025 class UnresolvedName(NamespaceDict, Constant): 1026 1027 "A module, class or function which was mentioned but could not be imported." 1028 1029 def __init__(self, name, parent_name, module=None): 1030 NamespaceDict.__init__(self, module) 1031 self.name = name 1032 self.parent_name = parent_name 1033 self.parent = None 1034 self.referenced = 0 1035 1036 self.descendants = set() 1037 1038 def set_referenced(self): 1039 self.referenced = 1 1040 1041 def add_descendant(self, cls): 1042 self.descendants.add(cls) 1043 1044 def all_class_attributes(self): 1045 return {} 1046 1047 def instance_attributes(self): 1048 return {} 1049 1050 def __repr__(self): 1051 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 1052 1053 __shortrepr__ = __repr__ 1054 1055 def full_name(self): 1056 if self.name is not None: 1057 return self.parent_name + "." + self.name 1058 else: 1059 return self.parent_name 1060 1061 class Module(NamespaceDict, Constant): 1062 1063 "An inspected module's core details." 1064 1065 def __init__(self, name): 1066 NamespaceDict.__init__(self, self) 1067 self.name = name 1068 self.parent = None 1069 self.referenced = 0 1070 1071 # Original location details. 1072 1073 self.astnode = None 1074 1075 # Complete lists of classes and functions. 1076 1077 self.all_objects = set() 1078 1079 # Keyword records. 1080 1081 self.keyword_names = set() 1082 1083 # Image generation details. 1084 1085 self.location = None 1086 self.code_location = None 1087 1088 # Program-related details. 1089 1090 self.blocks = None 1091 self.temp_usage = 0 1092 self.local_usage = 0 1093 self.all_local_usage = 0 1094 1095 def set_referenced(self): 1096 self.referenced = 1 1097 1098 def full_name(self): 1099 return self.name 1100 1101 def __repr__(self): 1102 if self.location is not None: 1103 return "Module(%r, location=%r)" % (self.name, self.location) 1104 else: 1105 return "Module(%r)" % self.name 1106 1107 def __shortrepr__(self): 1108 return "Module(%r)" % self.name 1109 1110 def as_raw(self, objtable, paramtable): 1111 return [ 1112 DataObject( 1113 objtable.as_list().get_code(self.full_name()), 1114 None, # module name not used as an attribute 1115 None, 1116 None, 1117 0, 1118 self.full_name() 1119 ) 1120 ] 1121 1122 # Attribute methods. 1123 1124 "Return the module attribute names provided by the module." 1125 1126 module_attribute_names = NamespaceDict.keys 1127 1128 def module_attributes(self): 1129 1130 "Return a dictionary mapping names to module attributes." 1131 1132 return dict(self) 1133 1134 # vim: tabstop=4 expandtab shiftwidth=4