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