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