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