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