1 #!/usr/bin/env python 2 3 """ 4 Inspect source files, obtaining details of classes and attributes. 5 6 Copyright (C) 2007, 2008 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 classes in this module are the following: 24 25 * Class 26 * Function 27 * Module 28 * InspectedModule (derived from Module) 29 30 All of the above support the Naming interface either explicitly or through 31 general conformance, meaning that all can be asked to provide their 'full_name' 32 using the method of that name. 33 34 Additionally, all of the above also support a dictionary interface in order to 35 access names within their defined scopes. Specific methods also exist in order 36 to distinguish between certain kinds of attributes: 37 38 * Class: (class|all_class|instance|all)_attributes 39 * Function: parameters, locals, all_locals 40 * Module: module_attributes 41 42 These specific methods are useful in certain situations. 43 44 The above classes also provide a 'node' attribute, indicating the AST node where 45 each such object is defined. 46 """ 47 48 from micropython.common import * 49 import compiler.ast 50 from compiler.visitor import ASTVisitor 51 try: 52 set 53 except NameError: 54 from sets import Set as set 55 56 class InspectError(ProcessingError): pass 57 58 class AtLeast: 59 60 "A special representation for numbers of a given value or greater." 61 62 def __init__(self, count): 63 self.count = count 64 65 def __eq__(self, other): 66 return 0 67 68 __lt__ = __le__ = __eq__ 69 70 def __ne__(self, other): 71 return 1 72 73 def __gt__(self, other): 74 if isinstance(other, AtLeast): 75 return 0 76 else: 77 return self.count > other 78 79 def __ge__(self, other): 80 if isinstance(other, AtLeast): 81 return 0 82 else: 83 return self.count >= other 84 85 def __iadd__(self, other): 86 if isinstance(other, AtLeast): 87 self.count += other.count 88 else: 89 self.count += other 90 return self 91 92 def __radd__(self, other): 93 if isinstance(other, AtLeast): 94 return AtLeast(self.count + other.count) 95 else: 96 return AtLeast(self.count + other) 97 98 def __repr__(self): 99 return "AtLeast(%r)" % self.count 100 101 # Mix-ins and abstract classes. 102 103 class NamespaceDict: 104 105 "A mix-in providing dictionary methods." 106 107 def __init__(self, global_namespace=None): 108 self.namespace = {} 109 self.globals = set() 110 self.global_namespace = global_namespace 111 112 def __getitem__(self, name): 113 return self.namespace[name] 114 115 def get(self, name, default=None): 116 return self.namespace.get(name, default) 117 118 def __setitem__(self, name, value): 119 self.set(name, value) 120 121 def set(self, name, value, single_assignment=1): 122 123 """ 124 A more powerful set operation, making 'name' refer to 'value' whilst 125 indicating whether a 'single_assignment' (true by default) occurs in 126 this operation (or whether the operation covers potentially many 127 assignments in the lifetime of a program). 128 """ 129 130 if name in self.globals: 131 self.global_namespace.set(name, value, 0) 132 else: 133 attr = self._set(name, value) 134 135 # NOTE: Insist on assignments with known values. 136 137 if value is not None: 138 attr.update(value, single_assignment) 139 140 def set_module(self, name, value): 141 142 """ 143 A specialised set operation, making 'name' refer to 'value' in the 144 context of making a module reference available in association with 145 'name' as part of the import of that module or a submodule of that 146 module. 147 """ 148 149 attr = self._set(name, value) 150 if attr.assignments is None: 151 attr.assignments = 1 152 attr.assignment_values.add(value) 153 154 def _set(self, name, value): 155 156 "The underlying set operation associating 'name' with 'value'." 157 158 if not self.namespace.has_key(name): 159 self.namespace[name] = Attr(None, self, name, value) 160 return self.namespace[name] 161 162 def __delitem__(self, name): 163 del self.namespace[name] 164 165 def has_key(self, name): 166 return self.namespace.has_key(name) 167 168 def keys(self): 169 return self.namespace.keys() 170 171 def values(self): 172 return self.namespace.values() 173 174 def items(self): 175 return self.namespace.items() 176 177 def make_global(self, name): 178 if not self.namespace.has_key(name): 179 self.globals.add(name) 180 else: 181 raise InspectError(self.full_name(), self.node, "Name %r is both global and local in %r" % (name, self.full_name())) 182 183 def get_assignments(self, name): 184 if self.assignments.has_key(name): 185 return max(self.assignments[name], len(self.assignment_values[name])) 186 else: 187 return None 188 189 def attributes_as_list(self): 190 self.finalise_attributes() 191 l = [None] * len(self.keys()) 192 for attr in self.values(): 193 l[attr.position] = attr 194 return l 195 196 def finalise_attributes(self): 197 198 "Make sure all attributes are fully defined." 199 200 # The default action is to assign attribute positions sequentially. 201 202 for i, attr in enumerate(self.values()): 203 attr.position = i 204 205 class Naming: 206 207 "A mix-in providing naming conveniences." 208 209 def full_name(self): 210 if self.name is not None: 211 return self.parent.full_name() + "." + self.name 212 else: 213 return self.parent.full_name() 214 215 # Program data structures. 216 217 class Attr: 218 219 "An attribute entry having a parent as context." 220 221 def __init__(self, position, parent, name, value=None, assignments=None): 222 self.position = position 223 self.parent = parent 224 self.name = name 225 self.value = value 226 227 # Number of assignments per name. 228 229 self.assignments = assignments 230 self.assignment_values = set() 231 232 def update(self, value, single_assignment): 233 234 """ 235 Update the attribute, adding the 'value' provided to the known values 236 associated with the attribute, changing the number of assignments 237 according to the 'single_assignment' status of the operation, where 238 a true value indicates that only one assignment is associated with the 239 update, and a false value indicates that potentially many assignments 240 may be involved. 241 """ 242 243 if self.assignments is None: 244 if single_assignment: 245 self.assignments = 1 246 else: 247 self.assignments = AtLeast(1) 248 else: 249 if single_assignment: 250 self.assignments += 1 251 else: 252 self.assignments += AtLeast(1) 253 self.assignment_values.add(value) 254 255 def __repr__(self): 256 return "Attr(%r, %r, %r, %r, %r)" % (self.position, self.parent, self.name, self.value, self.assignments) 257 258 class Const: 259 260 "A constant object with no context." 261 262 def __init__(self, value): 263 self.value = value 264 265 # Image generation details. 266 267 self.location = None 268 269 def __repr__(self): 270 if self.location is not None: 271 return "Const(%r, location=%r)" % (self.value, self.location) 272 else: 273 return "Const(%r)" % self.value 274 275 # Support constants as dictionary keys in order to build constant tables. 276 277 def __eq__(self, other): 278 return self.value == other.value 279 280 def __hash__(self): 281 return hash(self.value) 282 283 def value_type_name(self): 284 return "__builtins__." + self.value.__class__.__name__ 285 286 class Class(NamespaceDict, Naming): 287 288 "An inspected class." 289 290 def __init__(self, name, parent, global_namespace=None, node=None): 291 292 """ 293 Initialise the class with the given 'name', 'parent' object, optional 294 'global_namespace' and optional AST 'node'. 295 """ 296 297 NamespaceDict.__init__(self, global_namespace) 298 self.name = name 299 self.parent = parent 300 self.node = node 301 302 # Superclasses, descendants and attributes. 303 304 self.bases = [] 305 self.descendants = set() 306 self.instattr = set() # instance attributes 307 self.relocated = set() # attributes which do not have the same 308 # position as those of the same name in 309 # some superclasses 310 311 # Caches. 312 313 self.all_instattr = None # cache for instance_attributes 314 self.all_instattr_names = None # from all_instattr 315 self.all_classattr = None # cache for all_class_attributes 316 self.all_classattr_names = None # from all_classattr 317 self.allattr = None # cache for all_attributes 318 self.allattr_names = None # from allattr 319 320 # Add this class to its attributes. 321 322 self.set("__class__", self) 323 324 # Image generation details. 325 326 self.location = None 327 self.code_location = None 328 self.instantiator = None 329 330 # Program-related details. 331 332 self.stack_usage = 0 333 self.stack_temp_usage = 0 334 self.stack_local_usage = 0 335 336 def __repr__(self): 337 if self.location is not None: 338 return "Class(%r, %r, location=%r)" % (self.name, self.parent, self.location) 339 else: 340 return "Class(%r, %r)" % (self.name, self.parent) 341 342 def finalise_attributes(self): 343 344 "Make sure that all attributes are fully defined." 345 346 self.finalise_class_attributes() 347 self.finalise_instance_attributes() 348 349 def get_instantiator(self): 350 351 "Return a function which can be used to instantiate the class." 352 353 if self.instantiator is None: 354 init_method = self.all_class_attributes()["__init__"].value 355 self.instantiator = init_method.function_from_method() 356 return self.instantiator 357 358 # Class-specific methods. 359 360 def add_base(self, base): 361 self.bases.append(base) 362 base.add_descendant(self) 363 364 def add_instance_attribute(self, name): 365 self.instattr.add(name) 366 367 def add_descendant(self, cls): 368 self.descendants.add(cls) 369 for base in self.bases: 370 base.add_descendant(cls) 371 372 "Return the attribute names provided by this class only." 373 374 class_attribute_names = NamespaceDict.keys 375 376 def class_attributes(self): 377 378 "Return class attributes provided by this class only." 379 380 self.finalise_class_attributes() 381 return dict(self) 382 383 def all_class_attribute_names(self): 384 385 "Return the attribute names provided by classes in this hierarchy." 386 387 if self.all_classattr_names is None: 388 self.all_class_attributes() 389 return self.all_classattr_names 390 391 def all_class_attributes(self): 392 393 "Return all class attributes, indicating the class which provides them." 394 395 self.finalise_class_attributes() 396 return self.all_classattr 397 398 def finalise_class_attributes(self): 399 400 "Make sure that the class attributes are fully defined." 401 402 if self.all_classattr is None: 403 self.all_classattr = {} 404 clsattr = {} 405 406 # Record provisional position information for attributes of this 407 # class. 408 409 for name in self.class_attributes().keys(): 410 clsattr[name] = set() # position not yet defined 411 412 reversed_bases = self.bases[:] 413 reversed_bases.reverse() 414 415 # For the bases in reverse order, acquire class attribute details. 416 417 for cls in reversed_bases: 418 for name, attr in cls.all_class_attributes().items(): 419 self.all_classattr[name] = attr 420 421 # Record previous attribute information. 422 423 if clsattr.has_key(name): 424 clsattr[name].add(attr.position) 425 426 # Record class attributes provided by this class and its bases, 427 # along with their positions. 428 429 self.all_classattr.update(self.class_attributes()) 430 431 if clsattr: 432 for i, name in enumerate(self._get_position_list(clsattr)): 433 self.all_classattr[name].position = i 434 435 return self.all_classattr 436 437 def instance_attribute_names(self): 438 439 "Return the instance attribute names provided by the class." 440 441 if self.all_instattr_names is None: 442 self.instance_attributes() 443 return self.all_instattr_names 444 445 def instance_attributes(self): 446 447 "Return instance-only attributes for instances of this class." 448 449 self.finalise_instance_attributes() 450 return self.all_instattr 451 452 def finalise_instance_attributes(self): 453 454 "Make sure that the instance attributes are fully defined." 455 456 if self.all_instattr is None: 457 self.all_instattr = {} 458 instattr = {} 459 460 # Record provisional position information for attributes of this 461 # instance. 462 463 for name in self.instattr: 464 instattr[name] = set() # position not yet defined 465 466 reversed_bases = self.bases[:] 467 reversed_bases.reverse() 468 469 # For the bases in reverse order, acquire instance attribute 470 # details. 471 472 for cls in reversed_bases: 473 for name, attr in cls.instance_attributes().items(): 474 475 # Record previous attribute information. 476 477 if instattr.has_key(name): 478 instattr[name].add(attr.position) 479 480 # Cache the attributes by converting the positioned attributes into 481 # a dictionary. 482 483 if not instattr: 484 self.all_instattr = {} 485 else: 486 self.all_instattr = self._get_attributes(instattr) 487 488 self.all_instattr_names = self.all_instattr.keys() 489 490 return self.all_instattr 491 492 def _get_position_list(self, positions): 493 494 """ 495 Return a list of attribute names for the given 'positions' mapping from 496 names to positions, indicating the positions of the attributes in the 497 final instance structure. 498 """ 499 500 position_items = positions.items() 501 namearray = [None] * len(position_items) 502 503 # Get the positions in ascending order of list size, with lists 504 # of the same size ordered according to their smallest position 505 # value. 506 507 position_items.sort(self._cmp_positions) 508 509 # Get the names in position order. 510 511 held = [] 512 513 for name, pos in position_items: 514 pos = list(pos) 515 pos.sort() 516 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 517 namearray[pos[0]] = name 518 else: 519 if pos: 520 self.relocated.add(name) 521 held.append((name, pos)) 522 523 for i, attr in enumerate(namearray): 524 if attr is None: 525 name, pos = held.pop() 526 namearray[i] = name 527 528 #print self.name, positions 529 #print "->", namearray 530 return namearray 531 532 def _get_attributes(self, positions): 533 534 """ 535 For the given 'positions' mapping from names to positions, return a 536 dictionary mapping names to Attr instances incorporating information 537 about their positions in the final instance structure. 538 """ 539 540 d = {} 541 for i, name in enumerate(self._get_position_list(positions)): 542 d[name] = Attr(i, Instance(), name, None) 543 return d 544 545 def _cmp_positions(self, a, b): 546 547 "Compare name plus position list operands 'a' and 'b'." 548 549 name_a, list_a = a 550 name_b, list_b = b 551 if len(list_a) < len(list_b): 552 return -1 553 elif len(list_a) > len(list_b): 554 return 1 555 elif not list_a: 556 return 0 557 else: 558 return cmp(min(list_a), min(list_b)) 559 560 def all_attribute_names(self): 561 562 """ 563 Return the names of all attributes provided by instances of this class. 564 """ 565 566 self.allattr_names = self.allattr_names or self.all_attributes().keys() 567 return self.allattr_names 568 569 def all_attributes(self): 570 571 """ 572 Return all attributes for an instance, indicating either the class which 573 provides them or that the instance itself provides them. 574 """ 575 576 if self.allattr is None: 577 self.allattr = {} 578 self.allattr.update(self.all_class_attributes()) 579 for name, attr in self.instance_attributes().items(): 580 if self.allattr.has_key(name): 581 print "Instance attribute %r in %r overrides class attribute." % (name, self) 582 self.allattr[name] = attr 583 return self.allattr 584 585 class Function(NamespaceDict, Naming): 586 587 "An inspected function." 588 589 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, global_namespace=None, node=None): 590 591 """ 592 Initialise the function with the given 'name', 'parent', list of 593 'argnames', list of 'defaults', the 'has_star' flag (indicating the 594 presence of a * parameter), the 'has_dstar' flag (indicating the 595 presence of a ** parameter), optional 'global_namespace', and optional 596 AST 'node'. 597 """ 598 599 NamespaceDict.__init__(self, global_namespace) 600 self.name = name 601 self.parent = parent 602 self.argnames = argnames 603 self.defaults = defaults 604 self.has_star = has_star 605 self.has_dstar = has_dstar 606 self.node = node 607 608 # Initialise the positional names. 609 610 self.positional_names = self.argnames[:] 611 if has_dstar: 612 self.dstar_name = self.positional_names[-1] 613 del self.positional_names[-1] 614 if has_star: 615 self.star_name = self.positional_names[-1] 616 del self.positional_names[-1] 617 618 # Initialise default storage. 619 620 self.default_attrs = [] 621 622 # Caches. 623 624 self.localnames = None # cache for locals 625 626 # Add parameters to the namespace. 627 628 self._add_parameters(argnames) 629 630 # Image generation details. 631 632 self.location = None 633 self.code_location = None 634 635 # Program-related details. 636 637 self.stack_usage = 0 638 self.stack_temp_usage = 0 639 self.stack_local_usage = 0 640 641 def _add_parameters(self, argnames): 642 for name in argnames: 643 if isinstance(name, tuple): 644 self._add_parameters(name) 645 else: 646 self.set(name, None) 647 648 def __repr__(self): 649 if self.location is not None: 650 return "Function(%r, %r, %r, %r, %r, %r, location=%r)" % ( 651 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.location 652 ) 653 else: 654 return "Function(%r, %r, %r, %r, %r, %r)" % ( 655 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar 656 ) 657 658 def store_default(self, value): 659 attr = Attr(None, self, None, value) 660 attr.update(value, 1) 661 self.default_attrs.append(attr) 662 663 def make_global(self, name): 664 if name not in self.argnames and not self.has_key(name): 665 self.globals.add(name) 666 else: 667 raise InspectError(self.full_name(), self.node, "Name %r is global and local in %r" % (name, self.full_name())) 668 669 def parameters(self): 670 671 """ 672 Return a dictionary mapping parameter names to their position in the 673 parameter list. 674 """ 675 676 parameters = {} 677 for i, name in enumerate(self.argnames): 678 parameters[name] = i 679 return parameters 680 681 def all_locals(self): 682 683 "Return a dictionary mapping names to local and parameter details." 684 685 return dict(self) 686 687 def locals(self): 688 689 "Return a dictionary mapping names to local details." 690 691 if self.localnames is None: 692 self.localnames = {} 693 self.localnames.update(self.all_locals()) 694 for name in self.argnames: 695 del self.localnames[name] 696 return self.localnames 697 698 def is_method(self): 699 700 "Return whether this function is a method." 701 702 return isinstance(self.parent, Class) 703 704 def is_relocated(self, name): 705 706 """ 707 Determine whether the given attribute 'name' is relocated for instances 708 having this function as a method. 709 """ 710 711 for cls in self.parent.descendants: 712 if name in cls.relocated: 713 return 1 714 return 0 715 716 def finalise_attributes(self): 717 718 """ 719 Make sure all attributes (locals) are fully defined. Note that locals 720 are not attributes in the sense of class, module or instance attributes. 721 Defaults are also finalised by this method. 722 """ 723 724 for i, default in enumerate(self.default_attrs): 725 default.position = i 726 727 i = None 728 for i, name in enumerate(self.argnames): 729 self[name].position = i 730 731 if i is not None: 732 j = i 733 else: 734 j = 0 735 736 i = -1 737 for i, attr in enumerate(self.locals().values()): 738 attr.position = i + j 739 740 self.stack_local_usage = i + 1 741 742 def function_from_method(self): 743 744 "Make a function from a method." 745 746 return Function(self.name, self.parent, self.argnames[1:], self.defaults, 747 self.has_star, self.has_dstar, self.global_namespace, self.node) 748 749 class UnresolvedName(NamespaceDict): 750 751 "A module, class or function which was mentioned but could not be imported." 752 753 def __init__(self, name, parent_name, global_namespace=None): 754 NamespaceDict.__init__(self, global_namespace) 755 self.name = name 756 self.parent_name = parent_name 757 758 def all_class_attributes(self): 759 return {} 760 761 def instance_attributes(self): 762 return {} 763 764 def __repr__(self): 765 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 766 767 def full_name(self): 768 if self.name is not None: 769 return self.parent_name + "." + self.name 770 else: 771 return self.parent_name 772 773 class Instance: 774 775 "A placeholder indicating the involvement of an instance." 776 777 def __repr__(self): 778 return "Instance()" 779 780 class Module(NamespaceDict): 781 782 "An inspected module's core details." 783 784 def __init__(self, name): 785 NamespaceDict.__init__(self, self) 786 self.name = name 787 788 # Original location details. 789 790 self.node = None 791 792 # Complete lists of classes and functions. 793 794 self.all_objects = set() 795 796 # Constant records. 797 798 self.constant_values = {} 799 self.constant_list = None # cache for constants 800 801 # Keyword records. 802 803 self.keyword_names = set() 804 805 # Image generation details. 806 807 self.location = None 808 self.code_location = None 809 810 # Program-related details. 811 812 self.stack_usage = 0 813 self.stack_temp_usage = 0 814 self.stack_local_usage = 0 815 816 def full_name(self): 817 return self.name 818 819 def __repr__(self): 820 if self.location is not None: 821 return "Module(%r, location=%r)" % (self.name, self.location) 822 else: 823 return "Module(%r)" % self.name 824 825 # Attribute methods. 826 827 "Return the module attribute names provided by the module." 828 829 module_attribute_names = NamespaceDict.keys 830 831 def module_attributes(self): 832 833 "Return a dictionary mapping names to module attributes." 834 835 return dict(self) 836 837 def constants(self): 838 839 "Return a list of constants." 840 841 if self.constant_list is None: 842 self.constant_list = list(self.constant_values.values()) 843 844 return self.constant_list 845 846 # Program visitors. 847 848 class InspectedModule(ASTVisitor, Module): 849 850 """ 851 An inspected module, providing core details via the Module superclass, but 852 capable of being used as an AST visitor. 853 """ 854 855 def __init__(self, name, importer): 856 857 """ 858 Initialise this visitor with a module 'name' and an 'importer' which is 859 used to provide access to other modules when required. 860 """ 861 862 ASTVisitor.__init__(self) 863 Module.__init__(self, name) 864 self.visitor = self 865 866 self.importer = importer 867 self.builtins = self.importer.modules.get("__builtins__") 868 self.loaded = 0 869 870 # Current expression state. 871 872 self.expr = None 873 874 # Namespace state. 875 876 self.in_init = 0 # Find instance attributes in __init__ methods. 877 self.in_loop = 0 # Note loop "membership", affecting assignments. 878 self.namespaces = [] 879 self.module = None 880 881 def parse(self, filename): 882 883 "Parse the file having the given 'filename'." 884 885 module = compiler.parseFile(filename) 886 self.process(module) 887 888 def process(self, module): 889 890 "Process the given 'module'." 891 892 self.node = self.module = module 893 processed = self.dispatch(module) 894 if self.has_key("__all__"): 895 all = self["__all__"] 896 if isinstance(all, compiler.ast.List): 897 for n in all.nodes: 898 self[n.value] = self.importer.add_module(self.name + "." + n.value) 899 return processed 900 901 def vacuum(self): 902 903 "Vacuum the module namespace, removing unloaded module references." 904 905 for name, value in self.items(): 906 if isinstance(value, Module) and not value.loaded: 907 del self[name] 908 909 # Complain about globals not initialised at the module level. 910 911 if isinstance(value, Global): 912 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name) 913 914 # Namespace methods. 915 916 def store(self, name, obj): 917 918 "Record attribute or local 'name', storing 'obj'." 919 920 if not self.namespaces: 921 self.set(name, obj, not self.in_loop) 922 else: 923 self.namespaces[-1].set(name, obj, not self.in_loop) 924 925 # Record all non-local objects. 926 927 if not (self.namespaces and isinstance(self.namespaces[-1], Function)): 928 self.all_objects.add(obj) 929 930 def store_instance_attr(self, name): 931 932 "Record instance attribute 'name' in the current class." 933 934 if self.in_init: 935 936 # Current namespace is the function. 937 # Previous namespace is the class. 938 939 self.namespaces[-2].add_instance_attribute(name) 940 941 def get_parent(self): 942 943 "Return the parent (or most recent) namespace currently exposed." 944 945 return (self.namespaces[-1:] or [self])[0] 946 947 # Visitor methods. 948 949 def default(self, node, *args): 950 raise InspectError(self.full_name(), node, "Node class %r is not supported." % node.__class__) 951 952 def dispatch(self, node, *args): 953 return ASTVisitor.dispatch(self, node, *args) 954 955 def NOP(self, node): 956 for n in node.getChildNodes(): 957 self.dispatch(n) 958 return None 959 960 visitAdd = NOP 961 962 visitAnd = NOP 963 964 visitAssert = NOP 965 966 def visitAssign(self, node): 967 self.expr = self.dispatch(node.expr) 968 for n in node.nodes: 969 self.dispatch(n) 970 return None 971 972 def visitAssAttr(self, node): 973 expr = self.dispatch(node.expr) 974 if isinstance(expr, Attr) and expr.name == "self": 975 self.store_instance_attr(node.attrname) 976 return None 977 978 def visitAssList(self, node): 979 for n in node.nodes: 980 self.dispatch(n) 981 return None 982 983 def visitAssName(self, node): 984 if isinstance(self.expr, Attr): 985 self.store(node.name, self.expr.value) 986 else: 987 self.store(node.name, self.expr) 988 return None 989 990 visitAssTuple = visitAssList 991 992 visitAugAssign = NOP 993 994 visitBackquote = NOP 995 996 visitBitand = NOP 997 998 visitBitor = NOP 999 1000 visitBitxor = NOP 1001 1002 visitBreak = NOP 1003 1004 visitCallFunc = NOP 1005 1006 def visitClass(self, node): 1007 if self.namespaces: 1008 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 1009 else: 1010 cls = Class(node.name, self.get_parent(), self, node) 1011 1012 # Visit the base class expressions, attempting to find concrete 1013 # definitions of classes. 1014 1015 for base in node.bases: 1016 expr = self.dispatch(base) 1017 if isinstance(expr, Attr): 1018 if expr.assignments != 1: 1019 raise InspectError(self.full_name(), node, 1020 "Base class %r for %r is not constant." % (base, cls.full_name())) 1021 else: 1022 cls.add_base(expr.value) 1023 else: # if expr is None: 1024 raise InspectError(self.full_name(), node, 1025 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 1026 1027 # NOTE: Potentially dubious measure to permit __init__ availability. 1028 # If no bases exist, adopt the 'object' class. 1029 1030 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 1031 expr = self.dispatch(compiler.ast.Name("object")) 1032 cls.add_base(expr.value) 1033 1034 # Make a back reference from the node for code generation. 1035 1036 node.unit = cls 1037 1038 # Make an entry for the class. 1039 1040 self.store(node.name, cls) 1041 1042 # Process the class body. 1043 1044 self.namespaces.append(cls) 1045 self.dispatch(node.code) 1046 self.namespaces.pop() 1047 1048 return None 1049 1050 visitCompare = NOP 1051 1052 def visitConst(self, node): 1053 const = Const(node.value) 1054 self.constant_values[node.value] = const 1055 return const 1056 1057 visitContinue = NOP 1058 1059 visitDecorators = NOP 1060 1061 visitDict = NOP 1062 1063 visitDiscard = NOP 1064 1065 visitDiv = NOP 1066 1067 visitEllipsis = NOP 1068 1069 visitExec = NOP 1070 1071 visitExpression = NOP 1072 1073 visitFloorDiv = NOP 1074 1075 def visitFor(self, node): 1076 self.in_loop = 1 1077 self.NOP(node) 1078 self.in_loop = 0 1079 1080 def visitFrom(self, node): 1081 module = self.importer.load(node.modname, 1) 1082 1083 #if module is None: 1084 # print "Warning:", node.modname, "not imported." 1085 1086 for name, alias in node.names: 1087 if name != "*": 1088 if module is not None and module.namespace.has_key(name): 1089 attr = module[name] 1090 self.store(alias or name, attr.value) 1091 if isinstance(attr, Module) and not attr.loaded: 1092 self.importer.load(attr.name) 1093 1094 # Support the import of names from missing modules. 1095 1096 else: 1097 self.store(alias or name, UnresolvedName(name, node.modname, self)) 1098 else: 1099 if module is not None: 1100 for n in module.namespace.keys(): 1101 attr = module[n] 1102 self.store(n, attr.value) 1103 if isinstance(attr, Module) and not attr.loaded: 1104 self.importer.load(attr.name) 1105 1106 return None 1107 1108 def visitFunction(self, node): 1109 function = Function( 1110 node.name, 1111 self.get_parent(), 1112 node.argnames, 1113 node.defaults, 1114 (node.flags & 4 != 0), 1115 (node.flags & 8 != 0), 1116 self, 1117 node 1118 ) 1119 1120 # Make a back reference from the node for code generation. 1121 1122 node.unit = function 1123 1124 # Process the defaults. 1125 1126 for n in node.defaults: 1127 self.expr = self.dispatch(n) 1128 if isinstance(self.expr, Attr): 1129 function.store_default(self.expr.value) 1130 else: 1131 function.store_default(self.expr) 1132 1133 # Enter the function. 1134 1135 self.namespaces.append(function) 1136 1137 # Current namespace is the function. 1138 # Previous namespace is the class. 1139 1140 if node.name == "__init__" and isinstance(self.namespaces[-2], Class): 1141 self.in_init = 1 1142 1143 self.dispatch(node.code) 1144 self.in_init = 0 1145 self.namespaces.pop() 1146 1147 self.store(node.name, function) 1148 return None 1149 1150 visitGenExpr = NOP 1151 1152 visitGenExprFor = NOP 1153 1154 visitGenExprIf = NOP 1155 1156 visitGenExprInner = NOP 1157 1158 def visitGetattr(self, node): 1159 expr = self.dispatch(node.expr) 1160 if isinstance(expr, Attr): 1161 value = expr.value 1162 if isinstance(value, Module): 1163 return value.namespace.get(node.attrname) 1164 elif isinstance(value, UnresolvedName): 1165 return UnresolvedName(node.attrname, value.full_name(), self) 1166 if self.builtins is not None: 1167 return self.builtins.get(node.attrname) 1168 else: 1169 return UnresolvedName(node.attrname, value.full_name(), self) 1170 1171 def visitGlobal(self, node): 1172 if self.namespaces: 1173 for name in node.names: 1174 self.namespaces[-1].make_global(name) 1175 1176 # Record a global entry for the name in the module. 1177 1178 if not self.has_key(name): 1179 self[name] = Global() 1180 1181 def visitIf(self, node): 1182 for test, body in node.tests: 1183 self.dispatch(body) 1184 if node.else_ is not None: 1185 self.dispatch(node.else_) 1186 return None 1187 1188 visitIfExp = NOP 1189 1190 def visitImport(self, node): 1191 for name, alias in node.names: 1192 if alias is not None: 1193 self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self)) 1194 else: 1195 self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)) 1196 1197 return None 1198 1199 visitInvert = NOP 1200 1201 def visitKeyword(self, node): 1202 self.dispatch(node.expr) 1203 const = Const(node.name) 1204 self.constant_values[node.name] = const 1205 self.keyword_names.add(node.name) 1206 return None 1207 1208 visitLambda = NOP 1209 1210 visitLeftShift = NOP 1211 1212 visitList = NOP 1213 1214 visitListComp = NOP 1215 1216 visitListCompFor = NOP 1217 1218 visitListCompIf = NOP 1219 1220 visitMod = NOP 1221 1222 def visitModule(self, node): 1223 return self.dispatch(node.node) 1224 1225 visitMul = NOP 1226 1227 def visitName(self, node): 1228 name = node.name 1229 if self.namespaces and self.namespaces[-1].has_key(name): 1230 return self.namespaces[-1][name] 1231 elif self.has_key(name): 1232 return self[name] 1233 elif self.builtins is not None and self.builtins.has_key(name): 1234 return self.builtins[name] 1235 else: 1236 return None 1237 1238 visitNot = NOP 1239 1240 visitOr = NOP 1241 1242 visitPass = NOP 1243 1244 visitPower = NOP 1245 1246 visitPrint = NOP 1247 1248 visitPrintnl = NOP 1249 1250 visitRaise = NOP 1251 1252 visitReturn = NOP 1253 1254 visitRightShift = NOP 1255 1256 visitSlice = NOP 1257 1258 visitSliceobj = NOP 1259 1260 def visitStmt(self, node): 1261 for n in node.nodes: 1262 self.dispatch(n) 1263 return None 1264 1265 visitSub = NOP 1266 1267 visitSubscript = NOP 1268 1269 def visitTryExcept(self, node): 1270 self.dispatch(node.body) 1271 for name, var, n in node.handlers: 1272 self.dispatch(n) 1273 if node.else_ is not None: 1274 self.dispatch(node.else_) 1275 return None 1276 1277 visitTryFinally = NOP 1278 1279 visitTuple = NOP 1280 1281 visitUnaryAdd = NOP 1282 1283 visitUnarySub = NOP 1284 1285 def visitWhile(self, node): 1286 self.in_loop = 1 1287 self.NOP(node) 1288 self.in_loop = 0 1289 1290 visitWith = NOP 1291 1292 visitYield = NOP 1293 1294 class Global: 1295 1296 """ 1297 A reference to an object assigned to a global from outside the module 1298 top-level. 1299 """ 1300 1301 pass 1302 1303 # vim: tabstop=4 expandtab shiftwidth=4