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