1 #!/usr/bin/env python 2 3 """ 4 Common functions. 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 errors import * 24 from os import listdir, makedirs, remove 25 from os.path import exists, isdir, join, split 26 from results import ConstantValueRef, LiteralSequenceRef, NameRef 27 import compiler 28 29 class CommonOutput: 30 31 "Common output functionality." 32 33 def check_output(self): 34 35 "Check the existing output and remove it if irrelevant." 36 37 if not exists(self.output): 38 makedirs(self.output) 39 40 details = self.importer.get_cache_details() 41 recorded_details = self.get_output_details() 42 43 if recorded_details != details: 44 self.remove_output() 45 46 writefile(self.get_output_details_filename(), details) 47 48 def get_output_details_filename(self): 49 50 "Return the output details filename." 51 52 return join(self.output, "$details") 53 54 def get_output_details(self): 55 56 "Return details of the existing output." 57 58 details_filename = self.get_output_details_filename() 59 60 if not exists(details_filename): 61 return None 62 else: 63 return readfile(details_filename) 64 65 def remove_output(self, dirname=None): 66 67 "Remove the output." 68 69 dirname = dirname or self.output 70 71 for filename in listdir(dirname): 72 path = join(dirname, filename) 73 if isdir(path): 74 self.remove_output(path) 75 else: 76 remove(path) 77 78 class CommonModule: 79 80 "A common module representation." 81 82 def __init__(self, name, importer): 83 84 """ 85 Initialise this module with the given 'name' and an 'importer' which is 86 used to provide access to other modules when required. 87 """ 88 89 self.name = name 90 self.importer = importer 91 self.filename = None 92 93 # Inspection-related attributes. 94 95 self.astnode = None 96 self.iterators = {} 97 self.temp = {} 98 self.lambdas = {} 99 100 # Constants, literals and values. 101 102 self.constants = {} 103 self.constant_values = {} 104 self.literals = {} 105 self.literal_types = {} 106 107 # Nested namespaces. 108 109 self.namespace_path = [] 110 self.in_function = False 111 112 # Retain the assignment value expression and track invocations. 113 114 self.in_assignment = None 115 self.in_invocation = False 116 117 # Attribute chain state management. 118 119 self.attrs = [] 120 self.chain_assignment = [] 121 self.chain_invocation = [] 122 123 def __repr__(self): 124 return "CommonModule(%r, %r)" % (self.name, self.importer) 125 126 def parse_file(self, filename): 127 128 "Parse the file with the given 'filename', initialising attributes." 129 130 self.filename = filename 131 self.astnode = compiler.parseFile(filename) 132 133 # Module-relative naming. 134 135 def get_global_path(self, name): 136 return "%s.%s" % (self.name, name) 137 138 def get_namespace_path(self): 139 return ".".join([self.name] + self.namespace_path) 140 141 def get_object_path(self, name): 142 return ".".join([self.name] + self.namespace_path + [name]) 143 144 def get_parent_path(self): 145 return ".".join([self.name] + self.namespace_path[:-1]) 146 147 # Namespace management. 148 149 def enter_namespace(self, name): 150 151 "Enter the namespace having the given 'name'." 152 153 self.namespace_path.append(name) 154 155 def exit_namespace(self): 156 157 "Exit the current namespace." 158 159 self.namespace_path.pop() 160 161 # Constant reference naming. 162 163 def get_constant_name(self, value, value_type): 164 165 """ 166 Add a new constant to the current namespace for 'value' with 167 'value_type'. 168 """ 169 170 path = self.get_namespace_path() 171 init_item(self.constants, path, dict) 172 return "$c%d" % add_counter_item(self.constants[path], (value, value_type)) 173 174 # Literal reference naming. 175 176 def get_literal_name(self): 177 178 "Add a new literal to the current namespace." 179 180 path = self.get_namespace_path() 181 init_item(self.literals, path, lambda: 0) 182 return "$C%d" % self.literals[path] 183 184 def next_literal(self): 185 self.literals[self.get_namespace_path()] += 1 186 187 # Temporary iterator naming. 188 189 def get_iterator_path(self): 190 return self.in_function and self.get_namespace_path() or self.name 191 192 def get_iterator_name(self): 193 path = self.get_iterator_path() 194 init_item(self.iterators, path, lambda: 0) 195 return "$i%d" % self.iterators[path] 196 197 def next_iterator(self): 198 self.iterators[self.get_iterator_path()] += 1 199 200 # Temporary variable naming. 201 202 def get_temporary_name(self): 203 path = self.get_namespace_path() 204 init_item(self.temp, path, lambda: 0) 205 return "$t%d" % self.temp[path] 206 207 def next_temporary(self): 208 self.temp[self.get_namespace_path()] += 1 209 210 # Arbitrary function naming. 211 212 def get_lambda_name(self): 213 path = self.get_namespace_path() 214 init_item(self.lambdas, path, lambda: 0) 215 name = "$l%d" % self.lambdas[path] 216 self.lambdas[path] += 1 217 return name 218 219 def reset_lambdas(self): 220 self.lambdas = {} 221 222 # Constant and literal recording. 223 224 def get_constant_value(self, value): 225 226 "Encode the 'value' if appropriate." 227 228 if isinstance(value, unicode): 229 value = value.encode("utf-8") 230 return value 231 232 def get_constant_reference(self, ref, value): 233 234 "Return a constant reference for the given 'ref' type and 'value'." 235 236 constant_name = self.get_constant_name(value, ref.get_origin()) 237 238 # Return a reference for the constant. 239 240 objpath = self.get_object_path(constant_name) 241 name_ref = ConstantValueRef(constant_name, ref.instance_of(objpath), value) 242 243 # Record the value and type for the constant. 244 245 self._reserve_constant(objpath, name_ref.value, name_ref.get_origin()) 246 return name_ref 247 248 def reserve_constant(self, objpath, value, origin): 249 250 """ 251 Reserve a constant within 'objpath' with the given 'value' and having a 252 type with the given 'origin'. 253 """ 254 255 constant_name = self.get_constant_name(value, origin) 256 objpath = self.get_object_path(constant_name) 257 self._reserve_constant(objpath, value, origin) 258 259 def _reserve_constant(self, objpath, value, origin): 260 261 "Store a constant for 'objpath' with the given 'value' and 'origin'." 262 263 self.constant_values[objpath] = value, origin 264 265 def get_literal_reference(self, name, ref, items, cls): 266 267 """ 268 Return a literal reference for the given type 'name', literal 'ref', 269 node 'items' and employing the given 'cls' as the class of the returned 270 reference object. 271 """ 272 273 # Construct an invocation using the items as arguments. 274 275 typename = "$L%s" % name 276 277 invocation = compiler.ast.CallFunc( 278 compiler.ast.Name(typename), 279 items 280 ) 281 282 # Get a name for the actual literal. 283 284 instname = self.get_literal_name() 285 self.next_literal() 286 287 # Record the type for the literal. 288 289 objpath = self.get_object_path(instname) 290 self.literal_types[objpath] = ref.get_origin() 291 292 # Return a wrapper for the invocation exposing the items. 293 294 return cls( 295 instname, 296 ref.instance_of(), 297 self.process_structure_node(invocation), 298 invocation.args 299 ) 300 301 # Node handling. 302 303 def process_structure(self, node): 304 305 """ 306 Within the given 'node', process the program structure. 307 308 During inspection, this will process global declarations, adjusting the 309 module namespace, and import statements, building a module dependency 310 hierarchy. 311 312 During translation, this will consult deduced program information and 313 output translated code. 314 """ 315 316 l = [] 317 for n in node.getChildNodes(): 318 l.append(self.process_structure_node(n)) 319 return l 320 321 def process_augassign_node(self, n): 322 323 "Process the given augmented assignment node 'n'." 324 325 op = operator_functions[n.op] 326 327 if isinstance(n.node, compiler.ast.Getattr): 328 target = compiler.ast.AssAttr(n.node.expr, n.node.attrname, "OP_ASSIGN") 329 elif isinstance(n.node, compiler.ast.Name): 330 target = compiler.ast.AssName(n.node.name, "OP_ASSIGN") 331 else: 332 target = n.node 333 334 assignment = compiler.ast.Assign( 335 [target], 336 compiler.ast.CallFunc( 337 compiler.ast.Name("$op%s" % op), 338 [n.node, n.expr])) 339 340 return self.process_structure_node(assignment) 341 342 def process_assignment_for_object(self, original_name, source): 343 344 """ 345 Return an assignment operation making 'original_name' refer to the given 346 'source'. 347 """ 348 349 assignment = compiler.ast.Assign( 350 [compiler.ast.AssName(original_name, "OP_ASSIGN")], 351 source 352 ) 353 354 return self.process_structure_node(assignment) 355 356 def process_assignment_node_items(self, n, expr): 357 358 """ 359 Process the given assignment node 'n' whose children are to be assigned 360 items of 'expr'. 361 """ 362 363 name_ref = self.process_structure_node(expr) 364 365 # Either unpack the items and present them directly to each assignment 366 # node. 367 368 if isinstance(name_ref, LiteralSequenceRef): 369 self.process_literal_sequence_items(n, name_ref) 370 371 # Or have the assignment nodes access each item via the sequence API. 372 373 else: 374 self.process_assignment_node_items_by_position(n, expr, name_ref) 375 376 def process_assignment_node_items_by_position(self, n, expr, name_ref): 377 378 """ 379 Process the given sequence assignment node 'n', converting the node to 380 the separate assignment of each target using positional access on a 381 temporary variable representing the sequence. Use 'expr' as the assigned 382 value and 'name_ref' as the reference providing any existing temporary 383 variable. 384 """ 385 386 assignments = [] 387 388 if isinstance(name_ref, NameRef): 389 temp = name_ref.name 390 else: 391 temp = self.get_temporary_name() 392 self.next_temporary() 393 394 assignments.append( 395 compiler.ast.Assign([compiler.ast.AssName(temp, "OP_ASSIGN")], expr) 396 ) 397 398 for i, node in enumerate(n.nodes): 399 assignments.append( 400 compiler.ast.Assign([node], compiler.ast.Subscript( 401 compiler.ast.Name(temp), "OP_APPLY", [compiler.ast.Const(i, str(i))])) 402 ) 403 404 return self.process_structure_node(compiler.ast.Stmt(assignments)) 405 406 def process_literal_sequence_items(self, n, name_ref): 407 408 """ 409 Process the given assignment node 'n', obtaining from the given 410 'name_ref' the items to be assigned to the assignment targets. 411 """ 412 413 if len(n.nodes) == len(name_ref.items): 414 for node, item in zip(n.nodes, name_ref.items): 415 self.process_assignment_node(node, item) 416 else: 417 raise InspectError("In %s, item assignment needing %d items is given %d items." % ( 418 self.get_namespace_path(), len(n.nodes), len(name_ref.items))) 419 420 def process_compare_node(self, n): 421 422 """ 423 Process the given comparison node 'n', converting an operator sequence 424 from... 425 426 <expr1> <op1> <expr2> <op2> <expr3> 427 428 ...to... 429 430 <op1>(<expr1>, <expr2>) and <op2>(<expr2>, <expr3>) 431 """ 432 433 invocations = [] 434 last = n.expr 435 436 for op, op_node in n.ops: 437 op = operator_functions.get(op) 438 439 invocations.append(compiler.ast.CallFunc( 440 compiler.ast.Name("$op%s" % op), 441 [last, op_node])) 442 443 last = op_node 444 445 if len(invocations) > 1: 446 result = compiler.ast.And(invocations) 447 else: 448 result = invocations[0] 449 450 return self.process_structure_node(result) 451 452 def process_dict_node(self, node): 453 454 """ 455 Process the given dictionary 'node', returning a list of (key, value) 456 tuples. 457 """ 458 459 l = [] 460 for key, value in node.items: 461 l.append(( 462 self.process_structure_node(key), 463 self.process_structure_node(value))) 464 return l 465 466 def process_for_node(self, n): 467 468 """ 469 Generate attribute accesses for {n.list}.__iter__ and the next method on 470 the iterator, producing a replacement node for the original. 471 """ 472 473 node = compiler.ast.Stmt([ 474 475 # <iterator> = {n.list}.__iter__ 476 477 compiler.ast.Assign( 478 [compiler.ast.AssName(self.get_iterator_name(), "OP_ASSIGN")], 479 compiler.ast.CallFunc( 480 compiler.ast.Getattr(n.list, "__iter__"), 481 [] 482 )), 483 484 # try: 485 # while True: 486 # <var>... = <iterator>.next() 487 # ... 488 # except StopIteration: 489 # pass 490 491 compiler.ast.TryExcept( 492 compiler.ast.While( 493 compiler.ast.Name("True"), 494 compiler.ast.Stmt([ 495 compiler.ast.Assign( 496 [n.assign], 497 compiler.ast.CallFunc( 498 compiler.ast.Getattr(compiler.ast.Name(self.get_iterator_name()), "next"), 499 [] 500 )), 501 n.body]), 502 None), 503 [(compiler.ast.Name("StopIteration"), None, compiler.ast.Stmt([compiler.ast.Pass()]))], 504 None) 505 ]) 506 507 self.next_iterator() 508 self.process_structure_node(node) 509 510 def process_literal_sequence_node(self, n, name, ref, cls): 511 512 """ 513 Process the given literal sequence node 'n' as a function invocation, 514 with 'name' indicating the type of the sequence, and 'ref' being a 515 reference to the type. The 'cls' is used to instantiate a suitable name 516 reference. 517 """ 518 519 if name == "dict": 520 items = [] 521 for key, value in n.items: 522 items.append(compiler.ast.Tuple([key, value])) 523 else: # name in ("list", "tuple"): 524 items = n.nodes 525 526 return self.get_literal_reference(name, ref, items, cls) 527 528 def process_operator_node(self, n): 529 530 """ 531 Process the given operator node 'n' as an operator function invocation. 532 """ 533 534 op = operator_functions[n.__class__.__name__] 535 invocation = compiler.ast.CallFunc( 536 compiler.ast.Name("$op%s" % op), 537 list(n.getChildNodes()) 538 ) 539 return self.process_structure_node(invocation) 540 541 def process_print_node(self, n): 542 543 """ 544 Process the given print node 'n' as an invocation on a stream of the 545 form... 546 547 $print(dest, args, nl) 548 549 The special function name will be translated elsewhere. 550 """ 551 552 nl = isinstance(n, compiler.ast.Printnl) 553 invocation = compiler.ast.CallFunc( 554 compiler.ast.Name("$print"), 555 [n.dest or compiler.ast.Name("None"), 556 compiler.ast.List(list(n.nodes)), 557 nl and compiler.ast.Name("True") or compiler.ast.Name("False")] 558 ) 559 return self.process_structure_node(invocation) 560 561 def process_slice_node(self, n, expr=None): 562 563 """ 564 Process the given slice node 'n' as an operator function invocation. 565 """ 566 567 op = n.flags == "OP_ASSIGN" and "setslice" or "getslice" 568 invocation = compiler.ast.CallFunc( 569 compiler.ast.Name("$op%s" % op), 570 [n.expr, n.lower or compiler.ast.Name("None"), n.upper or compiler.ast.Name("None")] + 571 (expr and [expr] or []) 572 ) 573 return self.process_structure_node(invocation) 574 575 def process_sliceobj_node(self, n): 576 577 """ 578 Process the given slice object node 'n' as a slice constructor. 579 """ 580 581 op = "slice" 582 invocation = compiler.ast.CallFunc( 583 compiler.ast.Name("$op%s" % op), 584 n.nodes 585 ) 586 return self.process_structure_node(invocation) 587 588 def process_subscript_node(self, n, expr=None): 589 590 """ 591 Process the given subscript node 'n' as an operator function invocation. 592 """ 593 594 op = n.flags == "OP_ASSIGN" and "setitem" or "getitem" 595 invocation = compiler.ast.CallFunc( 596 compiler.ast.Name("$op%s" % op), 597 [n.expr] + list(n.subs) + (expr and [expr] or []) 598 ) 599 return self.process_structure_node(invocation) 600 601 def process_attribute_chain(self, n): 602 603 """ 604 Process the given attribute access node 'n'. Return a reference 605 describing the expression. 606 """ 607 608 # AssAttr/Getattr are nested with the outermost access being the last 609 # access in any chain. 610 611 self.attrs.insert(0, n.attrname) 612 attrs = self.attrs 613 614 # Break attribute chains where non-access nodes are found. 615 616 if not self.have_access_expression(n): 617 self.reset_attribute_chain() 618 619 # Descend into the expression, extending backwards any existing chain, 620 # or building another for the expression. 621 622 name_ref = self.process_structure_node(n.expr) 623 624 # Restore chain information applying to this node. 625 626 if not self.have_access_expression(n): 627 self.restore_attribute_chain(attrs) 628 629 # Return immediately if the expression was another access and thus a 630 # continuation backwards along the chain. The above processing will 631 # have followed the chain all the way to its conclusion. 632 633 if self.have_access_expression(n): 634 del self.attrs[0] 635 636 return name_ref 637 638 # Attribute chain handling. 639 640 def reset_attribute_chain(self): 641 642 "Reset the attribute chain for a subexpression of an attribute access." 643 644 self.attrs = [] 645 self.chain_assignment.append(self.in_assignment) 646 self.chain_invocation.append(self.in_invocation) 647 self.in_assignment = None 648 self.in_invocation = False 649 650 def restore_attribute_chain(self, attrs): 651 652 "Restore the attribute chain for an attribute access." 653 654 self.attrs = attrs 655 self.in_assignment = self.chain_assignment.pop() 656 self.in_invocation = self.chain_invocation.pop() 657 658 def have_access_expression(self, node): 659 660 "Return whether the expression associated with 'node' is Getattr." 661 662 return isinstance(node.expr, compiler.ast.Getattr) 663 664 def get_name_for_tracking(self, name, path=None): 665 666 """ 667 Return the name to be used for attribute usage observations involving 668 the given 'name' in the current namespace. If 'path' is indicated and 669 the name is being used outside a function, return the path value; 670 otherwise, return a path computed using the current namespace and the 671 given name. 672 673 The intention of this method is to provide a suitably-qualified name 674 that can be tracked across namespaces. Where globals are being 675 referenced in class namespaces, they should be referenced using their 676 path within the module, not using a path within each class. 677 678 It may not be possible to identify a global within a function at the 679 time of inspection (since a global may appear later in a file). 680 Consequently, globals are identified by their local name rather than 681 their module-qualified path. 682 """ 683 684 # For functions, use the appropriate local names. 685 686 if self.in_function: 687 return name 688 689 # For static namespaces, use the given qualified name. 690 691 elif path: 692 return path 693 694 # Otherwise, establish a name in the current namespace. 695 696 else: 697 return self.get_object_path(name) 698 699 def get_path_for_access(self): 700 701 "Outside functions, register accesses at the module level." 702 703 if not self.in_function: 704 return self.name 705 else: 706 return self.get_namespace_path() 707 708 def get_module_name(self, node): 709 710 """ 711 Using the given From 'node' in this module, calculate any relative import 712 information, returning a tuple containing a module to import along with any 713 names to import based on the node's name information. 714 715 Where the returned module is given as None, whole module imports should 716 be performed for the returned modules using the returned names. 717 """ 718 719 # Absolute import. 720 721 if node.level == 0: 722 return node.modname, node.names 723 724 # Relative to an ancestor of this module. 725 726 else: 727 path = self.name.split(".") 728 level = node.level 729 730 # Relative imports treat package roots as submodules. 731 732 if split(self.filename)[-1] == "__init__.py": 733 level -= 1 734 735 if level > len(path): 736 raise InspectError("Relative import %r involves too many levels up from module %r" % ( 737 ("%s%s" % ("." * node.level, node.modname or "")), self.name)) 738 739 basename = ".".join(path[:len(path)-level]) 740 741 # Name imports from a module. 742 743 if node.modname: 744 return "%s.%s" % (basename, node.modname), node.names 745 746 # Relative whole module imports. 747 748 else: 749 return basename, node.names 750 751 def get_argnames(args): 752 753 """ 754 Return a list of all names provided by 'args'. Since tuples may be 755 employed, the arguments are traversed depth-first. 756 """ 757 758 l = [] 759 for arg in args: 760 if isinstance(arg, tuple): 761 l += get_argnames(arg) 762 else: 763 l.append(arg) 764 return l 765 766 # Dictionary utilities. 767 768 def init_item(d, key, fn): 769 770 """ 771 Add to 'd' an entry for 'key' using the callable 'fn' to make an initial 772 value where no entry already exists. 773 """ 774 775 if not d.has_key(key): 776 d[key] = fn() 777 return d[key] 778 779 def dict_for_keys(d, keys): 780 781 "Return a new dictionary containing entries from 'd' for the given 'keys'." 782 783 nd = {} 784 for key in keys: 785 if d.has_key(key): 786 nd[key] = d[key] 787 return nd 788 789 def make_key(s): 790 791 "Make sequence 's' into a tuple-based key, first sorting its contents." 792 793 l = list(s) 794 l.sort() 795 return tuple(l) 796 797 def add_counter_item(d, key): 798 799 """ 800 Make a mapping in 'd' for 'key' to the number of keys added before it, thus 801 maintaining a mapping of keys to their order of insertion. 802 """ 803 804 if not d.has_key(key): 805 d[key] = len(d.keys()) 806 return d[key] 807 808 def remove_items(d1, d2): 809 810 "Remove from 'd1' all items from 'd2'." 811 812 for key in d2.keys(): 813 if d1.has_key(key): 814 del d1[key] 815 816 # Set utilities. 817 818 def first(s): 819 return list(s)[0] 820 821 def same(s1, s2): 822 return set(s1) == set(s2) 823 824 # General input/output. 825 826 def readfile(filename): 827 828 "Return the contents of 'filename'." 829 830 f = open(filename) 831 try: 832 return f.read() 833 finally: 834 f.close() 835 836 def writefile(filename, s): 837 838 "Write to 'filename' the string 's'." 839 840 f = open(filename, "w") 841 try: 842 f.write(s) 843 finally: 844 f.close() 845 846 # General encoding. 847 848 def sorted_output(x): 849 850 "Sort sequence 'x' and return a string with commas separating the values." 851 852 x = map(str, x) 853 x.sort() 854 return ", ".join(x) 855 856 # Attribute chain decoding. 857 858 def get_attrnames(attrnames): 859 860 """ 861 Split the qualified attribute chain 'attrnames' into its components, 862 handling special attributes starting with "#" that indicate type 863 conformance. 864 """ 865 866 if attrnames.startswith("#"): 867 return [attrnames] 868 else: 869 return attrnames.split(".") 870 871 def get_attrname_from_location(location): 872 873 """ 874 Extract the first attribute from the attribute names employed in a 875 'location'. 876 """ 877 878 path, name, attrnames, access = location 879 if not attrnames: 880 return attrnames 881 return get_attrnames(attrnames)[0] 882 883 def get_name_path(path, name): 884 885 "Return a suitable qualified name from the given 'path' and 'name'." 886 887 if "." in name: 888 return name 889 else: 890 return "%s.%s" % (path, name) 891 892 # Usage-related functions. 893 894 def get_types_for_usage(attrnames, objects): 895 896 """ 897 Identify the types that can support the given 'attrnames', using the 898 given 'objects' as the catalogue of type details. 899 """ 900 901 types = [] 902 for name, _attrnames in objects.items(): 903 if set(attrnames).issubset(_attrnames): 904 types.append(name) 905 return types 906 907 def get_invoked_attributes(usage): 908 909 "Obtain invoked attribute from the given 'usage'." 910 911 invoked = [] 912 if usage: 913 for attrname, invocation, assignment in usage: 914 if invocation: 915 invoked.append(attrname) 916 return invoked 917 918 def get_assigned_attributes(usage): 919 920 "Obtain assigned attribute from the given 'usage'." 921 922 assigned = [] 923 if usage: 924 for attrname, invocation, assignment in usage: 925 if assignment: 926 assigned.append(attrname) 927 return assigned 928 929 # Type and module functions. 930 931 def get_builtin_module(name): 932 933 "Return the module name containing the given type 'name'." 934 935 # NOTE: This makes assumptions about the __builtins__ structure. 936 937 if name == "string": 938 return "str" 939 elif name == "utf8string": 940 return "unicode" 941 elif name == "NoneType": 942 return "none" 943 else: 944 return name 945 946 def get_builtin_type(name): 947 948 "Return the type name provided by the given Python value 'name'." 949 950 if name == "str": 951 return "string" 952 elif name == "unicode": 953 return "utf8string" 954 else: 955 return name 956 957 # Useful data. 958 959 predefined_constants = "False", "None", "NotImplemented", "True" 960 961 operator_functions = { 962 963 # Fundamental operations. 964 965 "is" : "is_", 966 "is not" : "is_not", 967 968 # Binary operations. 969 970 "in" : "in_", 971 "not in" : "not_in", 972 "Add" : "add", 973 "Bitand" : "and_", 974 "Bitor" : "or_", 975 "Bitxor" : "xor", 976 "Div" : "div", 977 "FloorDiv" : "floordiv", 978 "LeftShift" : "lshift", 979 "Mod" : "mod", 980 "Mul" : "mul", 981 "Power" : "pow", 982 "RightShift" : "rshift", 983 "Sub" : "sub", 984 985 # Unary operations. 986 987 "Invert" : "invert", 988 "UnaryAdd" : "pos", 989 "UnarySub" : "neg", 990 991 # Augmented assignment. 992 993 "+=" : "iadd", 994 "-=" : "isub", 995 "*=" : "imul", 996 "/=" : "idiv", 997 "//=" : "ifloordiv", 998 "%=" : "imod", 999 "**=" : "ipow", 1000 "<<=" : "ilshift", 1001 ">>=" : "irshift", 1002 "&=" : "iand", 1003 "^=" : "ixor", 1004 "|=" : "ior", 1005 1006 # Comparisons. 1007 1008 "==" : "eq", 1009 "!=" : "ne", 1010 "<" : "lt", 1011 "<=" : "le", 1012 ">=" : "ge", 1013 ">" : "gt", 1014 } 1015 1016 # vim: tabstop=4 expandtab shiftwidth=4