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