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