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 def __eq__(self, other): 276 return self.value == other.value 277 278 def __hash__(self): 279 return hash(self.value) 280 281 class Class(NamespaceDict, Naming): 282 283 "An inspected class." 284 285 def __init__(self, name, parent, global_namespace=None, node=None): 286 287 """ 288 Initialise the class with the given 'name', 'parent' object, optional 289 'global_namespace' and optional AST 'node'. 290 """ 291 292 NamespaceDict.__init__(self, global_namespace) 293 self.name = name 294 self.parent = parent 295 self.node = node 296 297 # Superclasses, descendants and attributes. 298 299 self.bases = [] 300 self.descendants = set() 301 self.instattr = set() # instance attributes 302 self.relocated = set() # attributes which do not have the same 303 # position as those of the same name in 304 # some superclasses 305 306 # Caches. 307 308 self.all_instattr = None # cache for instance_attributes 309 self.all_instattr_names = None # from all_instattr 310 self.all_classattr = None # cache for all_class_attributes 311 self.all_classattr_names = None # from all_classattr 312 self.allattr = None # cache for all_attributes 313 self.allattr_names = None # from allattr 314 315 # Add this class to its attributes. 316 317 self.set("__class__", self) 318 319 # Image generation details. 320 321 self.location = None 322 self.code_location = None 323 self.instantiator = None 324 325 # Program-related details. 326 327 self.stack_usage = 0 328 self.stack_temp_usage = 0 329 self.stack_local_usage = 0 330 331 def __repr__(self): 332 if self.location is not None: 333 return "Class(%r, %r, location=%r)" % (self.name, self.parent, self.location) 334 else: 335 return "Class(%r, %r)" % (self.name, self.parent) 336 337 def finalise_attributes(self): 338 339 "Make sure that all attributes are fully defined." 340 341 self.finalise_class_attributes() 342 self.finalise_instance_attributes() 343 344 def get_instantiator(self): 345 346 "Return a function which can be used to instantiate the class." 347 348 if self.instantiator is None: 349 init_method = self.all_class_attributes()["__init__"].value 350 self.instantiator = init_method.function_from_method() 351 return self.instantiator 352 353 # Class-specific methods. 354 355 def add_base(self, base): 356 self.bases.append(base) 357 base.add_descendant(self) 358 359 def add_instance_attribute(self, name): 360 self.instattr.add(name) 361 362 def add_descendant(self, cls): 363 self.descendants.add(cls) 364 for base in self.bases: 365 base.add_descendant(cls) 366 367 "Return the attribute names provided by this class only." 368 369 class_attribute_names = NamespaceDict.keys 370 371 def class_attributes(self): 372 373 "Return class attributes provided by this class only." 374 375 self.finalise_class_attributes() 376 return dict(self) 377 378 def all_class_attribute_names(self): 379 380 "Return the attribute names provided by classes in this hierarchy." 381 382 if self.all_classattr_names is None: 383 self.all_class_attributes() 384 return self.all_classattr_names 385 386 def all_class_attributes(self): 387 388 "Return all class attributes, indicating the class which provides them." 389 390 self.finalise_class_attributes() 391 return self.all_classattr 392 393 def finalise_class_attributes(self): 394 395 "Make sure that the class attributes are fully defined." 396 397 if self.all_classattr is None: 398 self.all_classattr = {} 399 clsattr = {} 400 401 # Record provisional position information for attributes of this 402 # class. 403 404 for name in self.class_attributes().keys(): 405 clsattr[name] = set() # position not yet defined 406 407 reversed_bases = self.bases[:] 408 reversed_bases.reverse() 409 410 # For the bases in reverse order, acquire class attribute details. 411 412 for cls in reversed_bases: 413 for name, attr in cls.all_class_attributes().items(): 414 self.all_classattr[name] = attr 415 416 # Record previous attribute information. 417 418 if clsattr.has_key(name): 419 clsattr[name].add(attr.position) 420 421 # Record class attributes provided by this class and its bases, 422 # along with their positions. 423 424 self.all_classattr.update(self.class_attributes()) 425 426 if clsattr: 427 for i, name in enumerate(self._get_position_list(clsattr)): 428 self.all_classattr[name].position = i 429 430 return self.all_classattr 431 432 def instance_attribute_names(self): 433 434 "Return the instance attribute names provided by the class." 435 436 if self.all_instattr_names is None: 437 self.instance_attributes() 438 return self.all_instattr_names 439 440 def instance_attributes(self): 441 442 "Return instance-only attributes for instances of this class." 443 444 self.finalise_instance_attributes() 445 return self.all_instattr 446 447 def finalise_instance_attributes(self): 448 449 "Make sure that the instance attributes are fully defined." 450 451 if self.all_instattr is None: 452 self.all_instattr = {} 453 instattr = {} 454 455 # Record provisional position information for attributes of this 456 # instance. 457 458 for name in self.instattr: 459 instattr[name] = set() # position not yet defined 460 461 reversed_bases = self.bases[:] 462 reversed_bases.reverse() 463 464 # For the bases in reverse order, acquire instance attribute 465 # details. 466 467 for cls in reversed_bases: 468 for name, attr in cls.instance_attributes().items(): 469 470 # Record previous attribute information. 471 472 if instattr.has_key(name): 473 instattr[name].add(attr.position) 474 475 # Cache the attributes by converting the positioned attributes into 476 # a dictionary. 477 478 if not instattr: 479 self.all_instattr = {} 480 else: 481 self.all_instattr = self._get_attributes(instattr) 482 483 self.all_instattr_names = self.all_instattr.keys() 484 485 return self.all_instattr 486 487 def _get_position_list(self, positions): 488 489 """ 490 Return a list of attribute names for the given 'positions' mapping from 491 names to positions, indicating the positions of the attributes in the 492 final instance structure. 493 """ 494 495 position_items = positions.items() 496 namearray = [None] * len(position_items) 497 498 # Get the positions in ascending order of list size, with lists 499 # of the same size ordered according to their smallest position 500 # value. 501 502 position_items.sort(self._cmp_positions) 503 504 # Get the names in position order. 505 506 held = [] 507 508 for name, pos in position_items: 509 pos = list(pos) 510 pos.sort() 511 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 512 namearray[pos[0]] = name 513 else: 514 if pos: 515 self.relocated.add(name) 516 held.append((name, pos)) 517 518 for i, attr in enumerate(namearray): 519 if attr is None: 520 name, pos = held.pop() 521 namearray[i] = name 522 523 #print self.name, positions 524 #print "->", namearray 525 return namearray 526 527 def _get_attributes(self, positions): 528 529 """ 530 For the given 'positions' mapping from names to positions, return a 531 dictionary mapping names to Attr instances incorporating information 532 about their positions in the final instance structure. 533 """ 534 535 d = {} 536 for i, name in enumerate(self._get_position_list(positions)): 537 d[name] = Attr(i, Instance(), name, None) 538 return d 539 540 def _cmp_positions(self, a, b): 541 542 "Compare name plus position list operands 'a' and 'b'." 543 544 name_a, list_a = a 545 name_b, list_b = b 546 if len(list_a) < len(list_b): 547 return -1 548 elif len(list_a) > len(list_b): 549 return 1 550 elif not list_a: 551 return 0 552 else: 553 return cmp(min(list_a), min(list_b)) 554 555 def all_attribute_names(self): 556 557 """ 558 Return the names of all attributes provided by instances of this class. 559 """ 560 561 self.allattr_names = self.allattr_names or self.all_attributes().keys() 562 return self.allattr_names 563 564 def all_attributes(self): 565 566 """ 567 Return all attributes for an instance, indicating either the class which 568 provides them or that the instance itself provides them. 569 """ 570 571 if self.allattr is None: 572 self.allattr = {} 573 self.allattr.update(self.all_class_attributes()) 574 for name, attr in self.instance_attributes().items(): 575 if self.allattr.has_key(name): 576 print "Instance attribute %r in %r overrides class attribute." % (name, self) 577 self.allattr[name] = attr 578 return self.allattr 579 580 class Function(NamespaceDict, Naming): 581 582 "An inspected function." 583 584 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, global_namespace=None, node=None): 585 586 """ 587 Initialise the function with the given 'name', 'parent', list of 588 'argnames', list of 'defaults', the 'has_star' flag (indicating the 589 presence of a * parameter), the 'has_dstar' flag (indicating the 590 presence of a ** parameter), optional 'global_namespace', and optional 591 AST 'node'. 592 """ 593 594 NamespaceDict.__init__(self, global_namespace) 595 self.name = name 596 self.parent = parent 597 self.argnames = argnames 598 self.defaults = defaults 599 self.has_star = has_star 600 self.has_dstar = has_dstar 601 self.node = node 602 603 # Initialise the positional names. 604 605 self.positional_names = self.argnames[:] 606 if has_dstar: 607 self.dstar_name = self.positional_names[-1] 608 del self.positional_names[-1] 609 if has_star: 610 self.star_name = self.positional_names[-1] 611 del self.positional_names[-1] 612 613 # Initialise default storage. 614 615 self.default_attrs = [] 616 617 # Caches. 618 619 self.localnames = None # cache for locals 620 621 # Add parameters to the namespace. 622 623 self._add_parameters(argnames) 624 625 # Image generation details. 626 627 self.location = None 628 self.code_location = None 629 630 # Program-related details. 631 632 self.stack_usage = 0 633 self.stack_temp_usage = 0 634 self.stack_local_usage = 0 635 636 def _add_parameters(self, argnames): 637 for name in argnames: 638 if isinstance(name, tuple): 639 self._add_parameters(name) 640 else: 641 self.set(name, None) 642 643 def __repr__(self): 644 if self.location is not None: 645 return "Function(%r, %r, %r, %r, %r, %r, location=%r)" % ( 646 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.location 647 ) 648 else: 649 return "Function(%r, %r, %r, %r, %r, %r)" % ( 650 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar 651 ) 652 653 def store_default(self, value): 654 attr = Attr(None, self, None, value) 655 attr.update(value, 1) 656 self.default_attrs.append(attr) 657 658 def make_global(self, name): 659 if name not in self.argnames and not self.has_key(name): 660 self.globals.add(name) 661 else: 662 raise InspectError(self.full_name(), self.node, "Name %r is global and local in %r" % (name, self.full_name())) 663 664 def parameters(self): 665 666 """ 667 Return a dictionary mapping parameter names to their position in the 668 parameter list. 669 """ 670 671 parameters = {} 672 for i, name in enumerate(self.argnames): 673 parameters[name] = i 674 return parameters 675 676 def all_locals(self): 677 678 "Return a dictionary mapping names to local and parameter details." 679 680 return dict(self) 681 682 def locals(self): 683 684 "Return a dictionary mapping names to local details." 685 686 if self.localnames is None: 687 self.localnames = {} 688 self.localnames.update(self.all_locals()) 689 for name in self.argnames: 690 del self.localnames[name] 691 return self.localnames 692 693 def is_method(self): 694 695 "Return whether this function is a method." 696 697 return isinstance(self.parent, Class) 698 699 def is_relocated(self, name): 700 701 """ 702 Determine whether the given attribute 'name' is relocated for instances 703 having this function as a method. 704 """ 705 706 for cls in self.parent.descendants: 707 if name in cls.relocated: 708 return 1 709 return 0 710 711 def finalise_attributes(self): 712 713 """ 714 Make sure all attributes (locals) are fully defined. Note that locals 715 are not attributes in the sense of class, module or instance attributes. 716 Defaults are also finalised by this method. 717 """ 718 719 for i, default in enumerate(self.default_attrs): 720 default.position = i 721 722 i = None 723 for i, name in enumerate(self.argnames): 724 self[name].position = i 725 726 if i is not None: 727 j = i 728 else: 729 j = 0 730 731 i = -1 732 for i, attr in enumerate(self.locals().values()): 733 attr.position = i + j 734 735 self.stack_local_usage = i + 1 736 737 def function_from_method(self): 738 739 "Make a function from a method." 740 741 return Function(self.name, self.parent, self.argnames[1:], self.defaults, 742 self.has_star, self.has_dstar, self.global_namespace, self.node) 743 744 class UnresolvedName(NamespaceDict): 745 746 "A module, class or function which was mentioned but could not be imported." 747 748 def __init__(self, name, parent_name, global_namespace=None): 749 NamespaceDict.__init__(self, global_namespace) 750 self.name = name 751 self.parent_name = parent_name 752 753 def all_class_attributes(self): 754 return {} 755 756 def instance_attributes(self): 757 return {} 758 759 def __repr__(self): 760 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 761 762 def full_name(self): 763 if self.name is not None: 764 return self.parent_name + "." + self.name 765 else: 766 return self.parent_name 767 768 class Instance: 769 770 "A placeholder indicating the involvement of an instance." 771 772 def __repr__(self): 773 return "Instance()" 774 775 class Module(NamespaceDict): 776 777 "An inspected module's core details." 778 779 def __init__(self, name): 780 NamespaceDict.__init__(self, self) 781 self.name = name 782 783 # Original location details. 784 785 self.node = None 786 787 # Complete lists of classes and functions. 788 789 self.all_objects = set() 790 791 # Constant records. 792 793 self.constant_values = {} 794 self.constant_list = None # cache for constants 795 796 # Keyword records. 797 798 self.keyword_names = set() 799 800 # Image generation details. 801 802 self.location = None 803 self.code_location = None 804 805 # Program-related details. 806 807 self.stack_usage = 0 808 self.stack_temp_usage = 0 809 self.stack_local_usage = 0 810 811 def full_name(self): 812 return self.name 813 814 def __repr__(self): 815 if self.location is not None: 816 return "Module(%r, location=%r)" % (self.name, self.location) 817 else: 818 return "Module(%r)" % self.name 819 820 # Attribute methods. 821 822 "Return the module attribute names provided by the module." 823 824 module_attribute_names = NamespaceDict.keys 825 826 def module_attributes(self): 827 828 "Return a dictionary mapping names to module attributes." 829 830 return dict(self) 831 832 def constants(self): 833 834 "Return a list of constants." 835 836 if self.constant_list is None: 837 self.constant_list = list(self.constant_values.values()) 838 839 return self.constant_list 840 841 # Program visitors. 842 843 class InspectedModule(ASTVisitor, Module): 844 845 """ 846 An inspected module, providing core details via the Module superclass, but 847 capable of being used as an AST visitor. 848 """ 849 850 def __init__(self, name, importer): 851 852 """ 853 Initialise this visitor with a module 'name' and an 'importer' which is 854 used to provide access to other modules when required. 855 """ 856 857 ASTVisitor.__init__(self) 858 Module.__init__(self, name) 859 self.visitor = self 860 861 self.importer = importer 862 self.builtins = self.importer.modules.get("__builtins__") 863 self.loaded = 0 864 865 # Current expression state. 866 867 self.expr = None 868 869 # Namespace state. 870 871 self.in_init = 0 # Find instance attributes in __init__ methods. 872 self.in_loop = 0 # Note loop "membership", affecting assignments. 873 self.namespaces = [] 874 self.module = None 875 876 def parse(self, filename): 877 878 "Parse the file having the given 'filename'." 879 880 module = compiler.parseFile(filename) 881 self.process(module) 882 883 def process(self, module): 884 885 "Process the given 'module'." 886 887 self.node = self.module = module 888 processed = self.dispatch(module) 889 if self.has_key("__all__"): 890 all = self["__all__"] 891 if isinstance(all, compiler.ast.List): 892 for n in all.nodes: 893 self[n.value] = self.importer.add_module(self.name + "." + n.value) 894 return processed 895 896 def vacuum(self): 897 898 "Vacuum the module namespace, removing unloaded module references." 899 900 for name, value in self.items(): 901 if isinstance(value, Module) and not value.loaded: 902 del self[name] 903 904 # Complain about globals not initialised at the module level. 905 906 if isinstance(value, Global): 907 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name) 908 909 # Namespace methods. 910 911 def store(self, name, obj): 912 913 "Record attribute or local 'name', storing 'obj'." 914 915 if not self.namespaces: 916 self.set(name, obj, not self.in_loop) 917 else: 918 self.namespaces[-1].set(name, obj, not self.in_loop) 919 920 # Record all non-local objects. 921 922 if not (self.namespaces and isinstance(self.namespaces[-1], Function)): 923 self.all_objects.add(obj) 924 925 def store_instance_attr(self, name): 926 927 "Record instance attribute 'name' in the current class." 928 929 if self.in_init: 930 931 # Current namespace is the function. 932 # Previous namespace is the class. 933 934 self.namespaces[-2].add_instance_attribute(name) 935 936 def get_parent(self): 937 938 "Return the parent (or most recent) namespace currently exposed." 939 940 return (self.namespaces[-1:] or [self])[0] 941 942 # Visitor methods. 943 944 def default(self, node, *args): 945 raise InspectError(self.full_name(), node, "Node class %r is not supported." % node.__class__) 946 947 def dispatch(self, node, *args): 948 return ASTVisitor.dispatch(self, node, *args) 949 950 def NOP(self, node): 951 for n in node.getChildNodes(): 952 self.dispatch(n) 953 return None 954 955 visitAdd = NOP 956 957 visitAnd = NOP 958 959 visitAssert = NOP 960 961 def visitAssign(self, node): 962 self.expr = self.dispatch(node.expr) 963 for n in node.nodes: 964 self.dispatch(n) 965 return None 966 967 def visitAssAttr(self, node): 968 expr = self.dispatch(node.expr) 969 if isinstance(expr, Attr) and expr.name == "self": 970 self.store_instance_attr(node.attrname) 971 return None 972 973 def visitAssList(self, node): 974 for n in node.nodes: 975 self.dispatch(n) 976 return None 977 978 def visitAssName(self, node): 979 if isinstance(self.expr, Attr): 980 self.store(node.name, self.expr.value) 981 else: 982 self.store(node.name, self.expr) 983 return None 984 985 visitAssTuple = visitAssList 986 987 visitAugAssign = NOP 988 989 visitBackquote = NOP 990 991 visitBitand = NOP 992 993 visitBitor = NOP 994 995 visitBitxor = NOP 996 997 visitBreak = NOP 998 999 visitCallFunc = NOP 1000 1001 def visitClass(self, node): 1002 if self.namespaces: 1003 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 1004 else: 1005 cls = Class(node.name, self.get_parent(), self, node) 1006 1007 # Visit the base class expressions, attempting to find concrete 1008 # definitions of classes. 1009 1010 for base in node.bases: 1011 expr = self.dispatch(base) 1012 if isinstance(expr, Attr): 1013 if expr.assignments != 1: 1014 raise InspectError(self.full_name(), node, 1015 "Base class %r for %r is not constant." % (base, cls.full_name())) 1016 else: 1017 cls.add_base(expr.value) 1018 else: # if expr is None: 1019 raise InspectError(self.full_name(), node, 1020 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 1021 1022 # NOTE: Potentially dubious measure to permit __init__ availability. 1023 # If no bases exist, adopt the 'object' class. 1024 1025 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 1026 expr = self.dispatch(compiler.ast.Name("object")) 1027 cls.add_base(expr.value) 1028 1029 # Make a back reference from the node for code generation. 1030 1031 node.unit = cls 1032 1033 # Make an entry for the class. 1034 1035 self.store(node.name, cls) 1036 1037 # Process the class body. 1038 1039 self.namespaces.append(cls) 1040 self.dispatch(node.code) 1041 self.namespaces.pop() 1042 1043 return None 1044 1045 visitCompare = NOP 1046 1047 def visitConst(self, node): 1048 const = Const(node.value) 1049 self.constant_values[node.value] = const 1050 return const 1051 1052 visitContinue = NOP 1053 1054 visitDecorators = NOP 1055 1056 visitDict = NOP 1057 1058 visitDiscard = NOP 1059 1060 visitDiv = NOP 1061 1062 visitEllipsis = NOP 1063 1064 visitExec = NOP 1065 1066 visitExpression = NOP 1067 1068 visitFloorDiv = NOP 1069 1070 def visitFor(self, node): 1071 self.in_loop = 1 1072 self.NOP(node) 1073 self.in_loop = 0 1074 1075 def visitFrom(self, node): 1076 module = self.importer.load(node.modname, 1) 1077 1078 #if module is None: 1079 # print "Warning:", node.modname, "not imported." 1080 1081 for name, alias in node.names: 1082 if name != "*": 1083 if module is not None and module.namespace.has_key(name): 1084 attr = module[name] 1085 self.store(alias or name, attr.value) 1086 if isinstance(attr, Module) and not attr.loaded: 1087 self.importer.load(attr.name) 1088 1089 # Support the import of names from missing modules. 1090 1091 else: 1092 self.store(alias or name, UnresolvedName(name, node.modname, self)) 1093 else: 1094 if module is not None: 1095 for n in module.namespace.keys(): 1096 attr = module[n] 1097 self.store(n, attr.value) 1098 if isinstance(attr, Module) and not attr.loaded: 1099 self.importer.load(attr.name) 1100 1101 return None 1102 1103 def visitFunction(self, node): 1104 function = Function( 1105 node.name, 1106 self.get_parent(), 1107 node.argnames, 1108 node.defaults, 1109 (node.flags & 4 != 0), 1110 (node.flags & 8 != 0), 1111 self, 1112 node 1113 ) 1114 1115 # Make a back reference from the node for code generation. 1116 1117 node.unit = function 1118 1119 # Process the defaults. 1120 1121 for n in node.defaults: 1122 self.expr = self.dispatch(n) 1123 if isinstance(self.expr, Attr): 1124 function.store_default(self.expr.value) 1125 else: 1126 function.store_default(self.expr) 1127 1128 # Enter the function. 1129 1130 self.namespaces.append(function) 1131 1132 # Current namespace is the function. 1133 # Previous namespace is the class. 1134 1135 if node.name == "__init__" and isinstance(self.namespaces[-2], Class): 1136 self.in_init = 1 1137 1138 self.dispatch(node.code) 1139 self.in_init = 0 1140 self.namespaces.pop() 1141 1142 self.store(node.name, function) 1143 return None 1144 1145 visitGenExpr = NOP 1146 1147 visitGenExprFor = NOP 1148 1149 visitGenExprIf = NOP 1150 1151 visitGenExprInner = NOP 1152 1153 def visitGetattr(self, node): 1154 expr = self.dispatch(node.expr) 1155 if isinstance(expr, Attr): 1156 value = expr.value 1157 if isinstance(value, Module): 1158 return value.namespace.get(node.attrname) 1159 elif isinstance(value, UnresolvedName): 1160 return UnresolvedName(node.attrname, value.full_name(), self) 1161 if self.builtins is not None: 1162 return self.builtins.get(node.attrname) 1163 else: 1164 return UnresolvedName(node.attrname, value.full_name(), self) 1165 1166 def visitGlobal(self, node): 1167 if self.namespaces: 1168 for name in node.names: 1169 self.namespaces[-1].make_global(name) 1170 1171 # Record a global entry for the name in the module. 1172 1173 if not self.has_key(name): 1174 self[name] = Global() 1175 1176 def visitIf(self, node): 1177 for test, body in node.tests: 1178 self.dispatch(body) 1179 if node.else_ is not None: 1180 self.dispatch(node.else_) 1181 return None 1182 1183 visitIfExp = NOP 1184 1185 def visitImport(self, node): 1186 for name, alias in node.names: 1187 if alias is not None: 1188 self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self)) 1189 else: 1190 self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)) 1191 1192 return None 1193 1194 visitInvert = NOP 1195 1196 def visitKeyword(self, node): 1197 self.dispatch(node.expr) 1198 const = Const(node.name) 1199 self.constant_values[node.name] = const 1200 self.keyword_names.add(node.name) 1201 return None 1202 1203 visitLambda = NOP 1204 1205 visitLeftShift = NOP 1206 1207 visitList = NOP 1208 1209 visitListComp = NOP 1210 1211 visitListCompFor = NOP 1212 1213 visitListCompIf = NOP 1214 1215 visitMod = NOP 1216 1217 def visitModule(self, node): 1218 return self.dispatch(node.node) 1219 1220 visitMul = NOP 1221 1222 def visitName(self, node): 1223 name = node.name 1224 if self.namespaces and self.namespaces[-1].has_key(name): 1225 return self.namespaces[-1][name] 1226 elif self.has_key(name): 1227 return self[name] 1228 elif self.builtins is not None and self.builtins.has_key(name): 1229 return self.builtins[name] 1230 else: 1231 return None 1232 1233 visitNot = NOP 1234 1235 visitOr = NOP 1236 1237 visitPass = NOP 1238 1239 visitPower = NOP 1240 1241 visitPrint = NOP 1242 1243 visitPrintnl = NOP 1244 1245 visitRaise = NOP 1246 1247 visitReturn = NOP 1248 1249 visitRightShift = NOP 1250 1251 visitSlice = NOP 1252 1253 visitSliceobj = NOP 1254 1255 def visitStmt(self, node): 1256 for n in node.nodes: 1257 self.dispatch(n) 1258 return None 1259 1260 visitSub = NOP 1261 1262 visitSubscript = NOP 1263 1264 def visitTryExcept(self, node): 1265 self.dispatch(node.body) 1266 for name, var, n in node.handlers: 1267 self.dispatch(n) 1268 if node.else_ is not None: 1269 self.dispatch(node.else_) 1270 return None 1271 1272 visitTryFinally = NOP 1273 1274 visitTuple = NOP 1275 1276 visitUnaryAdd = NOP 1277 1278 visitUnarySub = NOP 1279 1280 def visitWhile(self, node): 1281 self.in_loop = 1 1282 self.NOP(node) 1283 self.in_loop = 0 1284 1285 visitWith = NOP 1286 1287 visitYield = NOP 1288 1289 class Global: 1290 1291 """ 1292 A reference to an object assigned to a global from outside the module 1293 top-level. 1294 """ 1295 1296 pass 1297 1298 # vim: tabstop=4 expandtab shiftwidth=4