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, \ 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.literals) 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 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 target = None 1138 target_structure = None 1139 function = None 1140 instantiation = False 1141 literal_instantiation = False 1142 context_required = True 1143 1144 # Obtain details of the callable. 1145 1146 # Literals may be instantiated specially. 1147 1148 if expr.is_name() and expr.name.startswith("$L") and objpath: 1149 instantiation = literal_instantiation = objpath 1150 parameters = None 1151 target = encode_literal_instantiator(objpath) 1152 context_required = False 1153 1154 # Identified targets employ function pointers directly. 1155 1156 elif objpath: 1157 parameters = self.importer.function_parameters.get(objpath) 1158 1159 # Class invocation involves instantiators. 1160 1161 if expr.has_kind("<class>"): 1162 instantiation = objpath 1163 target = encode_instantiator_pointer(objpath) 1164 target_structure = "&%s" % encode_path("%s.__init__" % objpath) 1165 context_required = False 1166 1167 # Only plain functions and bound methods employ function pointers. 1168 1169 elif expr.has_kind("<function>"): 1170 function = objpath 1171 1172 # Test for functions and methods. 1173 1174 context_required = self.is_method(objpath) 1175 accessor_kinds = expr.get_accessor_kinds() 1176 instance_accessor = accessor_kinds and \ 1177 len(accessor_kinds) == 1 and \ 1178 first(accessor_kinds) == "<instance>" 1179 1180 # Only identify certain bound methods or functions. 1181 1182 if not context_required or instance_accessor: 1183 target = encode_function_pointer(objpath) 1184 1185 # Access bound method defaults even if it is not clear whether 1186 # the accessor is appropriate. 1187 1188 target_structure = "&%s" % encode_path(objpath) 1189 1190 # Other targets are retrieved at run-time. 1191 1192 else: 1193 parameters = None 1194 1195 # Arguments are presented in a temporary frame array with any context 1196 # always being the first argument. Where it would be unused, it may be 1197 # set to null. 1198 1199 if context_required: 1200 self.record_temp("__tmp_targets") 1201 args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] 1202 else: 1203 args = ["__NULL"] 1204 1205 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 1206 kwcodes = [] 1207 kwargs = [] 1208 1209 # Any invocations in the arguments will store target details in a 1210 # different location. 1211 1212 self.function_target += 1 1213 1214 for i, arg in enumerate(n.args): 1215 argexpr = self.process_structure_node(arg) 1216 1217 # Store a keyword argument, either in the argument list or 1218 # in a separate keyword argument list for subsequent lookup. 1219 1220 if isinstance(arg, compiler.ast.Keyword): 1221 1222 # With knowledge of the target, store the keyword 1223 # argument directly. 1224 1225 if parameters: 1226 try: 1227 argnum = parameters.index(arg.name) 1228 except ValueError: 1229 raise TranslateError("Argument %s is not recognised." % arg.name, 1230 self.get_namespace_path(), n) 1231 args[argnum+1] = str(argexpr) 1232 1233 # Otherwise, store the details in a separate collection. 1234 1235 else: 1236 kwargs.append(str(argexpr)) 1237 kwcodes.append("{%s, %s}" % ( 1238 encode_symbol("ppos", arg.name), 1239 encode_symbol("pcode", arg.name))) 1240 1241 # Store non-keyword arguments in the argument list, rejecting 1242 # superfluous arguments. 1243 1244 else: 1245 try: 1246 args[i+1] = str(argexpr) 1247 except IndexError: 1248 raise TranslateError("Too many arguments specified.", 1249 self.get_namespace_path(), n) 1250 1251 # Reference the current target again. 1252 1253 self.function_target -= 1 1254 1255 # Defaults are added to the frame where arguments are missing. 1256 1257 if parameters: 1258 function_defaults = self.importer.function_defaults.get(objpath) 1259 if function_defaults: 1260 1261 # Visit each default and set any missing arguments. 1262 # Use the target structure to obtain defaults, as opposed to the 1263 # actual function involved. 1264 1265 for i, (argname, default) in enumerate(function_defaults): 1266 argnum = parameters.index(argname) 1267 if not args[argnum+1]: 1268 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i) 1269 1270 # Test for missing arguments. 1271 1272 if None in args: 1273 raise TranslateError("Not all arguments supplied.", 1274 self.get_namespace_path(), n) 1275 1276 # Encode the arguments. 1277 1278 argstr = "__ARGS(%s)" % ", ".join(args) 1279 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 1280 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 1281 1282 # Where literal instantiation is occurring, add an argument indicating 1283 # the number of values. 1284 1285 if literal_instantiation: 1286 argstr += ", %d" % (len(args) - 1) 1287 1288 # First, the invocation expression is presented. 1289 1290 stages = [] 1291 1292 # Without a known specific callable, the expression provides the target. 1293 1294 if not target or context_required: 1295 self.record_temp("__tmp_targets") 1296 stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr)) 1297 1298 # Any specific callable is then obtained. 1299 1300 if target: 1301 stages.append(target) 1302 1303 # Methods accessed via unidentified accessors are obtained. 1304 1305 elif function: 1306 self.record_temp("__tmp_targets") 1307 1308 if context_required: 1309 stages.append("__get_function(__tmp_targets[%d])" % self.function_target) 1310 else: 1311 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % ( 1312 self.function_target, encode_symbol("pos", "__fn__"))) 1313 1314 # With a known target, the function is obtained directly and called. 1315 # By putting the invocation at the end of the final element in the 1316 # instruction sequence (the stages), the result becomes the result of 1317 # the sequence. Moreover, the parameters become part of the sequence 1318 # and thereby participate in a guaranteed evaluation order. 1319 1320 if target or function: 1321 stages[-1] += "(%s)" % argstr 1322 if instantiation: 1323 return InstantiationResult(instantiation, stages) 1324 else: 1325 return InvocationResult(stages) 1326 1327 # With unknown targets, the generic invocation function is applied to 1328 # the callable and argument collections. 1329 1330 else: 1331 self.record_temp("__tmp_targets") 1332 stages.append("__invoke(\n__tmp_targets[%d],\n%d, %d, %s, %s,\n%d, %s\n)" % ( 1333 self.function_target, 1334 self.always_callable and 1 or 0, 1335 len(kwargs), kwcodestr, kwargstr, 1336 len(args), argstr)) 1337 return InvocationResult(stages) 1338 1339 def always_callable(self, refs): 1340 1341 "Determine whether all 'refs' are callable." 1342 1343 for ref in refs: 1344 if not ref.static(): 1345 return False 1346 else: 1347 origin = ref.final() 1348 if not self.importer.get_attribute(origin, "__fn__"): 1349 return False 1350 return True 1351 1352 def need_default_arguments(self, objpath, nargs): 1353 1354 """ 1355 Return whether any default arguments are needed when invoking the object 1356 given by 'objpath'. 1357 """ 1358 1359 parameters = self.importer.function_parameters.get(objpath) 1360 return nargs < len(parameters) 1361 1362 def process_lambda_node(self, n): 1363 1364 "Process the given lambda node 'n'." 1365 1366 name = self.get_lambda_name() 1367 function_name = self.get_object_path(name) 1368 1369 defaults = self.process_function_defaults(n, name, function_name, "__tmp_value") 1370 1371 # Without defaults, produce an attribute referring to the function. 1372 1373 if not defaults: 1374 return make_expression("((__attr) {.context=0, .value=&%s})" % encode_path(function_name)) 1375 1376 # With defaults, copy the function structure and set the defaults on the 1377 # copy. 1378 1379 else: 1380 self.record_temp("__tmp_value") 1381 return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.context=0, .value=__tmp_value})" % ( 1382 encode_path(function_name), 1383 encode_symbol("obj", function_name), 1384 ", ".join(defaults))) 1385 1386 def process_logical_node(self, n): 1387 1388 """ 1389 Process the given operator node 'n'. 1390 1391 Convert ... to ... 1392 1393 <a> and <b> 1394 (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b> 1395 1396 <a> or <b> 1397 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b> 1398 """ 1399 1400 self.record_temp("__tmp_result") 1401 1402 if isinstance(n, compiler.ast.And): 1403 op = "!" 1404 else: 1405 op = "" 1406 1407 results = [] 1408 1409 for node in n.nodes[:-1]: 1410 expr = self.process_structure_node(node) 1411 results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, op)) 1412 1413 expr = self.process_structure_node(n.nodes[-1]) 1414 results.append(str(expr)) 1415 1416 return make_expression("(%s)" % "".join(results)) 1417 1418 def process_name_node(self, n, expr=None): 1419 1420 "Process the given name node 'n' with the optional assignment 'expr'." 1421 1422 # Determine whether the name refers to a static external entity. 1423 1424 if n.name in predefined_constants: 1425 return PredefinedConstantRef(n.name, expr) 1426 1427 # Convert literal references, operator function names, and print 1428 # function names to references. 1429 1430 elif n.name.startswith("$L") or n.name.startswith("$op") or \ 1431 n.name.startswith("$print"): 1432 1433 ref, paths = self.importer.get_module(self.name).special[n.name] 1434 return TrResolvedNameRef(n.name, ref) 1435 1436 # Get the appropriate name for the name reference, using the same method 1437 # as in the inspector. 1438 1439 path = self.get_namespace_path() 1440 objpath = self.get_object_path(n.name) 1441 1442 # Determine any assigned globals. 1443 1444 globals = self.importer.get_module(self.name).scope_globals.get(path) 1445 if globals and n.name in globals: 1446 objpath = self.get_global_path(n.name) 1447 1448 # Get the static identity of the name. 1449 1450 ref = self.importer.identify(objpath) 1451 if ref and not ref.get_name(): 1452 ref = ref.alias(objpath) 1453 1454 # Obtain any resolved names for non-assignment names. 1455 1456 if not expr and not ref and self.in_function: 1457 locals = self.importer.function_locals.get(path) 1458 ref = locals and locals.get(n.name) 1459 1460 # Determine whether the name refers to a parameter. The generation of 1461 # parameter references is different from other names. 1462 1463 parameters = self.importer.function_parameters.get(path) 1464 parameter = n.name == "self" and self.in_method() or \ 1465 parameters and n.name in parameters 1466 1467 # Qualified names are used for resolved static references or for 1468 # static namespace members. The reference should be configured to return 1469 # such names. 1470 1471 return TrResolvedNameRef(n.name, ref, expr=expr, parameter=parameter) 1472 1473 def process_not_node(self, n): 1474 1475 "Process the given operator node 'n'." 1476 1477 return make_expression("(__BOOL(%s) ? %s : %s)" % 1478 (self.process_structure_node(n.expr), PredefinedConstantRef("False"), 1479 PredefinedConstantRef("True"))) 1480 1481 def process_raise_node(self, n): 1482 1483 "Process the given raise node 'n'." 1484 1485 # NOTE: Determine which raise statement variants should be permitted. 1486 1487 if n.expr1: 1488 1489 # Names with accompanying arguments are treated like invocations. 1490 1491 if n.expr2: 1492 call = compiler.ast.CallFunc(n.expr1, [n.expr2]) 1493 exc = self.process_structure_node(call) 1494 self.writestmt("__Raise(%s);" % exc) 1495 1496 # Raise instances, testing the kind at run-time if necessary and 1497 # instantiating any non-instance. 1498 1499 else: 1500 exc = self.process_structure_node(n.expr1) 1501 1502 if isinstance(exc, TrInstanceRef): 1503 self.writestmt("__Raise(%s);" % exc) 1504 else: 1505 self.writestmt("__Raise(__ensure_instance(%s));" % exc) 1506 else: 1507 self.writestmt("__Throw(__tmp_exc);") 1508 1509 def process_return_node(self, n): 1510 1511 "Process the given return node 'n'." 1512 1513 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1514 if self.in_try_finally or self.in_try_except: 1515 self.writestmt("__Return(%s);" % expr) 1516 else: 1517 self.writestmt("return %s;" % expr) 1518 1519 return ReturnRef() 1520 1521 def process_try_node(self, n): 1522 1523 """ 1524 Process the given "try...except" node 'n'. 1525 """ 1526 1527 in_try_except = self.in_try_except 1528 self.in_try_except = True 1529 1530 # Use macros to implement exception handling. 1531 1532 self.writestmt("__Try") 1533 self.writeline("{") 1534 self.indent += 1 1535 self.process_structure_node(n.body) 1536 1537 # Put the else statement in another try block that handles any raised 1538 # exceptions and converts them to exceptions that will not be handled by 1539 # the main handling block. 1540 1541 if n.else_: 1542 self.writestmt("__Try") 1543 self.writeline("{") 1544 self.indent += 1 1545 self.process_structure_node(n.else_) 1546 self.indent -= 1 1547 self.writeline("}") 1548 self.writeline("__Catch (__tmp_exc)") 1549 self.writeline("{") 1550 self.indent += 1 1551 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1552 self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1553 self.indent -= 1 1554 self.writeline("}") 1555 1556 # Complete the try block and enter the finally block, if appropriate. 1557 1558 if self.in_try_finally: 1559 self.writestmt("__Complete;") 1560 1561 self.indent -= 1 1562 self.writeline("}") 1563 1564 self.in_try_except = in_try_except 1565 1566 # Handlers are tests within a common handler block. 1567 1568 self.writeline("__Catch (__tmp_exc)") 1569 self.writeline("{") 1570 self.indent += 1 1571 1572 # Introduce an if statement to handle the completion of a try block. 1573 1574 self.process_try_completion() 1575 1576 # Handle exceptions in else blocks converted to __RaiseElse, converting 1577 # them back to normal exceptions. 1578 1579 if n.else_: 1580 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1581 1582 # Exception handling. 1583 1584 for name, var, handler in n.handlers: 1585 1586 # Test for specific exceptions. 1587 1588 if name is not None: 1589 name_ref = self.process_structure_node(name) 1590 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref) 1591 else: 1592 self.writeline("else if (1)") 1593 1594 self.writeline("{") 1595 self.indent += 1 1596 1597 # Establish the local for the handler. 1598 1599 if var is not None: 1600 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) 1601 1602 if handler is not None: 1603 self.process_structure_node(handler) 1604 1605 self.indent -= 1 1606 self.writeline("}") 1607 1608 # Re-raise unhandled exceptions. 1609 1610 self.writeline("else __Throw(__tmp_exc);") 1611 1612 # End the handler block. 1613 1614 self.indent -= 1 1615 self.writeline("}") 1616 1617 def process_try_finally_node(self, n): 1618 1619 """ 1620 Process the given "try...finally" node 'n'. 1621 """ 1622 1623 in_try_finally = self.in_try_finally 1624 self.in_try_finally = True 1625 1626 # Use macros to implement exception handling. 1627 1628 self.writestmt("__Try") 1629 self.writeline("{") 1630 self.indent += 1 1631 self.process_structure_node(n.body) 1632 self.indent -= 1 1633 self.writeline("}") 1634 1635 self.in_try_finally = in_try_finally 1636 1637 # Finally clauses handle special exceptions. 1638 1639 self.writeline("__Catch (__tmp_exc)") 1640 self.writeline("{") 1641 self.indent += 1 1642 self.process_structure_node(n.final) 1643 1644 # Introduce an if statement to handle the completion of a try block. 1645 1646 self.process_try_completion() 1647 self.writeline("else __Throw(__tmp_exc);") 1648 1649 self.indent -= 1 1650 self.writeline("}") 1651 1652 def process_try_completion(self): 1653 1654 "Generate a test for the completion of a try block." 1655 1656 self.writestmt("if (__tmp_exc.completing)") 1657 self.writeline("{") 1658 self.indent += 1 1659 1660 # Do not return anything at the module level. 1661 1662 if self.get_namespace_path() != self.name: 1663 1664 # Only use the normal return statement if no surrounding try blocks 1665 # apply. 1666 1667 if not self.in_try_finally and not self.in_try_except: 1668 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1669 else: 1670 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1671 1672 self.indent -= 1 1673 self.writeline("}") 1674 1675 def process_while_node(self, n): 1676 1677 "Process the given while node 'n'." 1678 1679 self.writeline("while (1)") 1680 self.writeline("{") 1681 self.indent += 1 1682 test = self.process_structure_node(n.test) 1683 1684 # Emit the loop termination condition unless "while <true value>" is 1685 # indicated. 1686 1687 if not (isinstance(test, PredefinedConstantRef) and test.value): 1688 1689 # NOTE: This needs to evaluate whether the operand is true or false 1690 # NOTE: according to Python rules. 1691 1692 self.writeline("if (!__BOOL(%s))" % test) 1693 self.writeline("{") 1694 self.indent += 1 1695 if n.else_: 1696 self.process_structure_node(n.else_) 1697 self.writestmt("break;") 1698 self.indent -= 1 1699 self.writeline("}") 1700 1701 in_conditional = self.in_conditional 1702 self.in_conditional = True 1703 self.process_structure_node(n.body) 1704 self.in_conditional = in_conditional 1705 1706 self.indent -= 1 1707 self.writeline("}") 1708 1709 # Special variable usage. 1710 1711 def record_temp(self, name): 1712 1713 """ 1714 Record the use of the temporary 'name' in the current namespace. At the 1715 class or module level, the temporary name is associated with the module, 1716 since the variable will then be allocated in the module's own main 1717 program. 1718 """ 1719 1720 if self.in_function: 1721 path = self.get_namespace_path() 1722 else: 1723 path = self.name 1724 1725 init_item(self.temp_usage, path, set) 1726 self.temp_usage[path].add(name) 1727 1728 def uses_temp(self, path, name): 1729 1730 """ 1731 Return whether the given namespace 'path' employs a temporary variable 1732 with the given 'name'. Note that 'path' should only be a module or a 1733 function or method, not a class. 1734 """ 1735 1736 return self.temp_usage.has_key(path) and name in self.temp_usage[path] 1737 1738 # Output generation. 1739 1740 def start_output(self): 1741 1742 "Write the declarations at the top of each source file." 1743 1744 print >>self.out, """\ 1745 #include "types.h" 1746 #include "exceptions.h" 1747 #include "ops.h" 1748 #include "progconsts.h" 1749 #include "progops.h" 1750 #include "progtypes.h" 1751 #include "main.h" 1752 """ 1753 1754 def start_unit(self): 1755 1756 "Record output within a generated function for later use." 1757 1758 self.out = StringIO() 1759 1760 def end_unit(self, name): 1761 1762 "Add declarations and generated code." 1763 1764 # Restore the output stream. 1765 1766 out = self.out 1767 self.out = self.out_toplevel 1768 1769 self.write_temporaries(name) 1770 out.seek(0) 1771 self.out.write(out.read()) 1772 1773 self.indent -= 1 1774 print >>self.out, "}" 1775 1776 def start_module(self): 1777 1778 "Write the start of each module's main function." 1779 1780 print >>self.out, "void __main_%s()" % encode_path(self.name) 1781 print >>self.out, "{" 1782 self.indent += 1 1783 self.start_unit() 1784 1785 def end_module(self): 1786 1787 "End each module by closing its main function." 1788 1789 self.end_unit(self.name) 1790 1791 def start_function(self, name): 1792 1793 "Start the function having the given 'name'." 1794 1795 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1796 print >>self.out, "{" 1797 self.indent += 1 1798 1799 # Obtain local names from parameters. 1800 1801 parameters = self.importer.function_parameters[name] 1802 locals = self.importer.function_locals[name].keys() 1803 names = [] 1804 1805 for n in locals: 1806 1807 # Filter out special names and parameters. Note that self is a local 1808 # regardless of whether it originally appeared in the parameters or 1809 # not. 1810 1811 if n.startswith("$l") or n in parameters or n == "self": 1812 continue 1813 names.append(encode_path(n)) 1814 1815 # Emit required local names. 1816 1817 if names: 1818 names.sort() 1819 self.writeline("__attr %s;" % ", ".join(names)) 1820 1821 self.write_parameters(name) 1822 self.start_unit() 1823 1824 def end_function(self, name): 1825 1826 "End the function having the given 'name'." 1827 1828 self.end_unit(name) 1829 print >>self.out 1830 1831 def write_temporaries(self, name): 1832 1833 "Write temporary storage employed by 'name'." 1834 1835 # Provide space for the given number of targets. 1836 1837 if self.uses_temp(name, "__tmp_targets"): 1838 targets = self.importer.function_targets.get(name) 1839 self.writeline("__attr __tmp_targets[%d];" % targets) 1840 1841 # Add temporary variable usage details. 1842 1843 if self.uses_temp(name, "__tmp_context"): 1844 self.writeline("__ref __tmp_context;") 1845 if self.uses_temp(name, "__tmp_value"): 1846 self.writeline("__ref __tmp_value;") 1847 if self.uses_temp(name, "__tmp_target_value"): 1848 self.writeline("__ref __tmp_target_value;") 1849 if self.uses_temp(name, "__tmp_result"): 1850 self.writeline("__attr __tmp_result;") 1851 1852 module = self.importer.get_module(self.name) 1853 1854 if name in module.exception_namespaces: 1855 self.writeline("__exc __tmp_exc;") 1856 1857 def write_parameters(self, name): 1858 1859 """ 1860 For the function having the given 'name', write definitions of 1861 parameters found in the arguments array. 1862 """ 1863 1864 parameters = self.importer.function_parameters[name] 1865 1866 # Generate any self reference. 1867 1868 if self.is_method(name): 1869 self.writeline("__attr * const self = &__args[0];") 1870 1871 # Generate aliases for the parameters. 1872 1873 for i, parameter in enumerate(parameters): 1874 self.writeline("__attr * const %s = &__args[%d];" % (encode_path(parameter), i+1)) 1875 1876 def start_if(self, first, test_ref): 1877 self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref)) 1878 self.writeline("{") 1879 self.indent += 1 1880 1881 def end_if(self): 1882 self.indent -= 1 1883 self.writeline("}") 1884 1885 def start_else(self): 1886 self.writeline("else") 1887 self.writeline("{") 1888 self.indent += 1 1889 1890 def end_else(self): 1891 self.indent -= 1 1892 self.writeline("}") 1893 1894 def statement(self, expr): 1895 # NOTE: Should never be None. 1896 if not expr: 1897 self.writestmt("...;") 1898 s = str(expr) 1899 if s: 1900 self.writestmt("%s;" % s) 1901 1902 def statements(self, results): 1903 for result in results: 1904 self.statement(result) 1905 1906 def writeline(self, s): 1907 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1908 1909 def writestmt(self, s): 1910 print >>self.out 1911 self.writeline(s) 1912 1913 def write_comment(self, s): 1914 self.writestmt("/* %s */" % s) 1915 1916 def pad(self, extra=0): 1917 return (self.indent + extra) * self.tabstop 1918 1919 def indenttext(self, s, levels): 1920 lines = s.split("\n") 1921 out = [lines[0]] 1922 for line in lines[1:]: 1923 out.append(levels * self.tabstop + line) 1924 if line.endswith("("): 1925 levels += 1 1926 elif line.startswith(")"): 1927 levels -= 1 1928 return "\n".join(out) 1929 1930 # vim: tabstop=4 expandtab shiftwidth=4