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