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