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.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1150 self.indent -= 1 1151 self.writeline("}") 1152 1153 # Complete the try block and enter the finally block, if appropriate. 1154 1155 if self.in_try_finally: 1156 self.writestmt("__Complete;") 1157 1158 self.indent -= 1 1159 self.writeline("}") 1160 1161 self.in_try_except = in_try_except 1162 1163 # Handlers are tests within a common handler block. 1164 1165 self.writeline("__Catch (__tmp_exc)") 1166 self.writeline("{") 1167 self.indent += 1 1168 1169 # Introduce an if statement to handle the completion of a try block. 1170 1171 self.process_try_completion() 1172 1173 # Handle exceptions in else blocks converted to __RaiseElse, converting 1174 # them back to normal exceptions. 1175 1176 if n.else_: 1177 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1178 1179 # Exception handling. 1180 1181 for name, var, handler in n.handlers: 1182 1183 # Test for specific exceptions. 1184 1185 if name is not None: 1186 name_ref = self.process_structure_node(name) 1187 self.writeline("else if (__BOOL(__fn_native__isinstance((__attr[]) {{0, 0}, __tmp_exc.arg, %s})))" % name_ref) 1188 else: 1189 self.writeline("else if (1)") 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("else __Throw(__tmp_exc);") 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 # Introduce an if statement to handle the completion of a try block. 1242 1243 self.process_try_completion() 1244 self.writeline("else __Throw(__tmp_exc);") 1245 1246 self.indent -= 1 1247 self.writeline("}") 1248 1249 def process_try_completion(self): 1250 1251 "Generate a test for the completion of a try block." 1252 1253 self.writestmt("if (__tmp_exc.completing)") 1254 self.writeline("{") 1255 self.indent += 1 1256 1257 # Only use the normal return statement if no surrounding try blocks 1258 # apply. 1259 1260 if not self.in_try_finally and not self.in_try_except: 1261 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1262 else: 1263 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1264 1265 self.indent -= 1 1266 self.writeline("}") 1267 1268 def process_while_node(self, n): 1269 1270 "Process the given while node 'n'." 1271 1272 self.writeline("while (1)") 1273 self.writeline("{") 1274 self.indent += 1 1275 test = self.process_structure_node(n.test) 1276 1277 # Emit the loop termination condition unless "while <true value>" is 1278 # indicated. 1279 1280 if not (isinstance(test, PredefinedConstantRef) and test.value): 1281 1282 # NOTE: This needs to evaluate whether the operand is true or false 1283 # NOTE: according to Python rules. 1284 1285 self.writeline("if (!__BOOL(%s))" % test) 1286 self.writeline("{") 1287 self.indent += 1 1288 if n.else_: 1289 self.process_structure_node(n.else_) 1290 self.writestmt("break;") 1291 self.indent -= 1 1292 self.writeline("}") 1293 1294 in_conditional = self.in_conditional 1295 self.in_conditional = True 1296 self.process_structure_node(n.body) 1297 self.in_conditional = in_conditional 1298 1299 self.indent -= 1 1300 self.writeline("}") 1301 1302 # Output generation. 1303 1304 def start_output(self): 1305 1306 "Write the declarations at the top of each source file." 1307 1308 print >>self.out, """\ 1309 #include "types.h" 1310 #include "exceptions.h" 1311 #include "ops.h" 1312 #include "progconsts.h" 1313 #include "progops.h" 1314 #include "progtypes.h" 1315 #include "main.h" 1316 """ 1317 1318 def start_module(self): 1319 1320 "Write the start of each module's main function." 1321 1322 print >>self.out, "void __main_%s()" % encode_path(self.name) 1323 print >>self.out, "{" 1324 self.indent += 1 1325 self.write_temporaries() 1326 1327 def end_module(self): 1328 1329 "End each module by closing its main function." 1330 1331 self.indent -= 1 1332 print >>self.out, "}" 1333 1334 def start_function(self, name): 1335 1336 "Start the function having the given 'name'." 1337 1338 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1339 print >>self.out, "{" 1340 self.indent += 1 1341 self.write_temporaries() 1342 1343 # Obtain local names from parameters. 1344 1345 parameters = self.importer.function_parameters[name] 1346 locals = self.importer.function_locals[name].keys() 1347 names = [] 1348 1349 for n in locals: 1350 1351 # Filter out special names and parameters. Note that self is a local 1352 # regardless of whether it originally appeared in the parameters or 1353 # not. 1354 1355 if n.startswith("$l") or n in parameters or n == "self": 1356 continue 1357 names.append(encode_path(n)) 1358 1359 # Emit required local names. 1360 1361 if names: 1362 names.sort() 1363 self.writeline("__attr %s;" % ", ".join(names)) 1364 1365 self.write_parameters(name, True) 1366 1367 def end_function(self, name): 1368 1369 "End the function having the given 'name'." 1370 1371 self.write_parameters(name, False) 1372 self.indent -= 1 1373 print >>self.out, "}" 1374 print >>self.out 1375 1376 def write_temporaries(self): 1377 1378 "Write temporary storage employed by functions." 1379 1380 self.writeline("__ref __tmp_context, __tmp_value;") 1381 self.writeline("__attr __tmp_target, __tmp_result;") 1382 self.writeline("__exc __tmp_exc;") 1383 1384 def write_parameters(self, name, define=True): 1385 1386 """ 1387 For the function having the given 'name', write definitions of 1388 parameters found in the arguments array if 'define' is set to a true 1389 value, or write "undefinitions" if 'define' is set to a false value. 1390 """ 1391 1392 parameters = self.importer.function_parameters[name] 1393 1394 # Generate any self reference. 1395 1396 if self.is_method(name): 1397 if define: 1398 self.writeline("#define self (__args[0])") 1399 else: 1400 self.writeline("#undef self") 1401 1402 # Generate aliases for the parameters. 1403 1404 for i, parameter in enumerate(parameters): 1405 if define: 1406 self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1)) 1407 else: 1408 self.writeline("#undef %s" % encode_path(parameter)) 1409 1410 def start_if(self, first, test_ref): 1411 self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref)) 1412 self.writeline("{") 1413 self.indent += 1 1414 1415 def end_if(self): 1416 self.indent -= 1 1417 self.writeline("}") 1418 1419 def start_else(self): 1420 self.writeline("else") 1421 self.writeline("{") 1422 self.indent += 1 1423 1424 def end_else(self): 1425 self.indent -= 1 1426 self.writeline("}") 1427 1428 def statement(self, expr): 1429 # NOTE: Should never be None. 1430 if not expr: 1431 self.writestmt("...;") 1432 s = str(expr) 1433 if s: 1434 self.writestmt("%s;" % s) 1435 1436 def statements(self, results): 1437 for result in results: 1438 self.statement(result) 1439 1440 def writeline(self, s): 1441 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1442 1443 def writestmt(self, s): 1444 print >>self.out 1445 self.writeline(s) 1446 1447 def write_comment(self, s): 1448 self.writestmt("/* %s */" % s) 1449 1450 def pad(self, extra=0): 1451 return (self.indent + extra) * self.tabstop 1452 1453 def indenttext(self, s, levels): 1454 lines = s.split("\n") 1455 out = [lines[0]] 1456 for line in lines[1:]: 1457 out.append(levels * self.tabstop + line) 1458 if line.endswith("("): 1459 levels += 1 1460 elif line.startswith(")"): 1461 levels -= 1 1462 return "\n".join(out) 1463 1464 # vim: tabstop=4 expandtab shiftwidth=4