1 #!/usr/bin/env python 2 3 """ 4 Module abstractions. 5 6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 7 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk> 8 9 This program is free software; you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free Software 11 Foundation; either version 3 of the License, or (at your option) any later 12 version. 13 14 This program is distributed in the hope that it will be useful, but WITHOUT 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 17 details. 18 19 You should have received a copy of the GNU General Public License along with 20 this program. If not, see <http://www.gnu.org/licenses/>. 21 """ 22 23 from common import init_item, remove_items, CommonModule 24 from encoders import decode_modifier_term, encode_modifiers, encode_usage 25 from referencing import decode_reference, Reference 26 from results import ResolvedNameRef 27 import sys 28 29 class BasicModule(CommonModule): 30 31 "The basic module information." 32 33 def __init__(self, name, importer): 34 CommonModule.__init__(self, name, importer) 35 36 # Import details, primarily for cache output. 37 38 self.imports = set() 39 self.required = set() 40 41 # Global name information. 42 43 self.objects = {} 44 self.special = {} 45 46 # Class relationships. 47 48 self.classes = {} 49 50 # Attributes. 51 52 self.class_attrs = {} 53 self.instance_attrs = {} 54 self.instance_attr_constants = {} 55 self.module_attrs = set() 56 57 # Names used and missing. 58 59 self.names_used = {} 60 self.names_missing = {} 61 62 # Function details. 63 64 self.function_parameters = {} 65 self.function_defaults = {} 66 self.function_locals = {} 67 self.scope_globals = {} 68 69 # Invocation details. 70 71 self.function_targets = {} 72 self.function_arguments = {} 73 74 # Attribute usage at module and function levels. 75 76 self.attr_usage = {} 77 self.name_initialisers = {} 78 79 # General attribute access expressions. 80 81 self.attr_accesses = {} 82 self.const_accesses = {} 83 84 # Attribute accessor definition details. 85 86 self.attr_accessors = {} 87 88 # Assignment details for accesses. 89 90 self.attr_access_modifiers = {} 91 92 # Name resolution details. 93 94 self.name_references = {} # references to globals 95 96 # Initialisation-related details. 97 98 self.initialised_names = {} 99 self.aliased_names = {} 100 101 def __repr__(self): 102 return "BasicModule(%r, %r)" % (self.name, self.importer) 103 104 # Derived information methods. 105 106 def propagate(self): 107 108 "Finalise and propagate module information." 109 110 self.propagate_attrs() 111 self.propagate_name_references() 112 self.propagate_attr_accesses() 113 self.propagate_constants() 114 115 def unpropagate(self): 116 117 """ 118 Retract information from the importer including information about this 119 module derived by the importer. 120 """ 121 122 del self.importer.all_module_attrs[self.name] 123 124 for name in self.classes.keys(): 125 del self.importer.all_class_attrs[name] 126 del self.importer.all_instance_attrs[name] 127 del self.importer.all_instance_attr_constants[name] 128 129 for name, bases in self.classes.items(): 130 for base in bases: 131 132 # Get the identity of the class from the reference. 133 134 base = base.get_origin() 135 136 try: 137 self.importer.subclasses[base].remove(name) 138 except (KeyError, ValueError): 139 pass 140 141 remove_items(self.importer.all_name_references, self.name_references) 142 remove_items(self.importer.all_initialised_names, self.initialised_names) 143 remove_items(self.importer.all_aliased_names, self.aliased_names) 144 remove_items(self.importer.all_attr_accesses, self.attr_accesses) 145 remove_items(self.importer.all_const_accesses, self.const_accesses) 146 remove_items(self.importer.all_attr_access_modifiers, self.attr_access_modifiers) 147 remove_items(self.importer.all_constants, self.constants) 148 remove_items(self.importer.all_constant_values, self.constant_values) 149 150 # Remove this module's objects from the importer. Objects are 151 # automatically propagated when defined. 152 153 for name, ref in self.objects.items(): 154 if not ref.has_kind("<module>"): 155 del self.importer.objects[name] 156 157 def propagate_attrs(self): 158 159 "Derive attributes from the class and module member details." 160 161 # Initialise class attribute records for all classes. 162 163 for name in self.classes.keys(): 164 self.importer.all_class_attrs[name] = self.class_attrs[name] = {} 165 166 # Separate the objects into module and class attributes. 167 168 for name in self.objects.keys(): 169 if "." in name: 170 parent, attrname = name.rsplit(".", 1) 171 if self.classes.has_key(parent): 172 self.class_attrs[parent][attrname] = name 173 elif parent == self.name: 174 self.module_attrs.add(attrname) 175 176 # Propagate the module attributes. 177 178 self.importer.all_module_attrs[self.name] = self.module_attrs 179 180 def propagate_name_references(self): 181 182 "Propagate name references for the module." 183 184 self.importer.all_name_references.update(self.name_references) 185 self.importer.all_initialised_names.update(self.initialised_names) 186 self.importer.all_aliased_names.update(self.aliased_names) 187 188 def propagate_attr_accesses(self): 189 190 "Propagate attribute accesses for the module." 191 192 self.importer.all_attr_accesses.update(self.attr_accesses) 193 self.importer.all_const_accesses.update(self.const_accesses) 194 self.importer.all_attr_access_modifiers.update(self.attr_access_modifiers) 195 196 def propagate_constants(self): 197 198 "Propagate constant values and aliases for the module." 199 200 self.importer.all_constants.update(self.constants) 201 self.importer.all_constant_values.update(self.constant_values) 202 203 for name in self.classes.keys(): 204 self.importer.all_instance_attrs[name] = self.instance_attrs.get(name) or {} 205 self.importer.all_instance_attr_constants[name] = self.instance_attr_constants.get(name) or {} 206 207 def set_object(self, name, value=None): 208 209 "Set an object with the given 'name' and the given 'value'." 210 211 ref = decode_reference(value, name) 212 multiple = self.objects.has_key(name) and self.objects[name].get_kind() != ref.get_kind() 213 self.importer.objects[name] = self.objects[name] = multiple and ref.as_var() or ref 214 215 def queue_module(self, name, required=False): 216 217 """ 218 Queue the module with the given 'name'. If 'required' is true (it is 219 false by default), indicate that the module is required in the final 220 program. 221 """ 222 223 self.importer.queue_module(name, self, required) 224 if required: 225 self.required.add(name) 226 self.imports.add(name) 227 228 class InspectionNaming: 229 230 "Name operations related to inspection." 231 232 # Module-relative naming. 233 234 def is_global(self, name): 235 236 """ 237 Return whether 'name' is registered as a global in the current 238 namespace. 239 """ 240 241 path = self.get_namespace_path() 242 return name in self.scope_globals.get(path, []) 243 244 def get_global(self, name): 245 246 """ 247 Get the global of the given 'name' from this module, returning a 248 reference incorporating the original definition details. 249 """ 250 251 path = self.get_global_path(name) 252 return self.objects.get(path) 253 254 # Name definition discovery. 255 256 def get_global_or_builtin(self, name): 257 258 """ 259 Return a reference for the given 'name' found in this module or in the 260 __builtins__. 261 """ 262 263 return self.get_global(name) or self.get_builtin(name) 264 265 def get_builtin(self, name): 266 267 "Return a reference to the built-in with the given 'name'." 268 269 self.queue_module("__builtins__") 270 return Reference("<depends>", "__builtins__.%s" % name) 271 272 def get_builtin_class(self, name): 273 274 "Return a reference to the actual object providing 'name'." 275 276 # NOTE: This makes assumptions about the __builtins__ structure. 277 278 self.queue_module("__builtins__.%s" % name, True) 279 return Reference("<class>", "__builtins__.%s.%s" % (name, name)) 280 281 def get_object(self, path): 282 283 """ 284 Get the details of an object with the given 'path'. Where the object 285 cannot be resolved, an unresolved reference is returned. 286 """ 287 288 if self.objects.has_key(path): 289 return self.objects[path] 290 else: 291 return Reference("<depends>", path) 292 293 def import_name_from_module(self, name, module_name): 294 295 "Import 'name' from the module having the given 'module_name'." 296 297 if module_name != self.name: 298 self.queue_module(module_name) 299 return Reference("<depends>", "%s.%s" % (module_name, name)) 300 301 class CachedModule(BasicModule): 302 303 "A cached module." 304 305 def __repr__(self): 306 return "CachedModule(%r, %r)" % (self.name, self.importer) 307 308 def to_cache(self, filename): 309 310 "Not actually writing the module back to 'filename'." 311 312 pass 313 314 def from_cache(self, filename): 315 316 """ 317 Read a module's details from the file with the given 'filename' as 318 described in the to_cache method of InspectedModule. 319 """ 320 321 f = open(filename) 322 try: 323 self.filename = f.readline().rstrip() 324 325 f.readline() # (empty line) 326 327 self._get_imports(f) 328 self._get_members(f) 329 self._get_class_relationships(f) 330 self._get_instance_attrs(f) 331 self._get_instance_attr_constants(f) 332 self.from_lines(f, self.names_used) # "names used:" 333 self.from_lines(f, self.names_missing) # "names missing:" 334 self._get_name_references(f) 335 self._get_initialised_names(f) 336 self._get_aliased_names(f) 337 self._get_function_parameters(f) 338 self._get_function_defaults(f) 339 self._get_function_locals(f) 340 self.from_lines(f, self.scope_globals) # "scope globals:" 341 self._get_function_targets(f) 342 self._get_function_arguments(f) 343 self._get_attribute_usage(f) 344 self._get_attr_accesses(f) 345 self._get_const_accesses(f) 346 self._get_attr_accessors(f) 347 self._get_attr_access_modifiers(f) 348 self._get_constant_literals(f) 349 self._get_constant_values(f) 350 351 finally: 352 f.close() 353 354 def complete(self): 355 self.propagate() 356 357 def _get_imports(self, f): 358 f.readline() # "imports:" 359 line = f.readline().strip() 360 self.required = line != "{}" and set(line.split(", ")) or set() 361 line = f.readline().strip() 362 self.imports = line != "{}" and set(line.split(", ")) or set() 363 f.readline() 364 365 for name in self.required: 366 self.queue_module(name, True) 367 for name in self.imports: 368 self.queue_module(name) 369 370 def _get_members(self, f): 371 f.readline() # "members:" 372 line = f.readline().rstrip() 373 while line: 374 name, ref = line.split(" ", 1) 375 self.set_object(name, ref) 376 line = f.readline().rstrip() 377 378 def _get_class_relationships(self, f): 379 f.readline() # "class relationships:" 380 line = f.readline().rstrip() 381 while line: 382 name, value = self._get_fields(line) 383 values = value and value.split(", ") or [] 384 self.importer.classes[name] = self.classes[name] = map(decode_reference, values) 385 self.importer.subclasses[name] = set() 386 line = f.readline().rstrip() 387 388 def _get_instance_attrs(self, f): 389 f.readline() # "instance attributes:" 390 line = f.readline().rstrip() 391 while line: 392 name, value = self._get_fields(line) 393 self.importer.all_instance_attrs[name] = self.instance_attrs[name] = set(value and value.split(", ") or []) 394 line = f.readline().rstrip() 395 396 def _get_instance_attr_constants(self, f): 397 f.readline() # "instance attribute constants:" 398 line = f.readline().rstrip() 399 while line: 400 name, attrname, ref = self._get_fields(line, 3) 401 init_item(self.instance_attr_constants, name, dict) 402 self.instance_attr_constants[name][attrname] = decode_reference(ref) 403 line = f.readline().rstrip() 404 405 def _get_name_references(self, f): 406 f.readline() # "name references:" 407 line = f.readline().rstrip() 408 while line: 409 name, value = self._get_fields(line) 410 self.name_references[name] = value 411 line = f.readline().rstrip() 412 413 def _get_initialised_names(self, f): 414 f.readline() # "initialised names:" 415 line = f.readline().rstrip() 416 while line: 417 name, version, value = self._get_fields(line, 3) 418 init_item(self.initialised_names, name, dict) 419 self.initialised_names[name][int(version)] = decode_reference(value) 420 line = f.readline().rstrip() 421 422 def _get_aliased_names(self, f): 423 f.readline() # "aliased names:" 424 line = f.readline().rstrip() 425 while line: 426 name, version, original_name, attrnames, number = self._get_fields(line, 5) 427 init_item(self.aliased_names, name, dict) 428 if number == "{}": number = None 429 else: number = int(number) 430 self.aliased_names[name][int(version)] = (original_name, attrnames != "{}" and attrnames or None, number) 431 line = f.readline().rstrip() 432 433 def _get_function_parameters(self, f): 434 f.readline() # "function parameters:" 435 line = f.readline().rstrip() 436 while line: 437 function, names = self._get_fields(line) 438 self.importer.function_parameters[function] = \ 439 self.function_parameters[function] = names and names.split(", ") or [] 440 line = f.readline().rstrip() 441 442 def _get_function_defaults(self, f): 443 f.readline() # "function default parameters:" 444 line = f.readline().rstrip() 445 while line: 446 function, defaults = self._get_fields(line) 447 self.importer.function_defaults[function] = \ 448 self.function_defaults[function] = l = [] 449 if defaults != "{}": 450 for value in defaults.split(", "): 451 name, default = value.split("=") 452 default = decode_reference(default) 453 l.append((name, default)) 454 line = f.readline().rstrip() 455 456 def _get_function_locals(self, f): 457 f.readline() # "function locals:" 458 line = f.readline().rstrip() 459 while line: 460 function, name, value = self._get_fields(line, 3) 461 init_item(self.function_locals, function, dict) 462 if name != "{}": 463 self.function_locals[function][name] = decode_reference(value) 464 line = f.readline().rstrip() 465 466 def _get_function_targets(self, f): 467 f.readline() # "function targets:" 468 line = f.readline().rstrip() 469 while line: 470 function, n = self._get_fields(line) 471 self.importer.function_targets[function] = \ 472 self.function_targets[function] = int(n) 473 line = f.readline().rstrip() 474 475 def _get_function_arguments(self, f): 476 f.readline() # "function arguments:" 477 line = f.readline().rstrip() 478 while line: 479 function, n = self._get_fields(line) 480 self.importer.function_arguments[function] = \ 481 self.function_arguments[function] = int(n) 482 line = f.readline().rstrip() 483 484 def _get_attribute_usage(self, f): 485 f.readline() # "attribute usage:" 486 line = f.readline().rstrip() 487 while line: 488 unit, value = self._get_fields(line) 489 init_item(self.attr_usage, unit, dict) 490 self.usage_from_cache(value, self.attr_usage[unit]) 491 line = f.readline().rstrip() 492 493 def _get_attr_accesses(self, f): 494 f.readline() # "attribute accesses:" 495 line = f.readline().rstrip() 496 while line: 497 name, value = self._get_fields(line) 498 self.attr_accesses[name] = set(value.split(", ")) 499 line = f.readline().rstrip() 500 501 def _get_const_accesses(self, f): 502 f.readline() # "constant accesses:" 503 line = f.readline().rstrip() 504 while line: 505 name, original_name, attrnames, objpath, ref, remaining = self._get_fields(line, 6) 506 if attrnames == "{}": attrnames = None 507 init_item(self.const_accesses, name, dict) 508 self.const_accesses[name][(original_name, attrnames)] = (objpath, decode_reference(ref), remaining != "{}" and remaining or "") 509 line = f.readline().rstrip() 510 511 def _get_attr_accessors(self, f): 512 f.readline() # "attribute access usage:" 513 line = f.readline().rstrip() 514 while line: 515 objpath, name, attrname, value = self._get_fields(line, 4) 516 if attrname == "{}": attrname = None 517 access = name, attrname 518 init_item(self.attr_accessors, objpath, dict) 519 init_item(self.attr_accessors[objpath], access, list) 520 positions = map(int, value.split(", ")) 521 self.attr_accessors[objpath][access].append(positions) 522 line = f.readline().rstrip() 523 524 def _get_attr_access_modifiers(self, f): 525 f.readline() # "attribute access modifiers:" 526 line = f.readline().rstrip() 527 while line: 528 objpath, name, attrnames, value = self._get_fields(line, 4) 529 if name == "{}": name = None 530 if attrnames == "{}": attrnames = None 531 access = name, attrnames 532 init_item(self.attr_access_modifiers, objpath, dict) 533 init_item(self.attr_access_modifiers[objpath], access, list) 534 modifiers = [decode_modifier_term(s) for s in value] 535 self.attr_access_modifiers[objpath][access] = modifiers 536 line = f.readline().rstrip() 537 538 def _get_constant_literals(self, f): 539 f.readline() # "constant literals:" 540 line = f.readline().rstrip() 541 last_path = None 542 n = None 543 while line: 544 path, constant = self._get_fields(line) 545 if path != last_path: 546 n = 0 547 last_path = path 548 else: 549 n += 1 550 init_item(self.constants, path, dict) 551 self.constants[path][eval(constant)] = n 552 line = f.readline().rstrip() 553 554 def _get_constant_values(self, f): 555 f.readline() # "constant values:" 556 line = f.readline().rstrip() 557 while line: 558 name, value_type, value = self._get_fields(line, 3) 559 self.constant_values[name] = eval(value), value_type 560 line = f.readline().rstrip() 561 562 # Generic parsing methods. 563 564 def from_lines(self, f, d): 565 566 "Read lines from 'f', populating 'd'." 567 568 f.readline() # section heading 569 line = f.readline().rstrip() 570 while line: 571 name, value = self._get_fields(line) 572 d[name] = set(value and value.split(", ") or []) 573 line = f.readline().rstrip() 574 575 def usage_from_cache(self, value, mapping): 576 577 """ 578 Interpret the given 'value' containing name and usage information, 579 storing the information in the given 'mapping'. 580 """ 581 582 local, usage = self._get_fields(value) 583 init_item(mapping, local, list) 584 self._usage_from_cache(mapping[local], usage) 585 586 def _usage_from_cache(self, d, usage): 587 588 # Interpret descriptions of each version of the name. 589 590 all_usages = set() 591 for attrnames in usage.split("; "): 592 if attrnames == "{}": 593 all_attrnames = () 594 else: 595 # Decode attribute details for each usage description. 596 597 all_attrnames = set() 598 for attrname_str in attrnames.split(", "): 599 all_attrnames.add(attrname_str) 600 601 all_attrnames = list(all_attrnames) 602 all_attrnames.sort() 603 604 all_usages.add(tuple(all_attrnames)) 605 606 d.append(all_usages) 607 608 def _get_fields(self, s, n=2): 609 result = s.split(" ", n-1) 610 if len(result) == n: 611 return result 612 else: 613 return tuple(result) + tuple([""] * (n - len(result))) 614 615 class CacheWritingModule: 616 617 """ 618 A mix-in providing cache-writing support, to be combined with BasicModule. 619 """ 620 621 def to_cache(self, filename): 622 623 """ 624 Write a cached representation of the inspected module with the following 625 format to the file having the given 'filename': 626 627 filename 628 (empty line) 629 "imports:" 630 required module names 631 possibly required module names 632 "members:" 633 zero or more: qualified name " " reference 634 (empty line) 635 "class relationships:" 636 zero or more: qualified class name " " base class references 637 (empty line) 638 "instance attributes:" 639 zero or more: qualified class name " " instance attribute names 640 (empty line) 641 "instance attribute constants:" 642 zero or more: qualified class name " " attribute name " " reference 643 (empty line) 644 "names used:" 645 zero or more: qualified class/function/module name " " names 646 (empty line) 647 "names missing:" 648 zero or more: qualified class/function/module name " " names 649 (empty line) 650 "name references:" 651 zero or more: qualified name " " reference 652 (empty line) 653 "initialised names:" 654 zero or more: qualified name " " definition version " " reference 655 (empty line) 656 "aliased names:" 657 zero or more: qualified name " " definition version " " original name " " attribute names " " access number 658 (empty line) 659 "function parameters:" 660 zero or more: qualified function name " " parameter names 661 (empty line) 662 "function default parameters:" 663 zero or more: qualified function name " " parameter names with defaults 664 (empty line) 665 "function locals:" 666 zero or more: qualified function name " " local variable name " " reference 667 (empty line) 668 "scope globals:" 669 zero or more: qualified function name " " global variable names 670 (empty line) 671 "function targets:" 672 zero or more: qualified function name " " maximum number of targets allocated 673 (empty line) 674 "function arguments:" 675 zero or more: qualified function name " " maximum number of arguments allocated 676 (empty line) 677 "attribute usage:" 678 zero or more: qualified scope name " " local/global/qualified variable name " " usages 679 (empty line) 680 "attribute accesses:" 681 zero or more: qualified scope name " " attribute-chains 682 (empty line) 683 "constant accesses:" 684 zero or more: qualified function name " " attribute-chain " " reference " " remaining attribute-chain 685 (empty line) 686 "attribute access usage:" 687 zero or more: qualified function name " " local/global variable name " " attribute name " " definition versions 688 (empty line) 689 "attribute access modifiers:" 690 zero or more: qualified function name " " local/global variable name " " attribute name " " access modifiers 691 "constant literals:" 692 zero or more: qualified scope name " " constant literal 693 "constant values:" 694 zero or more: qualified name " " value type " " constant literal 695 696 All collections of names are separated by ", " characters. 697 698 References can be "<var>", a module name, or one of "<class>" or 699 "<function>" followed optionally by a ":" character and a qualified 700 name. 701 702 Parameter names with defaults are separated by ", " characters, with 703 each name followed by "=" and then followed by a reference. If "{}" is 704 indicated, no defaults are defined for the function. Similarly, function 705 locals may be indicated as "{}" meaning that there are no locals. 706 707 All usages (attribute usage sets) are separated by "; " characters, with 708 the special string "{}" representing an empty set. 709 710 Each usage is a collection of names separated by ", " characters, with 711 assigned attribute names suffixed with a "*" character. 712 713 Each attribute-chain expression is a dot-separated chain of attribute 714 names, with assignments suffixed with a "*" character. 715 716 Definition versions are separated by ", " characters and indicate the 717 name definition version associated with the access. 718 719 Access modifiers are separated by ", " characters and indicate features 720 of each access, with multiple accesses described on a single line. 721 """ 722 723 f = open(filename, "w") 724 try: 725 print >>f, self.filename 726 727 print >>f 728 print >>f, "imports:" 729 required = list(self.required) 730 required.sort() 731 print >>f, required and ", ".join(required) or "{}" 732 imports = list(self.imports) 733 imports.sort() 734 print >>f, imports and ", ".join(imports) or "{}" 735 736 print >>f 737 print >>f, "members:" 738 objects = self.objects.keys() 739 objects.sort() 740 for name in objects: 741 print >>f, name, self.objects[name] 742 743 print >>f 744 print >>f, "class relationships:" 745 classes = self.classes.keys() 746 classes.sort() 747 for class_ in classes: 748 bases = self.classes[class_] 749 if bases: 750 print >>f, class_, ", ".join(map(str, bases)) 751 else: 752 print >>f, class_ 753 754 self.to_lines(f, "instance attributes:", self.instance_attrs) 755 756 print >>f 757 print >>f, "instance attribute constants:" 758 classes = self.instance_attr_constants.items() 759 classes.sort() 760 for name, attrs in classes: 761 attrs = attrs.items() 762 attrs.sort() 763 for attrname, ref in attrs: 764 print >>f, name, attrname, ref 765 766 self.to_lines(f, "names used:", self.names_used) 767 self.to_lines(f, "names missing:", self.names_missing) 768 769 print >>f 770 print >>f, "name references:" 771 refs = self.name_references.items() 772 refs.sort() 773 for name, ref in refs: 774 print >>f, name, ref 775 776 print >>f 777 print >>f, "initialised names:" 778 assignments = self.initialised_names.items() 779 assignments.sort() 780 for name, refs in assignments: 781 versions = refs.items() 782 versions.sort() 783 for version, ref in versions: 784 print >>f, name, version, ref 785 786 print >>f 787 print >>f, "aliased names:" 788 assignments = self.aliased_names.items() 789 assignments.sort() 790 for name, aliases in assignments: 791 versions = aliases.items() 792 versions.sort() 793 for version, alias in versions: 794 original_name, attrnames, number = alias 795 print >>f, name, version, original_name, attrnames or "{}", number is None and "{}" or number 796 797 print >>f 798 print >>f, "function parameters:" 799 functions = self.function_parameters.keys() 800 functions.sort() 801 for function in functions: 802 print >>f, function, ", ".join(self.function_parameters[function]) 803 804 print >>f 805 print >>f, "function default parameters:" 806 functions = self.function_defaults.keys() 807 functions.sort() 808 for function in functions: 809 parameters = self.function_defaults[function] 810 if parameters: 811 print >>f, function, ", ".join([("%s=%s" % (name, default)) for (name, default) in parameters]) 812 else: 813 print >>f, function, "{}" 814 815 print >>f 816 print >>f, "function locals:" 817 functions = self.function_locals.keys() 818 functions.sort() 819 for function in functions: 820 names = self.function_locals[function].items() 821 if names: 822 names.sort() 823 for name, value in names: 824 print >>f, function, name, value 825 else: 826 print >>f, function, "{}" 827 828 self.to_lines(f, "scope globals:", self.scope_globals) 829 830 print >>f 831 print >>f, "function targets:" 832 functions = self.function_targets.keys() 833 functions.sort() 834 for function in functions: 835 print >>f, function, self.function_targets[function] 836 837 print >>f 838 print >>f, "function arguments:" 839 functions = self.function_arguments.keys() 840 functions.sort() 841 for function in functions: 842 print >>f, function, self.function_arguments[function] 843 844 print >>f 845 print >>f, "attribute usage:" 846 units = self.attr_usage.keys() 847 units.sort() 848 for unit in units: 849 d = self.attr_usage[unit] 850 self.usage_to_cache(d, f, unit) 851 852 print >>f 853 print >>f, "attribute accesses:" 854 paths = self.attr_accesses.keys() 855 paths.sort() 856 for path in paths: 857 accesses = list(self.attr_accesses[path]) 858 accesses.sort() 859 print >>f, path, ", ".join(accesses) 860 861 print >>f 862 print >>f, "constant accesses:" 863 paths = self.const_accesses.keys() 864 paths.sort() 865 for path in paths: 866 accesses = self.const_accesses[path].items() 867 accesses.sort() 868 for (original_name, attrnames), (objpath, ref, remaining_attrnames) in accesses: 869 print >>f, path, original_name, attrnames, objpath, ref, remaining_attrnames or "{}" 870 871 print >>f 872 print >>f, "attribute access usage:" 873 paths = self.attr_accessors.keys() 874 paths.sort() 875 for path in paths: 876 all_accesses = self.attr_accessors[path].items() 877 all_accesses.sort() 878 for (name, attrname), accesses in all_accesses: 879 for positions in accesses: 880 positions = map(str, positions) 881 print >>f, path, name, attrname or "{}", ", ".join(positions) 882 883 print >>f 884 print >>f, "attribute access modifiers:" 885 paths = self.attr_access_modifiers.keys() 886 paths.sort() 887 for path in paths: 888 all_accesses = self.attr_access_modifiers[path].items() 889 all_accesses.sort() 890 for (name, attrnames), modifiers in all_accesses: 891 print >>f, path, name or "{}", attrnames or "{}", encode_modifiers(modifiers) 892 893 print >>f 894 print >>f, "constant literals:" 895 paths = self.constants.keys() 896 paths.sort() 897 for path in paths: 898 constants = [(v, k) for (k, v) in self.constants[path].items()] 899 constants.sort() 900 for n, constant in constants: 901 print >>f, path, repr(constant) 902 903 print >>f 904 print >>f, "constant values:" 905 names = self.constant_values.keys() 906 names.sort() 907 for name in names: 908 value, value_type = self.constant_values[name] 909 print >>f, name, value_type, repr(value) 910 911 finally: 912 f.close() 913 914 def to_lines(self, f, heading, d): 915 916 "Write lines to 'f' with the given 'heading', using 'd'." 917 918 print >>f 919 print >>f, heading 920 keys = d.keys() 921 keys.sort() 922 for key in keys: 923 attrs = list(d[key]) 924 if attrs: 925 attrs.sort() 926 print >>f, key, ", ".join(attrs) 927 928 def usage_to_cache(self, details, f, prefix): 929 930 "Write the given namespace usage details to the cache." 931 932 names = list(details.keys()) 933 if names: 934 names.sort() 935 for name in names: 936 if details[name]: 937 938 # Produce descriptions for each version of the name. 939 940 for version in details[name]: 941 all_usages = [] 942 for usage in version: 943 all_usages.append(encode_usage(usage)) 944 945 print >>f, "%s %s %s" % (prefix, name, "; ".join(all_usages)) 946 947 # vim: tabstop=4 expandtab shiftwidth=4