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