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