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