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