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