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