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