1 #!/usr/bin/env python 2 3 """ 4 Translate programs. 5 6 Copyright (C) 2015, 2016, 2017 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 from common import AccessLocation, CommonModule, CommonOutput, Location, \ 23 first, get_builtin_class, init_item, is_newer, \ 24 predefined_constants 25 from encoders import encode_access_instruction, encode_access_instruction_arg, \ 26 encode_function_pointer, encode_literal_instantiator, \ 27 encode_instantiator_pointer, encode_path, encode_symbol, \ 28 encode_type_attribute, is_type_attribute 29 from errors import InspectError, TranslateError 30 from os.path import exists, join 31 from os import makedirs 32 from referencing import Reference, combine_types 33 from results import Result 34 from transresults import TrConstantValueRef, TrInstanceRef, \ 35 TrLiteralSequenceRef, TrResolvedNameRef, \ 36 AliasResult, AttrResult, Expression, InstantiationResult, \ 37 InvocationResult, LogicalOperationResult, \ 38 LogicalResult, NegationResult, PredefinedConstantRef, \ 39 ReturnRef 40 from StringIO import StringIO 41 import compiler 42 import sys 43 44 class Translator(CommonOutput): 45 46 "A program translator." 47 48 def __init__(self, importer, deducer, optimiser, output): 49 self.importer = importer 50 self.deducer = deducer 51 self.optimiser = optimiser 52 self.output = output 53 54 def to_output(self, reset=False, debug=False, gc_sections=False): 55 56 "Write a program to the configured output directory." 57 58 # Make a directory for the final sources. 59 60 output = join(self.output, "src") 61 62 if not exists(output): 63 makedirs(output) 64 65 # Clean the output directory of irrelevant data. 66 67 self.check_output("debug=%r gc_sections=%r" % (debug, gc_sections)) 68 69 for module in self.importer.modules.values(): 70 output_filename = join(output, "%s.c" % module.name) 71 72 # Do not generate modules in the native package. They are provided 73 # by native functionality source files. 74 75 parts = module.name.split(".") 76 77 if parts[0] != "native" and \ 78 (reset or is_newer(module.filename, output_filename)): 79 80 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser) 81 tm.translate(module.filename, output_filename) 82 83 84 85 def make_expression(expr): 86 87 "Make a new expression from the existing 'expr'." 88 89 if isinstance(expr, Result): 90 return expr 91 else: 92 return Expression(str(expr)) 93 94 95 96 # The actual translation process itself. 97 98 class TranslatedModule(CommonModule): 99 100 "A module translator." 101 102 def __init__(self, name, importer, deducer, optimiser): 103 CommonModule.__init__(self, name, importer) 104 self.deducer = deducer 105 self.optimiser = optimiser 106 107 # Output stream. 108 109 self.out_toplevel = self.out = None 110 self.indent = 0 111 self.tabstop = " " 112 113 # Recorded namespaces. 114 115 self.namespaces = [] 116 self.in_conditional = False 117 118 # Exception raising adjustments. 119 120 self.in_try_finally = False 121 self.in_try_except = False 122 123 # Invocation adjustments. 124 125 self.in_argument_list = False 126 127 # Attribute access and accessor counting. 128 129 self.attr_accesses = {} 130 self.attr_accessors = {} 131 132 # Special variable usage. 133 134 self.temp_usage = {} 135 136 # Initialise some data used for attribute access generation. 137 138 self.init_substitutions() 139 140 def __repr__(self): 141 return "TranslatedModule(%r, %r)" % (self.name, self.importer) 142 143 def translate(self, filename, output_filename): 144 145 """ 146 Parse the file having the given 'filename', writing the translation to 147 the given 'output_filename'. 148 """ 149 150 self.parse_file(filename) 151 152 # Collect function namespaces for separate processing. 153 154 self.record_namespaces(self.astnode) 155 156 # Reset the lambda naming (in order to obtain the same names again) and 157 # translate the program. 158 159 self.reset_lambdas() 160 161 self.out_toplevel = self.out = open(output_filename, "w") 162 try: 163 self.start_output() 164 165 # Process namespaces, writing the translation. 166 167 for path, node in self.namespaces: 168 self.process_namespace(path, node) 169 170 # Process the module namespace including class namespaces. 171 172 self.process_namespace([], self.astnode) 173 174 finally: 175 self.out.close() 176 177 def have_object(self): 178 179 "Return whether a namespace is a recorded object." 180 181 return self.importer.objects.get(self.get_namespace_path()) 182 183 def get_builtin_class(self, name): 184 185 "Return a reference to the actual object providing 'name'." 186 187 return self.importer.get_object(get_builtin_class(name)) 188 189 def is_method(self, path): 190 191 "Return whether 'path' is a method." 192 193 class_name, method_name = path.rsplit(".", 1) 194 return self.importer.classes.has_key(class_name) and class_name or None 195 196 def in_method(self): 197 198 "Return whether the current namespace provides a method." 199 200 return self.in_function and self.is_method(self.get_namespace_path()) 201 202 # Namespace recording. 203 204 def record_namespaces(self, node): 205 206 "Process the program structure 'node', recording namespaces." 207 208 for n in node.getChildNodes(): 209 self.record_namespaces_in_node(n) 210 211 def record_namespaces_in_node(self, node): 212 213 "Process the program structure 'node', recording namespaces." 214 215 # Function namespaces within modules, classes and other functions. 216 # Functions appearing within conditional statements are given arbitrary 217 # names. 218 219 if isinstance(node, compiler.ast.Function): 220 self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name) 221 222 elif isinstance(node, compiler.ast.Lambda): 223 self.record_function_node(node, self.get_lambda_name()) 224 225 # Classes are visited, but may be ignored if inside functions. 226 227 elif isinstance(node, compiler.ast.Class): 228 self.enter_namespace(node.name) 229 if self.have_object(): 230 self.record_namespaces(node) 231 self.exit_namespace() 232 233 # Conditional nodes are tracked so that function definitions may be 234 # handled. Since "for" loops are converted to "while" loops, they are 235 # included here. 236 237 elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)): 238 in_conditional = self.in_conditional 239 self.in_conditional = True 240 self.record_namespaces(node) 241 self.in_conditional = in_conditional 242 243 # All other nodes are processed depth-first. 244 245 else: 246 self.record_namespaces(node) 247 248 def record_function_node(self, n, name): 249 250 """ 251 Record the given function, lambda, if expression or list comprehension 252 node 'n' with the given 'name'. 253 """ 254 255 self.in_function = True 256 self.enter_namespace(name) 257 258 if self.have_object(): 259 260 # Record the namespace path and the node itself. 261 262 self.namespaces.append((self.namespace_path[:], n)) 263 self.record_namespaces_in_node(n.code) 264 265 self.exit_namespace() 266 self.in_function = False 267 268 # Constant referencing. 269 270 def get_literal_instance(self, n, name=None): 271 272 """ 273 For node 'n', return a reference for the type of the given 'name', or if 274 'name' is not specified, deduce the type from the value. 275 """ 276 277 # Handle stray None constants (Sliceobj seems to produce them). 278 279 if name is None and n.value is None: 280 return self.process_name_node(compiler.ast.Name("None")) 281 282 if name in ("dict", "list", "tuple"): 283 ref = self.get_builtin_class(name) 284 return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef) 285 else: 286 value, typename, encoding = self.get_constant_value(n.value, n.literals) 287 ref = self.get_builtin_class(typename) 288 value_type = ref.get_origin() 289 290 path = self.get_namespace_path() 291 292 # Obtain the local numbering of the constant and thus the 293 # locally-qualified name. 294 295 local_number = self.importer.all_constants[path][(value, value_type, encoding)] 296 constant_name = "$c%d" % local_number 297 objpath = self.get_object_path(constant_name) 298 299 # Obtain the unique identifier for the constant. 300 301 number = self.optimiser.constant_numbers[objpath] 302 return TrConstantValueRef(constant_name, ref.instance_of(), value, number) 303 304 # Namespace translation. 305 306 def process_namespace(self, path, node): 307 308 """ 309 Process the namespace for the given 'path' defined by the given 'node'. 310 """ 311 312 self.namespace_path = path 313 314 if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)): 315 self.in_function = True 316 self.process_function_body_node(node) 317 else: 318 self.in_function = False 319 self.function_target = 0 320 self.max_function_targets = 0 321 self.start_module() 322 self.process_structure(node) 323 self.end_module() 324 325 def process_structure(self, node): 326 327 "Process the given 'node' or result." 328 329 # Handle processing requests on results. 330 331 if isinstance(node, Result): 332 return node 333 334 # Handle processing requests on nodes. 335 336 else: 337 l = CommonModule.process_structure(self, node) 338 339 # Return indications of return statement usage. 340 341 if l and isinstance(l[-1], ReturnRef): 342 return l[-1] 343 else: 344 return None 345 346 def process_structure_node(self, n): 347 348 "Process the individual node 'n'." 349 350 # Plain statements emit their expressions. 351 352 if isinstance(n, compiler.ast.Discard): 353 expr = self.process_structure_node(n.expr) 354 self.statement(expr) 355 356 # Module import declarations. 357 358 elif isinstance(n, compiler.ast.From): 359 self.process_from_node(n) 360 361 # Nodes using operator module functions. 362 363 elif isinstance(n, compiler.ast.Operator): 364 return self.process_operator_node(n) 365 366 elif isinstance(n, compiler.ast.AugAssign): 367 self.process_augassign_node(n) 368 369 elif isinstance(n, compiler.ast.Compare): 370 return self.process_compare_node(n) 371 372 elif isinstance(n, compiler.ast.Slice): 373 return self.process_slice_node(n) 374 375 elif isinstance(n, compiler.ast.Sliceobj): 376 return self.process_sliceobj_node(n) 377 378 elif isinstance(n, compiler.ast.Subscript): 379 return self.process_subscript_node(n) 380 381 # Classes are visited, but may be ignored if inside functions. 382 383 elif isinstance(n, compiler.ast.Class): 384 self.process_class_node(n) 385 386 # Functions within namespaces have any dynamic defaults initialised. 387 388 elif isinstance(n, compiler.ast.Function): 389 self.process_function_node(n) 390 391 # Lambdas are replaced with references to separately-generated 392 # functions. 393 394 elif isinstance(n, compiler.ast.Lambda): 395 return self.process_lambda_node(n) 396 397 # Assignments. 398 399 elif isinstance(n, compiler.ast.Assign): 400 401 # Handle each assignment node. 402 403 for node in n.nodes: 404 self.process_assignment_node(node, n.expr) 405 406 # Accesses. 407 408 elif isinstance(n, compiler.ast.Getattr): 409 return self.process_attribute_access(n) 410 411 # Names. 412 413 elif isinstance(n, compiler.ast.Name): 414 return self.process_name_node(n) 415 416 # Loops and conditionals. 417 418 elif isinstance(n, compiler.ast.For): 419 self.process_for_node(n) 420 421 elif isinstance(n, compiler.ast.While): 422 self.process_while_node(n) 423 424 elif isinstance(n, compiler.ast.If): 425 self.process_if_node(n) 426 427 elif isinstance(n, (compiler.ast.And, compiler.ast.Or)): 428 return self.process_logical_node(n) 429 430 elif isinstance(n, compiler.ast.Not): 431 return self.process_not_node(n) 432 433 # Exception control-flow tracking. 434 435 elif isinstance(n, compiler.ast.TryExcept): 436 self.process_try_node(n) 437 438 elif isinstance(n, compiler.ast.TryFinally): 439 self.process_try_finally_node(n) 440 441 # Control-flow modification statements. 442 443 elif isinstance(n, compiler.ast.Break): 444 self.writestmt("break;") 445 446 elif isinstance(n, compiler.ast.Continue): 447 self.writestmt("continue;") 448 449 elif isinstance(n, compiler.ast.Raise): 450 self.process_raise_node(n) 451 452 elif isinstance(n, compiler.ast.Return): 453 return self.process_return_node(n) 454 455 # Print statements. 456 457 elif isinstance(n, (compiler.ast.Print, compiler.ast.Printnl)): 458 self.statement(self.process_print_node(n)) 459 460 # Invocations. 461 462 elif isinstance(n, compiler.ast.CallFunc): 463 return self.process_invocation_node(n) 464 465 elif isinstance(n, compiler.ast.Keyword): 466 return self.process_structure_node(n.expr) 467 468 # Constant usage. 469 470 elif isinstance(n, compiler.ast.Const): 471 return self.get_literal_instance(n) 472 473 elif isinstance(n, compiler.ast.Dict): 474 return self.get_literal_instance(n, "dict") 475 476 elif isinstance(n, compiler.ast.List): 477 return self.get_literal_instance(n, "list") 478 479 elif isinstance(n, compiler.ast.Tuple): 480 return self.get_literal_instance(n, "tuple") 481 482 # All other nodes are processed depth-first. 483 484 else: 485 return self.process_structure(n) 486 487 def process_assignment_node(self, n, expr): 488 489 "Process the individual node 'n' to be assigned the contents of 'expr'." 490 491 # Names and attributes are assigned the entire expression. 492 493 if isinstance(n, compiler.ast.AssName): 494 name_ref = self.process_name_node(n, self.process_structure_node(expr)) 495 self.statement(name_ref) 496 497 # Employ guards after assignments if required. 498 499 if expr and name_ref.is_name(): 500 self.generate_guard(name_ref.name) 501 502 elif isinstance(n, compiler.ast.AssAttr): 503 in_assignment = self.in_assignment 504 self.in_assignment = self.process_structure_node(expr) 505 self.statement(self.process_attribute_access(n)) 506 self.in_assignment = in_assignment 507 508 # Lists and tuples are matched against the expression and their 509 # items assigned to expression items. 510 511 elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)): 512 self.process_assignment_node_items(n, expr) 513 514 # Slices and subscripts are permitted within assignment nodes. 515 516 elif isinstance(n, compiler.ast.Slice): 517 self.statement(self.process_slice_node(n, expr)) 518 519 elif isinstance(n, compiler.ast.Subscript): 520 self.statement(self.process_subscript_node(n, expr)) 521 522 def process_attribute_access(self, n): 523 524 "Process the given attribute access node 'n'." 525 526 # Obtain any completed chain and return the reference to it. 527 528 attr_expr = self.process_attribute_chain(n) 529 if self.have_access_expression(n): 530 return attr_expr 531 532 # Where the start of the chain of attributes has been reached, process 533 # the complete access. 534 535 name_ref = attr_expr and attr_expr.is_name() and attr_expr 536 name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref) or None 537 538 location = self.get_access_location(name, self.attrs) 539 refs = self.get_referenced_attributes(location) 540 541 # Generate access instructions. 542 543 subs = { 544 "<expr>" : attr_expr, 545 "<name>" : attr_expr, 546 "<assexpr>" : self.in_assignment, 547 } 548 549 subs.update(self.temp_subs) 550 subs.update(self.op_subs) 551 552 output = [] 553 substituted = set() 554 555 # The context set or retrieved will be that used by any enclosing 556 # invocation. 557 558 context_index = self.function_target - 1 559 context_identity = None 560 context_identity_verified = False 561 final_identity = None 562 563 # Obtain encoded versions of each instruction, accumulating temporary 564 # variables. 565 566 for instruction in self.deducer.access_instructions[location]: 567 568 # Intercept a special instruction identifying the context. 569 570 if instruction[0] in ("<context_identity>", "<context_identity_verified>"): 571 context_identity, _substituted = encode_access_instruction_arg(instruction[1], subs, instruction[0], context_index) 572 context_identity_verified = instruction[0] == "<context_identity_verified>" 573 continue 574 575 # Intercept a special instruction identifying the target. The value 576 # is not encoded since it is used internally. 577 578 elif instruction[0] == "<final_identity>": 579 final_identity = instruction[1] 580 continue 581 582 # Collect the encoded instruction, noting any temporary variables 583 # required by it. 584 585 encoded, _substituted = encode_access_instruction(instruction, subs, context_index) 586 output.append(encoded) 587 substituted.update(_substituted) 588 589 # Record temporary name usage. 590 591 for sub in substituted: 592 if self.temp_subs.has_key(sub): 593 self.record_temp(self.temp_subs[sub]) 594 595 # Get full final identity details. 596 597 if final_identity and not refs: 598 ref = self.importer.identify(final_identity) 599 refs = [ref] 600 601 del self.attrs[0] 602 return AttrResult(output, refs, location, context_identity, context_identity_verified) 603 604 def init_substitutions(self): 605 606 """ 607 Initialise substitutions, defining temporary variable mappings, some of 608 which are also used as substitutions, together with operation mappings 609 used as substitutions in instructions defined by the optimiser. 610 """ 611 612 self.temp_subs = { 613 614 # Substitutions used by instructions. 615 616 "<private_context>" : "__tmp_private_context", 617 "<accessor>" : "__tmp_value", 618 "<target_accessor>" : "__tmp_target_value", 619 620 # Mappings to be replaced by those given below. 621 622 "<context>" : "__tmp_contexts", 623 "<test_context_revert>" : "__tmp_contexts", 624 "<test_context_static>" : "__tmp_contexts", 625 "<set_context>" : "__tmp_contexts", 626 "<set_private_context>" : "__tmp_private_context", 627 "<set_accessor>" : "__tmp_value", 628 "<set_target_accessor>" : "__tmp_target_value", 629 } 630 631 self.op_subs = { 632 "<context>" : "__get_context", 633 "<test_context_revert>" : "__test_context_revert", 634 "<test_context_static>" : "__test_context_static", 635 "<set_context>" : "__set_context", 636 "<set_private_context>" : "__set_private_context", 637 "<set_accessor>" : "__set_accessor", 638 "<set_target_accessor>" : "__set_target_accessor", 639 } 640 641 def get_referenced_attributes(self, location): 642 643 """ 644 Convert 'location' to the form used by the deducer and retrieve any 645 identified attributes. 646 """ 647 648 # Determine whether any deduced references refer to the accessed 649 # attribute. 650 651 attrnames = location.attrnames 652 attrnames = attrnames and attrnames.split(".") 653 remaining = attrnames and len(attrnames) > 1 654 655 access_location = self.deducer.const_accesses.get(location) 656 657 if remaining and not access_location: 658 return [] 659 660 refs = [] 661 l = self.deducer.referenced_attrs.get(access_location or location) 662 if l: 663 for attrtype, objpath, attr in l: 664 refs.append(attr) 665 return refs 666 667 def get_referenced_attribute_invocations(self, location): 668 669 """ 670 Convert 'location' to the form used by the deducer and retrieve any 671 identified attribute invocation details. 672 """ 673 674 access_location = self.deducer.const_accesses.get(location) 675 return self.deducer.reference_invocations_unsuitable.get(access_location or location) 676 677 def get_accessor_kinds(self, location): 678 679 "Return the accessor kinds for 'location'." 680 681 return self.deducer.accessor_kinds.get(location) 682 683 def get_access_location(self, name, attrnames=None): 684 685 """ 686 Using the current namespace, the given 'name', and the 'attrnames' 687 employed in an access, return the access location. 688 """ 689 690 path = self.get_path_for_access() 691 692 # Get the location used by the deducer and optimiser and find any 693 # recorded access. 694 695 attrnames = attrnames and ".".join(self.attrs) 696 access_number = self.get_access_number(path, name, attrnames) 697 self.update_access_number(path, name, attrnames) 698 return AccessLocation(path, name, attrnames, access_number) 699 700 def get_access_number(self, path, name, attrnames): 701 access = name, attrnames 702 if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access): 703 return self.attr_accesses[path][access] 704 else: 705 return 0 706 707 def update_access_number(self, path, name, attrnames): 708 access = name, attrnames 709 if name: 710 init_item(self.attr_accesses, path, dict) 711 init_item(self.attr_accesses[path], access, lambda: 0) 712 self.attr_accesses[path][access] += 1 713 714 def get_accessor_location(self, name): 715 716 """ 717 Using the current namespace and the given 'name', return the accessor 718 location. 719 """ 720 721 path = self.get_path_for_access() 722 723 # Get the location used by the deducer and optimiser and find any 724 # recorded accessor. 725 726 version = self.get_accessor_number(path, name) 727 self.update_accessor_number(path, name) 728 return Location(path, name, None, version) 729 730 def get_accessor_number(self, path, name): 731 if self.attr_accessors.has_key(path) and self.attr_accessors[path].has_key(name): 732 return self.attr_accessors[path][name] 733 else: 734 return 0 735 736 def update_accessor_number(self, path, name): 737 if name: 738 init_item(self.attr_accessors, path, dict) 739 init_item(self.attr_accessors[path], name, lambda: 0) 740 self.attr_accessors[path][name] += 1 741 742 def process_class_node(self, n): 743 744 "Process the given class node 'n'." 745 746 class_name = self.get_object_path(n.name) 747 748 # Where a class is set conditionally or where the name may refer to 749 # different values, assign the name. 750 751 ref = self.importer.identify(class_name) 752 753 if not ref.static(): 754 self.process_assignment_for_object(n.name, 755 make_expression("__ATTRVALUE(&%s)" % encode_path(class_name))) 756 757 self.enter_namespace(n.name) 758 759 if self.have_object(): 760 self.write_comment("Class: %s" % class_name) 761 762 self.initialise_inherited_members(class_name) 763 764 self.process_structure(n) 765 self.write_comment("End class: %s" % class_name) 766 767 self.exit_namespace() 768 769 def initialise_inherited_members(self, class_name): 770 771 "Initialise members of 'class_name' inherited from its ancestors." 772 773 for name, path in self.importer.all_class_attrs[class_name].items(): 774 target = "%s.%s" % (class_name, name) 775 776 # Ignore attributes with definitions. 777 778 ref = self.importer.identify(target) 779 if ref: 780 continue 781 782 # Ignore special type attributes. 783 784 if is_type_attribute(name): 785 continue 786 787 # Reference inherited attributes. 788 789 ref = self.importer.identify(path) 790 if ref and not ref.static(): 791 parent, attrname = path.rsplit(".", 1) 792 793 self.writestmt("__store_via_object(&%s, %s, __load_via_object(&%s, %s));" % ( 794 encode_path(class_name), name, 795 encode_path(parent), attrname 796 )) 797 798 def process_from_node(self, n): 799 800 "Process the given node 'n', importing from another module." 801 802 path = self.get_namespace_path() 803 804 # Attempt to obtain the referenced objects. 805 806 for name, alias in n.names: 807 if name == "*": 808 raise InspectError("Only explicitly specified names can be imported from modules.", path, n) 809 810 # Obtain the path of the assigned name. 811 812 objpath = self.get_object_path(alias or name) 813 814 # Obtain the identity of the name. 815 816 ref = self.importer.identify(objpath) 817 818 # Where the name is not static, assign the value. 819 820 if ref and not ref.static() and ref.get_name(): 821 self.writestmt("%s;" % 822 TrResolvedNameRef(alias or name, Reference("<var>", None, objpath), 823 expr=TrResolvedNameRef(name, ref))) 824 825 def process_function_body_node(self, n): 826 827 """ 828 Process the given function, lambda, if expression or list comprehension 829 node 'n', generating the body. 830 """ 831 832 function_name = self.get_namespace_path() 833 self.start_function(function_name) 834 835 # Process the function body. 836 837 in_conditional = self.in_conditional 838 self.in_conditional = False 839 self.function_target = 0 840 self.max_function_targets = 0 841 842 # Volatile locals for exception handling. 843 844 self.volatile_locals = set() 845 846 # Process any guards defined for the parameters. 847 848 for name in self.importer.function_parameters.get(function_name): 849 self.generate_guard(name) 850 851 # Also support self in methods, since some mix-in methods may only work 852 # with certain descendant classes. 853 854 if self.in_method(): 855 self.generate_guard("self") 856 857 # Make assignments for .name entries in the parameters, provided this is 858 # a method. 859 860 if self.in_method(): 861 for name in self.importer.function_attr_initialisers.get(function_name) or []: 862 self.process_assignment_node( 863 compiler.ast.AssAttr(compiler.ast.Name("self"), name, "OP_ASSIGN"), 864 compiler.ast.Name(name)) 865 866 # Produce the body and any additional return statement. 867 868 expr = self.process_structure_node(n.code) or \ 869 self.in_method() and \ 870 function_name.rsplit(".", 1)[-1] == "__init__" and \ 871 TrResolvedNameRef("self", self.importer.function_locals[function_name]["self"]) or \ 872 PredefinedConstantRef("None") 873 874 if not isinstance(expr, ReturnRef): 875 self.writestmt("return %s;" % expr) 876 877 self.in_conditional = in_conditional 878 879 self.end_function(function_name) 880 881 def generate_guard(self, name): 882 883 """ 884 Get the accessor details for 'name', found in the current namespace, and 885 generate any guards defined for it. 886 """ 887 888 # Obtain the location, keeping track of assignment versions. 889 890 location = self.get_accessor_location(name) 891 test = self.deducer.accessor_guard_tests.get(location) 892 893 # Generate any guard from the deduced information. 894 895 if test: 896 guard, guard_type = test 897 898 if guard == "specific": 899 ref = first(self.deducer.accessor_all_types[location]) 900 argstr = "&%s" % encode_path(ref.get_origin()) 901 elif guard == "common": 902 ref = first(self.deducer.accessor_all_general_types[location]) 903 argstr = encode_path(encode_type_attribute(ref.get_origin())) 904 else: 905 return 906 907 # Write a test that raises a TypeError upon failure. 908 909 self.writestmt("if (!__test_%s_%s(__VALUE(%s), %s)) __raise_type_error();" % ( 910 guard, guard_type, encode_path(name), argstr)) 911 912 def process_function_node(self, n): 913 914 """ 915 Process the given function, lambda, if expression or list comprehension 916 node 'n', generating any initialisation statements. 917 """ 918 919 # Where a function is declared conditionally, use a separate name for 920 # the definition, and assign the definition to the stated name. 921 922 original_name = n.name 923 924 if self.in_conditional or self.in_function: 925 name = self.get_lambda_name() 926 else: 927 name = n.name 928 929 objpath = self.get_object_path(name) 930 931 # Obtain details of the defaults. 932 933 defaults = self.process_function_defaults(n, name, objpath) 934 if defaults: 935 for default in defaults: 936 self.writeline("%s;" % default) 937 938 # Where a function is set conditionally or where the name may refer to 939 # different values, assign the name. 940 941 ref = self.importer.identify(objpath) 942 943 if self.in_conditional or self.in_function: 944 self.process_assignment_for_object(original_name, compiler.ast.Name(name)) 945 elif not ref.static(): 946 context = self.is_method(objpath) 947 948 self.process_assignment_for_object(original_name, 949 make_expression("__ATTRVALUE(&%s)" % encode_path(objpath))) 950 951 def process_function_defaults(self, n, name, objpath, instance_name=None): 952 953 """ 954 Process the given function or lambda node 'n', initialising defaults 955 that are dynamically set. The given 'name' indicates the name of the 956 function. The given 'objpath' indicates the origin of the function. 957 The given 'instance_name' indicates the name of any separate instance 958 of the function created to hold the defaults. 959 960 Return a list of operations setting defaults on a function instance. 961 """ 962 963 function_name = self.get_object_path(name) 964 function_defaults = self.importer.function_defaults.get(function_name) 965 if not function_defaults: 966 return None 967 968 # Determine whether any unidentified defaults are involved. 969 970 for argname, default in function_defaults: 971 if not default.static(): 972 break 973 else: 974 return None 975 976 # Handle bound methods. 977 978 if not instance_name: 979 instance_name = "&%s" % encode_path(objpath) 980 else: 981 instance_name = "__VALUE(%s)" % instance_name 982 983 # Where defaults are involved but cannot be identified, obtain a new 984 # instance of the lambda and populate the defaults. 985 986 defaults = [] 987 988 # Join the original defaults with the inspected defaults. 989 990 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 991 992 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 993 994 # Obtain any reference for the default. 995 996 if original: 997 argname, default = original 998 name_ref = self.process_structure_node(default) 999 elif inspected: 1000 argname, default = inspected 1001 name_ref = TrResolvedNameRef(argname, default) 1002 else: 1003 continue 1004 1005 # Generate default initialisers except when constants are employed. 1006 # Constants should be used when populating the function structures. 1007 1008 if name_ref and not isinstance(name_ref, TrConstantValueRef): 1009 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref)) 1010 1011 return defaults 1012 1013 def process_if_node(self, n): 1014 1015 """ 1016 Process the given "if" node 'n'. 1017 """ 1018 1019 first = True 1020 for test, body in n.tests: 1021 test_ref = self.process_structure_node(test) 1022 self.start_if(first, test_ref) 1023 1024 in_conditional = self.in_conditional 1025 self.in_conditional = True 1026 self.process_structure_node(body) 1027 self.in_conditional = in_conditional 1028 1029 self.end_if() 1030 first = False 1031 1032 if n.else_: 1033 self.start_else() 1034 self.process_structure_node(n.else_) 1035 self.end_else() 1036 1037 print >>self.out 1038 1039 def process_invocation_node(self, n): 1040 1041 "Process the given invocation node 'n'." 1042 1043 # Any invocations in the expression will store target details in a 1044 # different location. 1045 1046 self.next_target() 1047 1048 in_argument_list = self.in_argument_list 1049 self.in_argument_list = False 1050 1051 # Process the expression. 1052 1053 expr = self.process_structure_node(n.node) 1054 1055 # Reference the current target again. 1056 1057 self.in_argument_list = in_argument_list 1058 self.function_target -= 1 1059 1060 # Obtain details of the invocation expression. 1061 1062 objpath = expr.get_origin() 1063 location = expr.access_location() 1064 refs = expr.references() 1065 1066 # Identified target details. 1067 1068 target = None 1069 target_structure = None 1070 1071 # Specific function target information. 1072 1073 function = None 1074 1075 # Instantiation involvement. 1076 1077 instantiation = False 1078 literal_instantiation = False 1079 1080 # Invocation requirements. 1081 1082 context_required = True 1083 have_access_context = isinstance(expr, AttrResult) 1084 context_identity = have_access_context and expr.context() 1085 context_verified = have_access_context and expr.context_verified() 1086 parameters = None 1087 num_parameters = None 1088 num_defaults = None 1089 1090 # Obtain details of the callable and of its parameters. 1091 1092 # Literals may be instantiated specially. 1093 1094 if expr.is_name() and expr.name.startswith("$L") and objpath: 1095 instantiation = literal_instantiation = objpath 1096 target = encode_literal_instantiator(objpath) 1097 context_required = False 1098 1099 # Identified targets employ function pointers directly. 1100 1101 elif objpath: 1102 parameters = self.importer.function_parameters.get(objpath) 1103 function_defaults = self.importer.function_defaults.get(objpath) 1104 num_parameters = parameters and len(parameters) or 0 1105 num_defaults = function_defaults and len(function_defaults) or 0 1106 1107 # Class invocation involves instantiators. 1108 1109 if expr.has_kind("<class>"): 1110 instantiation = objpath 1111 target = encode_instantiator_pointer(objpath) 1112 init_ref = self.importer.all_class_attrs[objpath]["__init__"] 1113 target_structure = "&%s" % encode_path(init_ref) 1114 context_required = False 1115 1116 # Only plain functions and bound methods employ function pointers. 1117 1118 elif expr.has_kind("<function>"): 1119 function = objpath 1120 1121 # Test for functions and methods. 1122 1123 context_required = self.is_method(objpath) 1124 1125 accessor_kinds = location and self.get_accessor_kinds(location) 1126 1127 instance_accessor = accessor_kinds and \ 1128 len(accessor_kinds) == 1 and \ 1129 first(accessor_kinds) == "<instance>" 1130 1131 # Only identify certain bound methods or functions. 1132 1133 if not context_required or instance_accessor: 1134 target = encode_function_pointer(objpath) 1135 1136 # Access bound method defaults even if it is not clear whether 1137 # the accessor is appropriate. 1138 1139 target_structure = "&%s" % encode_path(objpath) 1140 1141 # Other targets are retrieved at run-time. 1142 1143 else: 1144 if location: 1145 attrnames = location.attrnames 1146 attrname = attrnames and attrnames.rsplit(".", 1)[-1] 1147 1148 # Determine any common aspects of any attribute. 1149 1150 if attrname: 1151 all_params = set() 1152 all_defaults = set() 1153 min_params = set() 1154 max_params = set() 1155 refs = set() 1156 1157 # Obtain parameters and defaults for each possible target. 1158 1159 for ref in self.get_attributes_for_attrname(attrname): 1160 origin = ref.get_origin() 1161 params = self.importer.function_parameters.get(origin) 1162 1163 defaults = self.importer.function_defaults.get(origin) 1164 if defaults is not None: 1165 all_defaults.add(tuple(defaults)) 1166 1167 if params is not None: 1168 all_params.add(tuple(params)) 1169 min_params.add(len(params) - (defaults and len(defaults) or 0)) 1170 max_params.add(len(params)) 1171 refs.add(ref) 1172 else: 1173 refs = set() 1174 break 1175 1176 # Where the parameters and defaults are always the same, 1177 # permit populating them in advance. 1178 1179 if refs: 1180 if self.uses_keyword_arguments(n): 1181 if len(all_params) == 1 and (not all_defaults or len(all_defaults) == 1): 1182 parameters = first(all_params) 1183 function_defaults = all_defaults and first(all_defaults) or [] 1184 num_parameters = parameters and len(parameters) or 0 1185 num_defaults = function_defaults and len(function_defaults) or 0 1186 else: 1187 if len(min_params) == 1 and len(max_params) == 1: 1188 num_parameters = first(max_params) 1189 num_defaults = first(max_params) - first(min_params) 1190 1191 # Some information about the target may be available and be used to 1192 # provide warnings about argument compatibility. 1193 1194 if self.importer.give_warning("args"): 1195 unsuitable = self.get_referenced_attribute_invocations(location) 1196 1197 if unsuitable: 1198 for ref in unsuitable: 1199 _objpath = ref.get_origin() 1200 print >>sys.stderr, \ 1201 "In %s, at line %d, inappropriate number of " \ 1202 "arguments given. Need %d arguments to call %s." % ( 1203 self.get_namespace_path(), n.lineno, 1204 len(self.importer.function_parameters[_objpath]), 1205 _objpath) 1206 1207 # Determine any readily-accessible target identity. 1208 1209 target_named = expr.is_name() and str(expr) or None 1210 target_stored = "__tmp_targets[%d]" % self.function_target 1211 1212 target_identity = target or target_named 1213 target_var = target_identity or target_stored 1214 context_var = target_named or target_stored 1215 1216 if not target_identity: 1217 self.record_temp("__tmp_targets") 1218 1219 if context_identity: 1220 if context_identity.startswith("__tmp_contexts"): 1221 self.record_temp("__tmp_contexts") 1222 1223 # Arguments are presented in a temporary frame array with any context 1224 # always being the first argument. Where it would be unused, it may be 1225 # set to null. 1226 1227 known_parameters = num_parameters is not None 1228 1229 if context_required: 1230 if have_access_context: 1231 args = [context_identity] 1232 else: 1233 args = ["__CONTEXT_AS_VALUE(%s)" % context_var] 1234 else: 1235 args = ["__NULL"] 1236 1237 # Complete the array with null values, permitting tests for a complete 1238 # set of arguments. 1239 1240 args += [None] * (num_parameters is None and len(n.args) or num_parameters is not None and num_parameters or 0) 1241 kwcodes = [] 1242 kwargs = [] 1243 1244 # Any invocations in the arguments will store target details in a 1245 # different location. 1246 1247 function_target = self.function_target 1248 1249 if not target_identity: 1250 self.next_target() 1251 1252 in_argument_list = self.in_argument_list 1253 self.in_argument_list = True 1254 1255 for i, arg in enumerate(n.args): 1256 argexpr = self.process_structure_node(arg) 1257 1258 # Store a keyword argument, either in the argument list or 1259 # in a separate keyword argument list for subsequent lookup. 1260 1261 if isinstance(arg, compiler.ast.Keyword): 1262 1263 # With knowledge of the target, store the keyword 1264 # argument directly. 1265 1266 if parameters: 1267 try: 1268 argnum = parameters.index(arg.name) 1269 except ValueError: 1270 raise TranslateError("Argument %s is not recognised." % arg.name, 1271 self.get_namespace_path(), n) 1272 args[argnum+1] = str(argexpr) 1273 1274 # Otherwise, store the details in a separate collection. 1275 1276 else: 1277 kwargs.append(str(argexpr)) 1278 kwcodes.append("{%s, %s}" % ( 1279 encode_ppos(arg.name), encode_pcode(arg.name))) 1280 1281 # Store non-keyword arguments in the argument list, rejecting 1282 # superfluous arguments. 1283 1284 else: 1285 try: 1286 args[i+1] = str(argexpr) 1287 except IndexError: 1288 raise TranslateError("Too many arguments specified.", 1289 self.get_namespace_path(), n) 1290 1291 # Reference the current target again. 1292 1293 self.in_argument_list = in_argument_list 1294 1295 if not self.in_argument_list: 1296 self.function_target = function_target 1297 1298 # Defaults are added to the frame where arguments are missing. 1299 1300 if parameters and function_defaults is not None: 1301 1302 # Visit each default and set any missing arguments. Where keyword 1303 # arguments have been used, the defaults must be inspected and, if 1304 # necessary, inserted into gaps in the argument list. 1305 1306 for i, (argname, default) in enumerate(function_defaults): 1307 argnum = parameters.index(argname) 1308 if not args[argnum+1]: 1309 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i) 1310 1311 elif known_parameters: 1312 1313 # No specific parameter details are provided, but no keyword 1314 # arguments are used. Thus, defaults can be supplied using position 1315 # information only. 1316 1317 i = len(n.args) 1318 pos = i - (num_parameters - num_defaults) 1319 while i < num_parameters: 1320 args[i+1] = "__GETDEFAULT(%s.value, %d)" % (target_var, pos) 1321 i += 1 1322 pos += 1 1323 1324 # Test for missing arguments. 1325 1326 if None in args: 1327 raise TranslateError("Not all arguments supplied.", 1328 self.get_namespace_path(), n) 1329 1330 # Encode the arguments. 1331 1332 # Where literal instantiation is occurring, add an argument indicating 1333 # the number of values. The context is excluded. 1334 1335 if literal_instantiation: 1336 argstr = "%d, %s" % (len(args) - 1, ", ".join(args[1:])) 1337 else: 1338 argstr = ", ".join(args) 1339 1340 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 1341 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 1342 1343 # First, the invocation expression is presented. 1344 1345 stages = [] 1346 1347 # Without a known specific callable, the expression provides the target. 1348 1349 if not target or context_required: 1350 1351 # The context is set in the expression. 1352 1353 if target and not target_named: 1354 1355 # Test whether the expression provides anything. 1356 1357 if expr: 1358 stages.append(str(expr)) 1359 1360 elif not target_identity: 1361 stages.append("%s = %s" % (target_var, expr)) 1362 1363 # Any specific callable is then obtained for invocation. 1364 1365 if target: 1366 stages.append(target) 1367 1368 # Methods accessed via unidentified accessors are obtained for 1369 # invocation. 1370 1371 elif function: 1372 if context_required: 1373 if have_access_context: 1374 if context_verified: 1375 stages.append("__get_function_member(%s)" % target_var) 1376 else: 1377 stages.append("__get_function(%s, %s)" % ( 1378 context_identity, target_var)) 1379 else: 1380 stages.append("__get_function(__CONTEXT_AS_VALUE(%s), %s)" % ( 1381 context_var, target_var)) 1382 else: 1383 stages.append("_get_function_member(%s)" % target_var) 1384 1385 # With known parameters, the target can be tested. 1386 1387 elif known_parameters: 1388 context_arg = context_required and args[0] or "__NULL" 1389 if self.always_callable(refs): 1390 if context_verified: 1391 stages.append("__get_function_member(%s)" % target_var) 1392 else: 1393 stages.append("__get_function(%s, %s)" % (context_arg, target_var)) 1394 else: 1395 stages.append("__check_and_get_function(%s, %s)" % (context_arg, target_var)) 1396 1397 # With a known target, the function is obtained directly and called. 1398 # By putting the invocation at the end of the final element in the 1399 # instruction sequence (the stages), the result becomes the result of 1400 # the sequence. Moreover, the parameters become part of the sequence 1401 # and thereby participate in a guaranteed evaluation order. 1402 1403 if target or function or known_parameters: 1404 stages[-1] += "(%s)" % argstr 1405 if instantiation: 1406 return InstantiationResult(instantiation, stages) 1407 else: 1408 return InvocationResult(stages) 1409 1410 # With unknown targets, the generic invocation function is applied to 1411 # the callable and argument collections. 1412 1413 else: 1414 stages.append("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % ( 1415 target_var, 1416 self.always_callable(refs) and 1 or 0, 1417 len(kwargs), kwcodestr, kwargstr, 1418 len(args), "__ARGS(%s)" % argstr)) 1419 return InvocationResult(stages) 1420 1421 def next_target(self): 1422 1423 "Allocate the next function target storage." 1424 1425 self.function_target += 1 1426 self.max_function_targets = max(self.function_target, self.max_function_targets) 1427 1428 def always_callable(self, refs): 1429 1430 "Determine whether all 'refs' are callable." 1431 1432 if not refs: 1433 return False 1434 1435 for ref in refs: 1436 if not ref.has_kind("<function>") and not self.importer.get_attributes(ref, "__fn__"): 1437 return False 1438 1439 return True 1440 1441 def need_default_arguments(self, objpath, nargs): 1442 1443 """ 1444 Return whether any default arguments are needed when invoking the object 1445 given by 'objpath'. 1446 """ 1447 1448 parameters = self.importer.function_parameters.get(objpath) 1449 return nargs < len(parameters) 1450 1451 def uses_keyword_arguments(self, n): 1452 1453 "Return whether invocation node 'n' uses keyword arguments." 1454 1455 for arg in enumerate(n.args): 1456 if isinstance(arg, compiler.ast.Keyword): 1457 return True 1458 1459 return False 1460 1461 def get_attributes_for_attrname(self, attrname): 1462 1463 "Return a set of all attributes exposed by 'attrname'." 1464 1465 usage = [(attrname, True, False)] 1466 class_types = self.deducer.get_class_types_for_usage(usage) 1467 instance_types = self.deducer.get_instance_types_for_usage(usage) 1468 module_types = self.deducer.get_module_types_for_usage(usage) 1469 attrs = set() 1470 1471 for ref in combine_types(class_types, instance_types, module_types): 1472 attrs.update(self.importer.get_attributes(ref, attrname)) 1473 1474 return attrs 1475 1476 def process_lambda_node(self, n): 1477 1478 "Process the given lambda node 'n'." 1479 1480 name = self.get_lambda_name() 1481 function_name = self.get_object_path(name) 1482 1483 defaults = self.process_function_defaults(n, name, function_name, "__tmp_value") 1484 1485 # Without defaults, produce an attribute referring to the function. 1486 1487 if not defaults: 1488 return make_expression("__ATTRVALUE(&%s)" % encode_path(function_name)) 1489 1490 # With defaults, copy the function structure and set the defaults on the 1491 # copy. 1492 1493 else: 1494 self.record_temp("__tmp_value") 1495 return make_expression("(__tmp_value = __ATTRVALUE(__COPY(&%s, sizeof(%s))), %s, __tmp_value)" % ( 1496 encode_path(function_name), 1497 encode_symbol("obj", function_name), 1498 ", ".join(defaults))) 1499 1500 def process_logical_node(self, n): 1501 1502 "Process the given operator node 'n'." 1503 1504 self.record_temp("__tmp_result") 1505 1506 conjunction = isinstance(n, compiler.ast.And) 1507 results = [] 1508 1509 for node in n.nodes: 1510 results.append(self.process_structure_node(node)) 1511 1512 return LogicalOperationResult(results, conjunction) 1513 1514 def process_name_node(self, n, expr=None): 1515 1516 "Process the given name node 'n' with the optional assignment 'expr'." 1517 1518 # Determine whether the name refers to a static external entity. 1519 1520 if n.name in predefined_constants: 1521 return PredefinedConstantRef(n.name, expr) 1522 1523 # Convert literal references, operator function names, and print 1524 # function names to references. 1525 1526 elif n.name.startswith("$L") or n.name.startswith("$op") or \ 1527 n.name.startswith("$print"): 1528 1529 ref, paths = self.importer.get_module(self.name).special[n.name] 1530 return TrResolvedNameRef(n.name, ref) 1531 1532 # Get the appropriate name for the name reference, using the same method 1533 # as in the inspector. 1534 1535 path = self.get_namespace_path() 1536 objpath = self.get_object_path(n.name) 1537 1538 # Determine any assigned globals. 1539 1540 globals = self.importer.get_module(self.name).scope_globals.get(path) 1541 1542 # Explicitly declared globals. 1543 1544 if globals and n.name in globals: 1545 objpath = self.get_global_path(n.name) 1546 is_global = True 1547 1548 # Implicitly referenced globals in functions. 1549 1550 elif self.in_function: 1551 is_global = n.name not in self.importer.function_locals[path] 1552 1553 # Implicitly referenced globals elsewhere. 1554 1555 else: 1556 namespace = self.importer.identify(path) 1557 is_global = not self.importer.get_attributes(namespace, n.name) 1558 1559 # Get the static identity of the name. 1560 1561 ref = self.importer.identify(objpath) 1562 if ref and not ref.get_name(): 1563 ref = ref.alias(objpath) 1564 1565 # Obtain any resolved names for non-assignment names. 1566 1567 if not expr and not ref and self.in_function: 1568 locals = self.importer.function_locals.get(path) 1569 ref = locals and locals.get(n.name) 1570 1571 # Find any invocation or alias details. 1572 1573 name = self.get_name_for_tracking(n.name, is_global=is_global) 1574 location = not expr and self.get_access_location(name) or None 1575 1576 # Mark any local assignments as volatile in exception blocks. 1577 1578 if expr and self.in_function and not is_global and self.in_try_except: 1579 self.make_volatile(n.name) 1580 1581 # Qualified names are used for resolved static references or for 1582 # static namespace members. The reference should be configured to return 1583 # such names. 1584 1585 name_ref = TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, 1586 location=location) 1587 return not expr and self.get_aliases(name_ref) or name_ref 1588 1589 def get_aliases(self, name_ref): 1590 1591 "Return alias references for the given 'name_ref'." 1592 1593 location = name_ref.access_location() 1594 1595 refs = self.deducer.referenced_objects.get(location) 1596 refs = refs or self.deducer.accessor_all_types.get(location) 1597 return AliasResult(name_ref, refs or set(), location) 1598 1599 def make_volatile(self, name): 1600 1601 "Record 'name' as volatile in the current namespace." 1602 1603 self.volatile_locals.add(name) 1604 1605 def process_not_node(self, n): 1606 1607 "Process the given operator node 'n'." 1608 1609 return self.make_negation(self.process_structure_node(n.expr)) 1610 1611 def process_raise_node(self, n): 1612 1613 "Process the given raise node 'n'." 1614 1615 # NOTE: Determine which raise statement variants should be permitted. 1616 1617 if n.expr1: 1618 1619 # Names with accompanying arguments are treated like invocations. 1620 1621 if n.expr2: 1622 call = compiler.ast.CallFunc(n.expr1, [n.expr2]) 1623 exc = self.process_structure_node(call) 1624 self.writestmt("__Raise(%s);" % exc) 1625 1626 # Raise instances, testing the kind at run-time if necessary and 1627 # instantiating any non-instance. 1628 1629 else: 1630 exc = self.process_structure_node(n.expr1) 1631 1632 if isinstance(exc, TrInstanceRef): 1633 self.writestmt("__Raise(%s);" % exc) 1634 else: 1635 self.writestmt("__Raise(__ensure_instance(%s));" % exc) 1636 else: 1637 self.writestmt("__Throw(__tmp_exc);") 1638 1639 def process_return_node(self, n): 1640 1641 "Process the given return node 'n'." 1642 1643 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1644 if self.in_try_finally or self.in_try_except: 1645 self.writestmt("__Return(%s);" % expr) 1646 else: 1647 self.writestmt("return %s;" % expr) 1648 1649 return ReturnRef() 1650 1651 def process_try_node(self, n): 1652 1653 """ 1654 Process the given "try...except" node 'n'. 1655 """ 1656 1657 in_try_except = self.in_try_except 1658 self.in_try_except = True 1659 1660 # Use macros to implement exception handling. 1661 1662 self.writestmt("__Try") 1663 self.writeline("{") 1664 self.indent += 1 1665 self.process_structure_node(n.body) 1666 1667 # Put the else statement in another try block that handles any raised 1668 # exceptions and converts them to exceptions that will not be handled by 1669 # the main handling block. 1670 1671 if n.else_: 1672 self.writestmt("__Try") 1673 self.writeline("{") 1674 self.indent += 1 1675 self.process_structure_node(n.else_) 1676 self.indent -= 1 1677 self.writeline("}") 1678 self.writeline("__Catch (__tmp_exc)") 1679 self.writeline("{") 1680 self.indent += 1 1681 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1682 self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1683 self.indent -= 1 1684 self.writeline("}") 1685 1686 # Complete the try block and enter the finally block, if appropriate. 1687 1688 if self.in_try_finally: 1689 self.writestmt("__Complete;") 1690 1691 self.indent -= 1 1692 self.writeline("}") 1693 1694 self.in_try_except = in_try_except 1695 1696 # Handlers are tests within a common handler block. 1697 1698 self.writeline("__Catch (__tmp_exc)") 1699 self.writeline("{") 1700 self.indent += 1 1701 1702 # Introduce an if statement to handle the completion of a try block. 1703 1704 self.process_try_completion() 1705 1706 # Handle exceptions in else blocks converted to __RaiseElse, converting 1707 # them back to normal exceptions. 1708 1709 if n.else_: 1710 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1711 1712 # Exception handling. 1713 1714 for name, var, handler in n.handlers: 1715 1716 # Test for specific exceptions. 1717 1718 if name is not None: 1719 name_ref = self.process_structure_node(name) 1720 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref) 1721 else: 1722 self.writeline("else if (1)") 1723 1724 self.writeline("{") 1725 self.indent += 1 1726 1727 # Establish the local for the handler. 1728 1729 if var is not None: 1730 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) 1731 1732 if handler is not None: 1733 self.process_structure_node(handler) 1734 1735 self.indent -= 1 1736 self.writeline("}") 1737 1738 # Re-raise unhandled exceptions. 1739 1740 self.writeline("else __Throw(__tmp_exc);") 1741 1742 # End the handler block. 1743 1744 self.indent -= 1 1745 self.writeline("}") 1746 print >>self.out 1747 1748 def process_try_finally_node(self, n): 1749 1750 """ 1751 Process the given "try...finally" node 'n'. 1752 """ 1753 1754 in_try_finally = self.in_try_finally 1755 self.in_try_finally = True 1756 1757 # Use macros to implement exception handling. 1758 1759 self.writestmt("__Try") 1760 self.writeline("{") 1761 self.indent += 1 1762 self.process_structure_node(n.body) 1763 self.indent -= 1 1764 self.writeline("}") 1765 1766 self.in_try_finally = in_try_finally 1767 1768 # Finally clauses handle special exceptions. 1769 1770 self.writeline("__Catch (__tmp_exc)") 1771 self.writeline("{") 1772 self.indent += 1 1773 self.process_structure_node(n.final) 1774 1775 # Introduce an if statement to handle the completion of a try block. 1776 1777 self.process_try_completion() 1778 self.writeline("else __Throw(__tmp_exc);") 1779 1780 self.indent -= 1 1781 self.writeline("}") 1782 print >>self.out 1783 1784 def process_try_completion(self): 1785 1786 "Generate a test for the completion of a try block." 1787 1788 self.writestmt("if (__tmp_exc.completing)") 1789 self.writeline("{") 1790 self.indent += 1 1791 1792 # Do not return anything at the module level. 1793 1794 if self.get_namespace_path() != self.name: 1795 1796 # Only use the normal return statement if no surrounding try blocks 1797 # apply. 1798 1799 if not self.in_try_finally and not self.in_try_except: 1800 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1801 else: 1802 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1803 1804 self.indent -= 1 1805 self.writeline("}") 1806 1807 def process_while_node(self, n): 1808 1809 "Process the given while node 'n'." 1810 1811 self.writeline("while (1)") 1812 self.writeline("{") 1813 self.indent += 1 1814 test = self.process_structure_node(n.test) 1815 1816 # Emit the loop termination condition unless "while <true value>" is 1817 # indicated. 1818 1819 if not (isinstance(test, PredefinedConstantRef) and test.value): 1820 1821 # Emit a negated test of the continuation condition. 1822 1823 self.start_if(True, self.make_negation(test)) 1824 if n.else_: 1825 self.process_structure_node(n.else_) 1826 self.writestmt("break;") 1827 self.end_if() 1828 1829 in_conditional = self.in_conditional 1830 self.in_conditional = True 1831 self.process_structure_node(n.body) 1832 self.in_conditional = in_conditional 1833 1834 self.indent -= 1 1835 self.writeline("}") 1836 print >>self.out 1837 1838 # Special variable usage. 1839 1840 def get_temp_path(self): 1841 1842 """ 1843 Return the appropriate namespace path for temporary names in the current 1844 namespace. 1845 """ 1846 1847 if self.in_function: 1848 return self.get_namespace_path() 1849 else: 1850 return self.name 1851 1852 def record_temp(self, name): 1853 1854 """ 1855 Record the use of the temporary 'name' in the current namespace. At the 1856 class or module level, the temporary name is associated with the module, 1857 since the variable will then be allocated in the module's own main 1858 program. 1859 """ 1860 1861 path = self.get_temp_path() 1862 1863 init_item(self.temp_usage, path, list) 1864 self.temp_usage[path].append(name) 1865 1866 def remove_temps(self, names): 1867 1868 """ 1869 Remove 'names' from temporary storage allocations, each instance 1870 removing each request for storage. 1871 """ 1872 1873 path = self.get_temp_path() 1874 1875 for name in names: 1876 if self.uses_temp(path, name): 1877 self.temp_usage[path].remove(name) 1878 1879 def uses_temp(self, path, name): 1880 1881 """ 1882 Return whether the given namespace 'path' employs a temporary variable 1883 with the given 'name'. Note that 'path' should only be a module or a 1884 function or method, not a class. 1885 """ 1886 1887 return self.temp_usage.has_key(path) and name in self.temp_usage[path] 1888 1889 def make_negation(self, expr): 1890 1891 "Return a negated form of 'expr'." 1892 1893 result = NegationResult(expr) 1894 1895 # Negation discards the temporary results of its operand. 1896 1897 temps = expr.discards_temporary() 1898 if temps: 1899 self.remove_temps(temps) 1900 1901 return result 1902 1903 # Output generation. 1904 1905 def start_output(self): 1906 1907 "Write the declarations at the top of each source file." 1908 1909 print >>self.out, """\ 1910 #include "types.h" 1911 #include "exceptions.h" 1912 #include "ops.h" 1913 #include "progconsts.h" 1914 #include "progops.h" 1915 #include "progtypes.h" 1916 #include "main.h" 1917 """ 1918 1919 def start_unit(self): 1920 1921 "Record output within a generated function for later use." 1922 1923 self.out = StringIO() 1924 1925 def end_unit(self): 1926 1927 "Restore the output stream." 1928 1929 out = self.out 1930 self.out = self.out_toplevel 1931 return out 1932 1933 def flush_unit(self, name, out): 1934 1935 "Add declarations and generated code." 1936 1937 self.write_temporaries(name) 1938 print >>self.out 1939 out.seek(0) 1940 self.out.write(out.read()) 1941 1942 def start_module(self): 1943 1944 "Write the start of each module's main function." 1945 1946 print >>self.out, "void __main_%s()" % encode_path(self.name) 1947 print >>self.out, "{" 1948 self.indent += 1 1949 1950 # Define temporary variables, excluded from the module structure itself. 1951 1952 tempnames = [] 1953 1954 for n in self.importer.all_module_attrs[self.name]: 1955 if n.startswith("$t"): 1956 tempnames.append(encode_path(n)) 1957 1958 if tempnames: 1959 tempnames.sort() 1960 self.writeline("__attr %s;" % ", ".join(tempnames)) 1961 1962 self.start_unit() 1963 1964 def end_module(self): 1965 1966 "End each module by closing its main function." 1967 1968 out = self.end_unit() 1969 self.flush_unit(self.name, out) 1970 1971 self.indent -= 1 1972 print >>self.out, "}" 1973 1974 def start_function(self, name): 1975 1976 "Start the function having the given 'name'." 1977 1978 self.indent += 1 1979 1980 self.start_unit() 1981 1982 def end_function(self, name): 1983 1984 "End the function having the given 'name'." 1985 1986 out = self.end_unit() 1987 1988 # Write the signature at the top indentation level. 1989 1990 self.indent -= 1 1991 self.write_parameters(name) 1992 print >>self.out, "{" 1993 1994 # Obtain local names from parameters. 1995 1996 parameters = self.importer.function_parameters[name] 1997 locals = self.importer.function_locals[name].keys() 1998 names = [] 1999 volatile_names = [] 2000 2001 for n in locals: 2002 2003 # Filter out special names and parameters. Note that self is a local 2004 # regardless of whether it originally appeared in the parameters or 2005 # not. 2006 2007 if n.startswith("$l") or n in parameters or n == "self": 2008 continue 2009 if n in self.volatile_locals: 2010 volatile_names.append(encode_path(n)) 2011 else: 2012 names.append(encode_path(n)) 2013 2014 # Emit required local names at the function indentation level. 2015 2016 self.indent += 1 2017 2018 if names: 2019 names.sort() 2020 self.writeline("__attr %s;" % ", ".join(names)) 2021 2022 if volatile_names: 2023 volatile_names.sort() 2024 self.writeline("volatile __attr %s;" % ", ".join(volatile_names)) 2025 2026 self.flush_unit(name, out) 2027 2028 self.indent -= 1 2029 print >>self.out, "}" 2030 print >>self.out 2031 2032 def write_parameters(self, name): 2033 2034 """ 2035 For the function having the given 'name', write definitions of 2036 parameters found in the arguments array. 2037 """ 2038 2039 # Generate any self reference. 2040 2041 l = [] 2042 2043 if self.is_method(name): 2044 l.append("__attr self") 2045 else: 2046 l.append("__attr __self") 2047 2048 # Generate aliases for the parameters. 2049 2050 for parameter in self.importer.function_parameters[name]: 2051 l.append("%s__attr %s" % ( 2052 parameter in self.volatile_locals and "volatile " or "", 2053 encode_path(parameter))) 2054 2055 self.writeline("__attr %s(%s)" % ( 2056 encode_function_pointer(name), ", ".join(l))) 2057 2058 def write_temporaries(self, name): 2059 2060 "Write temporary storage employed by 'name'." 2061 2062 # Provide space for the given number of targets. 2063 2064 targets = self.max_function_targets 2065 2066 if self.uses_temp(name, "__tmp_targets"): 2067 self.writeline("__attr __tmp_targets[%d];" % targets) 2068 if self.uses_temp(name, "__tmp_contexts"): 2069 self.writeline("__attr __tmp_contexts[%d];" % targets) 2070 2071 # Add temporary variable usage details. 2072 2073 if self.uses_temp(name, "__tmp_private_context"): 2074 self.writeline("__attr __tmp_private_context;") 2075 if self.uses_temp(name, "__tmp_value"): 2076 self.writeline("__attr __tmp_value;") 2077 if self.uses_temp(name, "__tmp_target_value"): 2078 self.writeline("__attr __tmp_target_value;") 2079 if self.uses_temp(name, "__tmp_result"): 2080 self.writeline("__attr __tmp_result;") 2081 2082 module = self.importer.get_module(self.name) 2083 2084 if name in module.exception_namespaces: 2085 self.writeline("__exc __tmp_exc;") 2086 2087 def start_if(self, first, test_ref): 2088 statement = "%sif" % (not first and "else " or "") 2089 2090 # Consume logical results directly. 2091 2092 if isinstance(test_ref, LogicalResult): 2093 self.writeline("%s %s" % (statement, test_ref.apply_test())) 2094 temps = test_ref.discards_temporary() 2095 if temps: 2096 self.remove_temps(temps) 2097 else: 2098 self.writeline("%s (__BOOL(%s))" % (statement, test_ref)) 2099 2100 self.writeline("{") 2101 self.indent += 1 2102 2103 def end_if(self): 2104 self.indent -= 1 2105 self.writeline("}") 2106 2107 def start_else(self): 2108 self.writeline("else") 2109 self.writeline("{") 2110 self.indent += 1 2111 2112 def end_else(self): 2113 self.indent -= 1 2114 self.writeline("}") 2115 2116 def statement(self, expr): 2117 s = str(expr) 2118 if s: 2119 self.writestmt("%s;" % s) 2120 2121 def statements(self, results): 2122 for result in results: 2123 self.statement(result) 2124 2125 def writeline(self, s): 2126 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 2127 2128 def writestmt(self, s): 2129 self.writeline(s) 2130 2131 def write_comment(self, s): 2132 self.writestmt("/* %s */" % s) 2133 2134 def pad(self, extra=0): 2135 return (self.indent + extra) * self.tabstop 2136 2137 def indenttext(self, s, levels): 2138 lines = s.split("\n") 2139 out = [lines[0]] 2140 for line in lines[1:]: 2141 out.append(levels * self.tabstop + line) 2142 if line.endswith("("): 2143 levels += 1 2144 elif line.startswith(")"): 2145 levels -= 1 2146 return "\n".join(out) 2147 2148 # vim: tabstop=4 expandtab shiftwidth=4