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