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