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