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