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