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