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