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