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