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