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