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