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