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