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