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