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