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_contexts", 743 "<set_context>" : "__tmp_contexts", 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 "<context>" : "__get_context", 752 "<set_context>" : "__set_context", 753 "<set_accessor>" : "__set_accessor", 754 "<set_target_accessor>" : "__set_target_accessor", 755 } 756 757 subs.update(temp_subs) 758 subs.update(op_subs) 759 760 output = [] 761 substituted = set() 762 763 # The context set or retrieved will be that used by any enclosing 764 # invocation. 765 766 context_index = self.function_target - 1 767 768 # Obtain encoded versions of each instruction, accumulating temporary 769 # variables. 770 771 for instruction in self.optimiser.access_instructions[location]: 772 encoded, _substituted = encode_access_instruction(instruction, subs, context_index) 773 output.append(encoded) 774 substituted.update(_substituted) 775 776 # Record temporary name usage. 777 778 for sub in substituted: 779 if temp_subs.has_key(sub): 780 self.record_temp(temp_subs[sub]) 781 782 del self.attrs[0] 783 return AttrResult(output, refs, location) 784 785 def get_referenced_attributes(self, location): 786 787 """ 788 Convert 'location' to the form used by the deducer and retrieve any 789 identified attributes. 790 """ 791 792 access_location = self.deducer.const_accesses.get(location) 793 refs = [] 794 for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]: 795 refs.append(attr) 796 return refs 797 798 def get_referenced_attribute_invocations(self, location): 799 800 """ 801 Convert 'location' to the form used by the deducer and retrieve any 802 identified attribute invocation details. 803 """ 804 805 access_location = self.deducer.const_accesses.get(location) 806 return self.deducer.reference_invocations_unsuitable.get(access_location or location) 807 808 def get_accessor_kinds(self, location): 809 810 "Return the accessor kinds for 'location'." 811 812 return self.optimiser.accessor_kinds.get(location) 813 814 def get_access_location(self, name, attrnames=None): 815 816 """ 817 Using the current namespace, the given 'name', and the 'attrnames' 818 employed in an access, return the access location. 819 """ 820 821 path = self.get_path_for_access() 822 823 # Get the location used by the deducer and optimiser and find any 824 # recorded access. 825 826 attrnames = attrnames and ".".join(self.attrs) 827 access_number = self.get_access_number(path, name, attrnames) 828 self.update_access_number(path, name, attrnames) 829 return (path, name, attrnames, access_number) 830 831 def get_access_number(self, path, name, attrnames): 832 access = name, attrnames 833 if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access): 834 return self.attr_accesses[path][access] 835 else: 836 return 0 837 838 def update_access_number(self, path, name, attrnames): 839 access = name, attrnames 840 if name: 841 init_item(self.attr_accesses, path, dict) 842 init_item(self.attr_accesses[path], access, lambda: 0) 843 self.attr_accesses[path][access] += 1 844 845 def get_accessor_location(self, name): 846 847 """ 848 Using the current namespace and the given 'name', return the accessor 849 location. 850 """ 851 852 path = self.get_path_for_access() 853 854 # Get the location used by the deducer and optimiser and find any 855 # recorded accessor. 856 857 access_number = self.get_accessor_number(path, name) 858 self.update_accessor_number(path, name) 859 return (path, name, None, access_number) 860 861 def get_accessor_number(self, path, name): 862 if self.attr_accessors.has_key(path) and self.attr_accessors[path].has_key(name): 863 return self.attr_accessors[path][name] 864 else: 865 return 0 866 867 def update_accessor_number(self, path, name): 868 if name: 869 init_item(self.attr_accessors, path, dict) 870 init_item(self.attr_accessors[path], name, lambda: 0) 871 self.attr_accessors[path][name] += 1 872 873 def process_class_node(self, n): 874 875 "Process the given class node 'n'." 876 877 class_name = self.get_object_path(n.name) 878 879 # Where a class is set conditionally or where the name may refer to 880 # different values, assign the name. 881 882 ref = self.importer.identify(class_name) 883 884 if not ref.static(): 885 self.process_assignment_for_object( 886 n.name, make_expression("((__attr) {.value=&%s})" % 887 encode_path(class_name))) 888 889 self.enter_namespace(n.name) 890 891 if self.have_object(): 892 self.write_comment("Class: %s" % class_name) 893 894 self.initialise_inherited_members(class_name) 895 896 self.process_structure(n) 897 self.write_comment("End class: %s" % class_name) 898 899 self.exit_namespace() 900 901 def initialise_inherited_members(self, class_name): 902 903 "Initialise members of 'class_name' inherited from its ancestors." 904 905 for name, path in self.importer.all_class_attrs[class_name].items(): 906 target = "%s.%s" % (class_name, name) 907 908 # Ignore attributes with definitions. 909 910 ref = self.importer.identify(target) 911 if ref: 912 continue 913 914 # Ignore special type attributes. 915 916 if is_type_attribute(name): 917 continue 918 919 # Reference inherited attributes. 920 921 ref = self.importer.identify(path) 922 if ref and not ref.static(): 923 parent, attrname = path.rsplit(".", 1) 924 925 self.writestmt("__store_via_object(&%s, %s, __load_via_object(&%s, %s));" % ( 926 encode_path(class_name), encode_symbol("pos", name), 927 encode_path(parent), encode_symbol("pos", attrname) 928 )) 929 930 def process_from_node(self, n): 931 932 "Process the given node 'n', importing from another module." 933 934 path = self.get_namespace_path() 935 936 # Attempt to obtain the referenced objects. 937 938 for name, alias in n.names: 939 if name == "*": 940 raise InspectError("Only explicitly specified names can be imported from modules.", path, n) 941 942 # Obtain the path of the assigned name. 943 944 objpath = self.get_object_path(alias or name) 945 946 # Obtain the identity of the name. 947 948 ref = self.importer.identify(objpath) 949 950 # Where the name is not static, assign the value. 951 952 if ref and not ref.static() and ref.get_name(): 953 self.writestmt("%s;" % 954 TrResolvedNameRef(alias or name, Reference("<var>", None, objpath), 955 expr=TrResolvedNameRef(name, ref))) 956 957 def process_function_body_node(self, n): 958 959 """ 960 Process the given function, lambda, if expression or list comprehension 961 node 'n', generating the body. 962 """ 963 964 function_name = self.get_namespace_path() 965 self.start_function(function_name) 966 967 # Process the function body. 968 969 in_conditional = self.in_conditional 970 self.in_conditional = False 971 self.function_target = 0 972 973 # Process any guards defined for the parameters. 974 975 for name in self.importer.function_parameters.get(function_name): 976 self.generate_guard(name) 977 978 # Produce the body and any additional return statement. 979 980 expr = self.process_structure_node(n.code) or PredefinedConstantRef("None") 981 if not isinstance(expr, ReturnRef): 982 self.writestmt("return %s;" % expr) 983 984 self.in_conditional = in_conditional 985 986 self.end_function(function_name) 987 988 def generate_guard(self, name): 989 990 """ 991 Get the accessor details for 'name', found in the current namespace, and 992 generate any guards defined for it. 993 """ 994 995 # Obtain the location, keeping track of assignment versions. 996 997 location = self.get_accessor_location(name) 998 test = self.deducer.accessor_guard_tests.get(location) 999 1000 # Generate any guard from the deduced information. 1001 1002 if test: 1003 guard, guard_type = test 1004 1005 if guard == "specific": 1006 ref = first(self.deducer.accessor_all_types[location]) 1007 argstr = "&%s" % encode_path(ref.get_origin()) 1008 elif guard == "common": 1009 ref = first(self.deducer.accessor_all_general_types[location]) 1010 typeattr = encode_type_attribute(ref.get_origin()) 1011 argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr)) 1012 else: 1013 return 1014 1015 # Produce an appropriate access to an attribute's value. 1016 1017 parameters = self.importer.function_parameters.get(self.get_namespace_path()) 1018 if parameters and name in parameters: 1019 name_to_value = "%s->value" % name 1020 else: 1021 name_to_value = "%s.value" % name 1022 1023 # Write a test that raises a TypeError upon failure. 1024 1025 self.writestmt("if (!__test_%s_%s(%s, %s)) __raise_type_error();" % ( 1026 guard, guard_type, name_to_value, argstr)) 1027 1028 def process_function_node(self, n): 1029 1030 """ 1031 Process the given function, lambda, if expression or list comprehension 1032 node 'n', generating any initialisation statements. 1033 """ 1034 1035 # Where a function is declared conditionally, use a separate name for 1036 # the definition, and assign the definition to the stated name. 1037 1038 original_name = n.name 1039 1040 if self.in_conditional or self.in_function: 1041 name = self.get_lambda_name() 1042 else: 1043 name = n.name 1044 1045 objpath = self.get_object_path(name) 1046 1047 # Obtain details of the defaults. 1048 1049 defaults = self.process_function_defaults(n, name, objpath) 1050 if defaults: 1051 for default in defaults: 1052 self.writeline("%s;" % default) 1053 1054 # Where a function is set conditionally or where the name may refer to 1055 # different values, assign the name. 1056 1057 ref = self.importer.identify(objpath) 1058 1059 if self.in_conditional or self.in_function: 1060 self.process_assignment_for_object(original_name, compiler.ast.Name(name)) 1061 elif not ref.static(): 1062 context = self.is_method(objpath) 1063 1064 self.process_assignment_for_object(original_name, 1065 make_expression("((__attr) {.value=&%s})" % encode_path(objpath))) 1066 1067 def process_function_defaults(self, n, name, objpath, instance_name=None): 1068 1069 """ 1070 Process the given function or lambda node 'n', initialising defaults 1071 that are dynamically set. The given 'name' indicates the name of the 1072 function. The given 'objpath' indicates the origin of the function. 1073 The given 'instance_name' indicates the name of any separate instance 1074 of the function created to hold the defaults. 1075 1076 Return a list of operations setting defaults on a function instance. 1077 """ 1078 1079 function_name = self.get_object_path(name) 1080 function_defaults = self.importer.function_defaults.get(function_name) 1081 if not function_defaults: 1082 return None 1083 1084 # Determine whether any unidentified defaults are involved. 1085 1086 for argname, default in function_defaults: 1087 if not default.static(): 1088 break 1089 else: 1090 return None 1091 1092 # Handle bound methods. 1093 1094 if not instance_name: 1095 instance_name = "&%s" % encode_path(objpath) 1096 1097 # Where defaults are involved but cannot be identified, obtain a new 1098 # instance of the lambda and populate the defaults. 1099 1100 defaults = [] 1101 1102 # Join the original defaults with the inspected defaults. 1103 1104 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 1105 1106 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 1107 1108 # Obtain any reference for the default. 1109 1110 if original: 1111 argname, default = original 1112 name_ref = self.process_structure_node(default) 1113 elif inspected: 1114 argname, default = inspected 1115 name_ref = TrResolvedNameRef(argname, default) 1116 else: 1117 continue 1118 1119 # Generate default initialisers except when constants are employed. 1120 # Constants should be used when populating the function structures. 1121 1122 if name_ref and not isinstance(name_ref, TrConstantValueRef): 1123 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref)) 1124 1125 return defaults 1126 1127 def process_if_node(self, n): 1128 1129 """ 1130 Process the given "if" node 'n'. 1131 """ 1132 1133 first = True 1134 for test, body in n.tests: 1135 test_ref = self.process_structure_node(test) 1136 self.start_if(first, test_ref) 1137 1138 in_conditional = self.in_conditional 1139 self.in_conditional = True 1140 self.process_structure_node(body) 1141 self.in_conditional = in_conditional 1142 1143 self.end_if() 1144 first = False 1145 1146 if n.else_: 1147 self.start_else() 1148 self.process_structure_node(n.else_) 1149 self.end_else() 1150 1151 def process_invocation_node(self, n): 1152 1153 "Process the given invocation node 'n'." 1154 1155 # Any invocations in the expression will store target details in a 1156 # different location. 1157 1158 self.function_target += 1 1159 1160 # Process the expression. 1161 1162 expr = self.process_structure_node(n.node) 1163 1164 # Reference the current target again. 1165 1166 self.function_target -= 1 1167 1168 # Obtain details of the invocation expression. 1169 1170 objpath = expr.get_origin() 1171 location = expr.access_location() 1172 1173 # Identified target details. 1174 1175 target = None 1176 target_structure = None 1177 1178 # Specific function target information. 1179 1180 function = None 1181 1182 # Instantiation involvement. 1183 1184 instantiation = False 1185 literal_instantiation = False 1186 1187 # Invocation requirements. 1188 1189 context_required = True 1190 have_access_context = isinstance(expr, AttrResult) 1191 parameters = None 1192 1193 # Obtain details of the callable and of its parameters. 1194 1195 # Literals may be instantiated specially. 1196 1197 if expr.is_name() and expr.name.startswith("$L") and objpath: 1198 instantiation = literal_instantiation = objpath 1199 target = encode_literal_instantiator(objpath) 1200 context_required = False 1201 1202 # Identified targets employ function pointers directly. 1203 1204 elif objpath: 1205 parameters = self.importer.function_parameters.get(objpath) 1206 1207 # Class invocation involves instantiators. 1208 1209 if expr.has_kind("<class>"): 1210 instantiation = objpath 1211 target = encode_instantiator_pointer(objpath) 1212 init_ref = self.importer.all_class_attrs[objpath]["__init__"] 1213 target_structure = "&%s" % encode_path(init_ref) 1214 context_required = False 1215 1216 # Only plain functions and bound methods employ function pointers. 1217 1218 elif expr.has_kind("<function>"): 1219 function = objpath 1220 1221 # Test for functions and methods. 1222 1223 context_required = self.is_method(objpath) 1224 accessor_kinds = self.get_accessor_kinds(location) 1225 instance_accessor = accessor_kinds and \ 1226 len(accessor_kinds) == 1 and \ 1227 first(accessor_kinds) == "<instance>" 1228 1229 # Only identify certain bound methods or functions. 1230 1231 if not context_required or instance_accessor: 1232 target = encode_function_pointer(objpath) 1233 1234 # Access bound method defaults even if it is not clear whether 1235 # the accessor is appropriate. 1236 1237 target_structure = "&%s" % encode_path(objpath) 1238 1239 # Other targets are retrieved at run-time. Some information about them 1240 # may be available and be used to provide warnings about argument 1241 # compatibility. 1242 1243 elif self.importer.give_warning("args"): 1244 unsuitable = self.get_referenced_attribute_invocations(location) 1245 1246 if unsuitable: 1247 for ref in unsuitable: 1248 _objpath = ref.get_origin() 1249 num_parameters = len(self.importer.function_parameters[_objpath]) 1250 print >>sys.stderr, \ 1251 "In %s, at line %d, inappropriate number of " \ 1252 "arguments given. Need %d arguments to call %s." % ( 1253 self.get_namespace_path(), n.lineno, num_parameters, 1254 _objpath) 1255 1256 # Arguments are presented in a temporary frame array with any context 1257 # always being the first argument. Where it would be unused, it may be 1258 # set to null. 1259 1260 if context_required: 1261 if have_access_context: 1262 self.record_temp("__tmp_contexts") 1263 args = ["(__attr) {.value=__tmp_contexts[%d]}" % self.function_target] 1264 else: 1265 self.record_temp("__tmp_targets") 1266 args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] 1267 else: 1268 args = ["__NULL"] 1269 1270 # Complete the array with null values, permitting tests for a complete 1271 # set of arguments. 1272 1273 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 1274 kwcodes = [] 1275 kwargs = [] 1276 1277 # Any invocations in the arguments will store target details in a 1278 # different location. 1279 1280 self.function_target += 1 1281 1282 for i, arg in enumerate(n.args): 1283 argexpr = self.process_structure_node(arg) 1284 1285 # Store a keyword argument, either in the argument list or 1286 # in a separate keyword argument list for subsequent lookup. 1287 1288 if isinstance(arg, compiler.ast.Keyword): 1289 1290 # With knowledge of the target, store the keyword 1291 # argument directly. 1292 1293 if parameters: 1294 try: 1295 argnum = parameters.index(arg.name) 1296 except ValueError: 1297 raise TranslateError("Argument %s is not recognised." % arg.name, 1298 self.get_namespace_path(), n) 1299 args[argnum+1] = str(argexpr) 1300 1301 # Otherwise, store the details in a separate collection. 1302 1303 else: 1304 kwargs.append(str(argexpr)) 1305 kwcodes.append("{%s, %s}" % ( 1306 encode_symbol("ppos", arg.name), 1307 encode_symbol("pcode", arg.name))) 1308 1309 # Store non-keyword arguments in the argument list, rejecting 1310 # superfluous arguments. 1311 1312 else: 1313 try: 1314 args[i+1] = str(argexpr) 1315 except IndexError: 1316 raise TranslateError("Too many arguments specified.", 1317 self.get_namespace_path(), n) 1318 1319 # Reference the current target again. 1320 1321 self.function_target -= 1 1322 1323 # Defaults are added to the frame where arguments are missing. 1324 1325 if parameters: 1326 function_defaults = self.importer.function_defaults.get(objpath) 1327 if function_defaults: 1328 1329 # Visit each default and set any missing arguments. 1330 # Use the target structure to obtain defaults, as opposed to the 1331 # actual function involved. 1332 1333 for i, (argname, default) in enumerate(function_defaults): 1334 argnum = parameters.index(argname) 1335 if not args[argnum+1]: 1336 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i) 1337 1338 # Test for missing arguments. 1339 1340 if None in args: 1341 raise TranslateError("Not all arguments supplied.", 1342 self.get_namespace_path(), n) 1343 1344 # Encode the arguments. 1345 1346 argstr = "__ARGS(%s)" % ", ".join(args) 1347 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 1348 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 1349 1350 # Where literal instantiation is occurring, add an argument indicating 1351 # the number of values. 1352 1353 if literal_instantiation: 1354 argstr += ", %d" % (len(args) - 1) 1355 1356 # First, the invocation expression is presented. 1357 1358 stages = [] 1359 1360 # Without a known specific callable, the expression provides the target. 1361 1362 if not target or context_required: 1363 if target: 1364 stages.append(str(expr)) 1365 else: 1366 self.record_temp("__tmp_targets") 1367 stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr)) 1368 1369 # Any specific callable is then obtained. 1370 1371 if target: 1372 stages.append(target) 1373 1374 # Methods accessed via unidentified accessors are obtained. 1375 1376 elif function: 1377 self.record_temp("__tmp_contexts") 1378 self.record_temp("__tmp_targets") 1379 1380 if context_required: 1381 if have_access_context: 1382 stages.append("__get_function(__tmp_contexts[%d], __tmp_targets[%d])" % ( 1383 self.function_target, self.function_target)) 1384 else: 1385 stages.append("__get_function(__CONTEXT_AS_VALUE(__tmp_targets[%d]).value, __tmp_targets[%d])" % ( 1386 self.function_target, self.function_target)) 1387 else: 1388 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % ( 1389 self.function_target, encode_symbol("pos", "__fn__"))) 1390 1391 # With a known target, the function is obtained directly and called. 1392 # By putting the invocation at the end of the final element in the 1393 # instruction sequence (the stages), the result becomes the result of 1394 # the sequence. Moreover, the parameters become part of the sequence 1395 # and thereby participate in a guaranteed evaluation order. 1396 1397 if target or function: 1398 stages[-1] += "(%s)" % argstr 1399 if instantiation: 1400 return InstantiationResult(instantiation, stages) 1401 else: 1402 return InvocationResult(stages) 1403 1404 # With unknown targets, the generic invocation function is applied to 1405 # the callable and argument collections. 1406 1407 else: 1408 self.record_temp("__tmp_targets") 1409 stages.append("__invoke(\n__tmp_targets[%d],\n%d, %d, %s, %s,\n%d, %s\n)" % ( 1410 self.function_target, 1411 self.always_callable and 1 or 0, 1412 len(kwargs), kwcodestr, kwargstr, 1413 len(args), argstr)) 1414 return InvocationResult(stages) 1415 1416 def always_callable(self, refs): 1417 1418 "Determine whether all 'refs' are callable." 1419 1420 for ref in refs: 1421 if not ref.static(): 1422 return False 1423 else: 1424 origin = ref.final() 1425 if not self.importer.get_attribute(origin, "__fn__"): 1426 return False 1427 return True 1428 1429 def need_default_arguments(self, objpath, nargs): 1430 1431 """ 1432 Return whether any default arguments are needed when invoking the object 1433 given by 'objpath'. 1434 """ 1435 1436 parameters = self.importer.function_parameters.get(objpath) 1437 return nargs < len(parameters) 1438 1439 def process_lambda_node(self, n): 1440 1441 "Process the given lambda node 'n'." 1442 1443 name = self.get_lambda_name() 1444 function_name = self.get_object_path(name) 1445 1446 defaults = self.process_function_defaults(n, name, function_name, "__tmp_value") 1447 1448 # Without defaults, produce an attribute referring to the function. 1449 1450 if not defaults: 1451 return make_expression("((__attr) {.value=&%s})" % encode_path(function_name)) 1452 1453 # With defaults, copy the function structure and set the defaults on the 1454 # copy. 1455 1456 else: 1457 self.record_temp("__tmp_value") 1458 return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {.value=__tmp_value})" % ( 1459 encode_path(function_name), 1460 encode_symbol("obj", function_name), 1461 ", ".join(defaults))) 1462 1463 def process_logical_node(self, n): 1464 1465 """ 1466 Process the given operator node 'n'. 1467 1468 Convert ... to ... 1469 1470 <a> and <b> 1471 (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b> 1472 1473 <a> or <b> 1474 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b> 1475 """ 1476 1477 self.record_temp("__tmp_result") 1478 1479 if isinstance(n, compiler.ast.And): 1480 op = "!" 1481 else: 1482 op = "" 1483 1484 results = [] 1485 1486 for node in n.nodes[:-1]: 1487 expr = self.process_structure_node(node) 1488 results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, op)) 1489 1490 expr = self.process_structure_node(n.nodes[-1]) 1491 results.append(str(expr)) 1492 1493 return make_expression("(%s)" % "".join(results)) 1494 1495 def process_name_node(self, n, expr=None): 1496 1497 "Process the given name node 'n' with the optional assignment 'expr'." 1498 1499 # Determine whether the name refers to a static external entity. 1500 1501 if n.name in predefined_constants: 1502 return PredefinedConstantRef(n.name, expr) 1503 1504 # Convert literal references, operator function names, and print 1505 # function names to references. 1506 1507 elif n.name.startswith("$L") or n.name.startswith("$op") or \ 1508 n.name.startswith("$print"): 1509 1510 ref, paths = self.importer.get_module(self.name).special[n.name] 1511 return TrResolvedNameRef(n.name, ref) 1512 1513 # Temporary names are output program locals. 1514 1515 elif n.name.startswith("$t"): 1516 return TrResolvedNameRef(n.name, Reference("<var>"), expr=expr) 1517 1518 # Get the appropriate name for the name reference, using the same method 1519 # as in the inspector. 1520 1521 path = self.get_namespace_path() 1522 objpath = self.get_object_path(n.name) 1523 1524 # Determine any assigned globals. 1525 1526 globals = self.importer.get_module(self.name).scope_globals.get(path) 1527 if globals and n.name in globals: 1528 objpath = self.get_global_path(n.name) 1529 1530 # Get the static identity of the name. 1531 1532 ref = self.importer.identify(objpath) 1533 if ref and not ref.get_name(): 1534 ref = ref.alias(objpath) 1535 1536 # Obtain any resolved names for non-assignment names. 1537 1538 if not expr and not ref and self.in_function: 1539 locals = self.importer.function_locals.get(path) 1540 ref = locals and locals.get(n.name) 1541 1542 # Determine whether the name refers to a parameter. The generation of 1543 # parameter references is different from other names. 1544 1545 parameters = self.importer.function_parameters.get(path) 1546 parameter = n.name == "self" and self.in_method() or \ 1547 parameters and n.name in parameters 1548 1549 # Find any invocation details. 1550 1551 location = self.get_access_location(n.name) 1552 1553 # Qualified names are used for resolved static references or for 1554 # static namespace members. The reference should be configured to return 1555 # such names. 1556 1557 return TrResolvedNameRef(n.name, ref, expr=expr, parameter=parameter, location=location) 1558 1559 def process_not_node(self, n): 1560 1561 "Process the given operator node 'n'." 1562 1563 return make_expression("(__BOOL(%s) ? %s : %s)" % 1564 (self.process_structure_node(n.expr), PredefinedConstantRef("False"), 1565 PredefinedConstantRef("True"))) 1566 1567 def process_raise_node(self, n): 1568 1569 "Process the given raise node 'n'." 1570 1571 # NOTE: Determine which raise statement variants should be permitted. 1572 1573 if n.expr1: 1574 1575 # Names with accompanying arguments are treated like invocations. 1576 1577 if n.expr2: 1578 call = compiler.ast.CallFunc(n.expr1, [n.expr2]) 1579 exc = self.process_structure_node(call) 1580 self.writestmt("__Raise(%s);" % exc) 1581 1582 # Raise instances, testing the kind at run-time if necessary and 1583 # instantiating any non-instance. 1584 1585 else: 1586 exc = self.process_structure_node(n.expr1) 1587 1588 if isinstance(exc, TrInstanceRef): 1589 self.writestmt("__Raise(%s);" % exc) 1590 else: 1591 self.writestmt("__Raise(__ensure_instance(%s));" % exc) 1592 else: 1593 self.writestmt("__Throw(__tmp_exc);") 1594 1595 def process_return_node(self, n): 1596 1597 "Process the given return node 'n'." 1598 1599 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1600 if self.in_try_finally or self.in_try_except: 1601 self.writestmt("__Return(%s);" % expr) 1602 else: 1603 self.writestmt("return %s;" % expr) 1604 1605 return ReturnRef() 1606 1607 def process_try_node(self, n): 1608 1609 """ 1610 Process the given "try...except" node 'n'. 1611 """ 1612 1613 in_try_except = self.in_try_except 1614 self.in_try_except = True 1615 1616 # Use macros to implement exception handling. 1617 1618 self.writestmt("__Try") 1619 self.writeline("{") 1620 self.indent += 1 1621 self.process_structure_node(n.body) 1622 1623 # Put the else statement in another try block that handles any raised 1624 # exceptions and converts them to exceptions that will not be handled by 1625 # the main handling block. 1626 1627 if n.else_: 1628 self.writestmt("__Try") 1629 self.writeline("{") 1630 self.indent += 1 1631 self.process_structure_node(n.else_) 1632 self.indent -= 1 1633 self.writeline("}") 1634 self.writeline("__Catch (__tmp_exc)") 1635 self.writeline("{") 1636 self.indent += 1 1637 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1638 self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1639 self.indent -= 1 1640 self.writeline("}") 1641 1642 # Complete the try block and enter the finally block, if appropriate. 1643 1644 if self.in_try_finally: 1645 self.writestmt("__Complete;") 1646 1647 self.indent -= 1 1648 self.writeline("}") 1649 1650 self.in_try_except = in_try_except 1651 1652 # Handlers are tests within a common handler block. 1653 1654 self.writeline("__Catch (__tmp_exc)") 1655 self.writeline("{") 1656 self.indent += 1 1657 1658 # Introduce an if statement to handle the completion of a try block. 1659 1660 self.process_try_completion() 1661 1662 # Handle exceptions in else blocks converted to __RaiseElse, converting 1663 # them back to normal exceptions. 1664 1665 if n.else_: 1666 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1667 1668 # Exception handling. 1669 1670 for name, var, handler in n.handlers: 1671 1672 # Test for specific exceptions. 1673 1674 if name is not None: 1675 name_ref = self.process_structure_node(name) 1676 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref) 1677 else: 1678 self.writeline("else if (1)") 1679 1680 self.writeline("{") 1681 self.indent += 1 1682 1683 # Establish the local for the handler. 1684 1685 if var is not None: 1686 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) 1687 1688 if handler is not None: 1689 self.process_structure_node(handler) 1690 1691 self.indent -= 1 1692 self.writeline("}") 1693 1694 # Re-raise unhandled exceptions. 1695 1696 self.writeline("else __Throw(__tmp_exc);") 1697 1698 # End the handler block. 1699 1700 self.indent -= 1 1701 self.writeline("}") 1702 1703 def process_try_finally_node(self, n): 1704 1705 """ 1706 Process the given "try...finally" node 'n'. 1707 """ 1708 1709 in_try_finally = self.in_try_finally 1710 self.in_try_finally = True 1711 1712 # Use macros to implement exception handling. 1713 1714 self.writestmt("__Try") 1715 self.writeline("{") 1716 self.indent += 1 1717 self.process_structure_node(n.body) 1718 self.indent -= 1 1719 self.writeline("}") 1720 1721 self.in_try_finally = in_try_finally 1722 1723 # Finally clauses handle special exceptions. 1724 1725 self.writeline("__Catch (__tmp_exc)") 1726 self.writeline("{") 1727 self.indent += 1 1728 self.process_structure_node(n.final) 1729 1730 # Introduce an if statement to handle the completion of a try block. 1731 1732 self.process_try_completion() 1733 self.writeline("else __Throw(__tmp_exc);") 1734 1735 self.indent -= 1 1736 self.writeline("}") 1737 1738 def process_try_completion(self): 1739 1740 "Generate a test for the completion of a try block." 1741 1742 self.writestmt("if (__tmp_exc.completing)") 1743 self.writeline("{") 1744 self.indent += 1 1745 1746 # Do not return anything at the module level. 1747 1748 if self.get_namespace_path() != self.name: 1749 1750 # Only use the normal return statement if no surrounding try blocks 1751 # apply. 1752 1753 if not self.in_try_finally and not self.in_try_except: 1754 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1755 else: 1756 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1757 1758 self.indent -= 1 1759 self.writeline("}") 1760 1761 def process_while_node(self, n): 1762 1763 "Process the given while node 'n'." 1764 1765 self.writeline("while (1)") 1766 self.writeline("{") 1767 self.indent += 1 1768 test = self.process_structure_node(n.test) 1769 1770 # Emit the loop termination condition unless "while <true value>" is 1771 # indicated. 1772 1773 if not (isinstance(test, PredefinedConstantRef) and test.value): 1774 1775 # NOTE: This needs to evaluate whether the operand is true or false 1776 # NOTE: according to Python rules. 1777 1778 self.writeline("if (!__BOOL(%s))" % test) 1779 self.writeline("{") 1780 self.indent += 1 1781 if n.else_: 1782 self.process_structure_node(n.else_) 1783 self.writestmt("break;") 1784 self.indent -= 1 1785 self.writeline("}") 1786 1787 in_conditional = self.in_conditional 1788 self.in_conditional = True 1789 self.process_structure_node(n.body) 1790 self.in_conditional = in_conditional 1791 1792 self.indent -= 1 1793 self.writeline("}") 1794 1795 # Special variable usage. 1796 1797 def record_temp(self, name): 1798 1799 """ 1800 Record the use of the temporary 'name' in the current namespace. At the 1801 class or module level, the temporary name is associated with the module, 1802 since the variable will then be allocated in the module's own main 1803 program. 1804 """ 1805 1806 if self.in_function: 1807 path = self.get_namespace_path() 1808 else: 1809 path = self.name 1810 1811 init_item(self.temp_usage, path, set) 1812 self.temp_usage[path].add(name) 1813 1814 def uses_temp(self, path, name): 1815 1816 """ 1817 Return whether the given namespace 'path' employs a temporary variable 1818 with the given 'name'. Note that 'path' should only be a module or a 1819 function or method, not a class. 1820 """ 1821 1822 return self.temp_usage.has_key(path) and name in self.temp_usage[path] 1823 1824 # Output generation. 1825 1826 def start_output(self): 1827 1828 "Write the declarations at the top of each source file." 1829 1830 print >>self.out, """\ 1831 #include "types.h" 1832 #include "exceptions.h" 1833 #include "ops.h" 1834 #include "progconsts.h" 1835 #include "progops.h" 1836 #include "progtypes.h" 1837 #include "main.h" 1838 """ 1839 1840 def start_unit(self): 1841 1842 "Record output within a generated function for later use." 1843 1844 self.out = StringIO() 1845 1846 def end_unit(self, name): 1847 1848 "Add declarations and generated code." 1849 1850 # Restore the output stream. 1851 1852 out = self.out 1853 self.out = self.out_toplevel 1854 1855 self.write_temporaries(name) 1856 out.seek(0) 1857 self.out.write(out.read()) 1858 1859 self.indent -= 1 1860 print >>self.out, "}" 1861 1862 def start_module(self): 1863 1864 "Write the start of each module's main function." 1865 1866 print >>self.out, "void __main_%s()" % encode_path(self.name) 1867 print >>self.out, "{" 1868 self.indent += 1 1869 1870 # Define temporary variables, excluded from the module structure itself. 1871 1872 tempnames = [] 1873 1874 for n in self.importer.all_module_attrs[self.name]: 1875 if n.startswith("$t"): 1876 tempnames.append(encode_path(n)) 1877 1878 if tempnames: 1879 tempnames.sort() 1880 self.writeline("__attr %s;" % ", ".join(tempnames)) 1881 1882 self.start_unit() 1883 1884 def end_module(self): 1885 1886 "End each module by closing its main function." 1887 1888 self.end_unit(self.name) 1889 1890 def start_function(self, name): 1891 1892 "Start the function having the given 'name'." 1893 1894 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1895 print >>self.out, "{" 1896 self.indent += 1 1897 1898 # Obtain local names from parameters. 1899 1900 parameters = self.importer.function_parameters[name] 1901 locals = self.importer.function_locals[name].keys() 1902 names = [] 1903 1904 for n in locals: 1905 1906 # Filter out special names and parameters. Note that self is a local 1907 # regardless of whether it originally appeared in the parameters or 1908 # not. 1909 1910 if n.startswith("$l") or n in parameters or n == "self": 1911 continue 1912 names.append(encode_path(n)) 1913 1914 # Emit required local names. 1915 1916 if names: 1917 names.sort() 1918 self.writeline("__attr %s;" % ", ".join(names)) 1919 1920 self.write_parameters(name) 1921 self.start_unit() 1922 1923 def end_function(self, name): 1924 1925 "End the function having the given 'name'." 1926 1927 self.end_unit(name) 1928 print >>self.out 1929 1930 def write_temporaries(self, name): 1931 1932 "Write temporary storage employed by 'name'." 1933 1934 # Provide space for the given number of targets. 1935 1936 targets = self.importer.function_targets.get(name) 1937 1938 if self.uses_temp(name, "__tmp_targets"): 1939 self.writeline("__attr __tmp_targets[%d];" % targets) 1940 if self.uses_temp(name, "__tmp_contexts"): 1941 self.writeline("__ref __tmp_contexts[%d];" % targets) 1942 1943 # Add temporary variable usage details. 1944 1945 if self.uses_temp(name, "__tmp_value"): 1946 self.writeline("__ref __tmp_value;") 1947 if self.uses_temp(name, "__tmp_target_value"): 1948 self.writeline("__ref __tmp_target_value;") 1949 if self.uses_temp(name, "__tmp_result"): 1950 self.writeline("__attr __tmp_result;") 1951 1952 module = self.importer.get_module(self.name) 1953 1954 if name in module.exception_namespaces: 1955 self.writeline("__exc __tmp_exc;") 1956 1957 def write_parameters(self, name): 1958 1959 """ 1960 For the function having the given 'name', write definitions of 1961 parameters found in the arguments array. 1962 """ 1963 1964 parameters = self.importer.function_parameters[name] 1965 1966 # Generate any self reference. 1967 1968 if self.is_method(name): 1969 self.writeline("__attr * const self = &__args[0];") 1970 1971 # Generate aliases for the parameters. 1972 1973 for i, parameter in enumerate(parameters): 1974 self.writeline("__attr * const %s = &__args[%d];" % (encode_path(parameter), i+1)) 1975 1976 def start_if(self, first, test_ref): 1977 self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref)) 1978 self.writeline("{") 1979 self.indent += 1 1980 1981 def end_if(self): 1982 self.indent -= 1 1983 self.writeline("}") 1984 1985 def start_else(self): 1986 self.writeline("else") 1987 self.writeline("{") 1988 self.indent += 1 1989 1990 def end_else(self): 1991 self.indent -= 1 1992 self.writeline("}") 1993 1994 def statement(self, expr): 1995 s = str(expr) 1996 if s: 1997 self.writestmt("%s;" % s) 1998 1999 def statements(self, results): 2000 for result in results: 2001 self.statement(result) 2002 2003 def writeline(self, s): 2004 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 2005 2006 def writestmt(self, s): 2007 print >>self.out 2008 self.writeline(s) 2009 2010 def write_comment(self, s): 2011 self.writestmt("/* %s */" % s) 2012 2013 def pad(self, extra=0): 2014 return (self.indent + extra) * self.tabstop 2015 2016 def indenttext(self, s, levels): 2017 lines = s.split("\n") 2018 out = [lines[0]] 2019 for line in lines[1:]: 2020 out.append(levels * self.tabstop + line) 2021 if line.endswith("("): 2022 levels += 1 2023 elif line.startswith(")"): 2024 levels -= 1 2025 return "\n".join(out) 2026 2027 # vim: tabstop=4 expandtab shiftwidth=4