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