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