1 #!/usr/bin/env python 2 3 """ 4 Data classes. 5 6 Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 21 -------- 22 23 The central data structure classes in this module are the following: 24 25 * Class 26 * Function 27 * Module 28 29 All of the above support the Naming interface either explicitly or through 30 general conformance, meaning that all can be asked to provide their 'full_name' 31 using the method of that name. 32 33 Additionally, all of the above also support a dictionary interface in order to 34 access names within their defined scopes. Specific methods also exist in order 35 to distinguish between certain kinds of attributes: 36 37 * Class: class_attributes, all_class_attributes, instance_attributes, all_attributes 38 * Function: parameters, locals, all_locals 39 * Module: module_attributes 40 41 These specific methods are useful in certain situations. 42 43 The above classes also provide an 'astnode' attribute, indicating the AST node 44 where each such object is defined. 45 """ 46 47 from micropython.program import DataObject, ReplaceableContext, PlaceholderContext 48 49 def shortrepr(obj): 50 if obj is None: 51 return repr(None) 52 else: 53 return obj.__shortrepr__() 54 55 # Special representations. 56 57 class AtLeast: 58 59 "A special representation for numbers of a given value or greater." 60 61 def __init__(self, count): 62 self.count = count 63 64 def __eq__(self, other): 65 return 0 66 67 __lt__ = __le__ = __eq__ 68 69 def __ne__(self, other): 70 return 1 71 72 def __gt__(self, other): 73 if isinstance(other, AtLeast): 74 return 0 75 else: 76 return self.count > other 77 78 def __ge__(self, other): 79 if isinstance(other, AtLeast): 80 return 0 81 else: 82 return self.count >= other 83 84 def __iadd__(self, other): 85 if isinstance(other, AtLeast): 86 self.count += other.count 87 else: 88 self.count += other 89 return self 90 91 def __radd__(self, other): 92 if isinstance(other, AtLeast): 93 return AtLeast(self.count + other.count) 94 else: 95 return AtLeast(self.count + other) 96 97 def __repr__(self): 98 return "AtLeast(%r)" % self.count 99 100 # Mix-ins and abstract classes. 101 102 class Naming: 103 104 "A mix-in providing naming conveniences." 105 106 def full_name(self): 107 if self.name is not None: 108 return self.parent.full_name() + "." + self.name 109 else: 110 return self.parent.full_name() 111 112 class NamespaceDict: 113 114 "A mix-in providing dictionary methods." 115 116 def __init__(self, module=None): 117 self.namespace = {} 118 self.globals = set() 119 self.module = module 120 self.finalised = 0 121 122 def __delitem__(self, name): 123 del self.namespace[name] 124 125 def has_key(self, name): 126 return self.namespace.has_key(name) 127 128 def keys(self): 129 return self.namespace.keys() 130 131 def values(self): 132 return self.namespace.values() 133 134 def items(self): 135 return self.namespace.items() 136 137 def __getitem__(self, name): 138 return self.namespace[name] 139 140 def get(self, name, default=None): 141 return self.namespace.get(name, default) 142 143 def __setitem__(self, name, value): 144 self.set(name, value) 145 146 def set(self, name, value, single_assignment=1): 147 148 """ 149 A more powerful set operation, making 'name' refer to 'value' whilst 150 indicating whether a 'single_assignment' (true by default) occurs in 151 this operation (or whether the operation covers potentially many 152 assignments in the lifetime of a program). 153 """ 154 155 if name in self.globals: 156 self.module.set(name, value, 0) 157 else: 158 self._set(name, value, single_assignment) 159 160 def set_module(self, name, value): 161 162 """ 163 A specialised set operation, making 'name' refer to 'value' in the 164 context of making a module reference available in association with 165 'name' as part of the import of that module or a submodule of that 166 module. 167 """ 168 169 self._set(name, value, 1) 170 171 def _set(self, name, attr_or_value, single_assignment=1): 172 173 """ 174 The underlying set operation associating 'name' with the given 175 'attr_or_value'. 176 See: docs/assignment.txt 177 """ 178 179 # Add and/or obtain the namespace entry. 180 181 if not self.namespace.has_key(name): 182 self.namespace[name] = Attr(None, self, name) 183 184 attr = self.namespace[name] 185 186 # Handle attribute assignment as well as assignment of basic objects. 187 # Attempt to fix the context if not explicitly defined. 188 189 if isinstance(attr_or_value, Attr): 190 context_values = self.get_updated_context_values(attr_or_value.context_values) 191 else: 192 context_values = self.get_updated_context_values([self.get_context_and_value(attr_or_value)]) 193 194 attr.update(context_values, single_assignment) 195 196 def get_context_and_value(self, value): 197 198 "Return a context, value tuple for the given 'value'." 199 200 # Functions have a replaceable context. 201 202 if isinstance(value, Function): 203 return (ReplaceableContext, value) 204 205 # Classes use placeholder contexts which cannot be replaced but which 206 # do not communicate useful contextual information. 207 208 elif isinstance(value, Class): 209 return (PlaceholderContext, value) 210 211 # Other values employ themselves as the context. 212 213 else: 214 return (value, value) 215 216 def get_updated_context_values(self, context_values): 217 218 """ 219 Adapt the contexts found in the given 'context_values', returning a new 220 set. 221 See: docs/assignment.txt 222 """ 223 224 results = set() 225 226 for context, value in context_values: 227 228 # Set the context of instances to themselves. 229 230 if isinstance(value, Instance): 231 results.add((value, value)) 232 else: 233 results.add((context, value)) 234 235 return results 236 237 def make_global(self, name): 238 if not self.namespace.has_key(name): 239 self.globals.add(name) 240 return 1 241 else: 242 return 0 243 244 def attributes_as_list(self): 245 246 "Return the attributes in a list." 247 248 self.finalise_attributes() 249 l = [None] * len(self.keys()) 250 for attr in self.values(): 251 l[attr.position] = attr 252 return l 253 254 def finalise_attributes(self): 255 256 "Make sure all attributes are fully defined." 257 258 if self.finalised: 259 return 260 261 # The default action is to assign attribute positions sequentially. 262 263 for i, attr in enumerate(self.values()): 264 attr.position = i 265 266 self.finalised = 1 267 268 # Program data structures. There are two separate kinds of structures: those 269 # with context, which are the values manipulated by programs, and those without 270 # context, which are typically constant things which are stored alongside the 271 # program but which are wrapped in context-dependent structures in the running 272 # program. 273 274 class Attr: 275 276 "An attribute entry having a context." 277 278 def __init__(self, position, parent, name): 279 280 """ 281 Initialise the attribute with the given 'position' within the collection 282 of attributes of its 'parent', indicating its 'name'. 283 """ 284 285 self.position = position 286 self.parent = parent 287 self.name = name 288 289 self.context_values = set() 290 291 # Number of assignments per name. 292 293 self.assignments = None 294 self.referenced = 0 295 296 def set_referenced(self): 297 298 "Indicate that the contents are referenced via a namespace." 299 300 self.referenced = 1 301 302 for value in self.get_values(): 303 if value is not None: 304 value.set_referenced() 305 306 def get_contexts(self): 307 return [c for (c, v) in self.context_values] 308 309 def get_values(self): 310 return [v for (c, v) in self.context_values] 311 312 def get_context(self): 313 if len(self.context_values) == 1: 314 return self.get_contexts()[0] 315 else: 316 return None 317 318 def get_value(self): 319 if len(self.context_values) == 1: 320 return self.get_values()[0] 321 else: 322 return None 323 324 def update(self, context_values, single_assignment): 325 326 """ 327 Update the attribute, adding the 'context_values' provided to the 328 known details associated with the attribute, changing the number of 329 assignments according to the 'single_assignment' status of the 330 operation, where a true value indicates that only one assignment is 331 associated with the update, and a false value indicates that potentially 332 many assignments may be involved. 333 """ 334 335 if self.assignments is None: 336 if single_assignment: 337 self.assignments = 1 338 else: 339 self.assignments = AtLeast(1) 340 else: 341 if single_assignment: 342 self.assignments += 1 343 else: 344 self.assignments += AtLeast(1) 345 346 # Communicate referencing information. 347 348 if self.referenced: 349 for context, value in context_values: 350 if value is not None: 351 value.set_referenced() 352 353 self.context_values.update(context_values) 354 355 def is_static_attribute(self): 356 357 """ 358 Return whether this attribute is defined on a fixed/static object such 359 as a class or a module. 360 """ 361 362 return isinstance(self.parent, (Class, Module)) 363 364 def defines_ambiguous_class(self): 365 366 "Return whether this attribute defines more than one class." 367 368 if self.assignments > 1: 369 have_class = 0 370 for obj in self.get_values(): 371 if isinstance(obj, Class): 372 if have_class: 373 return 1 374 have_class = 1 375 376 return 0 377 378 def defined_within_hierarchy(self): 379 380 """ 381 Return whether the parent and context of the attribute belong to the 382 same class hierarchy. 383 """ 384 385 # Must be defined within a class. 386 387 if isinstance(self.parent, Class): 388 389 # To be sure, all contexts must be classes and be the same as the 390 # parent, or be a superclass of the parent, or be a subclass of the 391 # parent. 392 393 for context in self.get_contexts(): 394 if not ( 395 isinstance(context, Class) and ( 396 context is self.parent or 397 context.has_subclass(self.parent) or 398 self.parent.has_subclass(context)) 399 ): 400 return 0 401 402 return 1 403 404 # Instance attributes are not defined within a hierarchy. 405 406 else: 407 return 0 408 409 def defined_outside_hierarchy(self): 410 411 """ 412 Return whether the parent and context of the attribute never belong to 413 the same class hierarchy. 414 """ 415 416 # Must be defined within a class. 417 418 if isinstance(self.parent, Class): 419 420 # To be sure, all contexts must be classes and be the same as the 421 # parent, or be a superclass of the parent, or be a subclass of the 422 # parent. 423 424 for context in self.get_contexts(): 425 if not ( 426 isinstance(context, Class) and not ( 427 context is self.parent or 428 context.has_subclass(self.parent) or 429 self.parent.has_subclass(context)) 430 ): 431 return 0 432 433 return 1 434 435 # Instance attributes are not defined within a hierarchy. 436 437 else: 438 return 0 439 440 def __repr__(self): 441 return "Attr(%r, %s, %r) # [%s], %r" % ( 442 self.position, shortrepr(self.parent), self.name, 443 self._context_values_str(), self.assignments 444 ) 445 446 def _context_values_str(self): 447 l = [] 448 for (c, v) in self.context_values: 449 l.append("(c=%s, v=%s)" % (shortrepr(c), shortrepr(v))) 450 return ", ".join(l) 451 452 def as_raw(self, objtable, paramtable): 453 return [ 454 ( 455 self.get_context() and self.get_context().location, 456 self.get_value() and self.get_value().location 457 ) 458 ] 459 460 # Instances are special in that they need to be wrapped together with context in 461 # a running program, but they are not generally constant. 462 463 class Instance: 464 465 "A placeholder indicating the involvement of an instance." 466 467 def __init__(self): 468 self.parent = None 469 self.referenced = 0 470 471 # Image generation details. 472 473 self.location = None 474 475 def set_referenced(self): 476 self.referenced = 1 477 478 def __repr__(self): 479 return "Instance()" 480 481 __shortrepr__ = __repr__ 482 483 class Constant: 484 485 "A superclass for all constant or context-free structures." 486 487 pass 488 489 # Data objects appearing in programs before run-time. 490 491 class Const(Constant, Instance): 492 493 "A constant object with no context." 494 495 def __init__(self, value): 496 Instance.__init__(self) 497 self.value = value 498 499 def get_value(self): 500 return value 501 502 def __repr__(self): 503 if self.location is not None: 504 return "Const(%r, location=%r)" % (self.value, self.location) 505 else: 506 return "Const(%r)" % self.value 507 508 __shortrepr__ = __repr__ 509 510 def as_raw(self, objtable, paramtable): 511 # NOTE: Need class details! 512 return [ 513 DataObject( 514 objtable.as_list().get_code(self.value_type_name()), 515 objtable.get_index(self.value_type_name()), # is instance 516 None, 517 self.value_type_name(), 518 1 # size 519 ) 520 ] + self.raw_data() 521 522 def raw_data(self): 523 # NOTE: Start simple and use single entries for most types. 524 if self.value_type_name() in ("__builtins__.tuple", "__builtins__.list"): 525 return [len(self.value)] + list(self.value) 526 else: 527 return [self.value] 528 529 # Support constants as dictionary keys in order to build constant tables. 530 531 def __eq__(self, other): 532 return other is not None and self.value == other.value and self.value.__class__ is other.value.__class__ 533 534 def __hash__(self): 535 return hash(self.value) 536 537 def value_type_name(self): 538 return "__builtins__." + self.value.__class__.__name__ 539 540 class Class(NamespaceDict, Naming, Constant): 541 542 "An inspected class." 543 544 def __init__(self, name, parent, module=None, node=None): 545 546 """ 547 Initialise the class with the given 'name', 'parent' object, optional 548 'module' and optional AST 'node'. 549 """ 550 551 NamespaceDict.__init__(self, module) 552 self.name = name 553 self.parent = parent 554 self.astnode = node 555 self.referenced = 0 556 557 # Superclasses, descendants and attributes. 558 559 self.bases = [] 560 self.descendants = set() 561 self.instattr = set() # instance attributes 562 self.relocated = set() # attributes which do not have the same 563 # position as those of the same name in 564 # some superclasses 565 566 # Caches. 567 568 self.all_instattr = None # cache for instance_attributes 569 self.all_instattr_names = None # from all_instattr 570 self.all_classattr = None # cache for all_class_attributes 571 self.all_classattr_names = None # from all_classattr 572 self.allattr = None # cache for all_attributes 573 self.allattr_names = None # from allattr 574 575 # Image generation details. 576 577 self.location = None 578 self.code_location = None 579 self.code_body_location = None # corresponds to the instantiator 580 581 self.instantiator = None 582 self.instance_template_location = None # for creating instances at run-time 583 584 # Program-related details. 585 586 self.blocks = None 587 self.temp_usage = 0 588 self.local_usage = 0 589 self.all_local_usage = 0 590 591 # Add this class to its attributes. 592 593 self.set("__class__", self) 594 595 def set_referenced(self): 596 self.referenced = 1 597 598 def __repr__(self): 599 if self.location is not None: 600 return "Class(%r, %s, location=%r)" % (self.name, shortrepr(self.parent), self.location) 601 else: 602 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 603 604 def __shortrepr__(self): 605 return "Class(%r, %s)" % (self.name, shortrepr(self.parent)) 606 607 def as_raw(self, objtable, paramtable, with_instantiator=1): 608 classcode = objtable.as_list().get_code(self.full_name()) 609 attrcode = objtable.get_index(self.full_name()) 610 611 # Include a template of an instance for use when instantiating classes. 612 613 call_method = self.all_class_attributes().get("__call__") 614 call_method_value = call_method and call_method.get_value() 615 call_method_code_location = call_method_value and call_method_value.code_location 616 call_method_funccode = call_method_value and paramtable.as_list().get_code(call_method_value.full_name()) 617 618 instantiator_funccode = paramtable.as_list().get_code(self.get_instantiator().full_name()) 619 620 # NOTE: The instantiator code is the first block of the class. 621 622 if not with_instantiator: 623 instantiator_code_location = self.full_name() 624 else: 625 instantiator_code_location = self.get_instantiator().blocks[0].location 626 627 return [ 628 629 # Template instance... 630 631 DataObject( 632 classcode, 633 attrcode, # is instance 634 call_method_code_location, 635 self.full_name(), 636 len(self.instance_attributes()) + 1, # size 637 call_method_funccode # funccode 638 ), 639 640 # Class... 641 642 DataObject( 643 classcode, 644 None, # is not instance 645 instantiator_code_location, 646 self.full_name(), 647 len(self.class_attributes()) + 1, # size 648 instantiator_funccode # funccode 649 ) 650 ] 651 652 def get_body_block(self): 653 return self.get_instantiator().blocks[0] 654 655 # Namespace-related methods. 656 657 def get_updated_context_values(self, context_values): 658 659 """ 660 Adapt the contexts found in the given 'context_values', returning a new 661 set. 662 See: docs/assignment.txt 663 """ 664 665 results = set() 666 667 for context, value in context_values: 668 669 # Change the ownership of functions. 670 671 if context is ReplaceableContext and value is not None and isinstance(value, Function): 672 results.add((self, value)) 673 else: 674 results.add((context, value)) 675 676 return NamespaceDict.get_updated_context_values(self, results) 677 678 def finalise_attributes(self): 679 680 "Make sure that all attributes are fully defined." 681 682 if self.finalised: 683 return 684 685 self.finalise_class_attributes() 686 self.finalise_instance_attributes() 687 self.finalised = 1 688 689 # Convenience methods for accessing functions and methods. 690 691 def get_instantiator(self): 692 693 "Return a function which can be used to instantiate the class." 694 695 if self.instantiator is None: 696 self.instantiator = self.get_init_method().as_instantiator() 697 return self.instantiator 698 699 def get_init_method(self): 700 return self.all_class_attributes()["__init__"].get_value() 701 702 # Class-specific methods. 703 704 def add_base(self, base): 705 self.bases.append(base) 706 base.add_descendant(self) 707 708 def add_instance_attribute(self, name): 709 self.instattr.add(name) 710 711 def add_descendant(self, cls): 712 self.descendants.add(cls) 713 for base in self.bases: 714 base.add_descendant(cls) 715 716 def has_subclass(self, other): 717 return other in self.descendants 718 719 def all_descendants(self): 720 d = {} 721 for cls in self.descendants: 722 d[cls.full_name()] = cls 723 return d 724 725 "Return the attribute names provided by this class only." 726 727 class_attribute_names = NamespaceDict.keys 728 729 def class_attributes(self): 730 731 "Return class attributes provided by this class only." 732 733 return dict(self) 734 735 def all_class_attribute_names(self): 736 737 "Return the attribute names provided by classes in this hierarchy." 738 739 if self.all_classattr_names is None: 740 self.all_class_attributes() 741 return self.all_classattr_names 742 743 def all_class_attributes(self): 744 745 "Return all class attributes, indicating the class which provides them." 746 747 self.finalise_class_attributes() 748 return self.all_classattr 749 750 def finalise_class_attributes(self): 751 752 "Make sure that the class attributes are fully defined." 753 754 if self.all_classattr is None: 755 self.all_classattr = {} 756 clsattr = {} 757 758 # Record provisional position information for attributes of this 759 # class. 760 761 for name in self.class_attributes().keys(): 762 clsattr[name] = set() # position not yet defined 763 764 reversed_bases = self.bases[:] 765 reversed_bases.reverse() 766 767 # For the bases in reverse order, acquire class attribute details. 768 769 for cls in reversed_bases: 770 for name, attr in cls.all_class_attributes().items(): 771 self.all_classattr[name] = attr 772 773 # Record previous attribute information. 774 775 if clsattr.has_key(name): 776 clsattr[name].add(attr.position) 777 778 # Record class attributes provided by this class and its bases, 779 # along with their positions. 780 781 self.all_classattr.update(self.class_attributes()) 782 783 if clsattr: 784 for i, name in enumerate(self._get_position_list(clsattr)): 785 self.all_classattr[name].position = i 786 787 return self.all_classattr 788 789 def instance_attribute_names(self): 790 791 "Return the instance attribute names provided by the class." 792 793 if self.all_instattr_names is None: 794 self.instance_attributes() 795 return self.all_instattr_names 796 797 def instance_attributes(self): 798 799 "Return instance-only attributes for instances of this class." 800 801 self.finalise_instance_attributes() 802 return self.all_instattr 803 804 def finalise_instance_attributes(self): 805 806 "Make sure that the instance attributes are fully defined." 807 808 # Cache the attributes by converting the positioned attributes into a 809 # dictionary. 810 811 if self.all_instattr is None: 812 self.all_instattr = self._get_attributes() 813 self.all_instattr_names = self.all_instattr.keys() 814 815 return self.all_instattr 816 817 def _get_attributes(self): 818 819 """ 820 Return a dictionary mapping names to Attr instances incorporating 821 information about their positions in the final instance structure. 822 """ 823 824 instattr = {} 825 826 # Record provisional position information for attributes of this 827 # instance. 828 829 for name in self.instattr: 830 instattr[name] = set() # position not yet defined 831 832 reversed_bases = self.bases[:] 833 reversed_bases.reverse() 834 835 # For the bases in reverse order, acquire instance attribute 836 # details. 837 838 for cls in reversed_bases: 839 for name, attr in cls.instance_attributes().items(): 840 841 # Record previous attribute information. 842 843 if instattr.has_key(name): 844 instattr[name].add(attr.position) 845 else: 846 instattr[name] = set([attr.position]) 847 848 # Build the dictionary of attributes using the existing positions known 849 # for each name. 850 851 d = {} 852 for i, name in enumerate(self._get_position_list(instattr)): 853 d[name] = Attr(i, Instance(), name) 854 return d 855 856 def _get_position_list(self, positions): 857 858 """ 859 Return a list of attribute names for the given 'positions' mapping from 860 names to positions, indicating the positions of the attributes in the 861 final instance structure. 862 """ 863 864 position_items = positions.items() 865 namearray = [None] * len(position_items) 866 867 # Get the positions in ascending order of list size, with lists 868 # of the same size ordered according to their smallest position 869 # value. 870 871 position_items.sort(self._cmp_positions) 872 873 # Get the names in position order. 874 875 held = [] 876 877 for name, pos in position_items: 878 pos = list(pos) 879 pos.sort() 880 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 881 namearray[pos[0]] = name 882 else: 883 if pos: 884 self.relocated.add(name) 885 held.append((name, pos)) 886 887 for i, attr in enumerate(namearray): 888 if attr is None: 889 name, pos = held.pop() 890 namearray[i] = name 891 892 #print self.name, positions 893 #print "->", namearray 894 return namearray 895 896 def _cmp_positions(self, a, b): 897 898 "Compare name plus position list operands 'a' and 'b'." 899 900 name_a, list_a = a 901 name_b, list_b = b 902 if len(list_a) < len(list_b): 903 return -1 904 elif len(list_a) > len(list_b): 905 return 1 906 elif not list_a: 907 return 0 908 else: 909 return cmp(min(list_a), min(list_b)) 910 911 def all_attribute_names(self): 912 913 """ 914 Return the names of all attributes provided by instances of this class. 915 """ 916 917 self.allattr_names = self.allattr_names or self.all_attributes().keys() 918 return self.allattr_names 919 920 def all_attributes(self): 921 922 """ 923 Return all attributes for an instance, indicating either the class which 924 provides them or that the instance itself provides them. 925 """ 926 927 if self.allattr is None: 928 self.allattr = {} 929 self.allattr.update(self.all_class_attributes()) 930 for name, attr in self.instance_attributes().items(): 931 if self.allattr.has_key(name): 932 print "Instance attribute %r in %r overrides class attribute." % (name, self) 933 self.allattr[name] = attr 934 return self.allattr 935 936 class Function(NamespaceDict, Naming, Constant): 937 938 "An inspected function." 939 940 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, module=None, node=None): 941 942 """ 943 Initialise the function with the given 'name', 'parent', list of 944 'argnames', list of 'defaults', the 'has_star' flag (indicating the 945 presence of a * parameter), the 'has_dstar' flag (indicating the 946 presence of a ** parameter), optional 'module', and optional AST 'node'. 947 """ 948 949 NamespaceDict.__init__(self, module) 950 self.name = name 951 self.parent = parent 952 self.argnames = argnames 953 self.defaults = defaults 954 self.has_star = has_star 955 self.has_dstar = has_dstar 956 self.astnode = node 957 self.referenced = 0 958 959 # For lambda functions with defaults, add a context argument. 960 961 if name is None and defaults: 962 self.argnames.insert(0, "<context>") 963 964 # Initialise the positional names. 965 966 self.positional_names = self.argnames[:] 967 if has_dstar: 968 self.dstar_name = self.positional_names[-1] 969 del self.positional_names[-1] 970 if has_star: 971 self.star_name = self.positional_names[-1] 972 del self.positional_names[-1] 973 974 # Initialise default storage. 975 # NOTE: This must be initialised separately due to the reliance on node 976 # NOTE: visiting. 977 978 self.default_attrs = [] 979 980 # Caches. 981 982 self.localnames = None # cache for locals 983 984 # Add parameters to the namespace. 985 986 self._add_parameters(argnames) 987 988 # Image generation details. 989 990 self.location = None 991 self.code_location = None 992 self.code_body_location = None 993 994 # Program-related details. 995 996 self.blocks = None 997 self.body_block = None 998 999 self.temp_usage = 0 1000 self.local_usage = 0 1001 self.all_local_usage = 0 1002 1003 def set_referenced(self): 1004 self.referenced = 1 1005 1006 def _add_parameters(self, argnames): 1007 for name in argnames: 1008 if isinstance(name, tuple): 1009 self._add_parameters(name) 1010 else: 1011 self.set(name, None) 1012 1013 def __repr__(self): 1014 if self.location is not None: 1015 return "Function(%r, %s, %r, location=%r, code_location=%r)" % ( 1016 self.name, shortrepr(self.parent), self.argnames, self.location, self.code_location 1017 ) 1018 else: 1019 return "Function(%r, %s, %r)" % ( 1020 self.name, shortrepr(self.parent), self.argnames 1021 ) 1022 1023 def __shortrepr__(self): 1024 return "Function(%r, %s)" % ( 1025 self.name, shortrepr(self.parent) 1026 ) 1027 1028 def as_raw(self, objtable, paramtable): 1029 # NOTE: Need class and parameter details! Should arguably be an instance of types.FunctionType. 1030 return [ 1031 DataObject( 1032 objtable.as_list().get_code("__builtins__.function"), 1033 objtable.get_index("__builtins__.function"), # is instance 1034 self.code_location, 1035 "__builtins__.function", 1036 len(self.defaults) + 1, # size (not accurate for lambda functions before instantiation) 1037 paramtable.as_list().get_code(self.full_name()) # funccode 1038 ) 1039 ] 1040 1041 def get_body_block(self): 1042 return self.body_block 1043 1044 # Namespace-related methods. 1045 1046 def store_default(self, value): 1047 attr = Attr(None, self, None) 1048 attr.update([self.get_context_and_value(value)], 1) 1049 self.default_attrs.append(attr) 1050 1051 def make_global(self, name): 1052 if name not in self.argnames and not self.has_key(name): 1053 self.globals.add(name) 1054 return 1 1055 else: 1056 return 0 1057 1058 def parameters(self): 1059 1060 """ 1061 Return a dictionary mapping parameter names to their position in the 1062 parameter list. 1063 """ 1064 1065 parameters = {} 1066 for i, name in enumerate(self.argnames): 1067 parameters[name] = i 1068 return parameters 1069 1070 def all_locals(self): 1071 1072 "Return a dictionary mapping names to local and parameter details." 1073 1074 return dict(self) 1075 1076 def locals(self): 1077 1078 "Return a dictionary mapping names to local details." 1079 1080 if self.localnames is None: 1081 self.localnames = {} 1082 self.localnames.update(self.all_locals()) 1083 for name in self.argnames: 1084 del self.localnames[name] 1085 return self.localnames 1086 1087 def is_method(self): 1088 1089 """ 1090 Return whether this function is a method explicitly defined in a class. 1091 """ 1092 1093 return isinstance(self.parent, Class) 1094 1095 def is_relocated(self, name): 1096 1097 """ 1098 Determine whether the given attribute 'name' is relocated for instances 1099 having this function as a method. 1100 """ 1101 1102 for cls in self.parent.descendants: 1103 if name in cls.relocated: 1104 return 1 1105 return 0 1106 1107 def finalise_attributes(self): 1108 1109 """ 1110 Make sure all attributes (locals) are fully defined. Note that locals 1111 are not attributes in the sense of class, module or instance attributes. 1112 Defaults are also finalised by this method. 1113 """ 1114 1115 if self.finalised: 1116 return 1117 1118 # Defaults. 1119 1120 for i, default in enumerate(self.default_attrs): 1121 default.position = i 1122 1123 # Locals. 1124 1125 i = None 1126 for i, name in enumerate(self.argnames): 1127 self[name].position = i 1128 1129 if i is not None: 1130 nparams = i + 1 1131 else: 1132 nparams = 0 1133 1134 i = None 1135 for i, attr in enumerate(self.locals().values()): 1136 attr.position = i + nparams 1137 1138 if i is not None: 1139 nothers = i + 1 1140 else: 1141 nothers = 0 1142 1143 self.local_usage = nothers 1144 self.all_local_usage = nparams + nothers 1145 self.finalised = 1 1146 1147 def as_instantiator(self): 1148 1149 "Make an instantiator function from a method, keeping all arguments." 1150 1151 function = Function(self.parent.name, self.parent.parent, self.argnames, self.defaults, 1152 self.has_star, self.has_dstar, self.module, self.astnode) 1153 function.default_attrs = self.default_attrs 1154 return function 1155 1156 class UnresolvedName(NamespaceDict, Constant): 1157 1158 "A module, class or function which was mentioned but could not be imported." 1159 1160 def __init__(self, name, parent_name, module=None): 1161 NamespaceDict.__init__(self, module) 1162 self.name = name 1163 self.parent_name = parent_name 1164 self.parent = None 1165 self.referenced = 0 1166 1167 self.descendants = set() 1168 1169 def set_referenced(self): 1170 self.referenced = 1 1171 1172 def add_descendant(self, cls): 1173 self.descendants.add(cls) 1174 1175 def all_class_attributes(self): 1176 return {} 1177 1178 def instance_attributes(self): 1179 return {} 1180 1181 def __repr__(self): 1182 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 1183 1184 __shortrepr__ = __repr__ 1185 1186 def full_name(self): 1187 if self.name is not None: 1188 return self.parent_name + "." + self.name 1189 else: 1190 return self.parent_name 1191 1192 class Module(NamespaceDict, Constant): 1193 1194 "An inspected module's core details." 1195 1196 def __init__(self, name): 1197 NamespaceDict.__init__(self, self) 1198 self.name = name 1199 self.parent = None 1200 self.referenced = 0 1201 1202 # Original location details. 1203 1204 self.astnode = None 1205 1206 # Complete lists of classes and functions. 1207 1208 self.all_objects = set() 1209 1210 # Keyword records. 1211 1212 self.keyword_names = set() 1213 1214 # Image generation details. 1215 1216 self.location = None 1217 self.code_location = None 1218 1219 # Program-related details. 1220 1221 self.blocks = None 1222 self.temp_usage = 0 1223 self.local_usage = 0 1224 self.all_local_usage = 0 1225 1226 def set_referenced(self): 1227 self.referenced = 1 1228 1229 def full_name(self): 1230 return self.name 1231 1232 def __repr__(self): 1233 if self.location is not None: 1234 return "Module(%r, location=%r)" % (self.name, self.location) 1235 else: 1236 return "Module(%r)" % self.name 1237 1238 def __shortrepr__(self): 1239 return "Module(%r)" % self.name 1240 1241 def as_raw(self, objtable, paramtable): 1242 return [ 1243 DataObject( 1244 objtable.as_list().get_code(self.full_name()), 1245 None, # modules treated like classes 1246 None, 1247 self.full_name(), 1248 len(self.module_attributes()) + 1 # size 1249 ) 1250 ] 1251 1252 # Attribute methods. 1253 1254 "Return the module attribute names provided by the module." 1255 1256 module_attribute_names = NamespaceDict.keys 1257 1258 def module_attributes(self): 1259 1260 "Return a dictionary mapping names to module attributes." 1261 1262 return dict(self) 1263 1264 # vim: tabstop=4 expandtab shiftwidth=4