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