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