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