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_code, encode_function_pointer, encode_literal_constant, \ 27 encode_literal_instantiator, encode_instantiator_pointer, \ 28 encode_instructions, encode_path, encode_pos, \ 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), encode_pos(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), encode_pos(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), encode_pos(name), 1001 encode_path(parent), encode_pos(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 typeattr = encode_type_attribute(ref.get_origin()) 1085 argstr = "%s, %s" % (encode_pos(typeattr), encode_code(typeattr)) 1086 else: 1087 return 1088 1089 # Produce an appropriate access to an attribute's value. 1090 1091 parameters = self.importer.function_parameters.get(self.get_namespace_path()) 1092 if parameters and name in parameters: 1093 name_to_value = "%s->value" % name 1094 else: 1095 name_to_value = "%s.value" % name 1096 1097 # Write a test that raises a TypeError upon failure. 1098 1099 self.writestmt("if (!__test_%s_%s(%s, %s)) __raise_type_error();" % ( 1100 guard, guard_type, name_to_value, argstr)) 1101 1102 def process_function_node(self, n): 1103 1104 """ 1105 Process the given function, lambda, if expression or list comprehension 1106 node 'n', generating any initialisation statements. 1107 """ 1108 1109 # Where a function is declared conditionally, use a separate name for 1110 # the definition, and assign the definition to the stated name. 1111 1112 original_name = n.name 1113 1114 if self.in_conditional or self.in_function: 1115 name = self.get_lambda_name() 1116 else: 1117 name = n.name 1118 1119 objpath = self.get_object_path(name) 1120 1121 # Obtain details of the defaults. 1122 1123 defaults = self.process_function_defaults(n, name, objpath) 1124 if defaults: 1125 for default in defaults: 1126 self.writeline("%s;" % default) 1127 1128 # Where a function is set conditionally or where the name may refer to 1129 # different values, assign the name. 1130 1131 ref = self.importer.identify(objpath) 1132 1133 if self.in_conditional or self.in_function: 1134 self.process_assignment_for_object(original_name, compiler.ast.Name(name)) 1135 elif not ref.static(): 1136 context = self.is_method(objpath) 1137 1138 self.process_assignment_for_object(original_name, 1139 make_expression("__ATTRVALUE(&%s)" % encode_path(objpath))) 1140 1141 def process_function_defaults(self, n, name, objpath, instance_name=None): 1142 1143 """ 1144 Process the given function or lambda node 'n', initialising defaults 1145 that are dynamically set. The given 'name' indicates the name of the 1146 function. The given 'objpath' indicates the origin of the function. 1147 The given 'instance_name' indicates the name of any separate instance 1148 of the function created to hold the defaults. 1149 1150 Return a list of operations setting defaults on a function instance. 1151 """ 1152 1153 function_name = self.get_object_path(name) 1154 function_defaults = self.importer.function_defaults.get(function_name) 1155 if not function_defaults: 1156 return None 1157 1158 # Determine whether any unidentified defaults are involved. 1159 1160 for argname, default in function_defaults: 1161 if not default.static(): 1162 break 1163 else: 1164 return None 1165 1166 # Handle bound methods. 1167 1168 if not instance_name: 1169 instance_name = "&%s" % encode_path(objpath) 1170 1171 # Where defaults are involved but cannot be identified, obtain a new 1172 # instance of the lambda and populate the defaults. 1173 1174 defaults = [] 1175 1176 # Join the original defaults with the inspected defaults. 1177 1178 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 1179 1180 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 1181 1182 # Obtain any reference for the default. 1183 1184 if original: 1185 argname, default = original 1186 name_ref = self.process_structure_node(default) 1187 elif inspected: 1188 argname, default = inspected 1189 name_ref = TrResolvedNameRef(argname, default) 1190 else: 1191 continue 1192 1193 # Generate default initialisers except when constants are employed. 1194 # Constants should be used when populating the function structures. 1195 1196 if name_ref and not isinstance(name_ref, TrConstantValueRef): 1197 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref)) 1198 1199 return defaults 1200 1201 def process_if_node(self, n): 1202 1203 """ 1204 Process the given "if" node 'n'. 1205 """ 1206 1207 first = True 1208 for test, body in n.tests: 1209 test_ref = self.process_structure_node(test) 1210 self.start_if(first, test_ref) 1211 1212 in_conditional = self.in_conditional 1213 self.in_conditional = True 1214 self.process_structure_node(body) 1215 self.in_conditional = in_conditional 1216 1217 self.end_if() 1218 first = False 1219 1220 if n.else_: 1221 self.start_else() 1222 self.process_structure_node(n.else_) 1223 self.end_else() 1224 1225 def process_invocation_node(self, n): 1226 1227 "Process the given invocation node 'n'." 1228 1229 # Any invocations in the expression will store target details in a 1230 # different location. 1231 1232 self.function_target += 1 1233 1234 # Process the expression. 1235 1236 expr = self.process_structure_node(n.node) 1237 1238 # Reference the current target again. 1239 1240 self.function_target -= 1 1241 1242 # Obtain details of the invocation expression. 1243 1244 objpath = expr.get_origin() 1245 location = expr.access_location() 1246 1247 # Identified target details. 1248 1249 target = None 1250 target_structure = None 1251 1252 # Specific function target information. 1253 1254 function = None 1255 1256 # Instantiation involvement. 1257 1258 instantiation = False 1259 literal_instantiation = False 1260 1261 # Invocation requirements. 1262 1263 context_required = True 1264 have_access_context = isinstance(expr, AttrResult) 1265 context_identity = have_access_context and expr.context() 1266 parameters = None 1267 1268 # Obtain details of the callable and of its parameters. 1269 1270 # Literals may be instantiated specially. 1271 1272 if expr.is_name() and expr.name.startswith("$L") and objpath: 1273 instantiation = literal_instantiation = objpath 1274 target = encode_literal_instantiator(objpath) 1275 context_required = False 1276 1277 # Identified targets employ function pointers directly. 1278 1279 elif objpath: 1280 parameters = self.importer.function_parameters.get(objpath) 1281 1282 # Class invocation involves instantiators. 1283 1284 if expr.has_kind("<class>"): 1285 instantiation = objpath 1286 target = encode_instantiator_pointer(objpath) 1287 init_ref = self.importer.all_class_attrs[objpath]["__init__"] 1288 target_structure = "&%s" % encode_path(init_ref) 1289 context_required = False 1290 1291 # Only plain functions and bound methods employ function pointers. 1292 1293 elif expr.has_kind("<function>"): 1294 function = objpath 1295 1296 # Test for functions and methods. 1297 1298 context_required = self.is_method(objpath) 1299 accessor_kinds = self.get_accessor_kinds(location) 1300 instance_accessor = accessor_kinds and \ 1301 len(accessor_kinds) == 1 and \ 1302 first(accessor_kinds) == "<instance>" 1303 1304 # Only identify certain bound methods or functions. 1305 1306 if not context_required or instance_accessor: 1307 target = encode_function_pointer(objpath) 1308 1309 # Access bound method defaults even if it is not clear whether 1310 # the accessor is appropriate. 1311 1312 target_structure = "&%s" % encode_path(objpath) 1313 1314 # Other targets are retrieved at run-time. Some information about them 1315 # may be available and be used to provide warnings about argument 1316 # compatibility. 1317 1318 elif self.importer.give_warning("args"): 1319 unsuitable = self.get_referenced_attribute_invocations(location) 1320 1321 if unsuitable: 1322 for ref in unsuitable: 1323 _objpath = ref.get_origin() 1324 num_parameters = len(self.importer.function_parameters[_objpath]) 1325 print >>sys.stderr, \ 1326 "In %s, at line %d, inappropriate number of " \ 1327 "arguments given. Need %d arguments to call %s." % ( 1328 self.get_namespace_path(), n.lineno, num_parameters, 1329 _objpath) 1330 1331 # Determine any readily-accessible target identity. 1332 1333 target_identity = target or expr.is_name() and str(expr) or None 1334 target_var = target_identity or "__tmp_targets[%d]" % self.function_target 1335 1336 if not target_identity: 1337 self.record_temp("__tmp_targets") 1338 1339 if context_identity and context_identity.startswith("__tmp_contexts"): 1340 self.record_temp("__tmp_contexts") 1341 1342 # Arguments are presented in a temporary frame array with any context 1343 # always being the first argument. Where it would be unused, it may be 1344 # set to null. 1345 1346 if context_required: 1347 if have_access_context: 1348 args = ["__ATTRVALUE(%s)" % context_identity] 1349 else: 1350 args = ["__CONTEXT_AS_VALUE(%s)" % target_var] 1351 else: 1352 args = ["__NULL"] 1353 1354 # Complete the array with null values, permitting tests for a complete 1355 # set of arguments. 1356 1357 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 1358 kwcodes = [] 1359 kwargs = [] 1360 1361 # Any invocations in the arguments will store target details in a 1362 # different location. 1363 1364 self.function_target += 1 1365 1366 for i, arg in enumerate(n.args): 1367 argexpr = self.process_structure_node(arg) 1368 1369 # Store a keyword argument, either in the argument list or 1370 # in a separate keyword argument list for subsequent lookup. 1371 1372 if isinstance(arg, compiler.ast.Keyword): 1373 1374 # With knowledge of the target, store the keyword 1375 # argument directly. 1376 1377 if parameters: 1378 try: 1379 argnum = parameters.index(arg.name) 1380 except ValueError: 1381 raise TranslateError("Argument %s is not recognised." % arg.name, 1382 self.get_namespace_path(), n) 1383 args[argnum+1] = str(argexpr) 1384 1385 # Otherwise, store the details in a separate collection. 1386 1387 else: 1388 kwargs.append(str(argexpr)) 1389 kwcodes.append("{%s, %s}" % ( 1390 encode_ppos(arg.name), encode_pcode(arg.name))) 1391 1392 # Store non-keyword arguments in the argument list, rejecting 1393 # superfluous arguments. 1394 1395 else: 1396 try: 1397 args[i+1] = str(argexpr) 1398 except IndexError: 1399 raise TranslateError("Too many arguments specified.", 1400 self.get_namespace_path(), n) 1401 1402 # Reference the current target again. 1403 1404 self.function_target -= 1 1405 1406 # Defaults are added to the frame where arguments are missing. 1407 1408 if parameters: 1409 function_defaults = self.importer.function_defaults.get(objpath) 1410 if function_defaults: 1411 1412 # Visit each default and set any missing arguments. 1413 # Use the target structure to obtain defaults, as opposed to the 1414 # actual function involved. 1415 1416 for i, (argname, default) in enumerate(function_defaults): 1417 argnum = parameters.index(argname) 1418 if not args[argnum+1]: 1419 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i) 1420 1421 # Test for missing arguments. 1422 1423 if None in args: 1424 raise TranslateError("Not all arguments supplied.", 1425 self.get_namespace_path(), n) 1426 1427 # Encode the arguments. 1428 1429 argstr = "__ARGS(%s)" % ", ".join(args) 1430 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 1431 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 1432 1433 # Where literal instantiation is occurring, add an argument indicating 1434 # the number of values. 1435 1436 if literal_instantiation: 1437 argstr += ", %d" % (len(args) - 1) 1438 1439 # First, the invocation expression is presented. 1440 1441 stages = [] 1442 1443 # Without a known specific callable, the expression provides the target. 1444 1445 if not target or context_required: 1446 if target: 1447 if expr: 1448 stages.append(str(expr)) 1449 elif not target_identity: 1450 stages.append("%s = %s" % (target_var, expr)) 1451 1452 # Any specific callable is then obtained. 1453 1454 if target: 1455 stages.append(target) 1456 1457 # Methods accessed via unidentified accessors are obtained. 1458 1459 elif function: 1460 if context_required: 1461 if have_access_context: 1462 stages.append("__get_function(%s, %s)" % ( 1463 context_identity, target_var)) 1464 else: 1465 stages.append("__get_function(__CONTEXT_AS_VALUE(%s).value, %s)" % ( 1466 target_var, target_var)) 1467 else: 1468 stages.append("__load_via_object(%s.value, %s).fn" % ( 1469 target_var, encode_pos("__fn__"))) 1470 1471 # With a known target, the function is obtained directly and called. 1472 # By putting the invocation at the end of the final element in the 1473 # instruction sequence (the stages), the result becomes the result of 1474 # the sequence. Moreover, the parameters become part of the sequence 1475 # and thereby participate in a guaranteed evaluation order. 1476 1477 if target or function: 1478 stages[-1] += "(%s)" % argstr 1479 if instantiation: 1480 return InstantiationResult(instantiation, stages) 1481 else: 1482 return InvocationResult(stages) 1483 1484 # With unknown targets, the generic invocation function is applied to 1485 # the callable and argument collections. 1486 1487 else: 1488 stages.append("__invoke(\n%s,\n%d, %d, %s, %s,\n%d, %s\n)" % ( 1489 target_var, 1490 self.always_callable and 1 or 0, 1491 len(kwargs), kwcodestr, kwargstr, 1492 len(args), argstr)) 1493 return InvocationResult(stages) 1494 1495 def always_callable(self, refs): 1496 1497 "Determine whether all 'refs' are callable." 1498 1499 for ref in refs: 1500 if not ref.static(): 1501 return False 1502 else: 1503 origin = ref.final() 1504 if not self.importer.get_attribute(origin, "__fn__"): 1505 return False 1506 return True 1507 1508 def need_default_arguments(self, objpath, nargs): 1509 1510 """ 1511 Return whether any default arguments are needed when invoking the object 1512 given by 'objpath'. 1513 """ 1514 1515 parameters = self.importer.function_parameters.get(objpath) 1516 return nargs < len(parameters) 1517 1518 def process_lambda_node(self, n): 1519 1520 "Process the given lambda node 'n'." 1521 1522 name = self.get_lambda_name() 1523 function_name = self.get_object_path(name) 1524 1525 defaults = self.process_function_defaults(n, name, function_name, "__tmp_value") 1526 1527 # Without defaults, produce an attribute referring to the function. 1528 1529 if not defaults: 1530 return make_expression("__ATTRVALUE(&%s)" % encode_path(function_name)) 1531 1532 # With defaults, copy the function structure and set the defaults on the 1533 # copy. 1534 1535 else: 1536 self.record_temp("__tmp_value") 1537 return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, __ATTRVALUE(__tmp_value))" % ( 1538 encode_path(function_name), 1539 encode_symbol("obj", function_name), 1540 ", ".join(defaults))) 1541 1542 def process_logical_node(self, n): 1543 1544 """ 1545 Process the given operator node 'n'. 1546 1547 Convert ... to ... 1548 1549 <a> and <b> 1550 (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b> 1551 1552 <a> or <b> 1553 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b> 1554 """ 1555 1556 self.record_temp("__tmp_result") 1557 1558 if isinstance(n, compiler.ast.And): 1559 op = "!" 1560 else: 1561 op = "" 1562 1563 results = [] 1564 1565 for node in n.nodes[:-1]: 1566 expr = self.process_structure_node(node) 1567 results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, op)) 1568 1569 expr = self.process_structure_node(n.nodes[-1]) 1570 results.append(str(expr)) 1571 1572 return make_expression("(%s)" % "".join(results)) 1573 1574 def process_name_node(self, n, expr=None): 1575 1576 "Process the given name node 'n' with the optional assignment 'expr'." 1577 1578 # Determine whether the name refers to a static external entity. 1579 1580 if n.name in predefined_constants: 1581 return PredefinedConstantRef(n.name, expr) 1582 1583 # Convert literal references, operator function names, and print 1584 # function names to references. 1585 1586 elif n.name.startswith("$L") or n.name.startswith("$op") or \ 1587 n.name.startswith("$print"): 1588 1589 ref, paths = self.importer.get_module(self.name).special[n.name] 1590 return TrResolvedNameRef(n.name, ref) 1591 1592 # Temporary names are output program locals. 1593 1594 elif n.name.startswith("$t"): 1595 return TrResolvedNameRef(n.name, Reference("<var>"), expr=expr) 1596 1597 # Get the appropriate name for the name reference, using the same method 1598 # as in the inspector. 1599 1600 path = self.get_namespace_path() 1601 objpath = self.get_object_path(n.name) 1602 1603 # Determine any assigned globals. 1604 1605 globals = self.importer.get_module(self.name).scope_globals.get(path) 1606 1607 # Explicitly declared globals. 1608 1609 if globals and n.name in globals: 1610 objpath = self.get_global_path(n.name) 1611 is_global = True 1612 1613 # Implicitly referenced globals in functions. 1614 1615 elif self.in_function: 1616 is_global = n.name not in self.importer.function_locals[path] 1617 1618 # Implicitly referenced globals elsewhere. 1619 1620 else: 1621 namespace = self.importer.identify(path) 1622 is_global = not self.importer.get_attributes(namespace, n.name) 1623 1624 # Get the static identity of the name. 1625 1626 ref = self.importer.identify(objpath) 1627 if ref and not ref.get_name(): 1628 ref = ref.alias(objpath) 1629 1630 # Obtain any resolved names for non-assignment names. 1631 1632 if not expr and not ref and self.in_function: 1633 locals = self.importer.function_locals.get(path) 1634 ref = locals and locals.get(n.name) 1635 1636 # Determine whether the name refers to a parameter. The generation of 1637 # parameter references is different from other names. 1638 1639 parameters = self.importer.function_parameters.get(path) 1640 parameter = n.name == "self" and self.in_method() or \ 1641 parameters and n.name in parameters 1642 1643 # Find any invocation details. 1644 1645 location = self.get_access_location(n.name) 1646 1647 # Qualified names are used for resolved static references or for 1648 # static namespace members. The reference should be configured to return 1649 # such names. 1650 1651 return TrResolvedNameRef(n.name, ref, expr=expr, is_global=is_global, parameter=parameter, location=location) 1652 1653 def process_not_node(self, n): 1654 1655 "Process the given operator node 'n'." 1656 1657 return LogicalResult(self.process_structure_node(n.expr)) 1658 1659 def process_raise_node(self, n): 1660 1661 "Process the given raise node 'n'." 1662 1663 # NOTE: Determine which raise statement variants should be permitted. 1664 1665 if n.expr1: 1666 1667 # Names with accompanying arguments are treated like invocations. 1668 1669 if n.expr2: 1670 call = compiler.ast.CallFunc(n.expr1, [n.expr2]) 1671 exc = self.process_structure_node(call) 1672 self.writestmt("__Raise(%s);" % exc) 1673 1674 # Raise instances, testing the kind at run-time if necessary and 1675 # instantiating any non-instance. 1676 1677 else: 1678 exc = self.process_structure_node(n.expr1) 1679 1680 if isinstance(exc, TrInstanceRef): 1681 self.writestmt("__Raise(%s);" % exc) 1682 else: 1683 self.writestmt("__Raise(__ensure_instance(%s));" % exc) 1684 else: 1685 self.writestmt("__Throw(__tmp_exc);") 1686 1687 def process_return_node(self, n): 1688 1689 "Process the given return node 'n'." 1690 1691 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1692 if self.in_try_finally or self.in_try_except: 1693 self.writestmt("__Return(%s);" % expr) 1694 else: 1695 self.writestmt("return %s;" % expr) 1696 1697 return ReturnRef() 1698 1699 def process_try_node(self, n): 1700 1701 """ 1702 Process the given "try...except" node 'n'. 1703 """ 1704 1705 in_try_except = self.in_try_except 1706 self.in_try_except = True 1707 1708 # Use macros to implement exception handling. 1709 1710 self.writestmt("__Try") 1711 self.writeline("{") 1712 self.indent += 1 1713 self.process_structure_node(n.body) 1714 1715 # Put the else statement in another try block that handles any raised 1716 # exceptions and converts them to exceptions that will not be handled by 1717 # the main handling block. 1718 1719 if n.else_: 1720 self.writestmt("__Try") 1721 self.writeline("{") 1722 self.indent += 1 1723 self.process_structure_node(n.else_) 1724 self.indent -= 1 1725 self.writeline("}") 1726 self.writeline("__Catch (__tmp_exc)") 1727 self.writeline("{") 1728 self.indent += 1 1729 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1730 self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1731 self.indent -= 1 1732 self.writeline("}") 1733 1734 # Complete the try block and enter the finally block, if appropriate. 1735 1736 if self.in_try_finally: 1737 self.writestmt("__Complete;") 1738 1739 self.indent -= 1 1740 self.writeline("}") 1741 1742 self.in_try_except = in_try_except 1743 1744 # Handlers are tests within a common handler block. 1745 1746 self.writeline("__Catch (__tmp_exc)") 1747 self.writeline("{") 1748 self.indent += 1 1749 1750 # Introduce an if statement to handle the completion of a try block. 1751 1752 self.process_try_completion() 1753 1754 # Handle exceptions in else blocks converted to __RaiseElse, converting 1755 # them back to normal exceptions. 1756 1757 if n.else_: 1758 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1759 1760 # Exception handling. 1761 1762 for name, var, handler in n.handlers: 1763 1764 # Test for specific exceptions. 1765 1766 if name is not None: 1767 name_ref = self.process_structure_node(name) 1768 self.writeline("else if (__ISINSTANCE(__tmp_exc.arg, %s))" % name_ref) 1769 else: 1770 self.writeline("else if (1)") 1771 1772 self.writeline("{") 1773 self.indent += 1 1774 1775 # Establish the local for the handler. 1776 1777 if var is not None: 1778 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) 1779 1780 if handler is not None: 1781 self.process_structure_node(handler) 1782 1783 self.indent -= 1 1784 self.writeline("}") 1785 1786 # Re-raise unhandled exceptions. 1787 1788 self.writeline("else __Throw(__tmp_exc);") 1789 1790 # End the handler block. 1791 1792 self.indent -= 1 1793 self.writeline("}") 1794 1795 def process_try_finally_node(self, n): 1796 1797 """ 1798 Process the given "try...finally" node 'n'. 1799 """ 1800 1801 in_try_finally = self.in_try_finally 1802 self.in_try_finally = True 1803 1804 # Use macros to implement exception handling. 1805 1806 self.writestmt("__Try") 1807 self.writeline("{") 1808 self.indent += 1 1809 self.process_structure_node(n.body) 1810 self.indent -= 1 1811 self.writeline("}") 1812 1813 self.in_try_finally = in_try_finally 1814 1815 # Finally clauses handle special exceptions. 1816 1817 self.writeline("__Catch (__tmp_exc)") 1818 self.writeline("{") 1819 self.indent += 1 1820 self.process_structure_node(n.final) 1821 1822 # Introduce an if statement to handle the completion of a try block. 1823 1824 self.process_try_completion() 1825 self.writeline("else __Throw(__tmp_exc);") 1826 1827 self.indent -= 1 1828 self.writeline("}") 1829 1830 def process_try_completion(self): 1831 1832 "Generate a test for the completion of a try block." 1833 1834 self.writestmt("if (__tmp_exc.completing)") 1835 self.writeline("{") 1836 self.indent += 1 1837 1838 # Do not return anything at the module level. 1839 1840 if self.get_namespace_path() != self.name: 1841 1842 # Only use the normal return statement if no surrounding try blocks 1843 # apply. 1844 1845 if not self.in_try_finally and not self.in_try_except: 1846 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1847 else: 1848 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1849 1850 self.indent -= 1 1851 self.writeline("}") 1852 1853 def process_while_node(self, n): 1854 1855 "Process the given while node 'n'." 1856 1857 self.writeline("while (1)") 1858 self.writeline("{") 1859 self.indent += 1 1860 test = self.process_structure_node(n.test) 1861 1862 # Emit the loop termination condition unless "while <true value>" is 1863 # indicated. 1864 1865 if not (isinstance(test, PredefinedConstantRef) and test.value): 1866 1867 # Emit a negated test of the continuation condition. 1868 1869 self.start_if(True, test, True) 1870 if n.else_: 1871 self.process_structure_node(n.else_) 1872 self.writestmt("break;") 1873 self.end_if() 1874 1875 in_conditional = self.in_conditional 1876 self.in_conditional = True 1877 self.process_structure_node(n.body) 1878 self.in_conditional = in_conditional 1879 1880 self.indent -= 1 1881 self.writeline("}") 1882 1883 # Special variable usage. 1884 1885 def record_temp(self, name): 1886 1887 """ 1888 Record the use of the temporary 'name' in the current namespace. At the 1889 class or module level, the temporary name is associated with the module, 1890 since the variable will then be allocated in the module's own main 1891 program. 1892 """ 1893 1894 if self.in_function: 1895 path = self.get_namespace_path() 1896 else: 1897 path = self.name 1898 1899 init_item(self.temp_usage, path, set) 1900 self.temp_usage[path].add(name) 1901 1902 def uses_temp(self, path, name): 1903 1904 """ 1905 Return whether the given namespace 'path' employs a temporary variable 1906 with the given 'name'. Note that 'path' should only be a module or a 1907 function or method, not a class. 1908 """ 1909 1910 return self.temp_usage.has_key(path) and name in self.temp_usage[path] 1911 1912 # Output generation. 1913 1914 def start_output(self): 1915 1916 "Write the declarations at the top of each source file." 1917 1918 print >>self.out, """\ 1919 #include "types.h" 1920 #include "exceptions.h" 1921 #include "ops.h" 1922 #include "progconsts.h" 1923 #include "progops.h" 1924 #include "progtypes.h" 1925 #include "main.h" 1926 """ 1927 1928 def start_unit(self): 1929 1930 "Record output within a generated function for later use." 1931 1932 self.out = StringIO() 1933 1934 def end_unit(self, name): 1935 1936 "Add declarations and generated code." 1937 1938 # Restore the output stream. 1939 1940 out = self.out 1941 self.out = self.out_toplevel 1942 1943 self.write_temporaries(name) 1944 out.seek(0) 1945 self.out.write(out.read()) 1946 1947 self.indent -= 1 1948 print >>self.out, "}" 1949 1950 def start_module(self): 1951 1952 "Write the start of each module's main function." 1953 1954 print >>self.out, "void __main_%s()" % encode_path(self.name) 1955 print >>self.out, "{" 1956 self.indent += 1 1957 1958 # Define temporary variables, excluded from the module structure itself. 1959 1960 tempnames = [] 1961 1962 for n in self.importer.all_module_attrs[self.name]: 1963 if n.startswith("$t"): 1964 tempnames.append(encode_path(n)) 1965 1966 if tempnames: 1967 tempnames.sort() 1968 self.writeline("__attr %s;" % ", ".join(tempnames)) 1969 1970 self.start_unit() 1971 1972 def end_module(self): 1973 1974 "End each module by closing its main function." 1975 1976 self.end_unit(self.name) 1977 1978 def start_function(self, name): 1979 1980 "Start the function having the given 'name'." 1981 1982 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1983 print >>self.out, "{" 1984 self.indent += 1 1985 1986 # Obtain local names from parameters. 1987 1988 parameters = self.importer.function_parameters[name] 1989 locals = self.importer.function_locals[name].keys() 1990 names = [] 1991 1992 for n in locals: 1993 1994 # Filter out special names and parameters. Note that self is a local 1995 # regardless of whether it originally appeared in the parameters or 1996 # not. 1997 1998 if n.startswith("$l") or n in parameters or n == "self": 1999 continue 2000 names.append(encode_path(n)) 2001 2002 # Emit required local names. 2003 2004 if names: 2005 names.sort() 2006 self.writeline("__attr %s;" % ", ".join(names)) 2007 2008 self.write_parameters(name) 2009 self.start_unit() 2010 2011 def end_function(self, name): 2012 2013 "End the function having the given 'name'." 2014 2015 self.end_unit(name) 2016 print >>self.out 2017 2018 def write_temporaries(self, name): 2019 2020 "Write temporary storage employed by 'name'." 2021 2022 # Provide space for the given number of targets. 2023 2024 targets = self.importer.function_targets.get(name) 2025 2026 if self.uses_temp(name, "__tmp_targets"): 2027 self.writeline("__attr __tmp_targets[%d];" % targets) 2028 if self.uses_temp(name, "__tmp_contexts"): 2029 self.writeline("__ref __tmp_contexts[%d];" % targets) 2030 2031 # Add temporary variable usage details. 2032 2033 if self.uses_temp(name, "__tmp_private_context"): 2034 self.writeline("__ref __tmp_private_context;") 2035 if self.uses_temp(name, "__tmp_value"): 2036 self.writeline("__ref __tmp_value;") 2037 if self.uses_temp(name, "__tmp_target_value"): 2038 self.writeline("__ref __tmp_target_value;") 2039 if self.uses_temp(name, "__tmp_result"): 2040 self.writeline("__attr __tmp_result;") 2041 2042 module = self.importer.get_module(self.name) 2043 2044 if name in module.exception_namespaces: 2045 self.writeline("__exc __tmp_exc;") 2046 2047 def write_parameters(self, name): 2048 2049 """ 2050 For the function having the given 'name', write definitions of 2051 parameters found in the arguments array. 2052 """ 2053 2054 parameters = self.importer.function_parameters[name] 2055 2056 # Generate any self reference. 2057 2058 if self.is_method(name): 2059 self.writeline("__attr * const self = &__args[0];") 2060 2061 # Generate aliases for the parameters. 2062 2063 for i, parameter in enumerate(parameters): 2064 self.writeline("__attr * const %s = &__args[%d];" % (encode_path(parameter), i+1)) 2065 2066 def start_if(self, first, test_ref, negate=False): 2067 statement = "%sif" % (not first and "else " or "") 2068 2069 # Consume logical results directly. 2070 2071 if isinstance(test_ref, LogicalResult): 2072 self.writeline("%s %s" % (statement, test_ref.apply_test(negate))) 2073 else: 2074 self.writeline("%s (%s__BOOL(%s))" % (statement, negate and "!" or "", test_ref)) 2075 2076 self.writeline("{") 2077 self.indent += 1 2078 2079 def end_if(self): 2080 self.indent -= 1 2081 self.writeline("}") 2082 2083 def start_else(self): 2084 self.writeline("else") 2085 self.writeline("{") 2086 self.indent += 1 2087 2088 def end_else(self): 2089 self.indent -= 1 2090 self.writeline("}") 2091 2092 def statement(self, expr): 2093 s = str(expr) 2094 if s: 2095 self.writestmt("%s;" % s) 2096 2097 def statements(self, results): 2098 for result in results: 2099 self.statement(result) 2100 2101 def writeline(self, s): 2102 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 2103 2104 def writestmt(self, s): 2105 print >>self.out 2106 self.writeline(s) 2107 2108 def write_comment(self, s): 2109 self.writestmt("/* %s */" % s) 2110 2111 def pad(self, extra=0): 2112 return (self.indent + extra) * self.tabstop 2113 2114 def indenttext(self, s, levels): 2115 lines = s.split("\n") 2116 out = [lines[0]] 2117 for line in lines[1:]: 2118 out.append(levels * self.tabstop + line) 2119 if line.endswith("("): 2120 levels += 1 2121 elif line.startswith(")"): 2122 levels -= 1 2123 return "\n".join(out) 2124 2125 # vim: tabstop=4 expandtab shiftwidth=4