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