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 self.start_output() 214 215 # Process namespaces, writing the translation. 216 217 for path, node in self.namespaces: 218 self.process_namespace(path, node) 219 220 # Process the module namespace including class namespaces. 221 222 self.process_namespace([], self.astnode) 223 224 finally: 225 self.out.close() 226 227 def have_object(self): 228 229 "Return whether a namespace is a recorded object." 230 231 return self.importer.objects.get(self.get_namespace_path()) 232 233 def get_builtin(self, name): 234 return self.importer.get_object("__builtins__.%s" % name) 235 236 def in_method(self, path): 237 class_name, method_name = path.rsplit(".", 1) 238 return self.importer.classes.has_key(class_name) and class_name 239 240 # Namespace recording. 241 242 def record_namespaces(self, node): 243 244 "Process the program structure 'node', recording namespaces." 245 246 for n in node.getChildNodes(): 247 self.record_namespaces_in_node(n) 248 249 def record_namespaces_in_node(self, node): 250 251 "Process the program structure 'node', recording namespaces." 252 253 # Function namespaces within modules, classes and other functions. 254 # Functions appearing within conditional statements are given arbitrary 255 # names. 256 257 if isinstance(node, compiler.ast.Function): 258 self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name) 259 260 elif isinstance(node, compiler.ast.Lambda): 261 self.record_function_node(node, self.get_lambda_name()) 262 263 # Classes are visited, but may be ignored if inside functions. 264 265 elif isinstance(node, compiler.ast.Class): 266 self.enter_namespace(node.name) 267 if self.have_object(): 268 self.record_namespaces(node) 269 self.exit_namespace() 270 271 # Conditional nodes are tracked so that function definitions may be 272 # handled. Since "for" loops are converted to "while" loops, they are 273 # included here. 274 275 elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)): 276 in_conditional = self.in_conditional 277 self.in_conditional = True 278 self.record_namespaces(node) 279 self.in_conditional = in_conditional 280 281 # All other nodes are processed depth-first. 282 283 else: 284 self.record_namespaces(node) 285 286 def record_function_node(self, n, name): 287 288 """ 289 Record the given function, lambda, if expression or list comprehension 290 node 'n' with the given 'name'. 291 """ 292 293 self.in_function = True 294 self.enter_namespace(name) 295 296 if self.have_object(): 297 298 # Record the namespace path and the node itself. 299 300 self.namespaces.append((self.namespace_path[:], n)) 301 self.record_namespaces_in_node(n.code) 302 303 self.exit_namespace() 304 self.in_function = False 305 306 # Constant referencing. 307 308 def get_literal_instance(self, n, name): 309 310 """ 311 For node 'n', return a reference for the type of the given 'name'. 312 """ 313 314 ref = self.get_builtin(name) 315 316 if name in ("dict", "list", "tuple"): 317 return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef) 318 else: 319 path = self.get_namespace_path() 320 local_number = self.importer.all_constants[path][n.value] 321 constant_name = "$c%d" % local_number 322 objpath = self.get_object_path(constant_name) 323 number = self.optimiser.constant_numbers[objpath] 324 return TrConstantValueRef(constant_name, ref.instance_of(), n.value, number) 325 326 # Namespace translation. 327 328 def process_namespace(self, path, node): 329 330 """ 331 Process the namespace for the given 'path' defined by the given 'node'. 332 """ 333 334 self.namespace_path = path 335 336 if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)): 337 self.in_function = True 338 self.process_function_body_node(node) 339 else: 340 self.in_function = False 341 self.start_module() 342 self.process_structure(node) 343 self.end_module() 344 345 def process_structure(self, node): 346 347 "Process the given 'node' or result." 348 349 if isinstance(node, results.Result): 350 return node 351 else: 352 return CommonModule.process_structure(self, node) 353 354 def process_structure_node(self, n): 355 356 "Process the individual node 'n'." 357 358 # Plain statements emit their expressions. 359 360 if isinstance(n, compiler.ast.Discard): 361 expr = self.process_structure_node(n.expr) 362 self.statement(expr) 363 364 # Nodes using operator module functions. 365 366 elif isinstance(n, compiler.ast.Operator): 367 return self.process_operator_node(n) 368 369 elif isinstance(n, compiler.ast.AugAssign): 370 self.process_augassign_node(n) 371 372 elif isinstance(n, compiler.ast.Compare): 373 return self.process_compare_node(n) 374 375 elif isinstance(n, compiler.ast.Slice): 376 return self.process_slice_node(n) 377 378 elif isinstance(n, compiler.ast.Sliceobj): 379 return self.process_sliceobj_node(n) 380 381 elif isinstance(n, compiler.ast.Subscript): 382 return self.process_subscript_node(n) 383 384 # Classes are visited, but may be ignored if inside functions. 385 386 elif isinstance(n, compiler.ast.Class): 387 self.process_class_node(n) 388 389 # Functions within namespaces have any dynamic defaults initialised. 390 391 elif isinstance(n, compiler.ast.Function): 392 self.process_function_node(n) 393 394 # Lambdas are replaced with references to separately-generated 395 # functions. 396 397 elif isinstance(n, compiler.ast.Lambda): 398 return self.process_lambda_node(n) 399 400 # Assignments. 401 402 elif isinstance(n, compiler.ast.Assign): 403 404 # Handle each assignment node. 405 406 for node in n.nodes: 407 self.process_assignment_node(node, n.expr) 408 409 # Assignments within non-Assign nodes. 410 # NOTE: Cover all possible nodes employing these. 411 412 elif isinstance(n, compiler.ast.AssName): 413 self.process_assignment_node(n, compiler.ast.Name("$temp")) 414 415 elif isinstance(n, compiler.ast.AssAttr): 416 self.process_attribute_access(n) 417 418 # Accesses. 419 420 elif isinstance(n, compiler.ast.Getattr): 421 return self.process_attribute_access(n) 422 423 # Names. 424 425 elif isinstance(n, compiler.ast.Name): 426 return self.process_name_node(n) 427 428 # Loops and conditionals. 429 430 elif isinstance(n, compiler.ast.For): 431 self.process_for_node(n) 432 433 elif isinstance(n, compiler.ast.While): 434 self.process_while_node(n) 435 436 elif isinstance(n, compiler.ast.If): 437 self.process_if_node(n) 438 439 elif isinstance(n, (compiler.ast.And, compiler.ast.Or)): 440 return self.process_logical_node(n) 441 442 elif isinstance(n, compiler.ast.Not): 443 return self.process_not_node(n) 444 445 # Exception control-flow tracking. 446 447 elif isinstance(n, compiler.ast.TryExcept): 448 self.process_try_node(n) 449 450 elif isinstance(n, compiler.ast.TryFinally): 451 self.process_try_finally_node(n) 452 453 # Control-flow modification statements. 454 455 elif isinstance(n, compiler.ast.Break): 456 self.writestmt("break;") 457 458 elif isinstance(n, compiler.ast.Continue): 459 self.writestmt("continue;") 460 461 elif isinstance(n, compiler.ast.Return): 462 expr = self.process_structure_node(n.value) 463 if expr: 464 self.writestmt("return %s;" % expr) 465 else: 466 self.writestmt("return;") 467 468 # Invocations. 469 470 elif isinstance(n, compiler.ast.CallFunc): 471 return self.process_invocation_node(n) 472 473 elif isinstance(n, compiler.ast.Keyword): 474 return self.process_structure_node(n.expr) 475 476 # Constant usage. 477 478 elif isinstance(n, compiler.ast.Const): 479 return self.get_literal_instance(n, n.value.__class__.__name__) 480 481 elif isinstance(n, compiler.ast.Dict): 482 return self.get_literal_instance(n, "dict") 483 484 elif isinstance(n, compiler.ast.List): 485 return self.get_literal_instance(n, "list") 486 487 elif isinstance(n, compiler.ast.Tuple): 488 return self.get_literal_instance(n, "tuple") 489 490 # All other nodes are processed depth-first. 491 492 else: 493 self.process_structure(n) 494 495 def process_assignment_node(self, n, expr): 496 497 "Process the individual node 'n' to be assigned the contents of 'expr'." 498 499 # Names and attributes are assigned the entire expression. 500 501 if isinstance(n, compiler.ast.AssName): 502 name_ref = self.process_name_node(n, self.process_structure_node(expr)) 503 self.statement(name_ref) 504 505 elif isinstance(n, compiler.ast.AssAttr): 506 in_assignment = self.in_assignment 507 self.in_assignment = self.process_structure_node(expr) 508 self.statement(self.process_attribute_access(n)) 509 self.in_assignment = in_assignment 510 511 # Lists and tuples are matched against the expression and their 512 # items assigned to expression items. 513 514 elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)): 515 self.process_assignment_node_items(n, expr) 516 517 # Slices and subscripts are permitted within assignment nodes. 518 519 elif isinstance(n, compiler.ast.Slice): 520 self.statement(self.process_slice_node(n, expr)) 521 522 elif isinstance(n, compiler.ast.Subscript): 523 self.statement(self.process_subscript_node(n, expr)) 524 525 def process_attribute_access(self, n): 526 527 """ 528 Process the given attribute access node 'n'. 529 530 Where a name is provided, a single access should be recorded 531 involving potentially many attributes, thus providing a path to an 532 object. The remaining attributes are then accessed dynamically. 533 The remaining accesses could be deduced and computed, but they would 534 also need to be tested. 535 536 Where no name is provided, potentially many accesses should be 537 recorded, one per attribute name. These could be used to provide 538 computed accesses, but the accessors would need to be tested in each 539 case. 540 """ 541 542 # Obtain any completed chain and return the reference to it. 543 544 attr_expr = self.process_attribute_chain(n) 545 if self.have_access_expression(n): 546 return attr_expr 547 548 # Where the start of the chain of attributes has been reached, process 549 # the complete access. 550 551 name_ref = attr_expr and attr_expr.is_name() and attr_expr 552 name = name_ref and name_ref.name or None 553 554 location = self.get_access_location(name) 555 refs = self.get_referenced_attributes(location) 556 557 # Generate access instructions. 558 559 subs = { 560 "<expr>" : str(attr_expr), 561 "<assexpr>" : str(self.in_assignment), 562 "<context>" : "__tmp_context", 563 "<accessor>" : "__tmp_value", 564 } 565 566 output = [] 567 568 for instruction in self.optimiser.access_instructions[location]: 569 output.append(encode_access_instruction(instruction, subs)) 570 571 if len(output) == 1: 572 out = output[0] 573 else: 574 out = "(\n%s\n)" % ",\n".join(output) 575 576 del self.attrs[0] 577 return AttrResult(out, refs) 578 579 def get_referenced_attributes(self, location): 580 581 """ 582 Convert 'location' to the form used by the deducer and retrieve any 583 identified attribute. 584 """ 585 586 access_location = self.deducer.const_accesses.get(location) 587 refs = [] 588 for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]: 589 refs.append(attr) 590 return refs 591 592 def get_access_location(self, name): 593 594 """ 595 Using the current namespace and the given 'name', return the access 596 location. 597 """ 598 599 path = self.get_path_for_access() 600 601 # Get the location used by the deducer and optimiser and find any 602 # recorded access. 603 604 attrnames = ".".join(self.attrs) 605 access_number = self.get_access_number(path, name, attrnames) 606 self.update_access_number(path, name, attrnames) 607 return (path, name, attrnames, access_number) 608 609 def get_access_number(self, path, name, attrnames): 610 access = name, attrnames 611 if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access): 612 return self.attr_accesses[path][access] 613 else: 614 return 0 615 616 def update_access_number(self, path, name, attrnames): 617 access = name, attrnames 618 if name: 619 init_item(self.attr_accesses, path, dict) 620 init_item(self.attr_accesses[path], access, lambda: 1) 621 622 def process_class_node(self, n): 623 624 "Process the given class node 'n'." 625 626 self.enter_namespace(n.name) 627 628 if self.have_object(): 629 class_name = self.get_namespace_path() 630 self.write_comment("Class: %s" % class_name) 631 632 self.process_structure(n) 633 634 self.exit_namespace() 635 636 def process_function_body_node(self, n): 637 638 """ 639 Process the given function, lambda, if expression or list comprehension 640 node 'n', generating the body. 641 """ 642 643 function_name = self.get_namespace_path() 644 self.start_function(function_name) 645 646 # Process the function body. 647 648 in_conditional = self.in_conditional 649 self.in_conditional = False 650 651 expr = self.process_structure_node(n.code) 652 if expr: 653 self.writestmt("return %s;" % expr) 654 655 self.in_conditional = in_conditional 656 657 self.end_function() 658 659 def process_function_node(self, n): 660 661 """ 662 Process the given function, lambda, if expression or list comprehension 663 node 'n', generating any initialisation statements. 664 """ 665 666 # Where a function is declared conditionally, use a separate name for 667 # the definition, and assign the definition to the stated name. 668 669 if self.in_conditional or self.in_function: 670 original_name = n.name 671 name = self.get_lambda_name() 672 else: 673 original_name = None 674 name = n.name 675 676 # Obtain details of the defaults. 677 678 defaults = self.process_function_defaults(n, name, self.get_object_path(name)) 679 if defaults: 680 for default in defaults: 681 self.writeline("%s;" % default) 682 683 # Where a function is set conditionally, assign the name. 684 685 if original_name: 686 self.process_assignment_for_function(original_name, name) 687 688 def process_function_defaults(self, n, name, instance_name): 689 690 """ 691 Process the given function or lambda node 'n', initialising defaults 692 that are dynamically set. The given 'name' indicates the name of the 693 function. The given 'instance_name' indicates the name of any separate 694 instance of the function created to hold the defaults. 695 696 Return a list of operations setting defaults on a function instance. 697 """ 698 699 function_name = self.get_object_path(name) 700 function_defaults = self.importer.function_defaults.get(function_name) 701 if not function_defaults: 702 return None 703 704 # Determine whether any unidentified defaults are involved. 705 706 need_defaults = [argname for argname, default in function_defaults if default.has_kind("<var>")] 707 if not need_defaults: 708 return None 709 710 # Where defaults are involved but cannot be identified, obtain a new 711 # instance of the lambda and populate the defaults. 712 713 defaults = [] 714 715 # Join the original defaults with the inspected defaults. 716 717 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 718 719 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 720 721 # Obtain any reference for the default. 722 723 if original: 724 argname, default = original 725 name_ref = self.process_structure_node(default) 726 elif inspected: 727 argname, default = inspected 728 name_ref = TrResolvedNameRef(argname, default) 729 else: 730 continue 731 732 if name_ref: 733 defaults.append("__SETDEFAULT(%s, %s, %s)" % (encode_path(instance_name), i, name_ref)) 734 735 return defaults 736 737 def process_if_node(self, n): 738 739 """ 740 Process the given "if" node 'n'. 741 """ 742 743 first = True 744 for test, body in n.tests: 745 test_ref = self.process_structure_node(test) 746 self.start_if(first, test_ref) 747 748 in_conditional = self.in_conditional 749 self.in_conditional = True 750 self.process_structure_node(body) 751 self.in_conditional = in_conditional 752 753 self.end_if() 754 first = False 755 756 if n.else_: 757 self.start_else() 758 self.process_structure_node(n.else_) 759 self.end_else() 760 761 def process_invocation_node(self, n): 762 763 "Process the given invocation node 'n'." 764 765 expr = self.process_structure_node(n.node) 766 objpath = expr.get_origin() 767 target = None 768 769 # Obtain details of the callable. 770 771 if objpath: 772 parameters = self.importer.function_parameters.get(objpath) 773 if expr.has_kind("<class>"): 774 target = encode_instantiator_pointer(objpath) 775 elif expr.has_kind("<function>"): 776 target = encode_function_pointer(objpath) 777 else: 778 parameters = None 779 780 stages = [] 781 782 # First, the invocation target is presented. 783 784 stages.append("__tmp_target = %s" % expr) 785 786 # Arguments are presented in a temporary frame array with any context 787 # always being the first argument (although it may be set to null for 788 # invocations where it would be unused). 789 790 args = ["__CONTEXT_AS_VALUE(__tmp_target)"] 791 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 792 kwcodes = [] 793 kwargs = [] 794 795 for i, arg in enumerate(n.args): 796 argexpr = self.process_structure_node(arg) 797 798 # Store a keyword argument, either in the argument list or 799 # in a separate keyword argument list for subsequent lookup. 800 801 if isinstance(arg, compiler.ast.Keyword): 802 803 # With knowledge of the target, store the keyword 804 # argument directly. 805 806 if parameters: 807 argnum = parameters.index(arg.name) 808 args[argnum+1] = str(argexpr) 809 810 # Otherwise, store the details in a separate collection. 811 812 else: 813 kwargs.append(str(argexpr)) 814 kwcodes.append("{%s, %s}" % ( 815 encode_symbol("ppos", arg.name), 816 encode_symbol("pcode", arg.name))) 817 818 else: 819 args[i+1] = str(argexpr) 820 821 # Defaults are added to the frame where arguments are missing. 822 823 if parameters: 824 function_defaults = self.importer.function_defaults.get(objpath) 825 if function_defaults: 826 827 # Visit each default and set any missing arguments. 828 829 for i, (argname, default) in enumerate(function_defaults): 830 argnum = parameters.index(argname) 831 if not args[argnum+1]: 832 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target, i) 833 834 if None in args: 835 print self.get_namespace_path() 836 print n 837 print expr 838 print target 839 print args 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 = "__tmp_target" 849 850 elif self.always_callable: 851 callable = "__load_via_object(__tmp_target, %s)" % \ 852 encode_symbol("pos", "__fn__") 853 else: 854 callable = "__check_and_load_via_object(__tmp_target, %s, %s)" % ( 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.fn\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 opname = n.name[len("$op"):] 946 ref = self.importer.get_object("operator.%s" % opname) 947 return TrResolvedNameRef(n.name, ref) 948 949 # Get the appropriate name for the name reference, using the same method 950 # as in the inspector. 951 952 path = self.get_object_path(n.name) 953 ref = self.importer.get_object(path) 954 name = self.get_name_for_tracking(n.name, ref and ref.final()) 955 956 # Get the static identity of the name. 957 958 ref = self.importer.identify(path) 959 960 # Obtain any resolved names for non-assignment names. 961 962 if not expr and not ref and self.in_function: 963 locals = self.importer.function_locals.get(self.get_namespace_path()) 964 ref = locals and locals.get(n.name) 965 966 # Qualified names are used for resolved static references or for 967 # static namespace members. The reference should be configured to return 968 # such names. 969 970 return TrResolvedNameRef(name, ref, expr=expr) 971 972 def process_not_node(self, n): 973 974 "Process the given operator node 'n'." 975 976 # NOTE: This needs to evaluate whether the operand is true or false 977 # NOTE: according to Python rules. 978 979 return make_expression("(!(%s))" % n.expr) 980 981 def process_try_node(self, n): 982 983 """ 984 Process the given "try...except" node 'n'. 985 """ 986 987 # NOTE: Placeholders/macros. 988 989 self.writeline("TRY") 990 self.writeline("{") 991 self.indent += 1 992 self.process_structure_node(n.body) 993 self.indent -= 1 994 self.writeline("}") 995 996 for name, var, handler in n.handlers: 997 if name is not None: 998 name_ref = self.process_structure_node(name) 999 self.writeline("EXCEPT(%s)" % name_ref) 1000 1001 self.writeline("{") 1002 self.indent += 1 1003 1004 # Establish the local for the handler. 1005 # NOTE: Need to provide the exception value. 1006 1007 if var is not None: 1008 var_ref = self.process_structure_node(var) 1009 1010 if handler is not None: 1011 self.process_structure_node(handler) 1012 1013 self.indent -= 1 1014 self.writeline("}") 1015 1016 if n.else_: 1017 self.process_structure_node(n.else_) 1018 1019 def process_try_finally_node(self, n): 1020 1021 """ 1022 Process the given "try...finally" node 'n'. 1023 """ 1024 1025 # NOTE: Placeholders/macros. 1026 1027 self.writeline("TRY") 1028 self.writeline("{") 1029 self.indent += 1 1030 self.process_structure_node(n.body) 1031 self.indent -= 1 1032 self.writeline("}") 1033 self.writeline("FINALLY") 1034 self.writeline("{") 1035 self.indent += 1 1036 self.process_structure_node(n.final) 1037 self.indent -= 1 1038 self.writeline("}") 1039 1040 def process_while_node(self, n): 1041 1042 "Process the given while node 'n'." 1043 1044 self.writeline("while (1)") 1045 self.writeline("{") 1046 self.indent += 1 1047 test = self.process_structure_node(n.test) 1048 1049 # Emit the loop termination condition unless "while <true value>" is 1050 # indicated. 1051 1052 if not (isinstance(test, PredefinedConstantRef) and test.value): 1053 1054 # NOTE: This needs to evaluate whether the operand is true or false 1055 # NOTE: according to Python rules. 1056 1057 self.writeline("if (!(%s))" % test) 1058 self.writeline("{") 1059 self.indent += 1 1060 if n.else_: 1061 self.process_structure_node(n.else_) 1062 self.writestmt("break;") 1063 self.indent -= 1 1064 self.writeline("}") 1065 1066 in_conditional = self.in_conditional 1067 self.in_conditional = True 1068 self.process_structure_node(n.body) 1069 self.in_conditional = in_conditional 1070 1071 self.indent -= 1 1072 self.writeline("}") 1073 1074 # Output generation. 1075 1076 def start_output(self): 1077 print >>self.out, """\ 1078 #include "types.h" 1079 #include "ops.h" 1080 #include "progconsts.h" 1081 #include "progops.h" 1082 #include "progtypes.h" 1083 """ 1084 1085 def start_module(self): 1086 print >>self.out, "void __main_%s()" % encode_path(self.name) 1087 print >>self.out, "{" 1088 self.indent += 1 1089 1090 def end_module(self): 1091 self.indent -= 1 1092 self.end_function() 1093 1094 def start_function(self, name): 1095 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1096 print >>self.out, "{" 1097 self.indent += 1 1098 self.writeline("__attr __tmp_context, __tmp_target, __tmp_value;") 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