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