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