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