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