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