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