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 self.writestmt("__Raise(%s);" % self.process_structure_node(n.expr1)) 1101 1102 def process_return_node(self, n): 1103 1104 "Process the given return node 'n'." 1105 1106 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1107 if self.in_try_finally: 1108 self.writestmt("__Return(%s);" % expr) 1109 else: 1110 self.writestmt("return %s;" % expr) 1111 1112 return ReturnRef() 1113 1114 def process_try_node(self, n): 1115 1116 """ 1117 Process the given "try...except" node 'n'. 1118 """ 1119 1120 # Use macros to implement exception handling. 1121 1122 self.writestmt("__Try") 1123 self.writeline("{") 1124 self.indent += 1 1125 self.process_structure_node(n.body) 1126 1127 # Put the else statement in another try block that handles any raised 1128 # exceptions and converts them to exceptions that will not be handled by 1129 # the main handling block. 1130 1131 if n.else_: 1132 self.writestmt("__Try") 1133 self.writeline("{") 1134 self.indent += 1 1135 self.process_structure_node(n.else_) 1136 self.indent -= 1 1137 self.writeline("}") 1138 self.writeline("__Catch (__tmp_exc)") 1139 self.writeline("{") 1140 self.indent += 1 1141 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1142 self.indent -= 1 1143 self.writeline("}") 1144 1145 # Complete the try block and enter the finally block, if appropriate. 1146 1147 if self.in_try_finally: 1148 self.writestmt("__Complete;") 1149 1150 self.indent -= 1 1151 self.writeline("}") 1152 1153 # Handlers are tests within a common handler block. 1154 1155 self.writeline("__Catch (__tmp_exc)") 1156 self.writeline("{") 1157 self.indent += 1 1158 1159 # Handle exceptions in else blocks converted to __RaiseElse, converting 1160 # them back to normal exceptions. 1161 1162 else_str = "" 1163 1164 if n.else_: 1165 self.writeline("if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1166 else_str = "else " 1167 1168 # Handle the completion of try blocks or the execution of return 1169 # statements where finally blocks apply. 1170 1171 if self.in_try_finally: 1172 self.writeline("%sif (__tmp_exc.completing) __Throw(__tmp_exc);" % else_str) 1173 else_str = "else " 1174 1175 # Exception handling. 1176 1177 for name, var, handler in n.handlers: 1178 1179 # Test for specific exceptions. 1180 1181 if name is not None: 1182 name_ref = self.process_structure_node(name) 1183 self.writeline("%sif (__BOOL(__fn_native__isinstance((__attr[]) {__tmp_exc.arg, %s})))" % (else_str, name_ref)) 1184 else: 1185 self.writeline("%sif (1)" % else_str) 1186 else_str = "else " 1187 1188 self.writeline("{") 1189 self.indent += 1 1190 1191 # Establish the local for the handler. 1192 1193 if var is not None: 1194 var_ref = self.process_name_node(var, make_expression("__tmp_exc")) 1195 1196 if handler is not None: 1197 self.process_structure_node(handler) 1198 1199 self.indent -= 1 1200 self.writeline("}") 1201 1202 # Re-raise unhandled exceptions. 1203 1204 self.writeline("%s__Throw(__tmp_exc);" % else_str) 1205 1206 # End the handler block. 1207 1208 self.indent -= 1 1209 self.writeline("}") 1210 1211 def process_try_finally_node(self, n): 1212 1213 """ 1214 Process the given "try...finally" node 'n'. 1215 """ 1216 1217 in_try_finally = self.in_try_finally 1218 self.in_try_finally = True 1219 1220 # Use macros to implement exception handling. 1221 1222 self.writestmt("__Try") 1223 self.writeline("{") 1224 self.indent += 1 1225 self.process_structure_node(n.body) 1226 self.indent -= 1 1227 self.writeline("}") 1228 1229 self.in_try_finally = in_try_finally 1230 1231 # Finally clauses handle special exceptions. 1232 1233 self.writeline("__Catch (__tmp_exc)") 1234 self.writeline("{") 1235 self.indent += 1 1236 self.process_structure_node(n.final) 1237 1238 # Test for the completion of a try block. 1239 1240 self.writestmt("if (__tmp_exc.completing)") 1241 self.writeline("{") 1242 self.indent += 1 1243 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1244 self.indent -= 1 1245 self.writeline("}") 1246 self.writeline("else __Throw(__tmp_exc);") 1247 1248 self.indent -= 1 1249 self.writeline("}") 1250 1251 def process_while_node(self, n): 1252 1253 "Process the given while node 'n'." 1254 1255 self.writeline("while (1)") 1256 self.writeline("{") 1257 self.indent += 1 1258 test = self.process_structure_node(n.test) 1259 1260 # Emit the loop termination condition unless "while <true value>" is 1261 # indicated. 1262 1263 if not (isinstance(test, PredefinedConstantRef) and test.value): 1264 1265 # NOTE: This needs to evaluate whether the operand is true or false 1266 # NOTE: according to Python rules. 1267 1268 self.writeline("if (!__BOOL(%s))" % test) 1269 self.writeline("{") 1270 self.indent += 1 1271 if n.else_: 1272 self.process_structure_node(n.else_) 1273 self.writestmt("break;") 1274 self.indent -= 1 1275 self.writeline("}") 1276 1277 in_conditional = self.in_conditional 1278 self.in_conditional = True 1279 self.process_structure_node(n.body) 1280 self.in_conditional = in_conditional 1281 1282 self.indent -= 1 1283 self.writeline("}") 1284 1285 # Output generation. 1286 1287 def start_output(self): 1288 1289 "Write the declarations at the top of each source file." 1290 1291 print >>self.out, """\ 1292 #include "types.h" 1293 #include "exceptions.h" 1294 #include "ops.h" 1295 #include "progconsts.h" 1296 #include "progops.h" 1297 #include "progtypes.h" 1298 #include "main.h" 1299 """ 1300 1301 def start_module(self): 1302 1303 "Write the start of each module's main function." 1304 1305 print >>self.out, "void __main_%s()" % encode_path(self.name) 1306 print >>self.out, "{" 1307 self.indent += 1 1308 self.write_temporaries() 1309 1310 def end_module(self): 1311 1312 "End each module by closing its main function." 1313 1314 self.indent -= 1 1315 print >>self.out, "}" 1316 1317 def start_function(self, name): 1318 1319 "Start the function having the given 'name'." 1320 1321 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1322 print >>self.out, "{" 1323 self.indent += 1 1324 self.write_temporaries() 1325 1326 # Obtain local names from parameters. 1327 1328 parameters = self.importer.function_parameters[name] 1329 locals = self.importer.function_locals[name].keys() 1330 names = [] 1331 1332 for n in locals: 1333 1334 # Filter out special names and parameters. Note that self is a local 1335 # regardless of whether it originally appeared in the parameters or 1336 # not. 1337 1338 if n.startswith("$l") or n in parameters or n == "self": 1339 continue 1340 names.append(encode_path(n)) 1341 1342 # Emit required local names. 1343 1344 if names: 1345 names.sort() 1346 self.writeline("__attr %s;" % ", ".join(names)) 1347 1348 self.write_parameters(name, True) 1349 1350 def end_function(self, name): 1351 1352 "End the function having the given 'name'." 1353 1354 self.write_parameters(name, False) 1355 self.indent -= 1 1356 print >>self.out, "}" 1357 print >>self.out 1358 1359 def write_temporaries(self): 1360 1361 "Write temporary storage employed by functions." 1362 1363 self.writeline("__ref __tmp_context, __tmp_value;") 1364 self.writeline("__attr __tmp_target, __tmp_result;") 1365 self.writeline("__exc __tmp_exc;") 1366 1367 def write_parameters(self, name, define=True): 1368 1369 """ 1370 For the function having the given 'name', write definitions of 1371 parameters found in the arguments array if 'define' is set to a true 1372 value, or write "undefinitions" if 'define' is set to a false value. 1373 """ 1374 1375 parameters = self.importer.function_parameters[name] 1376 1377 # Generate any self reference. 1378 1379 if self.is_method(name): 1380 if define: 1381 self.writeline("#define self (__args[0])") 1382 else: 1383 self.writeline("#undef self") 1384 1385 # Generate aliases for the parameters. 1386 1387 for i, parameter in enumerate(parameters): 1388 if define: 1389 self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1)) 1390 else: 1391 self.writeline("#undef %s" % encode_path(parameter)) 1392 1393 def start_if(self, first, test_ref): 1394 self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref)) 1395 self.writeline("{") 1396 self.indent += 1 1397 1398 def end_if(self): 1399 self.indent -= 1 1400 self.writeline("}") 1401 1402 def start_else(self): 1403 self.writeline("else") 1404 self.writeline("{") 1405 self.indent += 1 1406 1407 def end_else(self): 1408 self.indent -= 1 1409 self.writeline("}") 1410 1411 def statement(self, expr): 1412 # NOTE: Should never be None. 1413 if not expr: 1414 self.writestmt("...;") 1415 s = str(expr) 1416 if s: 1417 self.writestmt("%s;" % s) 1418 1419 def statements(self, results): 1420 for result in results: 1421 self.statement(result) 1422 1423 def writeline(self, s): 1424 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1425 1426 def writestmt(self, s): 1427 print >>self.out 1428 self.writeline(s) 1429 1430 def write_comment(self, s): 1431 self.writestmt("/* %s */" % s) 1432 1433 def pad(self, extra=0): 1434 return (self.indent + extra) * self.tabstop 1435 1436 def indenttext(self, s, levels): 1437 lines = s.split("\n") 1438 out = [lines[0]] 1439 for line in lines[1:]: 1440 out.append(levels * self.tabstop + line) 1441 if line.endswith("("): 1442 levels += 1 1443 elif line.startswith(")"): 1444 levels -= 1 1445 return "\n".join(out) 1446 1447 # vim: tabstop=4 expandtab shiftwidth=4