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 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser) 49 tm.translate(module.filename, join(output, "%s.c" % module.name)) 50 51 # Classes representing intermediate translation results. 52 53 class TranslationResult: 54 55 "An abstract translation result mix-in." 56 57 pass 58 59 class Expression(results.Result, TranslationResult): 60 61 "A general expression." 62 63 def __init__(self, s): 64 self.s = s 65 def __str__(self): 66 return self.s 67 def __repr__(self): 68 return "Expression(%r)" % self.s 69 70 class TrResolvedNameRef(results.ResolvedNameRef, TranslationResult): 71 72 "A reference to a name in the translation." 73 74 def __str__(self): 75 76 "Return an output representation of the referenced name." 77 78 # Use any alias in preference to the origin of the name. 79 80 name = self.get_name() 81 82 # Use any static origin in preference to any alias. 83 # For sources, any identified static origin will be constant and thus 84 # usable directly. For targets, no constant should be assigned and thus 85 # the alias (or any plain name) will be used. 86 87 ref = self.static() 88 origin = ref and self.get_origin() 89 static_name = origin and encode_path(origin) 90 dynamic_name = name and encode_path(name) or encode_path(self.name) 91 92 # Assignments. 93 94 if self.expr: 95 96 # Eliminate assignments between constants. 97 98 if self.static() and isinstance(self.expr, results.ResolvedNameRef) and self.expr.static(): 99 return "" 100 else: 101 return "%s = %s" % (name, self.expr) 102 103 # Expressions. 104 105 elif static_name: 106 parent = ref.parent() 107 context = ref.has_kind("<function>") and parent or None 108 return "((__attr) {&%s, &%s})" % (context or "0", static_name) 109 110 else: 111 return dynamic_name 112 113 class TrConstantValueRef(results.ConstantValueRef, TranslationResult): 114 115 "A constant value reference in the translation." 116 117 def __str__(self): 118 return encode_literal_constant(self.number) 119 120 class TrLiteralSequenceRef(results.LiteralSequenceRef, TranslationResult): 121 122 "A reference representing a sequence of values." 123 124 def __str__(self): 125 return str(self.node) 126 127 class AttrResult(Expression, TranslationResult): 128 129 "A translation result for an attribute access." 130 131 def __init__(self, s, refs): 132 Expression.__init__(self, s) 133 self.refs = refs 134 135 def get_origin(self): 136 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() 137 138 def has_kind(self, kinds): 139 if not self.refs: 140 return False 141 for ref in self.refs: 142 if ref.has_kind(kinds): 143 return True 144 return False 145 146 def __repr__(self): 147 return "AttrResult(%r, %r)" % (self.s, self.get_origin()) 148 149 class PredefinedConstantRef(AttrResult): 150 151 "A predefined constant reference." 152 153 def __init__(self, value): 154 self.value = value 155 156 def __str__(self): 157 if self.value in ("False", "True"): 158 return encode_path("__builtins__.bool.%s" % self.value) 159 elif self.value == "None": 160 return encode_path("__builtins__.none.%s" % self.value) 161 elif self.value == "NotImplemented": 162 return encode_path("__builtins__.notimplemented.%s" % self.value) 163 else: 164 return self.value 165 166 def __repr__(self): 167 return "PredefinedConstantRef(%r)" % self.value 168 169 def make_expression(expr): 170 171 "Make a new expression from the existing 'expr'." 172 173 if isinstance(expr, results.Result): 174 return expr 175 else: 176 return Expression(str(expr)) 177 178 # The actual translation process itself. 179 180 class TranslatedModule(CommonModule): 181 182 "A module translator." 183 184 def __init__(self, name, importer, deducer, optimiser): 185 CommonModule.__init__(self, name, importer) 186 self.deducer = deducer 187 self.optimiser = optimiser 188 189 # Output stream. 190 191 self.out = None 192 self.indent = 0 193 self.tabstop = " " 194 195 # Recorded namespaces. 196 197 self.namespaces = [] 198 self.in_conditional = False 199 200 # Attribute access counting. 201 202 self.attr_accesses = {} 203 204 def __repr__(self): 205 return "TranslatedModule(%r, %r)" % (self.name, self.importer) 206 207 def translate(self, filename, output_filename): 208 209 """ 210 Parse the file having the given 'filename', writing the translation to 211 the given 'output_filename'. 212 """ 213 214 self.parse_file(filename) 215 216 # Collect function namespaces for separate processing. 217 218 self.record_namespaces(self.astnode) 219 220 # Reset the lambda naming (in order to obtain the same names again) and 221 # translate the program. 222 223 self.reset_lambdas() 224 225 self.out = open(output_filename, "w") 226 try: 227 self.start_output() 228 229 # Process namespaces, writing the translation. 230 231 for path, node in self.namespaces: 232 self.process_namespace(path, node) 233 234 # Process the module namespace including class namespaces. 235 236 self.process_namespace([], self.astnode) 237 238 finally: 239 self.out.close() 240 241 def have_object(self): 242 243 "Return whether a namespace is a recorded object." 244 245 return self.importer.objects.get(self.get_namespace_path()) 246 247 def get_builtin(self, name): 248 return self.importer.get_object("__builtins__.%s" % name) 249 250 def in_method(self, path): 251 class_name, method_name = path.rsplit(".", 1) 252 return self.importer.classes.has_key(class_name) and class_name 253 254 # Namespace recording. 255 256 def record_namespaces(self, node): 257 258 "Process the program structure 'node', recording namespaces." 259 260 for n in node.getChildNodes(): 261 self.record_namespaces_in_node(n) 262 263 def record_namespaces_in_node(self, node): 264 265 "Process the program structure 'node', recording namespaces." 266 267 # Function namespaces within modules, classes and other functions. 268 # Functions appearing within conditional statements are given arbitrary 269 # names. 270 271 if isinstance(node, compiler.ast.Function): 272 self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name) 273 274 elif isinstance(node, compiler.ast.Lambda): 275 self.record_function_node(node, self.get_lambda_name()) 276 277 # Classes are visited, but may be ignored if inside functions. 278 279 elif isinstance(node, compiler.ast.Class): 280 self.enter_namespace(node.name) 281 if self.have_object(): 282 self.record_namespaces(node) 283 self.exit_namespace() 284 285 # Conditional nodes are tracked so that function definitions may be 286 # handled. Since "for" loops are converted to "while" loops, they are 287 # included here. 288 289 elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)): 290 in_conditional = self.in_conditional 291 self.in_conditional = True 292 self.record_namespaces(node) 293 self.in_conditional = in_conditional 294 295 # All other nodes are processed depth-first. 296 297 else: 298 self.record_namespaces(node) 299 300 def record_function_node(self, n, name): 301 302 """ 303 Record the given function, lambda, if expression or list comprehension 304 node 'n' with the given 'name'. 305 """ 306 307 self.in_function = True 308 self.enter_namespace(name) 309 310 if self.have_object(): 311 312 # Record the namespace path and the node itself. 313 314 self.namespaces.append((self.namespace_path[:], n)) 315 self.record_namespaces_in_node(n.code) 316 317 self.exit_namespace() 318 self.in_function = False 319 320 # Constant referencing. 321 322 def get_literal_instance(self, n, name): 323 324 """ 325 For node 'n', return a reference for the type of the given 'name'. 326 """ 327 328 ref = self.get_builtin(name) 329 330 if name in ("dict", "list", "tuple"): 331 return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef) 332 else: 333 path = self.get_namespace_path() 334 local_number = self.importer.all_constants[path][n.value] 335 constant_name = "$c%d" % local_number 336 objpath = self.get_object_path(constant_name) 337 number = self.optimiser.constant_numbers[objpath] 338 return TrConstantValueRef(constant_name, ref.instance_of(), n.value, number) 339 340 # Namespace translation. 341 342 def process_namespace(self, path, node): 343 344 """ 345 Process the namespace for the given 'path' defined by the given 'node'. 346 """ 347 348 self.namespace_path = path 349 350 if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)): 351 self.in_function = True 352 self.process_function_body_node(node) 353 else: 354 self.in_function = False 355 self.start_module() 356 self.process_structure(node) 357 self.end_module() 358 359 def process_structure(self, node): 360 361 "Process the given 'node' or result." 362 363 if isinstance(node, results.Result): 364 return node 365 else: 366 return CommonModule.process_structure(self, node) 367 368 def process_structure_node(self, n): 369 370 "Process the individual node 'n'." 371 372 # Plain statements emit their expressions. 373 374 if isinstance(n, compiler.ast.Discard): 375 expr = self.process_structure_node(n.expr) 376 self.statement(expr) 377 378 # Nodes using operator module functions. 379 380 elif isinstance(n, compiler.ast.Operator): 381 return self.process_operator_node(n) 382 383 elif isinstance(n, compiler.ast.AugAssign): 384 self.process_augassign_node(n) 385 386 elif isinstance(n, compiler.ast.Compare): 387 return self.process_compare_node(n) 388 389 elif isinstance(n, compiler.ast.Slice): 390 return self.process_slice_node(n) 391 392 elif isinstance(n, compiler.ast.Sliceobj): 393 return self.process_sliceobj_node(n) 394 395 elif isinstance(n, compiler.ast.Subscript): 396 return self.process_subscript_node(n) 397 398 # Classes are visited, but may be ignored if inside functions. 399 400 elif isinstance(n, compiler.ast.Class): 401 self.process_class_node(n) 402 403 # Functions within namespaces have any dynamic defaults initialised. 404 405 elif isinstance(n, compiler.ast.Function): 406 self.process_function_node(n) 407 408 # Lambdas are replaced with references to separately-generated 409 # functions. 410 411 elif isinstance(n, compiler.ast.Lambda): 412 return self.process_lambda_node(n) 413 414 # Assignments. 415 416 elif isinstance(n, compiler.ast.Assign): 417 418 # Handle each assignment node. 419 420 for node in n.nodes: 421 self.process_assignment_node(node, n.expr) 422 423 # Assignments within non-Assign nodes. 424 # NOTE: Cover all possible nodes employing these. 425 426 elif isinstance(n, compiler.ast.AssName): 427 self.process_assignment_node(n, compiler.ast.Name("$temp")) 428 429 elif isinstance(n, compiler.ast.AssAttr): 430 self.process_attribute_access(n) 431 432 # Accesses. 433 434 elif isinstance(n, compiler.ast.Getattr): 435 return self.process_attribute_access(n) 436 437 # Names. 438 439 elif isinstance(n, compiler.ast.Name): 440 return self.process_name_node(n) 441 442 # Loops and conditionals. 443 444 elif isinstance(n, compiler.ast.For): 445 self.process_for_node(n) 446 447 elif isinstance(n, compiler.ast.While): 448 self.process_while_node(n) 449 450 elif isinstance(n, compiler.ast.If): 451 self.process_if_node(n) 452 453 elif isinstance(n, (compiler.ast.And, compiler.ast.Or)): 454 return self.process_logical_node(n) 455 456 elif isinstance(n, compiler.ast.Not): 457 return self.process_not_node(n) 458 459 # Exception control-flow tracking. 460 461 elif isinstance(n, compiler.ast.TryExcept): 462 self.process_try_node(n) 463 464 elif isinstance(n, compiler.ast.TryFinally): 465 self.process_try_finally_node(n) 466 467 # Control-flow modification statements. 468 469 elif isinstance(n, compiler.ast.Break): 470 self.writestmt("break;") 471 472 elif isinstance(n, compiler.ast.Continue): 473 self.writestmt("continue;") 474 475 elif isinstance(n, compiler.ast.Return): 476 expr = self.process_structure_node(n.value) 477 if expr: 478 self.writestmt("return %s;" % expr) 479 else: 480 self.writestmt("return;") 481 482 # Invocations. 483 484 elif isinstance(n, compiler.ast.CallFunc): 485 return self.process_invocation_node(n) 486 487 elif isinstance(n, compiler.ast.Keyword): 488 return self.process_structure_node(n.expr) 489 490 # Constant usage. 491 492 elif isinstance(n, compiler.ast.Const): 493 return self.get_literal_instance(n, n.value.__class__.__name__) 494 495 elif isinstance(n, compiler.ast.Dict): 496 return self.get_literal_instance(n, "dict") 497 498 elif isinstance(n, compiler.ast.List): 499 return self.get_literal_instance(n, "list") 500 501 elif isinstance(n, compiler.ast.Tuple): 502 return self.get_literal_instance(n, "tuple") 503 504 # All other nodes are processed depth-first. 505 506 else: 507 self.process_structure(n) 508 509 def process_assignment_node(self, n, expr): 510 511 "Process the individual node 'n' to be assigned the contents of 'expr'." 512 513 # Names and attributes are assigned the entire expression. 514 515 if isinstance(n, compiler.ast.AssName): 516 name_ref = self.process_name_node(n, self.process_structure_node(expr)) 517 self.statement(name_ref) 518 519 elif isinstance(n, compiler.ast.AssAttr): 520 in_assignment = self.in_assignment 521 self.in_assignment = self.process_structure_node(expr) 522 self.statement(self.process_attribute_access(n)) 523 self.in_assignment = in_assignment 524 525 # Lists and tuples are matched against the expression and their 526 # items assigned to expression items. 527 528 elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)): 529 self.process_assignment_node_items(n, expr) 530 531 # Slices and subscripts are permitted within assignment nodes. 532 533 elif isinstance(n, compiler.ast.Slice): 534 self.statement(self.process_slice_node(n, expr)) 535 536 elif isinstance(n, compiler.ast.Subscript): 537 self.statement(self.process_subscript_node(n, expr)) 538 539 def process_attribute_access(self, n): 540 541 """ 542 Process the given attribute access node 'n'. 543 544 Where a name is provided, a single access should be recorded 545 involving potentially many attributes, thus providing a path to an 546 object. The remaining attributes are then accessed dynamically. 547 The remaining accesses could be deduced and computed, but they would 548 also need to be tested. 549 550 Where no name is provided, potentially many accesses should be 551 recorded, one per attribute name. These could be used to provide 552 computed accesses, but the accessors would need to be tested in each 553 case. 554 """ 555 556 # Obtain any completed chain and return the reference to it. 557 558 attr_expr = self.process_attribute_chain(n) 559 if self.have_access_expression(n): 560 return attr_expr 561 562 # Where the start of the chain of attributes has been reached, process 563 # the complete access. 564 565 name_ref = attr_expr and attr_expr.is_name() and attr_expr 566 name = name_ref and name_ref.name or None 567 568 location = self.get_access_location(name) 569 refs = self.get_referenced_attributes(location) 570 571 # Generate access instructions. 572 573 subs = { 574 "<expr>" : str(attr_expr), 575 "<assexpr>" : str(self.in_assignment), 576 "<context>" : "__tmp_context", 577 "<accessor>" : "__tmp_value", 578 } 579 580 output = [] 581 582 for instruction in self.optimiser.access_instructions[location]: 583 output.append(encode_access_instruction(instruction, subs)) 584 585 if len(output) == 1: 586 out = output[0] 587 else: 588 out = "(\n%s\n)" % ",\n".join(output) 589 590 del self.attrs[0] 591 return AttrResult(out, refs) 592 593 def get_referenced_attributes(self, location): 594 595 """ 596 Convert 'location' to the form used by the deducer and retrieve any 597 identified attribute. 598 """ 599 600 access_location = self.deducer.const_accesses.get(location) 601 refs = [] 602 for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]: 603 refs.append(attr) 604 return refs 605 606 def get_access_location(self, name): 607 608 """ 609 Using the current namespace and the given 'name', return the access 610 location. 611 """ 612 613 path = self.get_path_for_access() 614 615 # Get the location used by the deducer and optimiser and find any 616 # recorded access. 617 618 attrnames = ".".join(self.attrs) 619 access_number = self.get_access_number(path, name, attrnames) 620 self.update_access_number(path, name, attrnames) 621 return (path, name, attrnames, access_number) 622 623 def get_access_number(self, path, name, attrnames): 624 access = name, attrnames 625 if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access): 626 return self.attr_accesses[path][access] 627 else: 628 return 0 629 630 def update_access_number(self, path, name, attrnames): 631 access = name, attrnames 632 if name: 633 init_item(self.attr_accesses, path, dict) 634 init_item(self.attr_accesses[path], access, lambda: 1) 635 636 def process_class_node(self, n): 637 638 "Process the given class node 'n'." 639 640 self.enter_namespace(n.name) 641 642 if self.have_object(): 643 class_name = self.get_namespace_path() 644 self.write_comment("Class: %s" % class_name) 645 646 self.process_structure(n) 647 648 self.exit_namespace() 649 650 def process_function_body_node(self, n): 651 652 """ 653 Process the given function, lambda, if expression or list comprehension 654 node 'n', generating the body. 655 """ 656 657 function_name = self.get_namespace_path() 658 self.start_function(function_name) 659 660 # Process the function body. 661 662 in_conditional = self.in_conditional 663 self.in_conditional = False 664 665 expr = self.process_structure_node(n.code) 666 if expr: 667 self.writestmt("return %s;" % expr) 668 669 self.in_conditional = in_conditional 670 671 self.end_function() 672 673 def process_function_node(self, n): 674 675 """ 676 Process the given function, lambda, if expression or list comprehension 677 node 'n', generating any initialisation statements. 678 """ 679 680 # Where a function is declared conditionally, use a separate name for 681 # the definition, and assign the definition to the stated name. 682 683 if self.in_conditional or self.in_function: 684 original_name = n.name 685 name = self.get_lambda_name() 686 else: 687 original_name = None 688 name = n.name 689 690 # Obtain details of the defaults. 691 692 defaults = self.process_function_defaults(n, name, self.get_object_path(name)) 693 if defaults: 694 for default in defaults: 695 self.writeline("%s;" % default) 696 697 # Where a function is set conditionally, assign the name. 698 699 if original_name: 700 self.process_assignment_for_function(original_name, name) 701 702 def process_function_defaults(self, n, name, instance_name): 703 704 """ 705 Process the given function or lambda node 'n', initialising defaults 706 that are dynamically set. The given 'name' indicates the name of the 707 function. The given 'instance_name' indicates the name of any separate 708 instance of the function created to hold the defaults. 709 710 Return a list of operations setting defaults on a function instance. 711 """ 712 713 function_name = self.get_object_path(name) 714 function_defaults = self.importer.function_defaults.get(function_name) 715 if not function_defaults: 716 return None 717 718 # Determine whether any unidentified defaults are involved. 719 720 need_defaults = [argname for argname, default in function_defaults if default.has_kind("<var>")] 721 if not need_defaults: 722 return None 723 724 # Where defaults are involved but cannot be identified, obtain a new 725 # instance of the lambda and populate the defaults. 726 727 defaults = [] 728 729 # Join the original defaults with the inspected defaults. 730 731 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 732 733 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 734 735 # Obtain any reference for the default. 736 737 if original: 738 argname, default = original 739 name_ref = self.process_structure_node(default) 740 elif inspected: 741 argname, default = inspected 742 name_ref = TrResolvedNameRef(argname, default) 743 else: 744 continue 745 746 if name_ref: 747 defaults.append("__SETDEFAULT(%s, %s, %s)" % (encode_path(instance_name), i, name_ref)) 748 749 return defaults 750 751 def process_if_node(self, n): 752 753 """ 754 Process the given "if" node 'n'. 755 """ 756 757 first = True 758 for test, body in n.tests: 759 test_ref = self.process_structure_node(test) 760 self.start_if(first, test_ref) 761 762 in_conditional = self.in_conditional 763 self.in_conditional = True 764 self.process_structure_node(body) 765 self.in_conditional = in_conditional 766 767 self.end_if() 768 first = False 769 770 if n.else_: 771 self.start_else() 772 self.process_structure_node(n.else_) 773 self.end_else() 774 775 def process_invocation_node(self, n): 776 777 "Process the given invocation node 'n'." 778 779 expr = self.process_structure_node(n.node) 780 objpath = expr.get_origin() 781 target = None 782 783 # Obtain details of the callable. 784 785 if objpath: 786 parameters = self.importer.function_parameters.get(objpath) 787 if expr.has_kind("<class>"): 788 target = encode_instantiator_pointer(objpath) 789 elif expr.has_kind("<function>"): 790 target = encode_function_pointer(objpath) 791 else: 792 parameters = None 793 794 stages = [] 795 796 # First, the invocation target is presented. 797 798 stages.append("__tmp_target = %s" % expr) 799 800 # Arguments are presented in a temporary frame array with any context 801 # always being the first argument (although it may be set to null for 802 # invocations where it would be unused). 803 804 args = ["__CONTEXT_AS_VALUE(__tmp_target)"] 805 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 806 kwcodes = [] 807 kwargs = [] 808 809 for i, arg in enumerate(n.args): 810 argexpr = self.process_structure_node(arg) 811 812 # Store a keyword argument, either in the argument list or 813 # in a separate keyword argument list for subsequent lookup. 814 815 if isinstance(arg, compiler.ast.Keyword): 816 817 # With knowledge of the target, store the keyword 818 # argument directly. 819 820 if parameters: 821 argnum = parameters.index(arg.name) 822 args[argnum+1] = str(argexpr) 823 824 # Otherwise, store the details in a separate collection. 825 826 else: 827 kwargs.append(str(argexpr)) 828 kwcodes.append("{%s, %s}" % ( 829 encode_symbol("ppos", arg.name), 830 encode_symbol("pcode", arg.name))) 831 832 else: 833 args[i+1] = str(argexpr) 834 835 # Defaults are added to the frame where arguments are missing. 836 837 if parameters: 838 function_defaults = self.importer.function_defaults.get(objpath) 839 if function_defaults: 840 841 # Visit each default and set any missing arguments. 842 843 for i, (argname, default) in enumerate(function_defaults): 844 argnum = parameters.index(argname) 845 if not args[argnum+1]: 846 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target, i) 847 848 argstr = "__ARGS(%s)" % ", ".join(args) 849 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 850 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 851 852 # The callable is then obtained. 853 854 if target: 855 callable = target 856 857 elif self.always_callable: 858 callable = "__load_via_object(__tmp_target.value, %s)" % \ 859 encode_symbol("pos", "__fn__") 860 else: 861 callable = "__check_and_load_via_object(__tmp_target.value, %s, %s)" % ( 862 encode_symbol("pos", "__fn__"), encode_symbol("code", "__fn__")) 863 864 stages.append(callable) 865 866 # With a known target, the function is obtained directly and called. 867 868 if target: 869 output = "(\n%s\n)(%s)" % (",\n".join(stages), argstr) 870 871 # With unknown targets, the generic invocation function is applied to 872 # the callable and argument collections. 873 874 else: 875 output = "__invoke(\n(\n%s\n),\n%d, %s, %s,\n%d, %s\n)" % ( 876 ",\n".join(stages), 877 len(kwargs), kwcodestr, kwargstr, 878 len(args), argstr) 879 880 return make_expression(output) 881 882 def always_callable(self, refs): 883 884 "Determine whether all 'refs' are callable." 885 886 for ref in refs: 887 if not ref.static(): 888 return False 889 else: 890 origin = ref.final() 891 if not self.importer.get_attribute(origin, "__fn__"): 892 return False 893 return True 894 895 def need_default_arguments(self, objpath, nargs): 896 897 """ 898 Return whether any default arguments are needed when invoking the object 899 given by 'objpath'. 900 """ 901 902 parameters = self.importer.function_parameters.get(objpath) 903 return nargs < len(parameters) 904 905 def process_lambda_node(self, n): 906 907 "Process the given lambda node 'n'." 908 909 name = self.get_lambda_name() 910 function_name = self.get_object_path(name) 911 912 defaults = self.process_function_defaults(n, name, "__tmp") 913 if not defaults: 914 return make_expression(encode_path(function_name)) 915 else: 916 return make_expression("(__COPY(%s, __tmp), %s)" % (encode_path(function_name), ", ".join(defaults))) 917 918 def process_logical_node(self, n): 919 920 "Process the given operator node 'n'." 921 922 if isinstance(n, compiler.ast.And): 923 op = " && " 924 else: 925 op = " || " 926 927 # NOTE: This needs to evaluate whether the operands are true or false 928 # NOTE: according to Python rules. 929 930 results = [("(%s)" % self.process_structure_node(node)) for node in n.nodes] 931 return make_expression("(%s)" % op.join(results)) 932 933 def process_name_node(self, n, expr=None): 934 935 "Process the given name node 'n' with the optional assignment 'expr'." 936 937 # Determine whether the name refers to a static external entity. 938 939 if n.name in predefined_constants: 940 return PredefinedConstantRef(n.name) 941 942 # Convert literal references. 943 944 elif n.name.startswith("$L"): 945 literal_name = n.name[len("$L"):] 946 ref = self.importer.get_object("__builtins__.%s" % literal_name) 947 return TrResolvedNameRef(n.name, ref) 948 949 # Convert operator function names to references. 950 951 elif n.name.startswith("$op"): 952 ref = self.importer.get_module(self.name).special.get(n.name) 953 return TrResolvedNameRef(n.name, ref) 954 955 # Get the appropriate name for the name reference, using the same method 956 # as in the inspector. 957 958 path = self.get_object_path(n.name) 959 ref = self.importer.get_object(path) 960 name = self.get_name_for_tracking(n.name, ref and ref.final()) 961 962 # Get the static identity of the name. 963 964 ref = self.importer.identify(path) 965 966 # Obtain any resolved names for non-assignment names. 967 968 if not expr and not ref and self.in_function: 969 locals = self.importer.function_locals.get(self.get_namespace_path()) 970 ref = locals and locals.get(n.name) 971 972 # Qualified names are used for resolved static references or for 973 # static namespace members. The reference should be configured to return 974 # such names. 975 976 return TrResolvedNameRef(name, ref, expr=expr) 977 978 def process_not_node(self, n): 979 980 "Process the given operator node 'n'." 981 982 # NOTE: This needs to evaluate whether the operand is true or false 983 # NOTE: according to Python rules. 984 985 return make_expression("(!(%s))" % n.expr) 986 987 def process_try_node(self, n): 988 989 """ 990 Process the given "try...except" node 'n'. 991 """ 992 993 # NOTE: Placeholders/macros. 994 995 self.writeline("TRY") 996 self.writeline("{") 997 self.indent += 1 998 self.process_structure_node(n.body) 999 self.indent -= 1 1000 self.writeline("}") 1001 1002 for name, var, handler in n.handlers: 1003 if name is not None: 1004 name_ref = self.process_structure_node(name) 1005 self.writeline("EXCEPT(%s)" % name_ref) 1006 1007 self.writeline("{") 1008 self.indent += 1 1009 1010 # Establish the local for the handler. 1011 # NOTE: Need to provide the exception value. 1012 1013 if var is not None: 1014 var_ref = self.process_structure_node(var) 1015 1016 if handler is not None: 1017 self.process_structure_node(handler) 1018 1019 self.indent -= 1 1020 self.writeline("}") 1021 1022 if n.else_: 1023 self.process_structure_node(n.else_) 1024 1025 def process_try_finally_node(self, n): 1026 1027 """ 1028 Process the given "try...finally" node 'n'. 1029 """ 1030 1031 # NOTE: Placeholders/macros. 1032 1033 self.writeline("TRY") 1034 self.writeline("{") 1035 self.indent += 1 1036 self.process_structure_node(n.body) 1037 self.indent -= 1 1038 self.writeline("}") 1039 self.writeline("FINALLY") 1040 self.writeline("{") 1041 self.indent += 1 1042 self.process_structure_node(n.final) 1043 self.indent -= 1 1044 self.writeline("}") 1045 1046 def process_while_node(self, n): 1047 1048 "Process the given while node 'n'." 1049 1050 self.writeline("while (1)") 1051 self.writeline("{") 1052 self.indent += 1 1053 test = self.process_structure_node(n.test) 1054 1055 # Emit the loop termination condition unless "while <true value>" is 1056 # indicated. 1057 1058 if not (isinstance(test, PredefinedConstantRef) and test.value): 1059 1060 # NOTE: This needs to evaluate whether the operand is true or false 1061 # NOTE: according to Python rules. 1062 1063 self.writeline("if (!(%s))" % test) 1064 self.writeline("{") 1065 self.indent += 1 1066 if n.else_: 1067 self.process_structure_node(n.else_) 1068 self.writestmt("break;") 1069 self.indent -= 1 1070 self.writeline("}") 1071 1072 in_conditional = self.in_conditional 1073 self.in_conditional = True 1074 self.process_structure_node(n.body) 1075 self.in_conditional = in_conditional 1076 1077 self.indent -= 1 1078 self.writeline("}") 1079 1080 # Output generation. 1081 1082 def start_output(self): 1083 print >>self.out, """\ 1084 #include "types.h" 1085 #include "ops.h" 1086 #include "progconsts.h" 1087 #include "progops.h" 1088 #include "progtypes.h" 1089 #include "main.h" 1090 """ 1091 1092 def start_module(self): 1093 print >>self.out, "void __main_%s()" % encode_path(self.name) 1094 print >>self.out, "{" 1095 self.indent += 1 1096 1097 def end_module(self): 1098 self.indent -= 1 1099 self.end_function() 1100 1101 def start_function(self, name): 1102 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1103 print >>self.out, "{" 1104 self.indent += 1 1105 self.writeline("__ref __tmp_context, __tmp_value;") 1106 self.writeline("__attr __tmp_target;") 1107 1108 # Obtain local names from parameters. 1109 1110 parameters = self.importer.function_parameters[name] 1111 names = [] 1112 locals = self.importer.function_locals[name].keys() 1113 1114 for n in locals: 1115 1116 # Filter out special names and parameters. Note that self is a local 1117 # regardless of whether it originally appeared in the parameters or 1118 # not. 1119 1120 if n.startswith("$l") or n in parameters or n == "self": 1121 continue 1122 names.append(encode_path(n)) 1123 1124 # Emit required local names. 1125 1126 if names: 1127 names.sort() 1128 self.writeline("__attr %s;" % ", ".join(names)) 1129 1130 # Generate any self reference. 1131 1132 if self.in_method(name): 1133 self.writeline("#define self (__args[0])") 1134 1135 # Generate aliases for the parameters. 1136 1137 for i, parameter in enumerate(parameters): 1138 self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1)) 1139 1140 def end_function(self): 1141 self.indent -= 1 1142 print >>self.out, "}" 1143 print >>self.out 1144 1145 def start_if(self, first, test_ref): 1146 1147 # NOTE: This needs to evaluate whether the operand is true or false 1148 # NOTE: according to Python rules. 1149 1150 self.writestmt("%sif (%s)" % (not first and "else " or "", test_ref)) 1151 self.writeline("{") 1152 self.indent += 1 1153 1154 def end_if(self): 1155 self.indent -= 1 1156 self.writeline("}") 1157 1158 def start_else(self): 1159 self.writeline("else") 1160 self.writeline("{") 1161 self.indent += 1 1162 1163 def end_else(self): 1164 self.indent -= 1 1165 self.writeline("}") 1166 1167 def statement(self, expr): 1168 # NOTE: Should never be None. 1169 if not expr: 1170 self.writestmt("...;") 1171 s = str(expr) 1172 if s: 1173 self.writestmt("%s;" % s) 1174 1175 def statements(self, results): 1176 for result in results: 1177 self.statement(result) 1178 1179 def pad(self, extra=0): 1180 return (self.indent + extra) * self.tabstop 1181 1182 def indenttext(self, s, levels): 1183 lines = s.split("\n") 1184 out = [lines[0]] 1185 for line in lines[1:]: 1186 out.append(levels * self.tabstop + line) 1187 if line.endswith("("): 1188 levels += 1 1189 elif line.startswith(")"): 1190 levels -= 1 1191 return "\n".join(out) 1192 1193 def writeline(self, s): 1194 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1195 1196 def writestmt(self, s): 1197 print >>self.out 1198 self.writeline(s) 1199 1200 def write_comment(self, s): 1201 self.writestmt("/* %s */" % s) 1202 1203 # vim: tabstop=4 expandtab shiftwidth=4