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