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