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