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 self.attr_position = 0 112 113 def __getitem__(self, name): 114 return self.namespace[name] 115 116 def get(self, name, default=None): 117 return self.namespace.get(name, default) 118 119 def __setitem__(self, name, value): 120 self.set(name, value) 121 122 def set(self, name, value, single_assignment=1): 123 124 """ 125 A more powerful set operation, making 'name' refer to 'value' whilst 126 indicating whether a 'single_assignment' (true by default) occurs in 127 this operation (or whether the operation covers potentially many 128 assignments in the lifetime of a program). 129 """ 130 131 if name in self.globals: 132 self.global_namespace.set(name, value, 0) 133 else: 134 attr = self._set(name, value) 135 136 # NOTE: Insist on assignments with known values. 137 138 if value is not None: 139 attr.update(value, single_assignment) 140 141 def set_module(self, name, value): 142 143 """ 144 A specialised set operation, making 'name' refer to 'value' in the 145 context of making a module reference available in association with 146 'name' as part of the import of that module or a submodule of that 147 module. 148 """ 149 150 attr = self._set(name, value) 151 if attr.assignments is None: 152 attr.assignments = 1 153 attr.assignment_values.add(value) 154 155 def _set(self, name, value): 156 157 "The underlying set operation associating 'name' with 'value'." 158 159 if not self.namespace.has_key(name): 160 self.namespace[name] = Attr(self.attr_position, self, name, value) 161 self.attr_position += 1 162 return self.namespace[name] 163 164 def __delitem__(self, name): 165 del self.namespace[name] 166 167 def has_key(self, name): 168 return self.namespace.has_key(name) 169 170 def keys(self): 171 return self.namespace.keys() 172 173 def values(self): 174 return self.namespace.values() 175 176 def items(self): 177 return self.namespace.items() 178 179 def make_global(self, name): 180 if not self.namespace.has_key(name): 181 self.globals.add(name) 182 else: 183 raise InspectError(self.full_name(), self.node, "Name %r is both global and local in %r" % (name, self.full_name())) 184 185 def get_assignments(self, name): 186 if self.assignments.has_key(name): 187 return max(self.assignments[name], len(self.assignment_values[name])) 188 else: 189 return None 190 191 def to_list(self, d): 192 l = [None] * len(d.keys()) 193 for attr in d.values(): 194 l[attr.position] = attr 195 return l 196 197 class Naming: 198 199 "A mix-in providing naming conveniences." 200 201 def full_name(self): 202 if self.name is not None: 203 return self.parent_name + "." + self.name 204 else: 205 return self.parent_name 206 207 # Program data structures. 208 209 class Attr: 210 211 "An attribute entry." 212 213 def __init__(self, position, parent, name, value=None, assignments=None): 214 self.position = position 215 self.parent = parent 216 self.name = name 217 self.value = value 218 219 # Number of assignments per name. 220 221 self.assignments = assignments 222 self.assignment_values = set() 223 224 def update(self, value, single_assignment): 225 226 """ 227 Update the attribute, adding the 'value' provided to the known values 228 associated with the attribute, changing the number of assignments 229 according to the 'single_assignment' status of the operation, where 230 a true value indicates that only one assignment is associated with the 231 update, and a false value indicates that potentially many assignments 232 may be involved. 233 """ 234 235 if self.assignments is None: 236 if single_assignment: 237 self.assignments = 1 238 else: 239 self.assignments = AtLeast(1) 240 else: 241 if single_assignment: 242 self.assignments += 1 243 else: 244 self.assignments += AtLeast(1) 245 self.assignment_values.add(value) 246 247 def __repr__(self): 248 return "Attr(%r, %r, %r, %r, %r)" % (self.position, self.parent, self.name, self.value, self.assignments) 249 250 class Const: 251 252 "A constant object." 253 254 def __init__(self, value): 255 self.value = value 256 257 # Image generation details. 258 259 self.location = None 260 261 def __repr__(self): 262 if self.location is not None: 263 return "Const(%r, location=%r)" % (self.value, self.location) 264 else: 265 return "Const(%r)" % self.value 266 267 def __eq__(self, other): 268 return self.value == other.value 269 270 def __hash__(self): 271 return hash(self.value) 272 273 class Class(NamespaceDict, Naming): 274 275 "An inspected class." 276 277 def __init__(self, name, parent_name, global_namespace=None, node=None): 278 NamespaceDict.__init__(self, global_namespace) 279 self.name = name 280 self.parent_name = parent_name 281 self.node = node 282 283 # Superclasses and attributes. 284 285 self.bases = [] 286 self.instattr = set() # instance attributes 287 self.instattr_relocated = set() # instance attributes which do not have 288 # the same position as those of the same 289 # name in some superclasses 290 291 # Caches. 292 293 self.all_instattr = None # cache for instance_attributes 294 self.all_instattr_names = None # from all_instattr 295 self.all_classattr = None # cache for all_class_attributes 296 self.all_classattr_names = None # from all_classattr 297 self.allattr = None # cache for all_attributes 298 self.allattr_names = None # from allattr 299 300 # Image generation details. 301 302 self.location = None 303 self.code_location = None 304 305 def __repr__(self): 306 if self.location is not None: 307 return "Class(%r, %r, location=%r)" % (self.name, self.parent_name, self.location) 308 else: 309 return "Class(%r, %r)" % (self.name, self.parent_name) 310 311 def add_base(self, base): 312 self.bases.append(base) 313 314 def add_instance_attribute(self, name): 315 self.instattr.add(name) 316 317 "Return the attribute names provided by this class only." 318 319 class_attribute_names = NamespaceDict.keys 320 321 def class_attributes(self): 322 323 "Return class attributes provided by this class only." 324 325 return self 326 327 def all_class_attribute_names(self): 328 329 "Return the attribute names provided by classes in this hierarchy." 330 331 if self.all_classattr_names is None: 332 self.all_class_attributes() 333 return self.all_classattr_names 334 335 def all_class_attributes(self): 336 337 "Return all class attributes, indicating the class which provides them." 338 339 if self.all_classattr is None: 340 self.all_classattr = {} 341 342 reversed_bases = self.bases[:] 343 reversed_bases.reverse() 344 for cls in reversed_bases: 345 self.all_classattr.update(cls.all_class_attributes()) 346 347 # Record attributes provided by this class, along with their 348 # positions. 349 350 self.all_classattr.update(self.class_attributes()) 351 352 return self.all_classattr 353 354 def instance_attribute_names(self): 355 356 "Return the instance attribute names provided by the class." 357 358 if self.all_instattr_names is None: 359 self.instance_attributes() 360 return self.all_instattr_names 361 362 def instance_attributes(self): 363 364 "Return instance-only attributes for instances of this class." 365 366 if self.all_instattr is None: 367 self.all_instattr = {} 368 instattr = {} 369 370 reversed_bases = self.bases[:] 371 reversed_bases.reverse() 372 373 # For the bases in reverse order, acquire instance attribute 374 # details. 375 376 for cls in reversed_bases: 377 for name, attr in cls.instance_attributes().items(): 378 if not instattr.has_key(name): 379 instattr[name] = set() 380 instattr[name].add(attr.position) 381 382 # Record instance attributes provided by this class and its bases, 383 # along with their positions. 384 385 for name in self.instattr: 386 if not instattr.has_key(name): 387 instattr[name] = set([-1]) # position not yet defined 388 389 # Cache the attributes by converting the positioned attributes into 390 # a dictionary. 391 392 if not instattr: 393 self.all_instattr = {} 394 else: 395 self.all_instattr = dict(self._get_position_list(instattr)) 396 397 self.all_instattr_names = self.all_instattr.keys() 398 399 return self.all_instattr 400 401 def _get_position_list(self, instattr): 402 403 """ 404 Return the instance attributes, 'instattr', as a list indicating the 405 positions of the attributes in the final instance structure. 406 """ 407 408 positions = instattr.items() 409 instarray = [None] * len(positions) 410 411 # Get the positions in ascending order of list size, with lists 412 # of the same size ordered according to their smallest position 413 # value. 414 415 positions.sort(self._cmp_positions) 416 #print self.name, positions 417 418 # Get the names in position order. 419 420 held = [] 421 422 for name, pos in positions: 423 pos = list(pos) 424 if pos[0] != -1 and instarray[pos[0]] is None: 425 instarray[pos[0]] = name, Attr(pos[0], None, name) 426 else: 427 if pos[0] != -1 or len(pos) > 1: 428 self.instattr_relocated.add(name) 429 held.append((name, pos)) 430 431 for i, attr in enumerate(instarray): 432 if attr is None: 433 name, pos = held.pop() 434 instarray[i] = name, Attr(i, None, name) 435 436 return instarray 437 438 def _cmp_positions(self, a, b): 439 440 "Compare name plus position list operands 'a' and 'b'." 441 442 name_a, list_a = a 443 name_b, list_b = b 444 if len(list_a) < len(list_b): 445 return -1 446 elif len(list_a) > len(list_b): 447 return 1 448 else: 449 return cmp(min(list_a), min(list_b)) 450 451 def all_attribute_names(self): 452 453 """ 454 Return the names of all attributes provided by instances of this class. 455 """ 456 457 self.allattr_names = self.allattr_names or self.all_attributes().keys() 458 return self.allattr_names 459 460 def all_attributes(self): 461 462 """ 463 Return all attributes for an instance, indicating either the class which 464 provides them or that the instance itself provides them. 465 """ 466 467 if self.allattr is None: 468 self.allattr = {} 469 self.allattr.update(self.all_class_attributes()) 470 for name, attr in self.instance_attributes().items(): 471 if self.allattr.has_key(name): 472 print "Instance attribute %r in %r overrides class attribute." % (name, self) 473 self.allattr[name] = attr 474 return self.allattr 475 476 class Function(NamespaceDict, Naming): 477 478 "An inspected function." 479 480 def __init__(self, name, parent_name, argnames, has_star, has_dstar, global_namespace=None, node=None): 481 NamespaceDict.__init__(self, global_namespace) 482 self.name = name 483 self.parent_name = parent_name 484 self.argnames = argnames 485 self.has_star = has_star 486 self.has_dstar = has_dstar 487 self.node = node 488 489 # Caches. 490 491 self.localnames = None # cache for locals 492 493 # Add parameters to the namespace. 494 495 self._add_parameters(argnames) 496 497 # Image generation details. 498 499 self.location = None 500 self.code_location = None 501 502 def _add_parameters(self, argnames): 503 for name in argnames: 504 if isinstance(name, tuple): 505 self._add_parameters(name) 506 else: 507 self[name] = None 508 509 def __repr__(self): 510 if self.location is not None: 511 return "Function(%r, %r, %r, %r, %r, location=%r)" % ( 512 self.name, self.parent_name, self.argnames, self.has_star, self.has_dstar, self.location 513 ) 514 else: 515 return "Function(%r, %r, %r, %r, %r)" % ( 516 self.name, self.parent_name, self.argnames, self.has_star, self.has_dstar 517 ) 518 519 def make_global(self, name): 520 if name not in self.argnames and not self.has_key(name): 521 self.globals.add(name) 522 else: 523 raise InspectError(self.full_name(), self.node, "Name %r is global and local in %r" % (name, self.full_name())) 524 525 def parameters(self): 526 527 """ 528 Return a dictionary mapping parameter names to their position in the 529 parameter list. 530 """ 531 532 parameters = {} 533 for i, name in enumerate(self.argnames): 534 parameters[name] = i 535 return parameters 536 537 def all_locals(self): 538 539 "Return a dictionary mapping names to local and parameter details." 540 541 return self 542 543 def locals(self): 544 545 "Return a dictionary mapping names to local details." 546 547 if self.localnames is None: 548 self.localnames = {} 549 self.localnames.update(self.all_locals()) 550 for name in self.argnames: 551 del self.localnames[name] 552 return self.localnames 553 554 class UnresolvedName(NamespaceDict, Naming): 555 556 "A module, class or function which was mentioned but could not be imported." 557 558 def __init__(self, name, parent_name, global_namespace=None): 559 NamespaceDict.__init__(self, global_namespace) 560 self.name = name 561 self.parent_name = parent_name 562 563 def all_class_attributes(self): 564 return {} 565 566 def instance_attributes(self): 567 return {} 568 569 def __repr__(self): 570 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 571 572 class Module(NamespaceDict): 573 574 "An inspected module's core details." 575 576 def __init__(self, name): 577 NamespaceDict.__init__(self, self) 578 self.name = name 579 580 # Complete lists of classes and functions. 581 582 self.all_objects = set() 583 584 # Constant records. 585 586 self.constant_values = {} 587 self.constant_list = None # cache for constants 588 589 # Image generation details. 590 591 self.location = None 592 self.code_location = None 593 594 # Original location details. 595 596 self.node = None 597 598 def full_name(self): 599 return self.name 600 601 def __repr__(self): 602 if self.location is not None: 603 return "Module(%r, location=%r)" % (self.name, self.location) 604 else: 605 return "Module(%r)" % self.name 606 607 # Attribute methods. 608 609 "Return the module attribute names provided by the module." 610 611 module_attribute_names = NamespaceDict.keys 612 613 def module_attributes(self): 614 615 "Return a dictionary mapping names to module attributes." 616 617 return self 618 619 def constants(self): 620 621 "Return a list of constants." 622 623 if self.constant_list is None: 624 self.constant_list = list(self.constant_values.values()) 625 626 return self.constant_list 627 628 # Program visitors. 629 630 class InspectedModule(ASTVisitor, Module): 631 632 """ 633 An inspected module, providing core details via the Module superclass, but 634 capable of being used as an AST visitor. 635 """ 636 637 def __init__(self, name, importer=None): 638 ASTVisitor.__init__(self) 639 Module.__init__(self, name) 640 self.visitor = self 641 642 self.importer = importer 643 self.loaded = 0 644 645 # Current expression state. 646 647 self.expr = None 648 649 # Namespace state. 650 651 self.in_init = 0 # Find instance attributes in __init__ methods. 652 self.in_loop = 0 # Note loop "membership", affecting assignments. 653 self.namespaces = [] 654 self.module = None 655 656 def parse(self, filename): 657 658 "Parse the file having the given 'filename'." 659 660 module = compiler.parseFile(filename) 661 self.process(module) 662 663 def process(self, module): 664 665 "Process the given 'module'." 666 667 self.node = self.module = module 668 processed = self.dispatch(module) 669 if self.has_key("__all__"): 670 all = self["__all__"] 671 if isinstance(all, compiler.ast.List): 672 for n in all.nodes: 673 self[n.value] = self.importer.add_module(self.name + "." + n.value) 674 return processed 675 676 def vacuum(self): 677 678 "Vacuum the module namespace, removing unloaded module references." 679 680 for name, value in self.items(): 681 if isinstance(value, Module) and not value.loaded: 682 del self[name] 683 684 # Complain about globals not initialised at the module level. 685 686 if isinstance(value, Global): 687 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name) 688 689 # Namespace methods. 690 691 def store(self, name, obj): 692 693 "Record attribute or local 'name', storing 'obj'." 694 695 if not self.namespaces: 696 self.set(name, obj, not self.in_loop) 697 else: 698 self.namespaces[-1].set(name, obj, not self.in_loop) 699 700 # Record all non-local objects. 701 702 if not (self.namespaces and isinstance(self.namespaces[-1], Function)): 703 self.all_objects.add(obj) 704 705 def store_instance_attr(self, name): 706 707 "Record instance attribute 'name' in the current class." 708 709 if self.in_init: 710 711 # Current namespace is the function. 712 # Previous namespace is the class. 713 714 self.namespaces[-2].add_instance_attribute(name) 715 716 def get_parent(self): 717 return (self.namespaces[-1:] or [self])[0] 718 719 # Visitor methods. 720 721 def default(self, node, *args): 722 raise InspectError(self.full_name(), node, "Node class %r is not supported." % node.__class__) 723 724 def dispatch(self, node, *args): 725 return ASTVisitor.dispatch(self, node, *args) 726 727 def NOP(self, node): 728 for n in node.getChildNodes(): 729 self.dispatch(n) 730 return None 731 732 visitAdd = NOP 733 734 visitAnd = NOP 735 736 visitAssert = NOP 737 738 def visitAssign(self, node): 739 self.expr = self.dispatch(node.expr) 740 for n in node.nodes: 741 self.dispatch(n) 742 return None 743 744 def visitAssAttr(self, node): 745 expr = self.dispatch(node.expr) 746 if isinstance(expr, Attr) and expr.name == "self": 747 self.store_instance_attr(node.attrname) 748 return None 749 750 def visitAssList(self, node): 751 for n in node.nodes: 752 self.dispatch(n) 753 return None 754 755 def visitAssName(self, node): 756 if isinstance(self.expr, Attr): 757 self.store(node.name, self.expr.value) 758 else: 759 self.store(node.name, self.expr) 760 return None 761 762 visitAssTuple = visitAssList 763 764 visitAugAssign = NOP 765 766 visitBackquote = NOP 767 768 visitBitand = NOP 769 770 visitBitor = NOP 771 772 visitBitxor = NOP 773 774 visitBreak = NOP 775 776 visitCallFunc = NOP 777 778 def visitClass(self, node): 779 if self.namespaces: 780 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 781 else: 782 cls = Class(node.name, self.get_parent().full_name(), self, node) 783 784 # Visit the base class expressions, attempting to find concrete 785 # definitions of classes. 786 787 for base in node.bases: 788 expr = self.dispatch(base) 789 if isinstance(expr, Attr): 790 if expr.assignments != 1: 791 raise InspectError(self.full_name(), node, 792 "Base class %r for %r is not constant." % (base, cls.full_name())) 793 else: 794 cls.add_base(expr.value) 795 else: # if expr is None: 796 raise InspectError(self.full_name(), node, 797 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 798 799 # Make a back reference from the node for code generation. 800 801 node.unit = cls 802 803 # Make an entry for the class. 804 805 self.store(node.name, cls) 806 807 self.namespaces.append(cls) 808 self.dispatch(node.code) 809 self.namespaces.pop() 810 811 return None 812 813 visitCompare = NOP 814 815 def visitConst(self, node): 816 const = Const(node.value) 817 self.constant_values[node.value] = const 818 return const 819 820 visitContinue = NOP 821 822 visitDecorators = NOP 823 824 visitDict = NOP 825 826 visitDiscard = NOP 827 828 visitDiv = NOP 829 830 visitEllipsis = NOP 831 832 visitExec = NOP 833 834 visitExpression = NOP 835 836 visitFloorDiv = NOP 837 838 def visitFor(self, node): 839 self.in_loop = 1 840 self.NOP(node) 841 self.in_loop = 0 842 843 def visitFrom(self, node): 844 if self.importer is None: 845 raise InspectError(self.full_name(), node, 846 "Please use the micropython.Importer class for code which uses the 'from' statement.") 847 848 module = self.importer.load(node.modname, 1) 849 850 #if module is None: 851 # print "Warning:", node.modname, "not imported." 852 853 for name, alias in node.names: 854 if name != "*": 855 if module is not None and module.namespace.has_key(name): 856 attr = module[name] 857 self.store(alias or name, attr.value) 858 if isinstance(attr, Module) and not attr.loaded: 859 self.importer.load(attr.name) 860 861 # Support the import of names from missing modules. 862 863 else: 864 self.store(alias or name, UnresolvedName(name, node.modname, self)) 865 else: 866 if module is not None: 867 for n in module.namespace.keys(): 868 attr = module[n] 869 self.store(n, attr.value) 870 if isinstance(attr, Module) and not attr.loaded: 871 self.importer.load(attr.name) 872 873 return None 874 875 def visitFunction(self, node): 876 function = Function( 877 node.name, 878 self.get_parent().full_name(), 879 node.argnames, 880 (node.flags & 4 != 0), 881 (node.flags & 8 != 0), 882 self, 883 node 884 ) 885 886 # Make a back reference from the node for code generation. 887 888 node.unit = function 889 890 self.namespaces.append(function) 891 892 # Current namespace is the function. 893 # Previous namespace is the class. 894 895 if node.name == "__init__" and isinstance(self.namespaces[-2], Class): 896 self.in_init = 1 897 898 self.dispatch(node.code) 899 self.in_init = 0 900 self.namespaces.pop() 901 902 self.store(node.name, function) 903 return None 904 905 visitGenExpr = NOP 906 907 visitGenExprFor = NOP 908 909 visitGenExprIf = NOP 910 911 visitGenExprInner = NOP 912 913 def visitGetattr(self, node): 914 expr = self.dispatch(node.expr) 915 if isinstance(expr, Attr): 916 value = expr.value 917 if isinstance(value, Module): 918 return value.namespace.get(node.attrname) 919 elif isinstance(value, UnresolvedName): 920 return UnresolvedName(node.attrname, value.full_name(), self) 921 return builtins.get(node.attrname) 922 923 def visitGlobal(self, node): 924 if self.namespaces: 925 for name in node.names: 926 self.namespaces[-1].make_global(name) 927 928 # Record a global entry for the name in the module. 929 930 if not self.has_key(name): 931 self[name] = Global() 932 933 def visitIf(self, node): 934 for test, body in node.tests: 935 self.dispatch(body) 936 if node.else_ is not None: 937 self.dispatch(node.else_) 938 return None 939 940 visitIfExp = NOP 941 942 def visitImport(self, node): 943 if self.importer is None: 944 raise InspectError(self.full_name(), node, 945 "Please use the micropython.Importer class for code which uses the 'import' statement.") 946 947 for name, alias in node.names: 948 if alias is not None: 949 self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self)) 950 else: 951 self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)) 952 953 return None 954 955 visitInvert = NOP 956 957 visitKeyword = NOP 958 959 visitLambda = NOP 960 961 visitLeftShift = NOP 962 963 visitList = NOP 964 965 visitListComp = NOP 966 967 visitListCompFor = NOP 968 969 visitListCompIf = NOP 970 971 visitMod = NOP 972 973 def visitModule(self, node): 974 return self.dispatch(node.node) 975 976 visitMul = NOP 977 978 def visitName(self, node): 979 name = node.name 980 if self.namespaces and self.namespaces[-1].has_key(name): 981 return self.namespaces[-1][name] 982 elif self.has_key(name): 983 return self[name] 984 elif builtins.has_key(name): 985 return builtins[name] 986 else: 987 return None 988 989 visitNot = NOP 990 991 visitOr = NOP 992 993 visitPass = NOP 994 995 visitPower = NOP 996 997 visitPrint = NOP 998 999 visitPrintnl = NOP 1000 1001 visitRaise = NOP 1002 1003 visitReturn = NOP 1004 1005 visitRightShift = NOP 1006 1007 visitSlice = NOP 1008 1009 visitSliceobj = NOP 1010 1011 def visitStmt(self, node): 1012 for n in node.nodes: 1013 self.dispatch(n) 1014 return None 1015 1016 visitSub = NOP 1017 1018 visitSubscript = NOP 1019 1020 def visitTryExcept(self, node): 1021 self.dispatch(node.body) 1022 for name, var, n in node.handlers: 1023 self.dispatch(n) 1024 if node.else_ is not None: 1025 self.dispatch(node.else_) 1026 return None 1027 1028 visitTryFinally = NOP 1029 1030 visitTuple = NOP 1031 1032 visitUnaryAdd = NOP 1033 1034 visitUnarySub = NOP 1035 1036 def visitWhile(self, node): 1037 self.in_loop = 1 1038 self.NOP(node) 1039 self.in_loop = 0 1040 1041 visitWith = NOP 1042 1043 visitYield = NOP 1044 1045 class Global: 1046 1047 """ 1048 A reference to an object assigned to a global from outside the module 1049 top-level. 1050 """ 1051 1052 pass 1053 1054 # Built-in types initialisation. 1055 1056 class Builtins(Module): 1057 1058 "The special built-in types module." 1059 1060 def __init__(self): 1061 Module.__init__(self, "__builtins__") 1062 self.loaded = 1 1063 self.module = None 1064 1065 for key in ['ArithmeticError', 'AssertionError', 'AttributeError', 1066 'BaseException', 'DeprecationWarning', 'EOFError', 'Ellipsis', 1067 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 1068 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 1069 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 1070 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 1071 'None', 'NotImplemented', 'NotImplementedError', 'OSError', 1072 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 1073 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 1074 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 1075 'TabError', 'True', 'TypeError', 'UnboundLocalError', 1076 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 1077 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 1078 'ValueError', 'Warning', 'ZeroDivisionError', 1079 'basestring', 'bool', 'buffer', 'complex', 'dict', 'file', 'float', 1080 'frozenset', 'int', # 'list', 1081 'long', 'object', 'set', 'slice', 'str', 1082 'tuple', 'type', 'unicode', 'xrange']: 1083 self.store(key, Class(key, self.full_name(), self)) 1084 1085 # NOTE: Temporary measure - provide detailed built-ins. 1086 1087 cls = Class("list", self.full_name(), self) 1088 cls.set("__iter__", Function("__iter__", cls.full_name(), [], 0, 0, cls)) 1089 self.store("list", cls) 1090 1091 cls = Class("listiterator", self.full_name(), self) 1092 cls.set("next", Function("next", cls.full_name(), [], 0, 0, cls)) 1093 self.store("listiterator", cls) 1094 1095 # NOTE: Incomplete: some functions have more than one parameter. 1096 1097 for key in ['__import__', 'abs', 'all', 'any', 'callable', 'chr', 1098 'classmethod', 'cmp', 'compile', 'delattr', 'dir', 'divmod', 1099 'enumerate', 'eval', 'execfile', 'filter', 'getattr', 'globals', 1100 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'isinstance', 1101 'issubclass', 'iter', 'len', 'locals', 'map', 'max', 'min', 'oct', 1102 'open', 'ord', 'pow', 'property', 'range', 'raw_input', 'reduce', 1103 'reload', 'repr', 'reversed', 'round', 'setattr', 'sorted', 1104 'staticmethod', 'sum', 'super', 'unichr', 'vars', 'zip']: 1105 self[key] = Function(key, self.full_name(), ['arg'], 0, 0, self) 1106 1107 def store(self, name, obj): 1108 self.set(name, obj) 1109 self.all_objects.add(obj) 1110 1111 def vacuum(self): 1112 pass 1113 1114 builtins = Builtins() 1115 1116 # vim: tabstop=4 expandtab shiftwidth=4