1 #!/usr/bin/env python 2 3 """ 4 Inspect source files, obtaining details of classes and attributes. 5 6 Copyright (C) 2007, 2008 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 21 -------- 22 23 The central classes in this module are the following: 24 25 * Class 26 * Function 27 * Module 28 * InspectedModule (derived from Module) 29 30 All of the above support the Naming interface either explicitly or through 31 general conformance, meaning that all can be asked to provide their 'full_name' 32 using the method of that name. 33 34 Additionally, all of the above also support a dictionary interface in order to 35 access names within their defined scopes. Specific methods also exist in order 36 to distinguish between certain kinds of attributes: 37 38 * Class: (class|all_class|instance|all)_attributes 39 * Function: parameters, locals, all_locals 40 * Module: module_attributes 41 42 These specific methods are useful in certain situations. 43 44 The above classes also provide a 'node' attribute, indicating the AST node where 45 each such object is defined. 46 """ 47 48 from micropython.common import * 49 import compiler.ast 50 from compiler.visitor import ASTVisitor 51 try: 52 set 53 except NameError: 54 from sets import Set as set 55 56 class InspectError(ProcessingError): pass 57 58 class AtLeast: 59 60 "A special representation for numbers of a given value or greater." 61 62 def __init__(self, count): 63 self.count = count 64 65 def __eq__(self, other): 66 return 0 67 68 __lt__ = __le__ = __eq__ 69 70 def __ne__(self, other): 71 return 1 72 73 def __gt__(self, other): 74 if isinstance(other, AtLeast): 75 return 0 76 else: 77 return self.count > other 78 79 def __ge__(self, other): 80 if isinstance(other, AtLeast): 81 return 0 82 else: 83 return self.count >= other 84 85 def __iadd__(self, other): 86 if isinstance(other, AtLeast): 87 self.count += other.count 88 else: 89 self.count += other 90 return self 91 92 def __radd__(self, other): 93 if isinstance(other, AtLeast): 94 return AtLeast(self.count + other.count) 95 else: 96 return AtLeast(self.count + other) 97 98 def __repr__(self): 99 return "AtLeast(%r)" % self.count 100 101 # Mix-ins and abstract classes. 102 103 class NamespaceDict: 104 105 "A mix-in providing dictionary methods." 106 107 def __init__(self, global_namespace=None): 108 self.namespace = {} 109 self.globals = set() 110 self.global_namespace = global_namespace 111 112 def __getitem__(self, name): 113 return self.namespace[name] 114 115 def get(self, name, default=None): 116 return self.namespace.get(name, default) 117 118 def __setitem__(self, name, value): 119 self.set(name, value) 120 121 def set(self, name, value, single_assignment=1): 122 123 """ 124 A more powerful set operation, making 'name' refer to 'value' whilst 125 indicating whether a 'single_assignment' (true by default) occurs in 126 this operation (or whether the operation covers potentially many 127 assignments in the lifetime of a program). 128 """ 129 130 if name in self.globals: 131 self.global_namespace.set(name, value, 0) 132 else: 133 attr = self._set(name, value) 134 135 # NOTE: Insist on assignments with known values. 136 137 if value is not None: 138 attr.update(value, single_assignment) 139 140 def set_module(self, name, value): 141 142 """ 143 A specialised set operation, making 'name' refer to 'value' in the 144 context of making a module reference available in association with 145 'name' as part of the import of that module or a submodule of that 146 module. 147 """ 148 149 attr = self._set(name, value) 150 if attr.assignments is None: 151 attr.assignments = 1 152 attr.assignment_values.add(value) 153 154 def _set(self, name, value): 155 156 "The underlying set operation associating 'name' with 'value'." 157 158 if not self.namespace.has_key(name): 159 self.namespace[name] = Attr(None, self, name, value) 160 return self.namespace[name] 161 162 def __delitem__(self, name): 163 del self.namespace[name] 164 165 def has_key(self, name): 166 return self.namespace.has_key(name) 167 168 def keys(self): 169 return self.namespace.keys() 170 171 def values(self): 172 return self.namespace.values() 173 174 def items(self): 175 return self.namespace.items() 176 177 def make_global(self, name): 178 if not self.namespace.has_key(name): 179 self.globals.add(name) 180 else: 181 raise InspectError(self.full_name(), self.node, "Name %r is both global and local in %r" % (name, self.full_name())) 182 183 def get_assignments(self, name): 184 if self.assignments.has_key(name): 185 return max(self.assignments[name], len(self.assignment_values[name])) 186 else: 187 return None 188 189 def attributes_as_list(self): 190 self.finalise_attributes() 191 l = [None] * len(self.keys()) 192 for attr in self.values(): 193 l[attr.position] = attr 194 return l 195 196 def finalise_attributes(self): 197 198 "Make sure all attributes are fully defined." 199 200 # The default action is to assign attribute positions sequentially. 201 202 for i, attr in enumerate(self.values()): 203 attr.position = i 204 205 class Naming: 206 207 "A mix-in providing naming conveniences." 208 209 def full_name(self): 210 if self.name is not None: 211 return self.parent.full_name() + "." + self.name 212 else: 213 return self.parent.full_name() 214 215 # Program data structures. 216 217 class Attr: 218 219 "An attribute entry having a parent as context." 220 221 def __init__(self, position, parent, name, value=None, assignments=None): 222 self.position = position 223 self.parent = parent 224 self.name = name 225 self.value = value 226 227 # Number of assignments per name. 228 229 self.assignments = assignments 230 self.assignment_values = set() 231 232 def update(self, value, single_assignment): 233 234 """ 235 Update the attribute, adding the 'value' provided to the known values 236 associated with the attribute, changing the number of assignments 237 according to the 'single_assignment' status of the operation, where 238 a true value indicates that only one assignment is associated with the 239 update, and a false value indicates that potentially many assignments 240 may be involved. 241 """ 242 243 if self.assignments is None: 244 if single_assignment: 245 self.assignments = 1 246 else: 247 self.assignments = AtLeast(1) 248 else: 249 if single_assignment: 250 self.assignments += 1 251 else: 252 self.assignments += AtLeast(1) 253 self.assignment_values.add(value) 254 255 def __repr__(self): 256 return "Attr(%r, %r, %r, %r, %r)" % (self.position, self.parent, self.name, self.value, self.assignments) 257 258 class Const: 259 260 "A constant object with no context." 261 262 def __init__(self, value): 263 self.value = value 264 265 # Image generation details. 266 267 self.location = None 268 269 def __repr__(self): 270 if self.location is not None: 271 return "Const(%r, location=%r)" % (self.value, self.location) 272 else: 273 return "Const(%r)" % self.value 274 275 def __eq__(self, other): 276 return self.value == other.value 277 278 def __hash__(self): 279 return hash(self.value) 280 281 class Class(NamespaceDict, Naming): 282 283 "An inspected class." 284 285 def __init__(self, name, parent, global_namespace=None, node=None): 286 287 """ 288 Initialise the class with the given 'name', 'parent' object, optional 289 'global_namespace' and optional AST 'node'. 290 """ 291 292 NamespaceDict.__init__(self, global_namespace) 293 self.name = name 294 self.parent = parent 295 self.node = node 296 297 # Superclasses, descendants and attributes. 298 299 self.bases = [] 300 self.descendants = set() 301 self.instattr = set() # instance attributes 302 self.relocated = set() # attributes which do not have the same 303 # position as those of the same name in 304 # some superclasses 305 306 # Caches. 307 308 self.all_instattr = None # cache for instance_attributes 309 self.all_instattr_names = None # from all_instattr 310 self.all_classattr = None # cache for all_class_attributes 311 self.all_classattr_names = None # from all_classattr 312 self.allattr = None # cache for all_attributes 313 self.allattr_names = None # from allattr 314 315 # Add this class to its attributes. 316 317 self.set("__class__", self) 318 319 # Image generation details. 320 321 self.location = None 322 self.code_location = None 323 self.instantiator = None 324 325 def __repr__(self): 326 if self.location is not None: 327 return "Class(%r, %r, location=%r)" % (self.name, self.parent, self.location) 328 else: 329 return "Class(%r, %r)" % (self.name, self.parent) 330 331 def finalise_attributes(self): 332 333 "Make sure that all attributes are fully defined." 334 335 self.finalise_class_attributes() 336 self.finalise_instance_attributes() 337 338 def get_instantiator(self): 339 340 "Return a function which can be used to instantiate the class." 341 342 if self.instantiator is None: 343 init_method = self.all_class_attributes()["__init__"].value 344 self.instantiator = init_method.function_from_method() 345 return self.instantiator 346 347 # Class-specific methods. 348 349 def add_base(self, base): 350 self.bases.append(base) 351 base.add_descendant(self) 352 353 def add_instance_attribute(self, name): 354 self.instattr.add(name) 355 356 def add_descendant(self, cls): 357 self.descendants.add(cls) 358 for base in self.bases: 359 base.add_descendant(cls) 360 361 "Return the attribute names provided by this class only." 362 363 class_attribute_names = NamespaceDict.keys 364 365 def class_attributes(self): 366 367 "Return class attributes provided by this class only." 368 369 self.finalise_class_attributes() 370 return dict(self) 371 372 def all_class_attribute_names(self): 373 374 "Return the attribute names provided by classes in this hierarchy." 375 376 if self.all_classattr_names is None: 377 self.all_class_attributes() 378 return self.all_classattr_names 379 380 def all_class_attributes(self): 381 382 "Return all class attributes, indicating the class which provides them." 383 384 self.finalise_class_attributes() 385 return self.all_classattr 386 387 def finalise_class_attributes(self): 388 389 "Make sure that the class attributes are fully defined." 390 391 if self.all_classattr is None: 392 self.all_classattr = {} 393 clsattr = {} 394 395 # Record provisional position information for attributes of this 396 # class. 397 398 for name in self.class_attributes().keys(): 399 clsattr[name] = set() # position not yet defined 400 401 reversed_bases = self.bases[:] 402 reversed_bases.reverse() 403 404 # For the bases in reverse order, acquire class attribute details. 405 406 for cls in reversed_bases: 407 for name, attr in cls.all_class_attributes().items(): 408 self.all_classattr[name] = attr 409 410 # Record previous attribute information. 411 412 if clsattr.has_key(name): 413 clsattr[name].add(attr.position) 414 415 # Record class attributes provided by this class and its bases, 416 # along with their positions. 417 418 self.all_classattr.update(self.class_attributes()) 419 420 if clsattr: 421 for i, name in enumerate(self._get_position_list(clsattr)): 422 self.all_classattr[name].position = i 423 424 return self.all_classattr 425 426 def instance_attribute_names(self): 427 428 "Return the instance attribute names provided by the class." 429 430 if self.all_instattr_names is None: 431 self.instance_attributes() 432 return self.all_instattr_names 433 434 def instance_attributes(self): 435 436 "Return instance-only attributes for instances of this class." 437 438 self.finalise_instance_attributes() 439 return self.all_instattr 440 441 def finalise_instance_attributes(self): 442 443 "Make sure that the instance attributes are fully defined." 444 445 if self.all_instattr is None: 446 self.all_instattr = {} 447 instattr = {} 448 449 # Record provisional position information for attributes of this 450 # instance. 451 452 for name in self.instattr: 453 instattr[name] = set() # position not yet defined 454 455 reversed_bases = self.bases[:] 456 reversed_bases.reverse() 457 458 # For the bases in reverse order, acquire instance attribute 459 # details. 460 461 for cls in reversed_bases: 462 for name, attr in cls.instance_attributes().items(): 463 464 # Record previous attribute information. 465 466 if instattr.has_key(name): 467 instattr[name].add(attr.position) 468 469 # Cache the attributes by converting the positioned attributes into 470 # a dictionary. 471 472 if not instattr: 473 self.all_instattr = {} 474 else: 475 self.all_instattr = self._get_attributes(instattr) 476 477 self.all_instattr_names = self.all_instattr.keys() 478 479 return self.all_instattr 480 481 def _get_position_list(self, positions): 482 483 """ 484 Return a list of attribute names for the given 'positions' mapping from 485 names to positions, indicating the positions of the attributes in the 486 final instance structure. 487 """ 488 489 position_items = positions.items() 490 namearray = [None] * len(position_items) 491 492 # Get the positions in ascending order of list size, with lists 493 # of the same size ordered according to their smallest position 494 # value. 495 496 position_items.sort(self._cmp_positions) 497 498 # Get the names in position order. 499 500 held = [] 501 502 for name, pos in position_items: 503 pos = list(pos) 504 pos.sort() 505 if pos and pos[0] < len(namearray) and namearray[pos[0]] is None: 506 namearray[pos[0]] = name 507 else: 508 if pos: 509 self.relocated.add(name) 510 held.append((name, pos)) 511 512 for i, attr in enumerate(namearray): 513 if attr is None: 514 name, pos = held.pop() 515 namearray[i] = name 516 517 #print self.name, positions 518 #print "->", namearray 519 return namearray 520 521 def _get_attributes(self, positions): 522 523 """ 524 For the given 'positions' mapping from names to positions, return a 525 dictionary mapping names to Attr instances incorporating information 526 about their positions in the final instance structure. 527 """ 528 529 d = {} 530 for i, name in enumerate(self._get_position_list(positions)): 531 d[name] = Attr(i, Instance(), name, None) 532 return d 533 534 def _cmp_positions(self, a, b): 535 536 "Compare name plus position list operands 'a' and 'b'." 537 538 name_a, list_a = a 539 name_b, list_b = b 540 if len(list_a) < len(list_b): 541 return -1 542 elif len(list_a) > len(list_b): 543 return 1 544 elif not list_a: 545 return 0 546 else: 547 return cmp(min(list_a), min(list_b)) 548 549 def all_attribute_names(self): 550 551 """ 552 Return the names of all attributes provided by instances of this class. 553 """ 554 555 self.allattr_names = self.allattr_names or self.all_attributes().keys() 556 return self.allattr_names 557 558 def all_attributes(self): 559 560 """ 561 Return all attributes for an instance, indicating either the class which 562 provides them or that the instance itself provides them. 563 """ 564 565 if self.allattr is None: 566 self.allattr = {} 567 self.allattr.update(self.all_class_attributes()) 568 for name, attr in self.instance_attributes().items(): 569 if self.allattr.has_key(name): 570 print "Instance attribute %r in %r overrides class attribute." % (name, self) 571 self.allattr[name] = attr 572 return self.allattr 573 574 class Function(NamespaceDict, Naming): 575 576 "An inspected function." 577 578 def __init__(self, name, parent, argnames, defaults, has_star, has_dstar, global_namespace=None, node=None): 579 NamespaceDict.__init__(self, global_namespace) 580 self.name = name 581 self.parent = parent 582 self.argnames = argnames 583 self.defaults = defaults 584 self.positional_names = self.argnames[:] 585 if has_dstar: 586 self.dstar_name = self.positional_names[-1] 587 del self.positional_names[-1] 588 if has_star: 589 self.star_name = self.positional_names[-1] 590 del self.positional_names[-1] 591 self.has_star = has_star 592 self.has_dstar = has_dstar 593 self.node = node 594 595 # Caches. 596 597 self.localnames = None # cache for locals 598 599 # Add parameters to the namespace. 600 601 self._add_parameters(argnames) 602 603 # Image generation details. 604 605 self.location = None 606 self.code_location = None 607 608 def _add_parameters(self, argnames): 609 for name in argnames: 610 if isinstance(name, tuple): 611 self._add_parameters(name) 612 else: 613 self.set(name, None) 614 615 def __repr__(self): 616 if self.location is not None: 617 return "Function(%r, %r, %r, %r, %r, %r, location=%r)" % ( 618 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar, self.location 619 ) 620 else: 621 return "Function(%r, %r, %r, %r, %r, %r)" % ( 622 self.name, self.parent, self.argnames, self.defaults, self.has_star, self.has_dstar 623 ) 624 625 def make_global(self, name): 626 if name not in self.argnames and not self.has_key(name): 627 self.globals.add(name) 628 else: 629 raise InspectError(self.full_name(), self.node, "Name %r is global and local in %r" % (name, self.full_name())) 630 631 def parameters(self): 632 633 """ 634 Return a dictionary mapping parameter names to their position in the 635 parameter list. 636 """ 637 638 parameters = {} 639 for i, name in enumerate(self.argnames): 640 parameters[name] = i 641 return parameters 642 643 def all_locals(self): 644 645 "Return a dictionary mapping names to local and parameter details." 646 647 return dict(self) 648 649 def locals(self): 650 651 "Return a dictionary mapping names to local details." 652 653 if self.localnames is None: 654 self.localnames = {} 655 self.localnames.update(self.all_locals()) 656 for name in self.argnames: 657 del self.localnames[name] 658 return self.localnames 659 660 def is_method(self): 661 662 "Return whether this function is a method." 663 664 return isinstance(self.parent, Class) 665 666 def is_relocated(self, name): 667 668 """ 669 Determine whether the given attribute 'name' is relocated for instances 670 having this function as a method. 671 """ 672 673 for cls in self.parent.descendants: 674 if name in cls.relocated: 675 return 1 676 return 0 677 678 def finalise_attributes(self): 679 680 "Make sure all attributes are fully defined." 681 682 i = None 683 for i, name in enumerate(self.argnames): 684 self[name].position = i 685 686 if i is not None: 687 j = i 688 for i, attr in enumerate(self.locals().values()): 689 attr.position = i + j 690 691 def function_from_method(self): 692 693 "Make a function from a method." 694 695 return Function(self.name, self.parent, self.argnames[1:], self.defaults, 696 self.has_star, self.has_dstar, self.global_namespace, self.node) 697 698 class UnresolvedName(NamespaceDict): 699 700 "A module, class or function which was mentioned but could not be imported." 701 702 def __init__(self, name, parent_name, global_namespace=None): 703 NamespaceDict.__init__(self, global_namespace) 704 self.name = name 705 self.parent_name = parent_name 706 707 def all_class_attributes(self): 708 return {} 709 710 def instance_attributes(self): 711 return {} 712 713 def __repr__(self): 714 return "UnresolvedName(%r, %r)" % (self.name, self.parent_name) 715 716 def full_name(self): 717 if self.name is not None: 718 return self.parent_name + "." + self.name 719 else: 720 return self.parent_name 721 722 class Instance: 723 724 "A placeholder indicating the involvement of an instance." 725 726 def __repr__(self): 727 return "Instance()" 728 729 class Module(NamespaceDict): 730 731 "An inspected module's core details." 732 733 def __init__(self, name): 734 NamespaceDict.__init__(self, self) 735 self.name = name 736 737 # Complete lists of classes and functions. 738 739 self.all_objects = set() 740 741 # Constant records. 742 743 self.constant_values = {} 744 self.constant_list = None # cache for constants 745 746 # Image generation details. 747 748 self.location = None 749 self.code_location = None 750 751 # Original location details. 752 753 self.node = None 754 755 def full_name(self): 756 return self.name 757 758 def __repr__(self): 759 if self.location is not None: 760 return "Module(%r, location=%r)" % (self.name, self.location) 761 else: 762 return "Module(%r)" % self.name 763 764 # Attribute methods. 765 766 "Return the module attribute names provided by the module." 767 768 module_attribute_names = NamespaceDict.keys 769 770 def module_attributes(self): 771 772 "Return a dictionary mapping names to module attributes." 773 774 return dict(self) 775 776 def constants(self): 777 778 "Return a list of constants." 779 780 if self.constant_list is None: 781 self.constant_list = list(self.constant_values.values()) 782 783 return self.constant_list 784 785 # Program visitors. 786 787 class InspectedModule(ASTVisitor, Module): 788 789 """ 790 An inspected module, providing core details via the Module superclass, but 791 capable of being used as an AST visitor. 792 """ 793 794 def __init__(self, name, importer=None): 795 ASTVisitor.__init__(self) 796 Module.__init__(self, name) 797 self.visitor = self 798 799 self.importer = importer 800 self.builtins = self.importer.modules.get("__builtins__") 801 self.loaded = 0 802 803 # Current expression state. 804 805 self.expr = None 806 807 # Namespace state. 808 809 self.in_init = 0 # Find instance attributes in __init__ methods. 810 self.in_loop = 0 # Note loop "membership", affecting assignments. 811 self.namespaces = [] 812 self.module = None 813 814 def parse(self, filename): 815 816 "Parse the file having the given 'filename'." 817 818 module = compiler.parseFile(filename) 819 self.process(module) 820 821 def process(self, module): 822 823 "Process the given 'module'." 824 825 self.node = self.module = module 826 processed = self.dispatch(module) 827 if self.has_key("__all__"): 828 all = self["__all__"] 829 if isinstance(all, compiler.ast.List): 830 for n in all.nodes: 831 self[n.value] = self.importer.add_module(self.name + "." + n.value) 832 return processed 833 834 def vacuum(self): 835 836 "Vacuum the module namespace, removing unloaded module references." 837 838 for name, value in self.items(): 839 if isinstance(value, Module) and not value.loaded: 840 del self[name] 841 842 # Complain about globals not initialised at the module level. 843 844 if isinstance(value, Global): 845 print "Warning: global %r in module %r not initialised at the module level." % (name, self.name) 846 847 # Namespace methods. 848 849 def store(self, name, obj): 850 851 "Record attribute or local 'name', storing 'obj'." 852 853 if not self.namespaces: 854 self.set(name, obj, not self.in_loop) 855 else: 856 self.namespaces[-1].set(name, obj, not self.in_loop) 857 858 # Record all non-local objects. 859 860 if not (self.namespaces and isinstance(self.namespaces[-1], Function)): 861 self.all_objects.add(obj) 862 863 def store_instance_attr(self, name): 864 865 "Record instance attribute 'name' in the current class." 866 867 if self.in_init: 868 869 # Current namespace is the function. 870 # Previous namespace is the class. 871 872 self.namespaces[-2].add_instance_attribute(name) 873 874 def get_parent(self): 875 return (self.namespaces[-1:] or [self])[0] 876 877 # Visitor methods. 878 879 def default(self, node, *args): 880 raise InspectError(self.full_name(), node, "Node class %r is not supported." % node.__class__) 881 882 def dispatch(self, node, *args): 883 return ASTVisitor.dispatch(self, node, *args) 884 885 def NOP(self, node): 886 for n in node.getChildNodes(): 887 self.dispatch(n) 888 return None 889 890 visitAdd = NOP 891 892 visitAnd = NOP 893 894 visitAssert = NOP 895 896 def visitAssign(self, node): 897 self.expr = self.dispatch(node.expr) 898 for n in node.nodes: 899 self.dispatch(n) 900 return None 901 902 def visitAssAttr(self, node): 903 expr = self.dispatch(node.expr) 904 if isinstance(expr, Attr) and expr.name == "self": 905 self.store_instance_attr(node.attrname) 906 return None 907 908 def visitAssList(self, node): 909 for n in node.nodes: 910 self.dispatch(n) 911 return None 912 913 def visitAssName(self, node): 914 if isinstance(self.expr, Attr): 915 self.store(node.name, self.expr.value) 916 else: 917 self.store(node.name, self.expr) 918 return None 919 920 visitAssTuple = visitAssList 921 922 visitAugAssign = NOP 923 924 visitBackquote = NOP 925 926 visitBitand = NOP 927 928 visitBitor = NOP 929 930 visitBitxor = NOP 931 932 visitBreak = NOP 933 934 visitCallFunc = NOP 935 936 def visitClass(self, node): 937 if self.namespaces: 938 print "Class %r in %r is not global: ignored." % (node.name, self.namespaces[-1].full_name()) 939 else: 940 cls = Class(node.name, self.get_parent(), self, node) 941 942 # Visit the base class expressions, attempting to find concrete 943 # definitions of classes. 944 945 for base in node.bases: 946 expr = self.dispatch(base) 947 if isinstance(expr, Attr): 948 if expr.assignments != 1: 949 raise InspectError(self.full_name(), node, 950 "Base class %r for %r is not constant." % (base, cls.full_name())) 951 else: 952 cls.add_base(expr.value) 953 else: # if expr is None: 954 raise InspectError(self.full_name(), node, 955 "Base class %r for %r is not found: it may be hidden in some way." % (base, cls.full_name())) 956 957 # NOTE: Potentially dubious measure to permit __init__ availability. 958 # If no bases exist, adopt the 'object' class. 959 960 if not node.bases and not (self.name == "__builtins__" and node.name == "object") : 961 expr = self.dispatch(compiler.ast.Name("object")) 962 cls.add_base(expr.value) 963 964 # Make a back reference from the node for code generation. 965 966 node.unit = cls 967 968 # Make an entry for the class. 969 970 self.store(node.name, cls) 971 972 # Process the class body. 973 974 self.namespaces.append(cls) 975 self.dispatch(node.code) 976 self.namespaces.pop() 977 978 return None 979 980 visitCompare = NOP 981 982 def visitConst(self, node): 983 const = Const(node.value) 984 self.constant_values[node.value] = const 985 return const 986 987 visitContinue = NOP 988 989 visitDecorators = NOP 990 991 visitDict = NOP 992 993 visitDiscard = NOP 994 995 visitDiv = NOP 996 997 visitEllipsis = NOP 998 999 visitExec = NOP 1000 1001 visitExpression = NOP 1002 1003 visitFloorDiv = NOP 1004 1005 def visitFor(self, node): 1006 self.in_loop = 1 1007 self.NOP(node) 1008 self.in_loop = 0 1009 1010 def visitFrom(self, node): 1011 if self.importer is None: 1012 raise InspectError(self.full_name(), node, 1013 "Please use the micropython.Importer class for code which uses the 'from' statement.") 1014 1015 module = self.importer.load(node.modname, 1) 1016 1017 #if module is None: 1018 # print "Warning:", node.modname, "not imported." 1019 1020 for name, alias in node.names: 1021 if name != "*": 1022 if module is not None and module.namespace.has_key(name): 1023 attr = module[name] 1024 self.store(alias or name, attr.value) 1025 if isinstance(attr, Module) and not attr.loaded: 1026 self.importer.load(attr.name) 1027 1028 # Support the import of names from missing modules. 1029 1030 else: 1031 self.store(alias or name, UnresolvedName(name, node.modname, self)) 1032 else: 1033 if module is not None: 1034 for n in module.namespace.keys(): 1035 attr = module[n] 1036 self.store(n, attr.value) 1037 if isinstance(attr, Module) and not attr.loaded: 1038 self.importer.load(attr.name) 1039 1040 return None 1041 1042 def visitFunction(self, node): 1043 function = Function( 1044 node.name, 1045 self.get_parent(), 1046 node.argnames, 1047 node.defaults, 1048 (node.flags & 4 != 0), 1049 (node.flags & 8 != 0), 1050 self, 1051 node 1052 ) 1053 1054 # Make a back reference from the node for code generation. 1055 1056 node.unit = function 1057 1058 self.namespaces.append(function) 1059 1060 # Current namespace is the function. 1061 # Previous namespace is the class. 1062 1063 if node.name == "__init__" and isinstance(self.namespaces[-2], Class): 1064 self.in_init = 1 1065 1066 self.dispatch(node.code) 1067 self.in_init = 0 1068 self.namespaces.pop() 1069 1070 self.store(node.name, function) 1071 return None 1072 1073 visitGenExpr = NOP 1074 1075 visitGenExprFor = NOP 1076 1077 visitGenExprIf = NOP 1078 1079 visitGenExprInner = NOP 1080 1081 def visitGetattr(self, node): 1082 expr = self.dispatch(node.expr) 1083 if isinstance(expr, Attr): 1084 value = expr.value 1085 if isinstance(value, Module): 1086 return value.namespace.get(node.attrname) 1087 elif isinstance(value, UnresolvedName): 1088 return UnresolvedName(node.attrname, value.full_name(), self) 1089 if self.builtins is not None: 1090 return self.builtins.get(node.attrname) 1091 else: 1092 return UnresolvedName(node.attrname, value.full_name(), self) 1093 1094 def visitGlobal(self, node): 1095 if self.namespaces: 1096 for name in node.names: 1097 self.namespaces[-1].make_global(name) 1098 1099 # Record a global entry for the name in the module. 1100 1101 if not self.has_key(name): 1102 self[name] = Global() 1103 1104 def visitIf(self, node): 1105 for test, body in node.tests: 1106 self.dispatch(body) 1107 if node.else_ is not None: 1108 self.dispatch(node.else_) 1109 return None 1110 1111 visitIfExp = NOP 1112 1113 def visitImport(self, node): 1114 if self.importer is None: 1115 raise InspectError(self.full_name(), node, 1116 "Please use the micropython.Importer class for code which uses the 'import' statement.") 1117 1118 for name, alias in node.names: 1119 if alias is not None: 1120 self.store(alias, self.importer.load(name, 1) or UnresolvedName(None, name, self)) 1121 else: 1122 self.store(name.split(".")[0], self.importer.load(name) or UnresolvedName(None, name.split(".")[0], self)) 1123 1124 return None 1125 1126 visitInvert = NOP 1127 1128 def visitKeyword(self, node): 1129 self.dispatch(node.expr) 1130 const = Const(node.name) 1131 self.constant_values[node.name] = const 1132 return None 1133 1134 visitLambda = NOP 1135 1136 visitLeftShift = NOP 1137 1138 visitList = NOP 1139 1140 visitListComp = NOP 1141 1142 visitListCompFor = NOP 1143 1144 visitListCompIf = NOP 1145 1146 visitMod = NOP 1147 1148 def visitModule(self, node): 1149 return self.dispatch(node.node) 1150 1151 visitMul = NOP 1152 1153 def visitName(self, node): 1154 name = node.name 1155 if self.namespaces and self.namespaces[-1].has_key(name): 1156 return self.namespaces[-1][name] 1157 elif self.has_key(name): 1158 return self[name] 1159 elif self.builtins is not None and self.builtins.has_key(name): 1160 return self.builtins[name] 1161 else: 1162 return None 1163 1164 visitNot = NOP 1165 1166 visitOr = NOP 1167 1168 visitPass = NOP 1169 1170 visitPower = NOP 1171 1172 visitPrint = NOP 1173 1174 visitPrintnl = NOP 1175 1176 visitRaise = NOP 1177 1178 visitReturn = NOP 1179 1180 visitRightShift = NOP 1181 1182 visitSlice = NOP 1183 1184 visitSliceobj = NOP 1185 1186 def visitStmt(self, node): 1187 for n in node.nodes: 1188 self.dispatch(n) 1189 return None 1190 1191 visitSub = NOP 1192 1193 visitSubscript = NOP 1194 1195 def visitTryExcept(self, node): 1196 self.dispatch(node.body) 1197 for name, var, n in node.handlers: 1198 self.dispatch(n) 1199 if node.else_ is not None: 1200 self.dispatch(node.else_) 1201 return None 1202 1203 visitTryFinally = NOP 1204 1205 visitTuple = NOP 1206 1207 visitUnaryAdd = NOP 1208 1209 visitUnarySub = NOP 1210 1211 def visitWhile(self, node): 1212 self.in_loop = 1 1213 self.NOP(node) 1214 self.in_loop = 0 1215 1216 visitWith = NOP 1217 1218 visitYield = NOP 1219 1220 class Global: 1221 1222 """ 1223 A reference to an object assigned to a global from outside the module 1224 top-level. 1225 """ 1226 1227 pass 1228 1229 # vim: tabstop=4 expandtab shiftwidth=4