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