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, defaults, 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.defaults = defaults 580 self.positional_names = self.argnames[:] 581 if has_dstar: 582 self.dstar_name = self.positional_names[-1] 583 del self.positional_names[-1] 584 if has_star: 585 self.star_name = self.positional_names[-1] 586 del self.positional_names[-1] 587 self.has_star = has_star 588 self.has_dstar = has_dstar 589 self.node = node 590 591 # Caches. 592 593 self.localnames = None # cache for locals 594 595 # Add parameters to the namespace. 596 597 self._add_parameters(argnames) 598 599 # Image generation details. 600 601 self.location = None 602 self.code_location = None 603 604 def _add_parameters(self, argnames): 605 for name in argnames: 606 if isinstance(name, tuple): 607 self._add_parameters(name) 608 else: 609 self.set(name, None) 610 611 def __repr__(self): 612 if self.location is not None: 613 return "Function(%r, %r, %r, %r, %r, %r, location=%r)" % ( 614 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.location 615 ) 616 else: 617 return "Function(%r, %r, %r, %r, %r, %r)" % ( 618 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar 619 ) 620 621 def make_global(self, name): 622 if name not in self.argnames and not self.has_key(name): 623 self.globals.add(name) 624 else: 625 raise InspectError(self.full_name(), self.node, "Name %r is global and local in %r" % (name, self.full_name())) 626 627 def parameters(self): 628 629 """ 630 Return a dictionary mapping parameter names to their position in the 631 parameter list. 632 """ 633 634 parameters = {} 635 for i, name in enumerate(self.argnames): 636 parameters[name] = i 637 return parameters 638 639 def all_locals(self): 640 641 "Return a dictionary mapping names to local and parameter details." 642 643 return dict(self) 644 645 def locals(self): 646 647 "Return a dictionary mapping names to local details." 648 649 if self.localnames is None: 650 self.localnames = {} 651 self.localnames.update(self.all_locals()) 652 for name in self.argnames: 653 del self.localnames[name] 654 return self.localnames 655 656 def is_relocated(self, name): 657 658 """ 659 Determine whether the given attribute 'name' is relocated for instances 660 having this function as a method. 661 """ 662 663 for cls in self.parent.descendants: 664 if name in cls.relocated: 665 return 1 666 return 0 667 668 def finalise_attributes(self): 669 670 "Make sure all attributes are fully defined." 671 672 for i, name in enumerate(self.argnames): 673 self[name].position = i 674 675 j = i 676 for i, attr in enumerate(self.locals().values()): 677 attr.position = i + j 678 679 def function_from_method(self): 680 681 "Make a function from a method." 682 683 return Function(self.name, self.parent, self.argnames[1:], self.defaults, 684 self.has_star, self.has_dstar, self.global_namespace, self.node) 685 686 class UnresolvedName(NamespaceDict): 687 688 "A module, class or function which was mentioned but could not be imported." 689 690 def __init__(self, name, parent_name, global_namespace=None): 691 NamespaceDict.__init__(self, global_namespace) 692 self.name = name 693 self.parent_name = parent_name 694 695 def all_class_attributes(self): 696 return {} 697 698 def instance_attributes(self): 699 return {} 700 701 def __repr__(self): 702 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 703 704 def full_name(self): 705 if self.name is not None: 706 return self.parent_name + "." + self.name 707 else: 708 return self.parent_name 709 710 class Instance: 711 712 "A placeholder indicating the involvement of an instance." 713 714 def __repr__(self): 715 return "Instance()" 716 717 class Module(NamespaceDict): 718 719 "An inspected module's core details." 720 721 def __init__(self, name): 722 NamespaceDict.__init__(self, self) 723 self.name = name 724 725 # Complete lists of classes and functions. 726 727 self.all_objects = set() 728 729 # Constant records. 730 731 self.constant_values = {} 732 self.constant_list = None # cache for constants 733 734 # Image generation details. 735 736 self.location = None 737 self.code_location = None 738 739 # Original location details. 740 741 self.node = None 742 743 def full_name(self): 744 return self.name 745 746 def __repr__(self): 747 if self.location is not None: 748 return "Module(%r, location=%r)" % (self.name, self.location) 749 else: 750 return "Module(%r)" % self.name 751 752 # Attribute methods. 753 754 "Return the module attribute names provided by the module." 755 756 module_attribute_names = NamespaceDict.keys 757 758 def module_attributes(self): 759 760 "Return a dictionary mapping names to module attributes." 761 762 return dict(self) 763 764 def constants(self): 765 766 "Return a list of constants." 767 768 if self.constant_list is None: 769 self.constant_list = list(self.constant_values.values()) 770 771 return self.constant_list 772 773 # Program visitors. 774 775 class InspectedModule(ASTVisitor, Module): 776 777 """ 778 An inspected module, providing core details via the Module superclass, but 779 capable of being used as an AST visitor. 780 """ 781 782 def __init__(self, name, importer=None): 783 ASTVisitor.__init__(self) 784 Module.__init__(self, name) 785 self.visitor = self 786 787 self.importer = importer 788 self.builtins = self.importer.modules.get("__builtins__") 789 self.loaded = 0 790 791 # Current expression state. 792 793 self.expr = None 794 795 # Namespace state. 796 797 self.in_init = 0 # Find instance attributes in __init__ methods. 798 self.in_loop = 0 # Note loop "membership", affecting assignments. 799 self.namespaces = [] 800 self.module = None 801 802 def parse(self, filename): 803 804 "Parse the file having the given 'filename'." 805 806 module = compiler.parseFile(filename) 807 self.process(module) 808 809 def process(self, module): 810 811 "Process the given 'module'." 812 813 self.node = self.module = module 814 processed = self.dispatch(module) 815 if self.has_key("__all__"): 816 all = self["__all__"] 817 if isinstance(all, compiler.ast.List): 818 for n in all.nodes: 819 self[n.value] = self.importer.add_module(self.name + "." + n.value) 820 return processed 821 822 def vacuum(self): 823 824 "Vacuum the module namespace, removing unloaded module references." 825 826 for name, value in self.items(): 827 if isinstance(value, Module) and not value.loaded: 828 del self[name] 829 830 # Complain about globals not initialised at the module level. 831 832 if isinstance(value, Global): 833 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name) 834 835 # Namespace methods. 836 837 def store(self, name, obj): 838 839 "Record attribute or local 'name', storing 'obj'." 840 841 if not self.namespaces: 842 self.set(name, obj, not self.in_loop) 843 else: 844 self.namespaces[-1].set(name, obj, not self.in_loop) 845 846 # Record all non-local objects. 847 848 if not (self.namespaces and isinstance(self.namespaces[-1], Function)): 849 self.all_objects.add(obj) 850 851 def store_instance_attr(self, name): 852 853 "Record instance attribute 'name' in the current class." 854 855 if self.in_init: 856 857 # Current namespace is the function. 858 # Previous namespace is the class. 859 860 self.namespaces[-2].add_instance_attribute(name) 861 862 def get_parent(self): 863 return (self.namespaces[-1:] or [self])[0] 864 865 # Visitor methods. 866 867 def default(self, node, *args): 868 raise InspectError(self.full_name(), node, "Node class %r is not supported." % node.__class__) 869 870 def dispatch(self, node, *args): 871 return ASTVisitor.dispatch(self, node, *args) 872 873 def NOP(self, node): 874 for n in node.getChildNodes(): 875 self.dispatch(n) 876 return None 877 878 visitAdd = NOP 879 880 visitAnd = NOP 881 882 visitAssert = NOP 883 884 def visitAssign(self, node): 885 self.expr = self.dispatch(node.expr) 886 for n in node.nodes: 887 self.dispatch(n) 888 return None 889 890 def visitAssAttr(self, node): 891 expr = self.dispatch(node.expr) 892 if isinstance(expr, Attr) and expr.name == "self": 893 self.store_instance_attr(node.attrname) 894 return None 895 896 def visitAssList(self, node): 897 for n in node.nodes: 898 self.dispatch(n) 899 return None 900 901 def visitAssName(self, node): 902 if isinstance(self.expr, Attr): 903 self.store(node.name, self.expr.value) 904 else: 905 self.store(node.name, self.expr) 906 return None 907 908 visitAssTuple = visitAssList 909 910 visitAugAssign = NOP 911 912 visitBackquote = NOP 913 914 visitBitand = NOP 915 916 visitBitor = NOP 917 918 visitBitxor = NOP 919 920 visitBreak = NOP 921 922 visitCallFunc = NOP 923 924 def visitClass(self, node): 925 if self.namespaces: 926 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 927 else: 928 cls = Class(node.name, self.get_parent(), self, node) 929 930 # Visit the base class expressions, attempting to find concrete 931 # definitions of classes. 932 933 for base in node.bases: 934 expr = self.dispatch(base) 935 if isinstance(expr, Attr): 936 if expr.assignments != 1: 937 raise InspectError(self.full_name(), node, 938 "Base class %r for %r is not constant." % (base, cls.full_name())) 939 else: 940 cls.add_base(expr.value) 941 else: # if expr is None: 942 raise InspectError(self.full_name(), node, 943 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 944 945 # NOTE: Potentially dubious measure to permit __init__ availability. 946 # If no bases exist, adopt the 'object' class. 947 948 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 949 expr = self.dispatch(compiler.ast.Name("object")) 950 cls.add_base(expr.value) 951 952 # Make a back reference from the node for code generation. 953 954 node.unit = cls 955 956 # Make an entry for the class. 957 958 self.store(node.name, cls) 959 960 # Process the class body. 961 962 self.namespaces.append(cls) 963 self.dispatch(node.code) 964 self.namespaces.pop() 965 966 return None 967 968 visitCompare = NOP 969 970 def visitConst(self, node): 971 const = Const(node.value) 972 self.constant_values[node.value] = const 973 return const 974 975 visitContinue = NOP 976 977 visitDecorators = NOP 978 979 visitDict = NOP 980 981 visitDiscard = NOP 982 983 visitDiv = NOP 984 985 visitEllipsis = NOP 986 987 visitExec = NOP 988 989 visitExpression = NOP 990 991 visitFloorDiv = NOP 992 993 def visitFor(self, node): 994 self.in_loop = 1 995 self.NOP(node) 996 self.in_loop = 0 997 998 def visitFrom(self, node): 999 if self.importer is None: 1000 raise InspectError(self.full_name(), node, 1001 "Please use the micropython.Importer class for code which uses the 'from' statement.") 1002 1003 module = self.importer.load(node.modname, 1) 1004 1005 #if module is None: 1006 # print "Warning:", node.modname, "not imported." 1007 1008 for name, alias in node.names: 1009 if name != "*": 1010 if module is not None and module.namespace.has_key(name): 1011 attr = module[name] 1012 self.store(alias or name, attr.value) 1013 if isinstance(attr, Module) and not attr.loaded: 1014 self.importer.load(attr.name) 1015 1016 # Support the import of names from missing modules. 1017 1018 else: 1019 self.store(alias or name, UnresolvedName(name, node.modname, self)) 1020 else: 1021 if module is not None: 1022 for n in module.namespace.keys(): 1023 attr = module[n] 1024 self.store(n, attr.value) 1025 if isinstance(attr, Module) and not attr.loaded: 1026 self.importer.load(attr.name) 1027 1028 return None 1029 1030 def visitFunction(self, node): 1031 function = Function( 1032 node.name, 1033 self.get_parent(), 1034 node.argnames, 1035 node.defaults, 1036 (node.flags & 4 != 0), 1037 (node.flags & 8 != 0), 1038 self, 1039 node 1040 ) 1041 1042 # Make a back reference from the node for code generation. 1043 1044 node.unit = function 1045 1046 self.namespaces.append(function) 1047 1048 # Current namespace is the function. 1049 # Previous namespace is the class. 1050 1051 if node.name == "__init__" and isinstance(self.namespaces[-2], Class): 1052 self.in_init = 1 1053 1054 self.dispatch(node.code) 1055 self.in_init = 0 1056 self.namespaces.pop() 1057 1058 self.store(node.name, function) 1059 return None 1060 1061 visitGenExpr = NOP 1062 1063 visitGenExprFor = NOP 1064 1065 visitGenExprIf = NOP 1066 1067 visitGenExprInner = NOP 1068 1069 def visitGetattr(self, node): 1070 expr = self.dispatch(node.expr) 1071 if isinstance(expr, Attr): 1072 value = expr.value 1073 if isinstance(value, Module): 1074 return value.namespace.get(node.attrname) 1075 elif isinstance(value, UnresolvedName): 1076 return UnresolvedName(node.attrname, value.full_name(), self) 1077 if self.builtins is not None: 1078 return self.builtins.get(node.attrname) 1079 else: 1080 return UnresolvedName(node.attrname, value.full_name(), self) 1081 1082 def visitGlobal(self, node): 1083 if self.namespaces: 1084 for name in node.names: 1085 self.namespaces[-1].make_global(name) 1086 1087 # Record a global entry for the name in the module. 1088 1089 if not self.has_key(name): 1090 self[name] = Global() 1091 1092 def visitIf(self, node): 1093 for test, body in node.tests: 1094 self.dispatch(body) 1095 if node.else_ is not None: 1096 self.dispatch(node.else_) 1097 return None 1098 1099 visitIfExp = NOP 1100 1101 def visitImport(self, node): 1102 if self.importer is None: 1103 raise InspectError(self.full_name(), node, 1104 "Please use the micropython.Importer class for code which uses the 'import' statement.") 1105 1106 for name, alias in node.names: 1107 if alias is not None: 1108 self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self)) 1109 else: 1110 self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)) 1111 1112 return None 1113 1114 visitInvert = NOP 1115 1116 def visitKeyword(self, node): 1117 self.dispatch(node.expr) 1118 const = Const(node.name) 1119 self.constant_values[node.name] = const 1120 return None 1121 1122 visitLambda = NOP 1123 1124 visitLeftShift = NOP 1125 1126 visitList = NOP 1127 1128 visitListComp = NOP 1129 1130 visitListCompFor = NOP 1131 1132 visitListCompIf = NOP 1133 1134 visitMod = NOP 1135 1136 def visitModule(self, node): 1137 return self.dispatch(node.node) 1138 1139 visitMul = NOP 1140 1141 def visitName(self, node): 1142 name = node.name 1143 if self.namespaces and self.namespaces[-1].has_key(name): 1144 return self.namespaces[-1][name] 1145 elif self.has_key(name): 1146 return self[name] 1147 elif self.builtins is not None and self.builtins.has_key(name): 1148 return self.builtins[name] 1149 else: 1150 return None 1151 1152 visitNot = NOP 1153 1154 visitOr = NOP 1155 1156 visitPass = NOP 1157 1158 visitPower = NOP 1159 1160 visitPrint = NOP 1161 1162 visitPrintnl = NOP 1163 1164 visitRaise = NOP 1165 1166 visitReturn = NOP 1167 1168 visitRightShift = NOP 1169 1170 visitSlice = NOP 1171 1172 visitSliceobj = NOP 1173 1174 def visitStmt(self, node): 1175 for n in node.nodes: 1176 self.dispatch(n) 1177 return None 1178 1179 visitSub = NOP 1180 1181 visitSubscript = NOP 1182 1183 def visitTryExcept(self, node): 1184 self.dispatch(node.body) 1185 for name, var, n in node.handlers: 1186 self.dispatch(n) 1187 if node.else_ is not None: 1188 self.dispatch(node.else_) 1189 return None 1190 1191 visitTryFinally = NOP 1192 1193 visitTuple = NOP 1194 1195 visitUnaryAdd = NOP 1196 1197 visitUnarySub = NOP 1198 1199 def visitWhile(self, node): 1200 self.in_loop = 1 1201 self.NOP(node) 1202 self.in_loop = 0 1203 1204 visitWith = NOP 1205 1206 visitYield = NOP 1207 1208 class Global: 1209 1210 """ 1211 A reference to an object assigned to a global from outside the module 1212 top-level. 1213 """ 1214 1215 pass 1216 1217 # vim: tabstop=4 expandtab shiftwidth=4