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