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