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