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_module, get_builtin_type, init_item, \ 24 predefined_constants 25 from encoders import encode_access_instruction, encode_bound_reference, \ 26 encode_function_pointer, encode_literal_constant, \ 27 encode_literal_instantiator, encode_instantiator_pointer, \ 28 encode_instructions, \ 29 encode_path, encode_symbol, encode_type_attribute, \ 30 is_type_attribute 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 get_origin(self): 198 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() 199 200 def has_kind(self, kinds): 201 if not self.refs: 202 return False 203 for ref in self.refs: 204 if ref.has_kind(kinds): 205 return True 206 return False 207 208 def get_accessor_kinds(self): 209 return self.accessor_kinds 210 211 def __str__(self): 212 return encode_instructions(self.instructions) 213 214 def __repr__(self): 215 return "AttrResult(%r, %r, %r)" % (self.instructions, self.refs, self.accessor_kinds) 216 217 class InvocationResult(Expression, TranslationResult, InstructionSequence): 218 219 "A translation result for an invocation." 220 221 def __init__(self, instructions): 222 InstructionSequence.__init__(self, instructions) 223 224 def __str__(self): 225 return encode_instructions(self.instructions) 226 227 def __repr__(self): 228 return "InvocationResult(%r)" % self.instructions 229 230 class InstantiationResult(InvocationResult, TrInstanceRef): 231 232 "An instantiation result acting like an invocation result." 233 234 def __init__(self, ref, instructions): 235 results.InstanceRef.__init__(self, ref) 236 InvocationResult.__init__(self, instructions) 237 238 def __repr__(self): 239 return "InstantiationResult(%r, %r)" % (self.ref, self.instructions) 240 241 class PredefinedConstantRef(Expression, TranslationResult): 242 243 "A predefined constant reference." 244 245 def __init__(self, value, expr=None): 246 self.value = value 247 self.expr = expr 248 249 def __str__(self): 250 251 # Eliminate predefined constant assignments. 252 253 if self.expr: 254 return "" 255 256 # Generate the specific constants. 257 258 if self.value in ("False", "True"): 259 return encode_path("__builtins__.boolean.%s" % self.value) 260 elif self.value == "None": 261 return encode_path("__builtins__.none.%s" % self.value) 262 elif self.value == "NotImplemented": 263 return encode_path("__builtins__.notimplemented.%s" % self.value) 264 else: 265 return self.value 266 267 def __repr__(self): 268 return "PredefinedConstantRef(%r)" % self.value 269 270 class BooleanResult(Expression, TranslationResult): 271 272 "A expression producing a boolean result." 273 274 def __str__(self): 275 return "__builtins___bool_bool(%s)" % self.s 276 277 def __repr__(self): 278 return "BooleanResult(%r)" % self.s 279 280 def make_expression(expr): 281 282 "Make a new expression from the existing 'expr'." 283 284 if isinstance(expr, results.Result): 285 return expr 286 else: 287 return Expression(str(expr)) 288 289 # The actual translation process itself. 290 291 class TranslatedModule(CommonModule): 292 293 "A module translator." 294 295 def __init__(self, name, importer, deducer, optimiser): 296 CommonModule.__init__(self, name, importer) 297 self.deducer = deducer 298 self.optimiser = optimiser 299 300 # Output stream. 301 302 self.out_toplevel = self.out = None 303 self.indent = 0 304 self.tabstop = " " 305 306 # Recorded namespaces. 307 308 self.namespaces = [] 309 self.in_conditional = False 310 311 # Exception raising adjustments. 312 313 self.in_try_finally = False 314 self.in_try_except = False 315 316 # Attribute access and accessor counting. 317 318 self.attr_accesses = {} 319 self.attr_accessors = {} 320 321 # Special variable usage. 322 323 self.temp_usage = {} 324 325 def __repr__(self): 326 return "TranslatedModule(%r, %r)" % (self.name, self.importer) 327 328 def translate(self, filename, output_filename): 329 330 """ 331 Parse the file having the given 'filename', writing the translation to 332 the given 'output_filename'. 333 """ 334 335 self.parse_file(filename) 336 337 # Collect function namespaces for separate processing. 338 339 self.record_namespaces(self.astnode) 340 341 # Reset the lambda naming (in order to obtain the same names again) and 342 # translate the program. 343 344 self.reset_lambdas() 345 346 self.out_toplevel = self.out = open(output_filename, "w") 347 try: 348 self.start_output() 349 350 # Process namespaces, writing the translation. 351 352 for path, node in self.namespaces: 353 self.process_namespace(path, node) 354 355 # Process the module namespace including class namespaces. 356 357 self.process_namespace([], self.astnode) 358 359 finally: 360 self.out.close() 361 362 def have_object(self): 363 364 "Return whether a namespace is a recorded object." 365 366 return self.importer.objects.get(self.get_namespace_path()) 367 368 def get_builtin_class(self, name): 369 370 "Return a reference to the actual object providing 'name'." 371 372 # NOTE: This makes assumptions about the __builtins__ structure. 373 374 modname = get_builtin_module(name) 375 typename = get_builtin_type(name) 376 return self.importer.get_object("__builtins__.%s.%s" % (modname, typename)) 377 378 def is_method(self, path): 379 380 "Return whether 'path' is a method." 381 382 class_name, method_name = path.rsplit(".", 1) 383 return self.importer.classes.has_key(class_name) and class_name or None 384 385 def in_method(self): 386 387 "Return whether the current namespace provides a method." 388 389 return self.in_function and self.is_method(self.get_namespace_path()) 390 391 # Namespace recording. 392 393 def record_namespaces(self, node): 394 395 "Process the program structure 'node', recording namespaces." 396 397 for n in node.getChildNodes(): 398 self.record_namespaces_in_node(n) 399 400 def record_namespaces_in_node(self, node): 401 402 "Process the program structure 'node', recording namespaces." 403 404 # Function namespaces within modules, classes and other functions. 405 # Functions appearing within conditional statements are given arbitrary 406 # names. 407 408 if isinstance(node, compiler.ast.Function): 409 self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name) 410 411 elif isinstance(node, compiler.ast.Lambda): 412 self.record_function_node(node, self.get_lambda_name()) 413 414 # Classes are visited, but may be ignored if inside functions. 415 416 elif isinstance(node, compiler.ast.Class): 417 self.enter_namespace(node.name) 418 if self.have_object(): 419 self.record_namespaces(node) 420 self.exit_namespace() 421 422 # Conditional nodes are tracked so that function definitions may be 423 # handled. Since "for" loops are converted to "while" loops, they are 424 # included here. 425 426 elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)): 427 in_conditional = self.in_conditional 428 self.in_conditional = True 429 self.record_namespaces(node) 430 self.in_conditional = in_conditional 431 432 # All other nodes are processed depth-first. 433 434 else: 435 self.record_namespaces(node) 436 437 def record_function_node(self, n, name): 438 439 """ 440 Record the given function, lambda, if expression or list comprehension 441 node 'n' with the given 'name'. 442 """ 443 444 self.in_function = True 445 self.enter_namespace(name) 446 447 if self.have_object(): 448 449 # Record the namespace path and the node itself. 450 451 self.namespaces.append((self.namespace_path[:], n)) 452 self.record_namespaces_in_node(n.code) 453 454 self.exit_namespace() 455 self.in_function = False 456 457 # Constant referencing. 458 459 def get_literal_instance(self, n, name=None): 460 461 """ 462 For node 'n', return a reference for the type of the given 'name', or if 463 'name' is not specified, deduce the type from the value. 464 """ 465 466 # Handle stray None constants (Sliceobj seems to produce them). 467 468 if name is None and n.value is None: 469 return self.process_name_node(compiler.ast.Name("None")) 470 471 if name in ("dict", "list", "tuple"): 472 ref = self.get_builtin_class(name) 473 return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef) 474 else: 475 value, typename, encoding = self.get_constant_value(n.value, n.literal) 476 name = get_builtin_type(typename) 477 ref = self.get_builtin_class(name) 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 if self.is_method(objpath): 1076 instance_name = "&%s" % encode_bound_reference(objpath) 1077 else: 1078 instance_name = "&%s" % encode_path(objpath) 1079 1080 # Where defaults are involved but cannot be identified, obtain a new 1081 # instance of the lambda and populate the defaults. 1082 1083 defaults = [] 1084 1085 # Join the original defaults with the inspected defaults. 1086 1087 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 1088 1089 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 1090 1091 # Obtain any reference for the default. 1092 1093 if original: 1094 argname, default = original 1095 name_ref = self.process_structure_node(default) 1096 elif inspected: 1097 argname, default = inspected 1098 name_ref = TrResolvedNameRef(argname, default) 1099 else: 1100 continue 1101 1102 # Generate default initialisers except when constants are employed. 1103 # Constants should be used when populating the function structures. 1104 1105 if name_ref and not isinstance(name_ref, TrConstantValueRef): 1106 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref)) 1107 1108 return defaults 1109 1110 def process_if_node(self, n): 1111 1112 """ 1113 Process the given "if" node 'n'. 1114 """ 1115 1116 first = True 1117 for test, body in n.tests: 1118 test_ref = self.process_structure_node(test) 1119 self.start_if(first, test_ref) 1120 1121 in_conditional = self.in_conditional 1122 self.in_conditional = True 1123 self.process_structure_node(body) 1124 self.in_conditional = in_conditional 1125 1126 self.end_if() 1127 first = False 1128 1129 if n.else_: 1130 self.start_else() 1131 self.process_structure_node(n.else_) 1132 self.end_else() 1133 1134 def process_invocation_node(self, n): 1135 1136 "Process the given invocation node 'n'." 1137 1138 expr = self.process_structure_node(n.node) 1139 objpath = expr.get_origin() 1140 target = None 1141 target_structure = None 1142 function = None 1143 instantiation = False 1144 literal_instantiation = False 1145 context_required = True 1146 1147 # Obtain details of the callable. 1148 1149 # Literals may be instantiated specially. 1150 1151 if expr.is_name() and expr.name.startswith("$L") and objpath: 1152 instantiation = literal_instantiation = objpath 1153 parameters = None 1154 target = encode_literal_instantiator(objpath) 1155 context_required = False 1156 1157 # Identified targets employ function pointers directly. 1158 1159 elif objpath: 1160 parameters = self.importer.function_parameters.get(objpath) 1161 1162 # Class invocation involves instantiators. 1163 1164 if expr.has_kind("<class>"): 1165 instantiation = objpath 1166 target = encode_instantiator_pointer(objpath) 1167 target_structure = "&%s" % encode_bound_reference("%s.__init__" % objpath) 1168 context_required = False 1169 1170 # Only plain functions and bound methods employ function pointers. 1171 1172 elif expr.has_kind("<function>"): 1173 function = objpath 1174 1175 # Test for functions and methods. 1176 1177 context_required = self.is_method(objpath) 1178 accessor_kinds = expr.get_accessor_kinds() 1179 instance_accessor = accessor_kinds and \ 1180 len(accessor_kinds) == 1 and \ 1181 first(accessor_kinds) == "<instance>" 1182 1183 # Only identify certain bound methods or functions. 1184 1185 if not context_required or instance_accessor: 1186 target = encode_function_pointer(objpath) 1187 1188 # Access bound method defaults even if it is not clear whether 1189 # the accessor is appropriate. 1190 1191 target_structure = self.is_method(objpath) and \ 1192 "&%s" % encode_bound_reference(objpath) or \ 1193 "&%s" % encode_path(objpath) 1194 1195 # Other targets are retrieved at run-time. 1196 1197 else: 1198 parameters = None 1199 1200 # Arguments are presented in a temporary frame array with any context 1201 # always being the first argument. Where it would be unused, it may be 1202 # set to null. 1203 1204 if context_required: 1205 self.record_temp("__tmp_targets") 1206 args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] 1207 else: 1208 args = ["__NULL"] 1209 1210 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 1211 kwcodes = [] 1212 kwargs = [] 1213 1214 # Any invocations in the arguments will store target details in a 1215 # different location. 1216 1217 self.function_target += 1 1218 1219 for i, arg in enumerate(n.args): 1220 argexpr = self.process_structure_node(arg) 1221 1222 # Store a keyword argument, either in the argument list or 1223 # in a separate keyword argument list for subsequent lookup. 1224 1225 if isinstance(arg, compiler.ast.Keyword): 1226 1227 # With knowledge of the target, store the keyword 1228 # argument directly. 1229 1230 if parameters: 1231 try: 1232 argnum = parameters.index(arg.name) 1233 except ValueError: 1234 raise TranslateError("Argument %s is not recognised." % arg.name, 1235 self.get_namespace_path(), n) 1236 args[argnum+1] = str(argexpr) 1237 1238 # Otherwise, store the details in a separate collection. 1239 1240 else: 1241 kwargs.append(str(argexpr)) 1242 kwcodes.append("{%s, %s}" % ( 1243 encode_symbol("ppos", arg.name), 1244 encode_symbol("pcode", arg.name))) 1245 1246 # Store non-keyword arguments in the argument list, rejecting 1247 # superfluous arguments. 1248 1249 else: 1250 try: 1251 args[i+1] = str(argexpr) 1252 except IndexError: 1253 raise TranslateError("Too many arguments specified.", 1254 self.get_namespace_path(), n) 1255 1256 # Reference the current target again. 1257 1258 self.function_target -= 1 1259 1260 # Defaults are added to the frame where arguments are missing. 1261 1262 if parameters: 1263 function_defaults = self.importer.function_defaults.get(objpath) 1264 if function_defaults: 1265 1266 # Visit each default and set any missing arguments. 1267 # Use the target structure to obtain defaults, as opposed to the 1268 # actual function involved. 1269 1270 for i, (argname, default) in enumerate(function_defaults): 1271 argnum = parameters.index(argname) 1272 if not args[argnum+1]: 1273 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i) 1274 1275 # Test for missing arguments. 1276 1277 if None in args: 1278 raise TranslateError("Not all arguments supplied.", 1279 self.get_namespace_path(), n) 1280 1281 # Encode the arguments. 1282 1283 argstr = "__ARGS(%s)" % ", ".join(args) 1284 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 1285 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 1286 1287 # Where literal instantiation is occurring, add an argument indicating 1288 # the number of values. 1289 1290 if literal_instantiation: 1291 argstr += ", %d" % (len(args) - 1) 1292 1293 # First, the invocation expression is presented. 1294 1295 stages = [] 1296 1297 # Without a known specific callable, the expression provides the target. 1298 1299 if not target or context_required: 1300 self.record_temp("__tmp_targets") 1301 stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr)) 1302 1303 # Any specific callable is then obtained. 1304 1305 if target: 1306 stages.append(target) 1307 1308 # Methods accessed via unidentified accessors are obtained. 1309 1310 elif function: 1311 self.record_temp("__tmp_targets") 1312 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % ( 1313 self.function_target, encode_symbol("pos", "__fn__"))) 1314 1315 # With a known target, the function is obtained directly and called. 1316 # By putting the invocation at the end of the final element in the 1317 # instruction sequence (the stages), the result becomes the result of 1318 # the sequence. Moreover, the parameters become part of the sequence 1319 # and thereby participate in a guaranteed evaluation order. 1320 1321 if target or function: 1322 stages[-1] += "(%s)" % argstr 1323 if instantiation: 1324 return InstantiationResult(instantiation, stages) 1325 else: 1326 return InvocationResult(stages) 1327 1328 # With unknown targets, the generic invocation function is applied to 1329 # the callable and argument collections. 1330 1331 else: 1332 self.record_temp("__tmp_targets") 1333 stages.append("__invoke(\n__tmp_targets[%d],\n%d, %d, %s, %s,\n%d, %s\n)" % ( 1334 self.function_target, 1335 self.always_callable and 1 or 0, 1336 len(kwargs), kwcodestr, kwargstr, 1337 len(args), argstr)) 1338 return InvocationResult(stages) 1339 1340 def always_callable(self, refs): 1341 1342 "Determine whether all 'refs' are callable." 1343 1344 for ref in refs: 1345 if not ref.static(): 1346 return False 1347 else: 1348 origin = ref.final() 1349 if not self.importer.get_attribute(origin, "__fn__"): 1350 return False 1351 return True 1352 1353 def need_default_arguments(self, objpath, nargs): 1354 1355 """ 1356 Return whether any default arguments are needed when invoking the object 1357 given by 'objpath'. 1358 """ 1359 1360 parameters = self.importer.function_parameters.get(objpath) 1361 return nargs < len(parameters) 1362 1363 def process_lambda_node(self, n): 1364 1365 "Process the given lambda node 'n'." 1366 1367 name = self.get_lambda_name() 1368 function_name = self.get_object_path(name) 1369 1370 defaults = self.process_function_defaults(n, name, function_name, "__tmp_value") 1371 1372 # Without defaults, produce an attribute referring to the function. 1373 1374 if not defaults: 1375 return make_expression("((__attr) {.context=0, .value=&%s})" % encode_path(function_name)) 1376 1377 # With defaults, copy the function structure and set the defaults on the 1378 # copy. 1379 1380 else: 1381 self.record_temp("__tmp_value") 1382 return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.context=0, .value=__tmp_value})" % ( 1383 encode_path(function_name), 1384 encode_symbol("obj", function_name), 1385 ", ".join(defaults))) 1386 1387 def process_logical_node(self, n): 1388 1389 """ 1390 Process the given operator node 'n'. 1391 1392 Convert ... to ... 1393 1394 <a> and <b> 1395 (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b> 1396 1397 <a> or <b> 1398 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b> 1399 """ 1400 1401 self.record_temp("__tmp_result") 1402 1403 if isinstance(n, compiler.ast.And): 1404 op = "!" 1405 else: 1406 op = "" 1407 1408 results = [] 1409 1410 for node in n.nodes[:-1]: 1411 expr = self.process_structure_node(node) 1412 results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, op)) 1413 1414 expr = self.process_structure_node(n.nodes[-1]) 1415 results.append(str(expr)) 1416 1417 return make_expression("(%s)" % "".join(results)) 1418 1419 def process_name_node(self, n, expr=None): 1420 1421 "Process the given name node 'n' with the optional assignment 'expr'." 1422 1423 # Determine whether the name refers to a static external entity. 1424 1425 if n.name in predefined_constants: 1426 return PredefinedConstantRef(n.name, expr) 1427 1428 # Convert literal references, operator function names, and print 1429 # function names to references. 1430 1431 elif n.name.startswith("$L") or n.name.startswith("$op") or \ 1432 n.name.startswith("$print"): 1433 1434 ref, paths = self.importer.get_module(self.name).special[n.name] 1435 return TrResolvedNameRef(n.name, ref) 1436 1437 # Get the appropriate name for the name reference, using the same method 1438 # as in the inspector. 1439 1440 path = self.get_namespace_path() 1441 objpath = self.get_object_path(n.name) 1442 1443 # Determine any assigned globals. 1444 1445 globals = self.importer.get_module(self.name).scope_globals.get(path) 1446 if globals and n.name in globals: 1447 objpath = self.get_global_path(n.name) 1448 1449 # Get the static identity of the name. 1450 1451 ref = self.importer.identify(objpath) 1452 if ref and not ref.get_name(): 1453 ref = ref.alias(objpath) 1454 1455 # Obtain any resolved names for non-assignment names. 1456 1457 if not expr and not ref and self.in_function: 1458 locals = self.importer.function_locals.get(path) 1459 ref = locals and locals.get(n.name) 1460 1461 # Determine whether the name refers to a parameter. The generation of 1462 # parameter references is different from other names. 1463 1464 parameters = self.importer.function_parameters.get(path) 1465 parameter = n.name == "self" and self.in_method() or \ 1466 parameters and n.name in parameters 1467 1468 # Qualified names are used for resolved static references or for 1469 # static namespace members. The reference should be configured to return 1470 # such names. 1471 1472 return TrResolvedNameRef(n.name, ref, expr=expr, parameter=parameter) 1473 1474 def process_not_node(self, n): 1475 1476 "Process the given operator node 'n'." 1477 1478 return make_expression("(__BOOL(%s) ? %s : %s)" % 1479 (self.process_structure_node(n.expr), PredefinedConstantRef("False"), 1480 PredefinedConstantRef("True"))) 1481 1482 def process_raise_node(self, n): 1483 1484 "Process the given raise node 'n'." 1485 1486 # NOTE: Determine which raise statement variants should be permitted. 1487 1488 if n.expr1: 1489 1490 # Names with accompanying arguments are treated like invocations. 1491 1492 if n.expr2: 1493 call = compiler.ast.CallFunc(n.expr1, [n.expr2]) 1494 exc = self.process_structure_node(call) 1495 self.writestmt("__Raise(%s);" % exc) 1496 1497 # Raise instances, testing the kind at run-time if necessary and 1498 # instantiating any non-instance. 1499 1500 else: 1501 exc = self.process_structure_node(n.expr1) 1502 1503 if isinstance(exc, TrInstanceRef): 1504 self.writestmt("__Raise(%s);" % exc) 1505 else: 1506 self.writestmt("__Raise(__ensure_instance(%s));" % exc) 1507 else: 1508 self.writestmt("__Throw(__tmp_exc);") 1509 1510 def process_return_node(self, n): 1511 1512 "Process the given return node 'n'." 1513 1514 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1515 if self.in_try_finally or self.in_try_except: 1516 self.writestmt("__Return(%s);" % expr) 1517 else: 1518 self.writestmt("return %s;" % expr) 1519 1520 return ReturnRef() 1521 1522 def process_try_node(self, n): 1523 1524 """ 1525 Process the given "try...except" node 'n'. 1526 """ 1527 1528 in_try_except = self.in_try_except 1529 self.in_try_except = True 1530 1531 # Use macros to implement exception handling. 1532 1533 self.writestmt("__Try") 1534 self.writeline("{") 1535 self.indent += 1 1536 self.process_structure_node(n.body) 1537 1538 # Put the else statement in another try block that handles any raised 1539 # exceptions and converts them to exceptions that will not be handled by 1540 # the main handling block. 1541 1542 if n.else_: 1543 self.writestmt("__Try") 1544 self.writeline("{") 1545 self.indent += 1 1546 self.process_structure_node(n.else_) 1547 self.indent -= 1 1548 self.writeline("}") 1549 self.writeline("__Catch (__tmp_exc)") 1550 self.writeline("{") 1551 self.indent += 1 1552 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1553 self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1554 self.indent -= 1 1555 self.writeline("}") 1556 1557 # Complete the try block and enter the finally block, if appropriate. 1558 1559 if self.in_try_finally: 1560 self.writestmt("__Complete;") 1561 1562 self.indent -= 1 1563 self.writeline("}") 1564 1565 self.in_try_except = in_try_except 1566 1567 # Handlers are tests within a common handler block. 1568 1569 self.writeline("__Catch (__tmp_exc)") 1570 self.writeline("{") 1571 self.indent += 1 1572 1573 # Introduce an if statement to handle the completion of a try block. 1574 1575 self.process_try_completion() 1576 1577 # Handle exceptions in else blocks converted to __RaiseElse, converting 1578 # them back to normal exceptions. 1579 1580 if n.else_: 1581 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1582 1583 # Exception handling. 1584 1585 for name, var, handler in n.handlers: 1586 1587 # Test for specific exceptions. 1588 1589 if name is not None: 1590 name_ref = self.process_structure_node(name) 1591 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref) 1592 else: 1593 self.writeline("else if (1)") 1594 1595 self.writeline("{") 1596 self.indent += 1 1597 1598 # Establish the local for the handler. 1599 1600 if var is not None: 1601 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) 1602 1603 if handler is not None: 1604 self.process_structure_node(handler) 1605 1606 self.indent -= 1 1607 self.writeline("}") 1608 1609 # Re-raise unhandled exceptions. 1610 1611 self.writeline("else __Throw(__tmp_exc);") 1612 1613 # End the handler block. 1614 1615 self.indent -= 1 1616 self.writeline("}") 1617 1618 def process_try_finally_node(self, n): 1619 1620 """ 1621 Process the given "try...finally" node 'n'. 1622 """ 1623 1624 in_try_finally = self.in_try_finally 1625 self.in_try_finally = True 1626 1627 # Use macros to implement exception handling. 1628 1629 self.writestmt("__Try") 1630 self.writeline("{") 1631 self.indent += 1 1632 self.process_structure_node(n.body) 1633 self.indent -= 1 1634 self.writeline("}") 1635 1636 self.in_try_finally = in_try_finally 1637 1638 # Finally clauses handle special exceptions. 1639 1640 self.writeline("__Catch (__tmp_exc)") 1641 self.writeline("{") 1642 self.indent += 1 1643 self.process_structure_node(n.final) 1644 1645 # Introduce an if statement to handle the completion of a try block. 1646 1647 self.process_try_completion() 1648 self.writeline("else __Throw(__tmp_exc);") 1649 1650 self.indent -= 1 1651 self.writeline("}") 1652 1653 def process_try_completion(self): 1654 1655 "Generate a test for the completion of a try block." 1656 1657 self.writestmt("if (__tmp_exc.completing)") 1658 self.writeline("{") 1659 self.indent += 1 1660 1661 # Do not return anything at the module level. 1662 1663 if self.get_namespace_path() != self.name: 1664 1665 # Only use the normal return statement if no surrounding try blocks 1666 # apply. 1667 1668 if not self.in_try_finally and not self.in_try_except: 1669 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1670 else: 1671 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1672 1673 self.indent -= 1 1674 self.writeline("}") 1675 1676 def process_while_node(self, n): 1677 1678 "Process the given while node 'n'." 1679 1680 self.writeline("while (1)") 1681 self.writeline("{") 1682 self.indent += 1 1683 test = self.process_structure_node(n.test) 1684 1685 # Emit the loop termination condition unless "while <true value>" is 1686 # indicated. 1687 1688 if not (isinstance(test, PredefinedConstantRef) and test.value): 1689 1690 # NOTE: This needs to evaluate whether the operand is true or false 1691 # NOTE: according to Python rules. 1692 1693 self.writeline("if (!__BOOL(%s))" % test) 1694 self.writeline("{") 1695 self.indent += 1 1696 if n.else_: 1697 self.process_structure_node(n.else_) 1698 self.writestmt("break;") 1699 self.indent -= 1 1700 self.writeline("}") 1701 1702 in_conditional = self.in_conditional 1703 self.in_conditional = True 1704 self.process_structure_node(n.body) 1705 self.in_conditional = in_conditional 1706 1707 self.indent -= 1 1708 self.writeline("}") 1709 1710 # Special variable usage. 1711 1712 def record_temp(self, name): 1713 1714 """ 1715 Record the use of the temporary 'name' in the current namespace. At the 1716 class or module level, the temporary name is associated with the module, 1717 since the variable will then be allocated in the module's own main 1718 program. 1719 """ 1720 1721 if self.in_function: 1722 path = self.get_namespace_path() 1723 else: 1724 path = self.name 1725 1726 init_item(self.temp_usage, path, set) 1727 self.temp_usage[path].add(name) 1728 1729 def uses_temp(self, path, name): 1730 1731 """ 1732 Return whether the given namespace 'path' employs a temporary variable 1733 with the given 'name'. Note that 'path' should only be a module or a 1734 function or method, not a class. 1735 """ 1736 1737 return self.temp_usage.has_key(path) and name in self.temp_usage[path] 1738 1739 # Output generation. 1740 1741 def start_output(self): 1742 1743 "Write the declarations at the top of each source file." 1744 1745 print >>self.out, """\ 1746 #include "types.h" 1747 #include "exceptions.h" 1748 #include "ops.h" 1749 #include "progconsts.h" 1750 #include "progops.h" 1751 #include "progtypes.h" 1752 #include "main.h" 1753 """ 1754 1755 def start_unit(self): 1756 1757 "Record output within a generated function for later use." 1758 1759 self.out = StringIO() 1760 1761 def end_unit(self, name): 1762 1763 "Add declarations and generated code." 1764 1765 # Restore the output stream. 1766 1767 out = self.out 1768 self.out = self.out_toplevel 1769 1770 self.write_temporaries(name) 1771 out.seek(0) 1772 self.out.write(out.read()) 1773 1774 self.indent -= 1 1775 print >>self.out, "}" 1776 1777 def start_module(self): 1778 1779 "Write the start of each module's main function." 1780 1781 print >>self.out, "void __main_%s()" % encode_path(self.name) 1782 print >>self.out, "{" 1783 self.indent += 1 1784 self.start_unit() 1785 1786 def end_module(self): 1787 1788 "End each module by closing its main function." 1789 1790 self.end_unit(self.name) 1791 1792 def start_function(self, name): 1793 1794 "Start the function having the given 'name'." 1795 1796 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1797 print >>self.out, "{" 1798 self.indent += 1 1799 1800 # Obtain local names from parameters. 1801 1802 parameters = self.importer.function_parameters[name] 1803 locals = self.importer.function_locals[name].keys() 1804 names = [] 1805 1806 for n in locals: 1807 1808 # Filter out special names and parameters. Note that self is a local 1809 # regardless of whether it originally appeared in the parameters or 1810 # not. 1811 1812 if n.startswith("$l") or n in parameters or n == "self": 1813 continue 1814 names.append(encode_path(n)) 1815 1816 # Emit required local names. 1817 1818 if names: 1819 names.sort() 1820 self.writeline("__attr %s;" % ", ".join(names)) 1821 1822 self.write_parameters(name) 1823 self.start_unit() 1824 1825 def end_function(self, name): 1826 1827 "End the function having the given 'name'." 1828 1829 self.end_unit(name) 1830 print >>self.out 1831 1832 def write_temporaries(self, name): 1833 1834 "Write temporary storage employed by 'name'." 1835 1836 # Provide space for the given number of targets. 1837 1838 if self.uses_temp(name, "__tmp_targets"): 1839 targets = self.importer.function_targets.get(name) 1840 self.writeline("__attr __tmp_targets[%d];" % targets) 1841 1842 # Add temporary variable usage details. 1843 1844 if self.uses_temp(name, "__tmp_context"): 1845 self.writeline("__ref __tmp_context;") 1846 if self.uses_temp(name, "__tmp_value"): 1847 self.writeline("__ref __tmp_value;") 1848 if self.uses_temp(name, "__tmp_target_value"): 1849 self.writeline("__ref __tmp_target_value;") 1850 if self.uses_temp(name, "__tmp_result"): 1851 self.writeline("__attr __tmp_result;") 1852 1853 module = self.importer.get_module(self.name) 1854 1855 if name in module.exception_namespaces: 1856 self.writeline("__exc __tmp_exc;") 1857 1858 def write_parameters(self, name): 1859 1860 """ 1861 For the function having the given 'name', write definitions of 1862 parameters found in the arguments array. 1863 """ 1864 1865 parameters = self.importer.function_parameters[name] 1866 1867 # Generate any self reference. 1868 1869 if self.is_method(name): 1870 self.writeline("__attr * const self = &__args[0];") 1871 1872 # Generate aliases for the parameters. 1873 1874 for i, parameter in enumerate(parameters): 1875 self.writeline("__attr * const %s = &__args[%d];" % (encode_path(parameter), i+1)) 1876 1877 def start_if(self, first, test_ref): 1878 self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref)) 1879 self.writeline("{") 1880 self.indent += 1 1881 1882 def end_if(self): 1883 self.indent -= 1 1884 self.writeline("}") 1885 1886 def start_else(self): 1887 self.writeline("else") 1888 self.writeline("{") 1889 self.indent += 1 1890 1891 def end_else(self): 1892 self.indent -= 1 1893 self.writeline("}") 1894 1895 def statement(self, expr): 1896 # NOTE: Should never be None. 1897 if not expr: 1898 self.writestmt("...;") 1899 s = str(expr) 1900 if s: 1901 self.writestmt("%s;" % s) 1902 1903 def statements(self, results): 1904 for result in results: 1905 self.statement(result) 1906 1907 def writeline(self, s): 1908 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1909 1910 def writestmt(self, s): 1911 print >>self.out 1912 self.writeline(s) 1913 1914 def write_comment(self, s): 1915 self.writestmt("/* %s */" % s) 1916 1917 def pad(self, extra=0): 1918 return (self.indent + extra) * self.tabstop 1919 1920 def indenttext(self, s, levels): 1921 lines = s.split("\n") 1922 out = [lines[0]] 1923 for line in lines[1:]: 1924 out.append(levels * self.tabstop + line) 1925 if line.endswith("("): 1926 levels += 1 1927 elif line.startswith(")"): 1928 levels -= 1 1929 return "\n".join(out) 1930 1931 # vim: tabstop=4 expandtab shiftwidth=4