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