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, 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 self.referenced = 0 295 296 def set_referenced(self): 297 298 "Indicate that the contents are referenced via a namespace." 299 300 self.referenced = 1 301 302 for value in self.get_values(): 303 if value is not None: 304 value.set_referenced() 305 306 def get_contexts(self): 307 return [c for (c, v) in self.context_values] 308 309 def get_values(self): 310 return [v for (c, v) in self.context_values] 311 312 def get_context(self): 313 if len(self.context_values) == 1: 314 return self.get_contexts()[0] 315 else: 316 return None 317 318 def get_value(self): 319 if len(self.context_values) == 1: 320 return self.get_values()[0] 321 else: 322 return None 323 324 def update(self, context_values, single_assignment): 325 326 """ 327 Update the attribute, adding the 'context_values' provided to the 328 known details associated with the attribute, changing the number of 329 assignments according to the 'single_assignment' status of the 330 operation, where a true value indicates that only one assignment is 331 associated with the update, and a false value indicates that potentially 332 many assignments may be involved. 333 """ 334 335 if self.assignments is None: 336 if single_assignment: 337 self.assignments = 1 338 else: 339 self.assignments = AtLeast(1) 340 else: 341 if single_assignment: 342 self.assignments += 1 343 else: 344 self.assignments += AtLeast(1) 345 346 # Communicate referencing information. 347 348 if self.referenced: 349 for context, value in context_values: 350 if value is not None: 351 value.set_referenced() 352 353 self.context_values.update(context_values) 354 355 def is_class_attribute(self): 356 return isinstance(self.parent, Class) 357 358 def defined_within_hierarchy(self): 359 360 """ 361 Return whether the parent and context of the attribute belong to the 362 same class hierarchy. 363 """ 364 365 # Must be defined within a class. 366 367 if isinstance(self.parent, Class): 368 369 # To be sure, all contexts must be classes and be the same as the 370 # parent, or be a superclass of the parent, or be a subclass of the 371 # parent. 372 373 for context in self.get_contexts(): 374 if not ( 375 isinstance(context, Class) and ( 376 context is self.parent or 377 context.has_subclass(self.parent) or 378 self.parent.has_subclass(context)) 379 ): 380 return 0 381 382 return 1 383 384 # Instance attributes are not defined within a hierarchy. 385 386 else: 387 return 0 388 389 def defined_outside_hierarchy(self): 390 391 """ 392 Return whether the parent and context of the attribute never belong to 393 the same class hierarchy. 394 """ 395 396 # Must be defined within a class. 397 398 if isinstance(self.parent, Class): 399 400 # To be sure, all contexts must be classes and be the same as the 401 # parent, or be a superclass of the parent, or be a subclass of the 402 # parent. 403 404 for context in self.get_contexts(): 405 if not ( 406 isinstance(context, Class) and not ( 407 context is self.parent or 408 context.has_subclass(self.parent) or 409 self.parent.has_subclass(context)) 410 ): 411 return 0 412 413 return 1 414 415 # Instance attributes are not defined within a hierarchy. 416 417 else: 418 return 0 419 420 def __repr__(self): 421 return "Attr(%r, %s, %r) # [%s], %r" % ( 422 self.position, shortrepr(self.parent), self.name, 423 self._context_values_str(), self.assignments 424 ) 425 426 def _context_values_str(self): 427 l = [] 428 for (c, v) in self.context_values: 429 l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) 430 return ", ".join(l) 431 432 def as_raw(self, objtable, paramtable): 433 return [ 434 ( 435 self.get_context() and self.get_context().location, 436 self.get_value() and self.get_value().location 437 ) 438 ] 439 440 # Instances are special in that they need to be wrapped together with context in 441 # a running program, but they are not generally constant. 442 443 class Instance: 444 445 "A placeholder indicating the involvement of an instance." 446 447 def __init__(self): 448 self.parent = None 449 self.referenced = 0 450 451 # Image generation details. 452 453 self.location = None 454 455 def set_referenced(self): 456 self.referenced = 1 457 458 def __repr__(self): 459 return "Instance()" 460 461 __shortrepr__ = __repr__ 462 463 class Constant: 464 465 "A superclass for all constant or context-free structures." 466 467 pass 468 469 # Data objects appearing in programs before run-time. 470 471 class Const(Constant, Instance): 472 473 "A constant object with no context." 474 475 def __init__(self, value): 476 Instance.__init__(self) 477 self.value = value 478 479 def get_value(self): 480 return value 481 482 def __repr__(self): 483 if self.location is not None: 484 return "Const(%r, location=%r)" % (self.value, self.location) 485 else: 486 return "Const(%r)" % self.value 487 488 __shortrepr__ = __repr__ 489 490 def as_raw(self, objtable, paramtable): 491 # NOTE: Need class details! 492 return [ 493 DataObject( 494 objtable.as_list().get_code(self.value_type_name()), 495 objtable.get_index(self.value_type_name()), # is instance 496 None, 497 self.value_type_name(), 498 1 # size 499 ) 500 ] + self.raw_data() 501 502 def raw_data(self): 503 # NOTE: Start simple and use single entries for most types. 504 if self.value_type_name() in ("__builtins__.tuple", "__builtins__.list"): 505 return [len(self.value)] + list(self.value) 506 else: 507 return [self.value] 508 509 # Support constants as dictionary keys in order to build constant tables. 510 511 def __eq__(self, other): 512 return other is not None and self.value == other.value and self.value.__class__ is other.value.__class__ 513 514 def __hash__(self): 515 return hash(self.value) 516 517 def value_type_name(self): 518 return "__builtins__." + self.value.__class__.__name__ 519 520 class Class(NamespaceDict, Naming, Constant): 521 522 "An inspected class." 523 524 def __init__(self, name, parent, module=None, node=None): 525 526 """ 527 Initialise the class with the given 'name', 'parent' object, optional 528 'module' and optional AST 'node'. 529 """ 530 531 NamespaceDict.__init__(self, module) 532 self.name = name 533 self.parent = parent 534 self.astnode = node 535 self.referenced = 0 536 537 # Superclasses, descendants and attributes. 538 539 self.bases = [] 540 self.descendants = set() 541 self.instattr = set() # instance attributes 542 self.relocated = set() # attributes which do not have the same 543 # position as those of the same name in 544 # some superclasses 545 546 # Caches. 547 548 self.all_instattr = None # cache for instance_attributes 549 self.all_instattr_names = None # from all_instattr 550 self.all_classattr = None # cache for all_class_attributes 551 self.all_classattr_names = None # from all_classattr 552 self.allattr = None # cache for all_attributes 553 self.allattr_names = None # from allattr 554 555 # Image generation details. 556 557 self.location = None 558 self.code_location = None 559 self.code_body_location = None # corresponds to the instantiator 560 561 self.instantiator = None 562 self.instance_template_location = None # for creating instances at run-time 563 564 # Program-related details. 565 566 self.blocks = None 567 self.temp_usage = 0 568 self.local_usage = 0 569 self.all_local_usage = 0 570 571 # Add this class to its attributes. 572 573 self.set("__class__", self) 574 575 def set_referenced(self): 576 self.referenced = 1 577 578 def __repr__(self): 579 if self.location is not None: 580 return "Class(%r, %s, location=%r)" % (self.name, shortrepr(self.parent), self.location) 581 else: 582 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 583 584 def __shortrepr__(self): 585 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 586 587 def as_raw(self, objtable, paramtable, with_instantiator=1): 588 classcode = objtable.as_list().get_code(self.full_name()) 589 attrcode = objtable.get_index(self.full_name()) 590 591 # Include a template of an instance for use when instantiating classes. 592 593 call_method = self.all_class_attributes().get("__call__") 594 call_method_value = call_method and call_method.get_value() 595 call_method_code_location = call_method_value and call_method_value.code_location 596 call_method_funccode = call_method_value and paramtable.as_list().get_code(call_method_value.full_name()) 597 598 instantiator_funccode = paramtable.as_list().get_code(self.get_instantiator().full_name()) 599 600 # NOTE: The instantiator code is the first block of the class. 601 602 if not with_instantiator: 603 instantiator_code_location = self.full_name() 604 else: 605 instantiator_code_location = self.get_instantiator().blocks[0].location 606 607 return [ 608 609 # Template instance... 610 611 DataObject( 612 classcode, 613 attrcode, # is instance 614 call_method_code_location, 615 self.full_name(), 616 len(self.instance_attributes()) + 1, # size 617 call_method_funccode # funccode 618 ), 619 620 # Class... 621 622 DataObject( 623 classcode, 624 None, # is not instance 625 instantiator_code_location, 626 self.full_name(), 627 len(self.class_attributes()) + 1, # size 628 instantiator_funccode # funccode 629 ) 630 ] 631 632 def get_body_block(self): 633 return self.get_instantiator().blocks[0] 634 635 # Namespace-related methods. 636 637 def get_updated_context_values(self, context_values): 638 639 """ 640 Adapt the contexts found in the given 'context_values', returning a new 641 set. 642 See: docs/assignment.txt 643 """ 644 645 results = set() 646 647 for context, value in context_values: 648 649 # Change the ownership of functions. 650 651 if context is ReplaceableContext and value is not None and isinstance(value, Function): 652 results.add((self, value)) 653 else: 654 results.add((context, value)) 655 656 return NamespaceDict.get_updated_context_values(self, results) 657 658 def finalise_attributes(self): 659 660 "Make sure that all attributes are fully defined." 661 662 if self.finalised: 663 return 664 665 self.finalise_class_attributes() 666 self.finalise_instance_attributes() 667 self.finalised = 1 668 669 # Convenience methods for accessing functions and methods. 670 671 def get_instantiator(self): 672 673 "Return a function which can be used to instantiate the class." 674 675 if self.instantiator is None: 676 self.instantiator = self.get_init_method().as_instantiator() 677 return self.instantiator 678 679 def get_init_method(self): 680 return self.all_class_attributes()["__init__"].get_value() 681 682 # Class-specific methods. 683 684 def add_base(self, base): 685 self.bases.append(base) 686 base.add_descendant(self) 687 688 def add_instance_attribute(self, name): 689 self.instattr.add(name) 690 691 def add_descendant(self, cls): 692 self.descendants.add(cls) 693 for base in self.bases: 694 base.add_descendant(cls) 695 696 def has_subclass(self, other): 697 return other in self.descendants 698 699 def all_descendants(self): 700 d = {} 701 for cls in self.descendants: 702 d[cls.full_name()] = cls 703 return d 704 705 "Return the attribute names provided by this class only." 706 707 class_attribute_names = NamespaceDict.keys 708 709 def class_attributes(self): 710 711 "Return class attributes provided by this class only." 712 713 return dict(self) 714 715 def all_class_attribute_names(self): 716 717 "Return the attribute names provided by classes in this hierarchy." 718 719 if self.all_classattr_names is None: 720 self.all_class_attributes() 721 return self.all_classattr_names 722 723 def all_class_attributes(self): 724 725 "Return all class attributes, indicating the class which provides them." 726 727 self.finalise_class_attributes() 728 return self.all_classattr 729 730 def finalise_class_attributes(self): 731 732 "Make sure that the class attributes are fully defined." 733 734 if self.all_classattr is None: 735 self.all_classattr = {} 736 clsattr = {} 737 738 # Record provisional position information for attributes of this 739 # class. 740 741 for name in self.class_attributes().keys(): 742 clsattr[name] = set() # position not yet defined 743 744 reversed_bases = self.bases[:] 745 reversed_bases.reverse() 746 747 # For the bases in reverse order, acquire class attribute details. 748 749 for cls in reversed_bases: 750 for name, attr in cls.all_class_attributes().items(): 751 self.all_classattr[name] = attr 752 753 # Record previous attribute information. 754 755 if clsattr.has_key(name): 756 clsattr[name].add(attr.position) 757 758 # Record class attributes provided by this class and its bases, 759 # along with their positions. 760 761 self.all_classattr.update(self.class_attributes()) 762 763 if clsattr: 764 for i, name in enumerate(self._get_position_list(clsattr)): 765 self.all_classattr[name].position = i 766 767 return self.all_classattr 768 769 def instance_attribute_names(self): 770 771 "Return the instance attribute names provided by the class." 772 773 if self.all_instattr_names is None: 774 self.instance_attributes() 775 return self.all_instattr_names 776 777 def instance_attributes(self): 778 779 "Return instance-only attributes for instances of this class." 780 781 self.finalise_instance_attributes() 782 return self.all_instattr 783 784 def finalise_instance_attributes(self): 785 786 "Make sure that the instance attributes are fully defined." 787 788 # Cache the attributes by converting the positioned attributes into a 789 # dictionary. 790 791 if self.all_instattr is None: 792 self.all_instattr = self._get_attributes() 793 self.all_instattr_names = self.all_instattr.keys() 794 795 return self.all_instattr 796 797 def _get_attributes(self): 798 799 """ 800 Return a dictionary mapping names to Attr instances incorporating 801 information about their positions in the final instance structure. 802 """ 803 804 instattr = {} 805 806 # Record provisional position information for attributes of this 807 # instance. 808 809 for name in self.instattr: 810 instattr[name] = set() # position not yet defined 811 812 reversed_bases = self.bases[:] 813 reversed_bases.reverse() 814 815 # For the bases in reverse order, acquire instance attribute 816 # details. 817 818 for cls in reversed_bases: 819 for name, attr in cls.instance_attributes().items(): 820 821 # Record previous attribute information. 822 823 if instattr.has_key(name): 824 instattr[name].add(attr.position) 825 else: 826 instattr[name] = set([attr.position]) 827 828 # Build the dictionary of attributes using the existing positions known 829 # for each name. 830 831 d = {} 832 for i, name in enumerate(self._get_position_list(instattr)): 833 d[name] = Attr(i, Instance(), name) 834 return d 835 836 def _get_position_list(self, positions): 837 838 """ 839 Return a list of attribute names for the given 'positions' mapping from 840 names to positions, indicating the positions of the attributes in the 841 final instance structure. 842 """ 843 844 position_items = positions.items() 845 namearray = [None] * len(position_items) 846 847 # Get the positions in ascending order of list size, with lists 848 # of the same size ordered according to their smallest position 849 # value. 850 851 position_items.sort(self._cmp_positions) 852 853 # Get the names in position order. 854 855 held = [] 856 857 for name, pos in position_items: 858 pos = list(pos) 859 pos.sort() 860 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 861 namearray[pos[0]] = name 862 else: 863 if pos: 864 self.relocated.add(name) 865 held.append((name, pos)) 866 867 for i, attr in enumerate(namearray): 868 if attr is None: 869 name, pos = held.pop() 870 namearray[i] = name 871 872 #print self.name, positions 873 #print "->", namearray 874 return namearray 875 876 def _cmp_positions(self, a, b): 877 878 "Compare name plus position list operands 'a' and 'b'." 879 880 name_a, list_a = a 881 name_b, list_b = b 882 if len(list_a) < len(list_b): 883 return -1 884 elif len(list_a) > len(list_b): 885 return 1 886 elif not list_a: 887 return 0 888 else: 889 return cmp(min(list_a), min(list_b)) 890 891 def all_attribute_names(self): 892 893 """ 894 Return the names of all attributes provided by instances of this class. 895 """ 896 897 self.allattr_names = self.allattr_names or self.all_attributes().keys() 898 return self.allattr_names 899 900 def all_attributes(self): 901 902 """ 903 Return all attributes for an instance, indicating either the class which 904 provides them or that the instance itself provides them. 905 """ 906 907 if self.allattr is None: 908 self.allattr = {} 909 self.allattr.update(self.all_class_attributes()) 910 for name, attr in self.instance_attributes().items(): 911 if self.allattr.has_key(name): 912 print "Instance attribute %r in %r overrides class attribute." % (name, self) 913 self.allattr[name] = attr 914 return self.allattr 915 916 class Function(NamespaceDict, Naming, Constant): 917 918 "An inspected function." 919 920 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, module=None, node=None): 921 922 """ 923 Initialise the function with the given 'name', 'parent', list of 924 'argnames', list of 'defaults', the 'has_star' flag (indicating the 925 presence of a * parameter), the 'has_dstar' flag (indicating the 926 presence of a ** parameter), optional 'module', and optional AST 'node'. 927 """ 928 929 NamespaceDict.__init__(self, module) 930 self.name = name 931 self.parent = parent 932 self.argnames = argnames 933 self.defaults = defaults 934 self.has_star = has_star 935 self.has_dstar = has_dstar 936 self.astnode = node 937 self.referenced = 0 938 939 # For lambda functions with defaults, add a context argument. 940 941 if name is None and defaults: 942 self.argnames.insert(0, "<context>") 943 944 # Initialise the positional names. 945 946 self.positional_names = self.argnames[:] 947 if has_dstar: 948 self.dstar_name = self.positional_names[-1] 949 del self.positional_names[-1] 950 if has_star: 951 self.star_name = self.positional_names[-1] 952 del self.positional_names[-1] 953 954 # Initialise default storage. 955 # NOTE: This must be initialised separately due to the reliance on node 956 # NOTE: visiting. 957 958 self.default_attrs = [] 959 960 # Caches. 961 962 self.localnames = None # cache for locals 963 964 # Add parameters to the namespace. 965 966 self._add_parameters(argnames) 967 968 # Image generation details. 969 970 self.location = None 971 self.code_location = None 972 self.code_body_location = None 973 974 # Program-related details. 975 976 self.blocks = None 977 self.body_block = None 978 979 self.temp_usage = 0 980 self.local_usage = 0 981 self.all_local_usage = 0 982 983 def set_referenced(self): 984 self.referenced = 1 985 986 def _add_parameters(self, argnames): 987 for name in argnames: 988 if isinstance(name, tuple): 989 self._add_parameters(name) 990 else: 991 self.set(name, None) 992 993 def __repr__(self): 994 if self.location is not None: 995 return "Function(%r, %s, %r, location=%r, code_location=%r)" % ( 996 self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location 997 ) 998 else: 999 return "Function(%r, %s, %r)" % ( 1000 self.name, shortrepr(self.parent), self.argnames 1001 ) 1002 1003 def __shortrepr__(self): 1004 return "Function(%r, %s)" % ( 1005 self.name, shortrepr(self.parent) 1006 ) 1007 1008 def as_raw(self, objtable, paramtable): 1009 # NOTE: Need class and parameter details! Should arguably be an instance of types.FunctionType. 1010 return [ 1011 DataObject( 1012 objtable.as_list().get_code("__builtins__.function"), 1013 objtable.get_index("__builtins__.function"), # is instance 1014 self.code_location, 1015 "__builtins__.function", 1016 len(self.defaults) + 1, # size (not accurate for lambda functions before instantiation) 1017 paramtable.as_list().get_code(self.full_name()) # funccode 1018 ) 1019 ] 1020 1021 def get_body_block(self): 1022 return self.body_block 1023 1024 # Namespace-related methods. 1025 1026 def store_default(self, value): 1027 attr = Attr(None, self, None) 1028 attr.update([self.get_context_and_value(value)], 1) 1029 self.default_attrs.append(attr) 1030 1031 def make_global(self, name): 1032 if name not in self.argnames and not self.has_key(name): 1033 self.globals.add(name) 1034 return 1 1035 else: 1036 return 0 1037 1038 def parameters(self): 1039 1040 """ 1041 Return a dictionary mapping parameter names to their position in the 1042 parameter list. 1043 """ 1044 1045 parameters = {} 1046 for i, name in enumerate(self.argnames): 1047 parameters[name] = i 1048 return parameters 1049 1050 def all_locals(self): 1051 1052 "Return a dictionary mapping names to local and parameter details." 1053 1054 return dict(self) 1055 1056 def locals(self): 1057 1058 "Return a dictionary mapping names to local details." 1059 1060 if self.localnames is None: 1061 self.localnames = {} 1062 self.localnames.update(self.all_locals()) 1063 for name in self.argnames: 1064 del self.localnames[name] 1065 return self.localnames 1066 1067 def is_method(self): 1068 1069 """ 1070 Return whether this function is a method explicitly defined in a class. 1071 """ 1072 1073 return isinstance(self.parent, Class) 1074 1075 def is_relocated(self, name): 1076 1077 """ 1078 Determine whether the given attribute 'name' is relocated for instances 1079 having this function as a method. 1080 """ 1081 1082 for cls in self.parent.descendants: 1083 if name in cls.relocated: 1084 return 1 1085 return 0 1086 1087 def finalise_attributes(self): 1088 1089 """ 1090 Make sure all attributes (locals) are fully defined. Note that locals 1091 are not attributes in the sense of class, module or instance attributes. 1092 Defaults are also finalised by this method. 1093 """ 1094 1095 if self.finalised: 1096 return 1097 1098 # Defaults. 1099 1100 for i, default in enumerate(self.default_attrs): 1101 default.position = i 1102 1103 # Locals. 1104 1105 i = None 1106 for i, name in enumerate(self.argnames): 1107 self[name].position = i 1108 1109 if i is not None: 1110 nparams = i + 1 1111 else: 1112 nparams = 0 1113 1114 i = None 1115 for i, attr in enumerate(self.locals().values()): 1116 attr.position = i + nparams 1117 1118 if i is not None: 1119 nothers = i + 1 1120 else: 1121 nothers = 0 1122 1123 self.local_usage = nothers 1124 self.all_local_usage = nparams + nothers 1125 self.finalised = 1 1126 1127 def as_instantiator(self): 1128 1129 "Make an instantiator function from a method, keeping all arguments." 1130 1131 function = Function(self.parent.name, self.parent.parent, self.argnames, self.defaults, 1132 self.has_star, self.has_dstar, self.module, self.astnode) 1133 function.default_attrs = self.default_attrs 1134 return function 1135 1136 class UnresolvedName(NamespaceDict, Constant): 1137 1138 "A module, class or function which was mentioned but could not be imported." 1139 1140 def __init__(self, name, parent_name, module=None): 1141 NamespaceDict.__init__(self, module) 1142 self.name = name 1143 self.parent_name = parent_name 1144 self.parent = None 1145 self.referenced = 0 1146 1147 self.descendants = set() 1148 1149 def set_referenced(self): 1150 self.referenced = 1 1151 1152 def add_descendant(self, cls): 1153 self.descendants.add(cls) 1154 1155 def all_class_attributes(self): 1156 return {} 1157 1158 def instance_attributes(self): 1159 return {} 1160 1161 def __repr__(self): 1162 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 1163 1164 __shortrepr__ = __repr__ 1165 1166 def full_name(self): 1167 if self.name is not None: 1168 return self.parent_name + "." + self.name 1169 else: 1170 return self.parent_name 1171 1172 class Module(NamespaceDict, Constant): 1173 1174 "An inspected module's core details." 1175 1176 def __init__(self, name): 1177 NamespaceDict.__init__(self, self) 1178 self.name = name 1179 self.parent = None 1180 self.referenced = 0 1181 1182 # Original location details. 1183 1184 self.astnode = None 1185 1186 # Complete lists of classes and functions. 1187 1188 self.all_objects = set() 1189 1190 # Keyword records. 1191 1192 self.keyword_names = set() 1193 1194 # Image generation details. 1195 1196 self.location = None 1197 self.code_location = None 1198 1199 # Program-related details. 1200 1201 self.blocks = None 1202 self.temp_usage = 0 1203 self.local_usage = 0 1204 self.all_local_usage = 0 1205 1206 def set_referenced(self): 1207 self.referenced = 1 1208 1209 def full_name(self): 1210 return self.name 1211 1212 def __repr__(self): 1213 if self.location is not None: 1214 return "Module(%r, location=%r)" % (self.name, self.location) 1215 else: 1216 return "Module(%r)" % self.name 1217 1218 def __shortrepr__(self): 1219 return "Module(%r)" % self.name 1220 1221 def as_raw(self, objtable, paramtable): 1222 return [ 1223 DataObject( 1224 objtable.as_list().get_code(self.full_name()), 1225 None, # NOTE: module name not used as an attribute, but should be instance 1226 None, 1227 self.full_name(), 1228 len(self.module_attributes()) + 1 # size 1229 ) 1230 ] 1231 1232 # Attribute methods. 1233 1234 "Return the module attribute names provided by the module." 1235 1236 module_attribute_names = NamespaceDict.keys 1237 1238 def module_attributes(self): 1239 1240 "Return a dictionary mapping names to module attributes." 1241 1242 return dict(self) 1243 1244 # vim: tabstop=4 expandtab shiftwidth=4