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