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