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