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