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