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