1 #!/usr/bin/env python 2 3 """ 4 Translate programs. 5 6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from common import * 23 from encoders import * 24 from os.path import exists, join 25 from os import makedirs 26 import compiler 27 import results 28 29 class Translator(CommonOutput): 30 31 "A program translator." 32 33 def __init__(self, importer, deducer, optimiser, output): 34 self.importer = importer 35 self.deducer = deducer 36 self.optimiser = optimiser 37 self.output = output 38 39 def to_output(self): 40 output = join(self.output, "src") 41 42 if not exists(output): 43 makedirs(output) 44 45 self.check_output() 46 47 for module in self.importer.modules.values(): 48 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser) 49 tm.translate(module.filename, join(output, "%s.c" % module.name)) 50 51 # Classes representing intermediate translation results. 52 53 class TranslationResult: 54 55 "An abstract translation result mix-in." 56 57 pass 58 59 class Expression(results.Result, TranslationResult): 60 61 "A general expression." 62 63 def __init__(self, s): 64 self.s = s 65 def __str__(self): 66 return self.s 67 def __repr__(self): 68 return "Expression(%r)" % self.s 69 70 class TrResolvedNameRef(results.ResolvedNameRef, TranslationResult): 71 72 "A reference to a name in the translation." 73 74 def __str__(self): 75 76 "Return an output representation of the referenced name." 77 78 # Use any alias in preference to the origin of the name. 79 80 name = self.get_name() 81 82 # Use any static origin in preference to any alias. 83 # For sources, any identified static origin will be constant and thus 84 # usable directly. For targets, no constant should be assigned and thus 85 # the alias (or any plain name) will be used. 86 87 origin = self.static() and self.get_origin() 88 name = origin and encode_path(origin) or name and encode_path(name) or encode_path(self.name) 89 90 # Assignments. 91 92 if self.expr: 93 94 # Eliminate assignments between constants. 95 96 if self.static() and isinstance(self.expr, results.ResolvedNameRef) and self.expr.static(): 97 return "" 98 else: 99 return "%s = %s" % (name, self.expr) 100 101 # Expressions. 102 103 else: 104 return name 105 106 class TrConstantValueRef(results.ConstantValueRef, TranslationResult): 107 108 "A constant value reference in the translation." 109 110 def __str__(self): 111 return "const%d" % self.number 112 113 class TrLiteralSequenceRef(results.LiteralSequenceRef, TranslationResult): 114 115 "A reference representing a sequence of values." 116 117 def __str__(self): 118 return str(self.node) 119 120 class AttrResult(Expression, TranslationResult): 121 122 "A translation result for an attribute access." 123 124 def __init__(self, s, refs): 125 Expression.__init__(self, s) 126 self.refs = refs 127 128 def get_origin(self): 129 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() 130 131 def has_kind(self, kinds): 132 if not self.refs: 133 return False 134 for ref in self.refs: 135 if ref.has_kind(kinds): 136 return True 137 return False 138 139 def __repr__(self): 140 return "AttrResult(%r, %r)" % (self.s, self.origin) 141 142 class PredefinedConstantRef(AttrResult): 143 144 "A predefined constant reference." 145 146 def __init__(self, value): 147 self.value = value 148 149 def __str__(self): 150 return self.value 151 152 def __repr__(self): 153 return "PredefinedConstantRef(%r)" % self.value 154 155 def make_expression(expr): 156 157 "Make a new expression from the existing 'expr'." 158 159 if isinstance(expr, results.Result): 160 return expr 161 else: 162 return Expression(str(expr)) 163 164 # The actual translation process itself. 165 166 class TranslatedModule(CommonModule): 167 168 "A module translator." 169 170 def __init__(self, name, importer, deducer, optimiser): 171 CommonModule.__init__(self, name, importer) 172 self.deducer = deducer 173 self.optimiser = optimiser 174 175 # Output stream. 176 177 self.out = None 178 self.indent = 0 179 self.tabstop = " " 180 181 # Recorded namespaces. 182 183 self.namespaces = [] 184 self.in_conditional = False 185 186 # Attribute access counting. 187 188 self.attr_accesses = {} 189 190 def __repr__(self): 191 return "TranslatedModule(%r, %r)" % (self.name, self.importer) 192 193 def translate(self, filename, output_filename): 194 195 """ 196 Parse the file having the given 'filename', writing the translation to 197 the given 'output_filename'. 198 """ 199 200 self.parse_file(filename) 201 202 # Collect function namespaces for separate processing. 203 204 self.record_namespaces(self.astnode) 205 206 # Reset the lambda naming (in order to obtain the same names again) and 207 # translate the program. 208 209 self.reset_lambdas() 210 211 self.out = open(output_filename, "w") 212 try: 213 # Process namespaces, writing the translation. 214 215 for path, node in self.namespaces: 216 self.process_namespace(path, node) 217 218 # Process the module namespace including class namespaces. 219 220 self.process_namespace([], self.astnode) 221 222 finally: 223 self.out.close() 224 225 def have_object(self): 226 227 "Return whether a namespace is a recorded object." 228 229 return self.importer.objects.get(self.get_namespace_path()) 230 231 def get_builtin(self, name): 232 return self.importer.get_object("__builtins__.%s" % name) 233 234 def in_method(self, path): 235 class_name, method_name = path.rsplit(".", 1) 236 return self.importer.classes.has_key(class_name) and class_name 237 238 # Namespace recording. 239 240 def record_namespaces(self, node): 241 242 "Process the program structure 'node', recording namespaces." 243 244 for n in node.getChildNodes(): 245 self.record_namespaces_in_node(n) 246 247 def record_namespaces_in_node(self, node): 248 249 "Process the program structure 'node', recording namespaces." 250 251 # Function namespaces within modules, classes and other functions. 252 # Functions appearing within conditional statements are given arbitrary 253 # names. 254 255 if isinstance(node, compiler.ast.Function): 256 self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name) 257 258 elif isinstance(node, compiler.ast.Lambda): 259 self.record_function_node(node, self.get_lambda_name()) 260 261 # Classes are visited, but may be ignored if inside functions. 262 263 elif isinstance(node, compiler.ast.Class): 264 self.enter_namespace(node.name) 265 if self.have_object(): 266 self.record_namespaces(node) 267 self.exit_namespace() 268 269 # Conditional nodes are tracked so that function definitions may be 270 # handled. Since "for" loops are converted to "while" loops, they are 271 # included here. 272 273 elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)): 274 in_conditional = self.in_conditional 275 self.in_conditional = True 276 self.record_namespaces(node) 277 self.in_conditional = in_conditional 278 279 # All other nodes are processed depth-first. 280 281 else: 282 self.record_namespaces(node) 283 284 def record_function_node(self, n, name): 285 286 """ 287 Record the given function, lambda, if expression or list comprehension 288 node 'n' with the given 'name'. 289 """ 290 291 self.in_function = True 292 self.enter_namespace(name) 293 294 if self.have_object(): 295 296 # Record the namespace path and the node itself. 297 298 self.namespaces.append((self.namespace_path[:], n)) 299 self.record_namespaces_in_node(n.code) 300 301 self.exit_namespace() 302 self.in_function = False 303 304 # Constant referencing. 305 306 def get_literal_instance(self, n, name): 307 308 """ 309 For node 'n', return a reference for the type of the given 'name'. 310 """ 311 312 ref = self.get_builtin(name) 313 314 if name in ("dict", "list", "tuple"): 315 return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef) 316 else: 317 path = self.get_namespace_path() 318 local_number = self.importer.all_constants[path][n.value] 319 constant_name = "$c%d" % local_number 320 objpath = self.get_object_path(constant_name) 321 number = self.optimiser.constant_numbers[objpath] 322 return TrConstantValueRef(constant_name, ref.instance_of(), n.value, number) 323 324 # Namespace translation. 325 326 def process_namespace(self, path, node): 327 328 """ 329 Process the namespace for the given 'path' defined by the given 'node'. 330 """ 331 332 self.namespace_path = path 333 334 if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)): 335 self.in_function = True 336 self.process_function_body_node(node) 337 else: 338 self.in_function = False 339 self.start_module() 340 self.process_structure(node) 341 self.end_module() 342 343 def process_structure(self, node): 344 345 "Process the given 'node' or result." 346 347 if isinstance(node, results.Result): 348 return node 349 else: 350 return CommonModule.process_structure(self, node) 351 352 def process_structure_node(self, n): 353 354 "Process the individual node 'n'." 355 356 # Plain statements emit their expressions. 357 358 if isinstance(n, compiler.ast.Discard): 359 expr = self.process_structure_node(n.expr) 360 self.statement(expr) 361 362 # Nodes using operator module functions. 363 364 elif isinstance(n, compiler.ast.Operator): 365 return self.process_operator_node(n) 366 367 elif isinstance(n, compiler.ast.AugAssign): 368 self.process_augassign_node(n) 369 370 elif isinstance(n, compiler.ast.Compare): 371 return self.process_compare_node(n) 372 373 elif isinstance(n, compiler.ast.Slice): 374 return self.process_slice_node(n) 375 376 elif isinstance(n, compiler.ast.Sliceobj): 377 return self.process_sliceobj_node(n) 378 379 elif isinstance(n, compiler.ast.Subscript): 380 return self.process_subscript_node(n) 381 382 # Classes are visited, but may be ignored if inside functions. 383 384 elif isinstance(n, compiler.ast.Class): 385 self.process_class_node(n) 386 387 # Functions within namespaces have any dynamic defaults initialised. 388 389 elif isinstance(n, compiler.ast.Function): 390 self.process_function_node(n) 391 392 # Lambdas are replaced with references to separately-generated 393 # functions. 394 395 elif isinstance(n, compiler.ast.Lambda): 396 return self.process_lambda_node(n) 397 398 # Assignments. 399 400 elif isinstance(n, compiler.ast.Assign): 401 402 # Handle each assignment node. 403 404 for node in n.nodes: 405 self.process_assignment_node(node, n.expr) 406 407 # Assignments within non-Assign nodes. 408 # NOTE: Cover all possible nodes employing these. 409 410 elif isinstance(n, compiler.ast.AssName): 411 self.process_assignment_node(n, compiler.ast.Name("$temp")) 412 413 elif isinstance(n, compiler.ast.AssAttr): 414 self.process_attribute_access(n) 415 416 # Accesses. 417 418 elif isinstance(n, compiler.ast.Getattr): 419 return self.process_attribute_access(n) 420 421 # Names. 422 423 elif isinstance(n, compiler.ast.Name): 424 return self.process_name_node(n) 425 426 # Loops and conditionals. 427 428 elif isinstance(n, compiler.ast.For): 429 self.process_for_node(n) 430 431 elif isinstance(n, compiler.ast.While): 432 self.process_while_node(n) 433 434 elif isinstance(n, compiler.ast.If): 435 self.process_if_node(n) 436 437 elif isinstance(n, (compiler.ast.And, compiler.ast.Or)): 438 return self.process_logical_node(n) 439 440 elif isinstance(n, compiler.ast.Not): 441 return self.process_not_node(n) 442 443 # Exception control-flow tracking. 444 445 elif isinstance(n, compiler.ast.TryExcept): 446 self.process_try_node(n) 447 448 elif isinstance(n, compiler.ast.TryFinally): 449 self.process_try_finally_node(n) 450 451 # Control-flow modification statements. 452 453 elif isinstance(n, compiler.ast.Break): 454 self.writeline("break;") 455 456 elif isinstance(n, compiler.ast.Continue): 457 self.writeline("continue;") 458 459 elif isinstance(n, compiler.ast.Return): 460 expr = self.process_structure_node(n.value) 461 if expr: 462 self.writeline("return %s;" % expr) 463 else: 464 self.writeline("return;") 465 466 # Invocations. 467 468 elif isinstance(n, compiler.ast.CallFunc): 469 return self.process_invocation_node(n) 470 471 elif isinstance(n, compiler.ast.Keyword): 472 return self.process_structure_node(n.expr) 473 474 # Constant usage. 475 476 elif isinstance(n, compiler.ast.Const): 477 return self.get_literal_instance(n, n.value.__class__.__name__) 478 479 elif isinstance(n, compiler.ast.Dict): 480 return self.get_literal_instance(n, "dict") 481 482 elif isinstance(n, compiler.ast.List): 483 return self.get_literal_instance(n, "list") 484 485 elif isinstance(n, compiler.ast.Tuple): 486 return self.get_literal_instance(n, "tuple") 487 488 # All other nodes are processed depth-first. 489 490 else: 491 self.process_structure(n) 492 493 def process_assignment_node(self, n, expr): 494 495 "Process the individual node 'n' to be assigned the contents of 'expr'." 496 497 # Names and attributes are assigned the entire expression. 498 499 if isinstance(n, compiler.ast.AssName): 500 name_ref = self.process_name_node(n, self.process_structure_node(expr)) 501 self.statement(name_ref) 502 503 elif isinstance(n, compiler.ast.AssAttr): 504 self.statement(self.process_attribute_access(n, self.process_structure_node(expr))) 505 506 # Lists and tuples are matched against the expression and their 507 # items assigned to expression items. 508 509 elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)): 510 self.process_assignment_node_items(n, expr) 511 512 # Slices and subscripts are permitted within assignment nodes. 513 514 elif isinstance(n, compiler.ast.Slice): 515 self.statement(self.process_slice_node(n, expr)) 516 517 elif isinstance(n, compiler.ast.Subscript): 518 self.statement(self.process_subscript_node(n, expr)) 519 520 def process_attribute_access(self, n, expr=None): 521 522 """ 523 Process the given attribute access node 'n'. 524 525 Where a name is provided, a single access should be recorded 526 involving potentially many attributes, thus providing a path to an 527 object. The remaining attributes are then accessed dynamically. 528 The remaining accesses could be deduced and computed, but they would 529 also need to be tested. 530 531 Where no name is provided, potentially many accesses should be 532 recorded, one per attribute name. These could be used to provide 533 computed accesses, but the accessors would need to be tested in each 534 case. 535 """ 536 537 # Obtain any completed chain and return the reference to it. 538 539 attr_expr = self.process_attribute_chain(n) 540 if self.have_access_expression(n): 541 return attr_expr 542 543 # Where the start of the chain of attributes has been reached, process 544 # the complete access. 545 546 name_ref = attr_expr and attr_expr.is_name() and attr_expr 547 name = name_ref and name_ref.name or None 548 549 location = self.get_access_location(name) 550 refs = self.get_referenced_attributes(location) 551 552 # Generate access instructions. 553 554 subs = { 555 "<expr>" : str(attr_expr), 556 "<assexpr>" : str(expr), 557 "<context>" : "__tmp_context", 558 "<accessor>" : "__tmp_value", 559 } 560 561 output = [] 562 563 for instruction in self.optimiser.access_instructions[location]: 564 output.append(encode_access_instruction(instruction, subs)) 565 566 out = "(\n%s\n)" % ",\n".join(output) 567 568 del self.attrs[0] 569 return AttrResult(out, refs) 570 571 def get_referenced_attributes(self, location): 572 573 """ 574 Convert 'location' to the form used by the deducer and retrieve any 575 identified attribute. 576 """ 577 578 access_location = self.deducer.const_accesses.get(location) 579 refs = [] 580 for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]: 581 refs.append(attr) 582 return refs 583 584 def get_access_location(self, name): 585 586 """ 587 Using the current namespace and the given 'name', return the access 588 location. 589 """ 590 591 path = self.get_path_for_access() 592 593 # Get the location used by the deducer and optimiser and find any 594 # recorded access. 595 596 attrnames = ".".join(self.attrs) 597 access_number = self.get_access_number(path, name, attrnames) 598 self.update_access_number(path, name, attrnames) 599 return (path, name, attrnames, access_number) 600 601 def get_access_number(self, path, name, attrnames): 602 access = name, attrnames 603 if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access): 604 return self.attr_accesses[path][access] 605 else: 606 return 0 607 608 def update_access_number(self, path, name, attrnames): 609 access = name, attrnames 610 if name: 611 init_item(self.attr_accesses, path, dict) 612 init_item(self.attr_accesses[path], access, lambda: 1) 613 614 def process_class_node(self, n): 615 616 "Process the given class node 'n'." 617 618 self.enter_namespace(n.name) 619 620 if self.have_object(): 621 class_name = self.get_namespace_path() 622 self.write_comment("Class: %s" % class_name) 623 624 self.process_structure(n) 625 626 self.exit_namespace() 627 628 def process_function_body_node(self, n): 629 630 """ 631 Process the given function, lambda, if expression or list comprehension 632 node 'n', generating the body. 633 """ 634 635 function_name = self.get_namespace_path() 636 self.start_function(function_name) 637 638 # Process the function body. 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 target = None 760 761 # Obtain details of the callable. 762 763 if objpath: 764 parameters = self.importer.function_parameters.get(objpath) 765 if expr.has_kind("<class>"): 766 target = encode_instantiator_pointer(objpath) 767 elif expr.has_kind("<function>"): 768 target = encode_function_pointer(objpath) 769 else: 770 parameters = None 771 772 stages = [] 773 774 # First, the invocation target is presented. 775 776 stages.append("__tmp_target = %s" % expr) 777 778 # Arguments are presented in a temporary frame array with any context 779 # always being the first argument (although it may be set to null for 780 # invocations where it would be unused). 781 782 args = ["__CONTEXT_AS_VALUE(__tmp_target)"] 783 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 784 kwcodes = [] 785 kwargs = [] 786 787 for i, arg in enumerate(n.args): 788 argexpr = self.process_structure_node(arg) 789 790 # Store a keyword argument, either in the argument list or 791 # in a separate keyword argument list for subsequent lookup. 792 793 if isinstance(arg, compiler.ast.Keyword): 794 795 # With knowledge of the target, store the keyword 796 # argument directly. 797 798 if parameters: 799 argnum = parameters.index(arg.name) 800 args[argnum+1] = str(argexpr) 801 802 # Otherwise, store the details in a separate collection. 803 804 else: 805 kwargs.append(str(argexpr)) 806 kwcodes.append("{%s, %s}" % ( 807 encode_symbol("ppos", arg.name), 808 encode_symbol("pcode", arg.name))) 809 810 else: 811 args[i+1] = str(argexpr) 812 813 # Defaults are added to the frame where arguments are missing. 814 815 if parameters: 816 function_defaults = self.importer.function_defaults.get(objpath) 817 if function_defaults: 818 819 # Visit each default and set any missing arguments. 820 821 for i, (argname, default) in enumerate(function_defaults): 822 argnum = parameters.index(argname) 823 if not args[argnum+1]: 824 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target, i) 825 826 if None in args: 827 print self.get_namespace_path() 828 print n 829 print expr 830 print target 831 print args 832 833 argstr = "__ARGS(%s)" % ", ".join(args) 834 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 835 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 836 837 # The callable is then obtained. 838 839 if target: 840 callable = "__tmp_target" 841 842 elif self.always_callable: 843 callable = "__load_via_object(__tmp_target, %s)" % \ 844 encode_symbol("pos", "__fn__") 845 else: 846 callable = "__check_and_load_via_object(__tmp_target, %s, %s)" % ( 847 encode_symbol("pos", "__fn__"), encode_symbol("code", "__fn__")) 848 849 stages.append(callable) 850 851 # With a known target, the function is obtained directly and called. 852 853 if target: 854 output = "(\n%s.fn\n)(%s)" % (",\n".join(stages), argstr) 855 856 # With unknown targets, the generic invocation function is applied to 857 # the callable and argument collections. 858 859 else: 860 output = "__invoke(\n(\n%s\n),\n%d, %s, %s,\n%d, %s\n)" % ( 861 ",\n".join(stages), 862 len(kwargs), kwcodestr, kwargstr, 863 len(args), argstr) 864 865 return make_expression(output) 866 867 def always_callable(self, refs): 868 869 "Determine whether all 'refs' are callable." 870 871 for ref in refs: 872 if not ref.static(): 873 return False 874 else: 875 origin = ref.final() 876 if not self.importer.get_attribute(origin, "__fn__"): 877 return False 878 return True 879 880 def need_default_arguments(self, objpath, nargs): 881 882 """ 883 Return whether any default arguments are needed when invoking the object 884 given by 'objpath'. 885 """ 886 887 parameters = self.importer.function_parameters.get(objpath) 888 return nargs < len(parameters) 889 890 def process_lambda_node(self, n): 891 892 "Process the given lambda node 'n'." 893 894 name = self.get_lambda_name() 895 function_name = self.get_object_path(name) 896 897 defaults = self.process_function_defaults(n, name, "__tmp") 898 if not defaults: 899 return make_expression(encode_path(function_name)) 900 else: 901 return make_expression("(__COPY(%s, __tmp), %s)" % (encode_path(function_name), ", ".join(defaults))) 902 903 def process_logical_node(self, n): 904 905 "Process the given operator node 'n'." 906 907 if isinstance(n, compiler.ast.And): 908 op = " && " 909 else: 910 op = " || " 911 912 # NOTE: This needs to evaluate whether the operands are true or false 913 # NOTE: according to Python rules. 914 915 results = [("(%s)" % self.process_structure_node(node)) for node in n.nodes] 916 return make_expression("(%s)" % op.join(results)) 917 918 def process_name_node(self, n, expr=None): 919 920 "Process the given name node 'n' with the optional assignment 'expr'." 921 922 # Determine whether the name refers to a static external entity. 923 924 if n.name in predefined_constants: 925 return PredefinedConstantRef(n.name) 926 927 # Convert literal references. 928 929 elif n.name.startswith("$L"): 930 literal_name = n.name[len("$L"):] 931 ref = self.importer.get_object("__builtins__.%s" % literal_name) 932 return TrResolvedNameRef(n.name, ref) 933 934 # Convert operator function names to references. 935 936 elif n.name.startswith("$op"): 937 opname = n.name[len("$op"):] 938 ref = self.importer.get_object("operator.%s" % opname) 939 return TrResolvedNameRef(n.name, ref) 940 941 # Get the appropriate name for the name reference, using the same method 942 # as in the inspector. 943 944 path = self.get_object_path(n.name) 945 ref = self.importer.get_object(path) 946 name = self.get_name_for_tracking(n.name, ref and ref.final()) 947 948 # Get the static identity of the name. 949 950 ref = self.importer.identify(path) 951 952 # Obtain any resolved names for non-assignment names. 953 954 if not expr and not ref and self.in_function: 955 locals = self.importer.function_locals.get(self.get_namespace_path()) 956 ref = locals and locals.get(n.name) 957 958 # Qualified names are used for resolved static references or for 959 # static namespace members. The reference should be configured to return 960 # such names. 961 962 return TrResolvedNameRef(name, ref, expr=expr) 963 964 def process_not_node(self, n): 965 966 "Process the given operator node 'n'." 967 968 # NOTE: This needs to evaluate whether the operand is true or false 969 # NOTE: according to Python rules. 970 971 return make_expression("(!(%s))" % n.expr) 972 973 def process_try_node(self, n): 974 975 """ 976 Process the given "try...except" node 'n'. 977 """ 978 979 # NOTE: Placeholders/macros. 980 981 self.writeline("TRY") 982 self.writeline("{") 983 self.indent += 1 984 self.process_structure_node(n.body) 985 self.indent -= 1 986 self.writeline("}") 987 988 for name, var, handler in n.handlers: 989 if name is not None: 990 name_ref = self.process_structure_node(name) 991 self.writeline("EXCEPT(%s)" % name_ref) 992 993 self.writeline("{") 994 self.indent += 1 995 996 # Establish the local for the handler. 997 # NOTE: Need to provide the exception value. 998 999 if var is not None: 1000 var_ref = self.process_structure_node(var) 1001 1002 if handler is not None: 1003 self.process_structure_node(handler) 1004 1005 self.indent -= 1 1006 self.writeline("}") 1007 1008 if n.else_: 1009 self.process_structure_node(n.else_) 1010 1011 def process_try_finally_node(self, n): 1012 1013 """ 1014 Process the given "try...finally" node 'n'. 1015 """ 1016 1017 # NOTE: Placeholders/macros. 1018 1019 self.writeline("TRY") 1020 self.writeline("{") 1021 self.indent += 1 1022 self.process_structure_node(n.body) 1023 self.indent -= 1 1024 self.writeline("}") 1025 self.writeline("FINALLY") 1026 self.writeline("{") 1027 self.indent += 1 1028 self.process_structure_node(n.final) 1029 self.indent -= 1 1030 self.writeline("}") 1031 1032 def process_while_node(self, n): 1033 1034 "Process the given while node 'n'." 1035 1036 self.writeline("while (1)") 1037 self.writeline("{") 1038 self.indent += 1 1039 test = self.process_structure_node(n.test) 1040 1041 # Emit the loop termination condition unless "while <true value>" is 1042 # indicated. 1043 1044 if not (isinstance(test, PredefinedConstantRef) and test.value): 1045 1046 # NOTE: This needs to evaluate whether the operand is true or false 1047 # NOTE: according to Python rules. 1048 1049 self.writeline("if (!(%s))" % test) 1050 self.writeline("{") 1051 self.indent += 1 1052 if n.else_: 1053 self.process_structure_node(n.else_) 1054 self.writeline("break;") 1055 self.indent -= 1 1056 self.writeline("}") 1057 1058 in_conditional = self.in_conditional 1059 self.in_conditional = True 1060 self.process_structure_node(n.body) 1061 self.in_conditional = in_conditional 1062 1063 self.indent -= 1 1064 self.writeline("}") 1065 1066 # Output generation. 1067 1068 def start_module(self): 1069 print >>self.out, "void __main_%s()" % encode_path(self.name) 1070 print >>self.out, "{" 1071 self.indent += 1 1072 1073 def end_module(self): 1074 self.indent -= 1 1075 self.end_function() 1076 1077 def start_function(self, name): 1078 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1079 print >>self.out, "{" 1080 self.indent += 1 1081 1082 # Obtain local names from parameters. 1083 1084 parameters = self.importer.function_parameters[name] 1085 names = [] 1086 locals = self.importer.function_locals[name].keys() 1087 1088 for n in locals: 1089 1090 # Filter out special names and parameters. Note that self is a local 1091 # regardless of whether it originally appeared in the parameters or 1092 # not. 1093 1094 if n.startswith("$l") or n in parameters or n == "self": 1095 continue 1096 names.append(encode_path(n)) 1097 1098 # Emit required local names. 1099 1100 if names: 1101 names.sort() 1102 self.writeline("__attr %s;" % ", ".join(names)) 1103 1104 # Generate any self reference. 1105 1106 if self.in_method(name): 1107 self.writeline("#define self (__args[0])") 1108 1109 # Generate aliases for the parameters. 1110 1111 for i, parameter in enumerate(parameters): 1112 self.writeline("#define %s (__args[%d])" % (encode_path(parameter), i+1)) 1113 1114 def end_function(self): 1115 self.indent -= 1 1116 print >>self.out, "}" 1117 1118 def start_if(self, first, test_ref): 1119 1120 # NOTE: This needs to evaluate whether the operand is true or false 1121 # NOTE: according to Python rules. 1122 1123 self.writeline("%sif (%s)" % (not first and "else " or "", test_ref)) 1124 self.writeline("{") 1125 self.indent += 1 1126 1127 def end_if(self): 1128 self.indent -= 1 1129 self.writeline("}") 1130 1131 def start_else(self): 1132 self.writeline("else") 1133 self.writeline("{") 1134 self.indent += 1 1135 1136 def end_else(self): 1137 self.indent -= 1 1138 self.writeline("}") 1139 1140 def statement(self, expr): 1141 # NOTE: Should never be None. 1142 if not expr: 1143 self.writeline("...;") 1144 s = str(expr) 1145 if s: 1146 self.writeline("%s;" % s) 1147 1148 def statements(self, results): 1149 for result in results: 1150 self.statement(result) 1151 1152 def pad(self, extra=0): 1153 return (self.indent + extra) * self.tabstop 1154 1155 def indenttext(self, s, levels): 1156 lines = s.split("\n") 1157 out = [lines[0]] 1158 for line in lines[1:]: 1159 out.append(levels * self.tabstop + line) 1160 if line.endswith("("): 1161 levels += 1 1162 elif line.startswith(")"): 1163 levels -= 1 1164 return "\n".join(out) 1165 1166 def writeline(self, s): 1167 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1168 1169 def write_comment(self, s): 1170 self.writeline("/* %s */" % s) 1171 1172 # vim: tabstop=4 expandtab shiftwidth=4