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