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