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 from referencing import Reference 27 import compiler 28 import results 29 30 class Translator(CommonOutput): 31 32 "A program translator." 33 34 def __init__(self, importer, deducer, optimiser, output): 35 self.importer = importer 36 self.deducer = deducer 37 self.optimiser = optimiser 38 self.output = output 39 40 def to_output(self): 41 output = join(self.output, "src") 42 43 if not exists(output): 44 makedirs(output) 45 46 self.check_output() 47 48 for module in self.importer.modules.values(): 49 if module.name != "native": 50 tm = TranslatedModule(module.name, self.importer, self.deducer, self.optimiser) 51 tm.translate(module.filename, join(output, "%s.c" % module.name)) 52 53 # Classes representing intermediate translation results. 54 55 class TranslationResult: 56 57 "An abstract translation result mix-in." 58 59 def get_accessor_kinds(self): 60 return None 61 62 class ReturnRef(TranslationResult): 63 64 "Indicates usage of a return statement." 65 66 pass 67 68 class Expression(results.Result, TranslationResult): 69 70 "A general expression." 71 72 def __init__(self, s): 73 self.s = s 74 def __str__(self): 75 return self.s 76 def __repr__(self): 77 return "Expression(%r)" % self.s 78 79 class TrResolvedNameRef(results.ResolvedNameRef, TranslationResult): 80 81 "A reference to a name in the translation." 82 83 def __init__(self, name, ref, expr=None, parameter=None): 84 results.ResolvedNameRef.__init__(self, name, ref, expr) 85 self.parameter = parameter 86 87 def __str__(self): 88 89 "Return an output representation of the referenced name." 90 91 # For sources, any identified static origin will be constant and thus 92 # usable directly. For targets, no constant should be assigned and thus 93 # the alias (or any plain name) will be used. 94 95 ref = self.static() 96 origin = ref and self.get_origin() 97 static_name = origin and encode_path(origin) 98 99 # Determine whether a qualified name is involved. 100 101 t = (self.get_name() or self.name).rsplit(".", 1) 102 parent = len(t) > 1 and t[0] or None 103 attrname = encode_path(t[-1]) 104 105 # Assignments. 106 107 if self.expr: 108 109 # Eliminate assignments between constants. 110 111 if ref and isinstance(self.expr, results.ResolvedNameRef) and self.expr.static(): 112 return "" 113 114 # Qualified names must be converted into parent-relative assignments. 115 116 elif parent: 117 return "__store_via_object(&%s, %s, %s)" % ( 118 encode_path(parent), encode_symbol("pos", attrname), self.expr) 119 120 # All other assignments involve the names as they were given. 121 122 else: 123 return "(%s%s) = %s" % (self.parameter and "*" or "", attrname, self.expr) 124 125 # Expressions. 126 127 elif static_name: 128 parent = ref.parent() 129 context = ref.has_kind("<function>") and encode_path(parent) or None 130 return "((__attr) {%s, &%s})" % (context and "&%s" % context or "0", static_name) 131 132 # Qualified names must be converted into parent-relative accesses. 133 134 elif parent: 135 return "__load_via_object(&%s, %s)" % ( 136 encode_path(parent), encode_symbol("pos", attrname)) 137 138 # All other accesses involve the names as they were given. 139 140 else: 141 return "(%s%s)" % (self.parameter and "*" or "", attrname) 142 143 class TrConstantValueRef(results.ConstantValueRef, TranslationResult): 144 145 "A constant value reference in the translation." 146 147 def __str__(self): 148 return encode_literal_constant(self.number) 149 150 class TrLiteralSequenceRef(results.LiteralSequenceRef, TranslationResult): 151 152 "A reference representing a sequence of values." 153 154 def __str__(self): 155 return str(self.node) 156 157 class AttrResult(Expression, TranslationResult): 158 159 "A translation result for an attribute access." 160 161 def __init__(self, s, refs, accessor_kinds): 162 Expression.__init__(self, s) 163 self.refs = refs 164 self.accessor_kinds = accessor_kinds 165 166 def get_origin(self): 167 return self.refs and len(self.refs) == 1 and first(self.refs).get_origin() 168 169 def has_kind(self, kinds): 170 if not self.refs: 171 return False 172 for ref in self.refs: 173 if ref.has_kind(kinds): 174 return True 175 return False 176 177 def get_accessor_kinds(self): 178 return self.accessor_kinds 179 180 def __repr__(self): 181 return "AttrResult(%r, %r)" % (self.s, self.get_origin()) 182 183 class PredefinedConstantRef(AttrResult): 184 185 "A predefined constant reference." 186 187 def __init__(self, value): 188 self.value = value 189 190 def __str__(self): 191 if self.value in ("False", "True"): 192 return encode_path("__builtins__.boolean.%s" % self.value) 193 elif self.value == "None": 194 return encode_path("__builtins__.none.%s" % self.value) 195 elif self.value == "NotImplemented": 196 return encode_path("__builtins__.notimplemented.%s" % self.value) 197 else: 198 return self.value 199 200 def __repr__(self): 201 return "PredefinedConstantRef(%r)" % self.value 202 203 class BooleanResult(Expression, TranslationResult): 204 205 "A expression producing a boolean result." 206 207 def __str__(self): 208 return "__builtins___bool_bool(%s)" % self.s 209 210 def __repr__(self): 211 return "BooleanResult(%r)" % self.s 212 213 def make_expression(expr): 214 215 "Make a new expression from the existing 'expr'." 216 217 if isinstance(expr, results.Result): 218 return expr 219 else: 220 return Expression(str(expr)) 221 222 # The actual translation process itself. 223 224 class TranslatedModule(CommonModule): 225 226 "A module translator." 227 228 def __init__(self, name, importer, deducer, optimiser): 229 CommonModule.__init__(self, name, importer) 230 self.deducer = deducer 231 self.optimiser = optimiser 232 233 # Output stream. 234 235 self.out = None 236 self.indent = 0 237 self.tabstop = " " 238 239 # Recorded namespaces. 240 241 self.namespaces = [] 242 self.in_conditional = False 243 244 # Exception raising adjustments. 245 246 self.in_try_finally = False 247 self.in_try_except = False 248 249 # Attribute access and accessor counting. 250 251 self.attr_accesses = {} 252 self.attr_accessors = {} 253 254 def __repr__(self): 255 return "TranslatedModule(%r, %r)" % (self.name, self.importer) 256 257 def translate(self, filename, output_filename): 258 259 """ 260 Parse the file having the given 'filename', writing the translation to 261 the given 'output_filename'. 262 """ 263 264 self.parse_file(filename) 265 266 # Collect function namespaces for separate processing. 267 268 self.record_namespaces(self.astnode) 269 270 # Reset the lambda naming (in order to obtain the same names again) and 271 # translate the program. 272 273 self.reset_lambdas() 274 275 self.out = open(output_filename, "w") 276 try: 277 self.start_output() 278 279 # Process namespaces, writing the translation. 280 281 for path, node in self.namespaces: 282 self.process_namespace(path, node) 283 284 # Process the module namespace including class namespaces. 285 286 self.process_namespace([], self.astnode) 287 288 finally: 289 self.out.close() 290 291 def have_object(self): 292 293 "Return whether a namespace is a recorded object." 294 295 return self.importer.objects.get(self.get_namespace_path()) 296 297 def get_builtin_class(self, name): 298 299 "Return a reference to the actual object providing 'name'." 300 301 # NOTE: This makes assumptions about the __builtins__ structure. 302 303 return self.importer.get_object("__builtins__.%s.%s" % (name, name)) 304 305 def is_method(self, path): 306 307 "Return whether 'path' is a method." 308 309 class_name, method_name = path.rsplit(".", 1) 310 return self.importer.classes.has_key(class_name) and class_name or None 311 312 def in_method(self): 313 314 "Return whether the current namespace provides a method." 315 316 return self.in_function and self.is_method(self.get_namespace_path()) 317 318 # Namespace recording. 319 320 def record_namespaces(self, node): 321 322 "Process the program structure 'node', recording namespaces." 323 324 for n in node.getChildNodes(): 325 self.record_namespaces_in_node(n) 326 327 def record_namespaces_in_node(self, node): 328 329 "Process the program structure 'node', recording namespaces." 330 331 # Function namespaces within modules, classes and other functions. 332 # Functions appearing within conditional statements are given arbitrary 333 # names. 334 335 if isinstance(node, compiler.ast.Function): 336 self.record_function_node(node, (self.in_conditional or self.in_function) and self.get_lambda_name() or node.name) 337 338 elif isinstance(node, compiler.ast.Lambda): 339 self.record_function_node(node, self.get_lambda_name()) 340 341 # Classes are visited, but may be ignored if inside functions. 342 343 elif isinstance(node, compiler.ast.Class): 344 self.enter_namespace(node.name) 345 if self.have_object(): 346 self.record_namespaces(node) 347 self.exit_namespace() 348 349 # Conditional nodes are tracked so that function definitions may be 350 # handled. Since "for" loops are converted to "while" loops, they are 351 # included here. 352 353 elif isinstance(node, (compiler.ast.For, compiler.ast.If, compiler.ast.While)): 354 in_conditional = self.in_conditional 355 self.in_conditional = True 356 self.record_namespaces(node) 357 self.in_conditional = in_conditional 358 359 # All other nodes are processed depth-first. 360 361 else: 362 self.record_namespaces(node) 363 364 def record_function_node(self, n, name): 365 366 """ 367 Record the given function, lambda, if expression or list comprehension 368 node 'n' with the given 'name'. 369 """ 370 371 self.in_function = True 372 self.enter_namespace(name) 373 374 if self.have_object(): 375 376 # Record the namespace path and the node itself. 377 378 self.namespaces.append((self.namespace_path[:], n)) 379 self.record_namespaces_in_node(n.code) 380 381 self.exit_namespace() 382 self.in_function = False 383 384 # Constant referencing. 385 386 def get_literal_instance(self, n, name): 387 388 """ 389 For node 'n', return a reference for the type of the given 'name'. 390 """ 391 392 ref = self.get_builtin_class(name) 393 394 if name in ("dict", "list", "tuple"): 395 return self.process_literal_sequence_node(n, name, ref, TrLiteralSequenceRef) 396 else: 397 path = self.get_namespace_path() 398 local_number = self.importer.all_constants[path][n.value] 399 constant_name = "$c%d" % local_number 400 objpath = self.get_object_path(constant_name) 401 number = self.optimiser.constant_numbers[objpath] 402 return TrConstantValueRef(constant_name, ref.instance_of(), n.value, number) 403 404 # Namespace translation. 405 406 def process_namespace(self, path, node): 407 408 """ 409 Process the namespace for the given 'path' defined by the given 'node'. 410 """ 411 412 self.namespace_path = path 413 414 if isinstance(node, (compiler.ast.Function, compiler.ast.Lambda)): 415 self.in_function = True 416 self.process_function_body_node(node) 417 else: 418 self.in_function = False 419 self.function_target = 0 420 self.start_module() 421 self.process_structure(node) 422 self.end_module() 423 424 def process_structure(self, node): 425 426 "Process the given 'node' or result." 427 428 # Handle processing requests on results. 429 430 if isinstance(node, results.Result): 431 return node 432 433 # Handle processing requests on nodes. 434 435 else: 436 l = CommonModule.process_structure(self, node) 437 438 # Return indications of return statement usage. 439 440 if l and isinstance(l[-1], ReturnRef): 441 return l[-1] 442 else: 443 return None 444 445 def process_structure_node(self, n): 446 447 "Process the individual node 'n'." 448 449 # Plain statements emit their expressions. 450 451 if isinstance(n, compiler.ast.Discard): 452 expr = self.process_structure_node(n.expr) 453 self.statement(expr) 454 455 # Module import declarations. 456 457 elif isinstance(n, compiler.ast.From): 458 self.process_from_node(n) 459 460 # Nodes using operator module functions. 461 462 elif isinstance(n, compiler.ast.Operator): 463 return self.process_operator_node(n) 464 465 elif isinstance(n, compiler.ast.AugAssign): 466 self.process_augassign_node(n) 467 468 elif isinstance(n, compiler.ast.Compare): 469 return self.process_compare_node(n) 470 471 elif isinstance(n, compiler.ast.Slice): 472 return self.process_slice_node(n) 473 474 elif isinstance(n, compiler.ast.Sliceobj): 475 return self.process_sliceobj_node(n) 476 477 elif isinstance(n, compiler.ast.Subscript): 478 return self.process_subscript_node(n) 479 480 # Classes are visited, but may be ignored if inside functions. 481 482 elif isinstance(n, compiler.ast.Class): 483 self.process_class_node(n) 484 485 # Functions within namespaces have any dynamic defaults initialised. 486 487 elif isinstance(n, compiler.ast.Function): 488 self.process_function_node(n) 489 490 # Lambdas are replaced with references to separately-generated 491 # functions. 492 493 elif isinstance(n, compiler.ast.Lambda): 494 return self.process_lambda_node(n) 495 496 # Assignments. 497 498 elif isinstance(n, compiler.ast.Assign): 499 500 # Handle each assignment node. 501 502 for node in n.nodes: 503 self.process_assignment_node(node, n.expr) 504 505 # Accesses. 506 507 elif isinstance(n, compiler.ast.Getattr): 508 return self.process_attribute_access(n) 509 510 # Names. 511 512 elif isinstance(n, compiler.ast.Name): 513 return self.process_name_node(n) 514 515 # Loops and conditionals. 516 517 elif isinstance(n, compiler.ast.For): 518 self.process_for_node(n) 519 520 elif isinstance(n, compiler.ast.While): 521 self.process_while_node(n) 522 523 elif isinstance(n, compiler.ast.If): 524 self.process_if_node(n) 525 526 elif isinstance(n, (compiler.ast.And, compiler.ast.Or)): 527 return self.process_logical_node(n) 528 529 elif isinstance(n, compiler.ast.Not): 530 return self.process_not_node(n) 531 532 # Exception control-flow tracking. 533 534 elif isinstance(n, compiler.ast.TryExcept): 535 self.process_try_node(n) 536 537 elif isinstance(n, compiler.ast.TryFinally): 538 self.process_try_finally_node(n) 539 540 # Control-flow modification statements. 541 542 elif isinstance(n, compiler.ast.Break): 543 self.writestmt("break;") 544 545 elif isinstance(n, compiler.ast.Continue): 546 self.writestmt("continue;") 547 548 elif isinstance(n, compiler.ast.Raise): 549 self.process_raise_node(n) 550 551 elif isinstance(n, compiler.ast.Return): 552 return self.process_return_node(n) 553 554 # Print statements. 555 556 elif isinstance(n, (compiler.ast.Print, compiler.ast.Printnl)): 557 self.statement(self.process_print_node(n)) 558 559 # Invocations. 560 561 elif isinstance(n, compiler.ast.CallFunc): 562 return self.process_invocation_node(n) 563 564 elif isinstance(n, compiler.ast.Keyword): 565 return self.process_structure_node(n.expr) 566 567 # Constant usage. 568 569 elif isinstance(n, compiler.ast.Const): 570 return self.get_literal_instance(n, n.value.__class__.__name__) 571 572 elif isinstance(n, compiler.ast.Dict): 573 return self.get_literal_instance(n, "dict") 574 575 elif isinstance(n, compiler.ast.List): 576 return self.get_literal_instance(n, "list") 577 578 elif isinstance(n, compiler.ast.Tuple): 579 return self.get_literal_instance(n, "tuple") 580 581 # All other nodes are processed depth-first. 582 583 else: 584 return self.process_structure(n) 585 586 def process_assignment_node(self, n, expr): 587 588 "Process the individual node 'n' to be assigned the contents of 'expr'." 589 590 # Names and attributes are assigned the entire expression. 591 592 if isinstance(n, compiler.ast.AssName): 593 name_ref = self.process_name_node(n, self.process_structure_node(expr)) 594 self.statement(name_ref) 595 596 # Employ guards after assignments if required. 597 598 if expr and name_ref.is_name(): 599 self.generate_guard(name_ref.name) 600 601 elif isinstance(n, compiler.ast.AssAttr): 602 in_assignment = self.in_assignment 603 self.in_assignment = self.process_structure_node(expr) 604 self.statement(self.process_attribute_access(n)) 605 self.in_assignment = in_assignment 606 607 # Lists and tuples are matched against the expression and their 608 # items assigned to expression items. 609 610 elif isinstance(n, (compiler.ast.AssList, compiler.ast.AssTuple)): 611 self.process_assignment_node_items(n, expr) 612 613 # Slices and subscripts are permitted within assignment nodes. 614 615 elif isinstance(n, compiler.ast.Slice): 616 self.statement(self.process_slice_node(n, expr)) 617 618 elif isinstance(n, compiler.ast.Subscript): 619 self.statement(self.process_subscript_node(n, expr)) 620 621 def process_attribute_access(self, n): 622 623 """ 624 Process the given attribute access node 'n'. 625 626 Where a name is provided, a single access should be recorded 627 involving potentially many attributes, thus providing a path to an 628 object. The remaining attributes are then accessed dynamically. 629 The remaining accesses could be deduced and computed, but they would 630 also need to be tested. 631 632 Where no name is provided, potentially many accesses should be 633 recorded, one per attribute name. These could be used to provide 634 computed accesses, but the accessors would need to be tested in each 635 case. 636 """ 637 638 # Obtain any completed chain and return the reference to it. 639 640 attr_expr = self.process_attribute_chain(n) 641 if self.have_access_expression(n): 642 return attr_expr 643 644 # Where the start of the chain of attributes has been reached, process 645 # the complete access. 646 647 name_ref = attr_expr and attr_expr.is_name() and attr_expr 648 name = name_ref and self.get_name_for_tracking(name_ref.name, name_ref and name_ref.final()) or None 649 650 location = self.get_access_location(name) 651 refs = self.get_referenced_attributes(location) 652 653 # Generate access instructions. 654 655 subs = { 656 "<expr>" : str(attr_expr), 657 "<assexpr>" : str(self.in_assignment), 658 "<context>" : "__tmp_context", 659 "<accessor>" : "__tmp_value", 660 } 661 662 output = [] 663 664 for instruction in self.optimiser.access_instructions[location]: 665 output.append(encode_access_instruction(instruction, subs)) 666 667 if len(output) == 1: 668 out = output[0] 669 else: 670 out = "(\n%s\n)" % ",\n".join(output) 671 672 del self.attrs[0] 673 return AttrResult(out, refs, self.get_accessor_kinds(location)) 674 675 def get_referenced_attributes(self, location): 676 677 """ 678 Convert 'location' to the form used by the deducer and retrieve any 679 identified attribute. 680 """ 681 682 access_location = self.deducer.const_accesses.get(location) 683 refs = [] 684 for attrtype, objpath, attr in self.deducer.referenced_attrs[access_location or location]: 685 refs.append(attr) 686 return refs 687 688 def get_accessor_kinds(self, location): 689 690 "Return the accessor kinds for 'location'." 691 692 return self.optimiser.accessor_kinds[location] 693 694 def get_access_location(self, name): 695 696 """ 697 Using the current namespace and the given 'name', return the access 698 location. 699 """ 700 701 path = self.get_path_for_access() 702 703 # Get the location used by the deducer and optimiser and find any 704 # recorded access. 705 706 attrnames = ".".join(self.attrs) 707 access_number = self.get_access_number(path, name, attrnames) 708 self.update_access_number(path, name, attrnames) 709 return (path, name, attrnames, access_number) 710 711 def get_access_number(self, path, name, attrnames): 712 access = name, attrnames 713 if self.attr_accesses.has_key(path) and self.attr_accesses[path].has_key(access): 714 return self.attr_accesses[path][access] 715 else: 716 return 0 717 718 def update_access_number(self, path, name, attrnames): 719 access = name, attrnames 720 if name: 721 init_item(self.attr_accesses, path, dict) 722 init_item(self.attr_accesses[path], access, lambda: 0) 723 self.attr_accesses[path][access] += 1 724 725 def get_accessor_location(self, name): 726 727 """ 728 Using the current namespace and the given 'name', return the accessor 729 location. 730 """ 731 732 path = self.get_path_for_access() 733 734 # Get the location used by the deducer and optimiser and find any 735 # recorded accessor. 736 737 access_number = self.get_accessor_number(path, name) 738 self.update_accessor_number(path, name) 739 return (path, name, None, access_number) 740 741 def get_accessor_number(self, path, name): 742 if self.attr_accessors.has_key(path) and self.attr_accessors[path].has_key(name): 743 return self.attr_accessors[path][name] 744 else: 745 return 0 746 747 def update_accessor_number(self, path, name): 748 if name: 749 init_item(self.attr_accessors, path, dict) 750 init_item(self.attr_accessors[path], name, lambda: 0) 751 self.attr_accessors[path][name] += 1 752 753 def process_class_node(self, n): 754 755 "Process the given class node 'n'." 756 757 self.enter_namespace(n.name) 758 759 if self.have_object(): 760 class_name = self.get_namespace_path() 761 self.write_comment("Class: %s" % class_name) 762 763 self.initialise_inherited_members(class_name) 764 765 self.process_structure(n) 766 self.write_comment("End class: %s" % class_name) 767 768 self.exit_namespace() 769 770 def initialise_inherited_members(self, class_name): 771 772 "Initialise members of 'class_name' inherited from its ancestors." 773 774 for name, path in self.importer.all_class_attrs[class_name].items(): 775 target = "%s.%s" % (class_name, name) 776 777 # Ignore attributes with definitions. 778 779 ref = self.importer.identify(target) 780 if ref: 781 continue 782 783 # Reference inherited attributes. 784 785 ref = self.importer.identify(path) 786 if ref and not ref.static(): 787 parent, attrname = path.rsplit(".", 1) 788 789 self.writestmt("__store_via_object(&%s, %s, __load_via_object(&%s, %s));" % ( 790 encode_path(class_name), encode_symbol("pos", name), 791 encode_path(parent), encode_symbol("pos", attrname) 792 )) 793 794 def process_from_node(self, n): 795 796 "Process the given node 'n', importing from another module." 797 798 path = self.get_namespace_path() 799 800 # Attempt to obtain the referenced objects. 801 802 for name, alias in n.names: 803 if name == "*": 804 raise InspectError("Only explicitly specified names can be imported from modules.", path, n) 805 806 # Obtain the path of the assigned name. 807 808 objpath = self.get_object_path(alias or name) 809 810 # Obtain the identity of the name. 811 812 ref = self.importer.identify(objpath) 813 814 # Where the name is not static, assign the value. 815 816 if ref and not ref.static() and ref.get_name(): 817 self.writestmt("%s;" % 818 TrResolvedNameRef(alias or name, Reference("<var>", None, objpath), 819 expr=TrResolvedNameRef(name, ref))) 820 821 def process_function_body_node(self, n): 822 823 """ 824 Process the given function, lambda, if expression or list comprehension 825 node 'n', generating the body. 826 """ 827 828 function_name = self.get_namespace_path() 829 self.start_function(function_name) 830 831 # Process the function body. 832 833 in_conditional = self.in_conditional 834 self.in_conditional = False 835 self.function_target = 0 836 837 # Process any guards defined for the parameters. 838 839 for name in self.importer.function_parameters.get(function_name): 840 self.generate_guard(name) 841 842 # Produce the body and any additional return statement. 843 844 expr = self.process_structure_node(n.code) or PredefinedConstantRef("None") 845 if not isinstance(expr, ReturnRef): 846 self.writestmt("return %s;" % expr) 847 848 self.in_conditional = in_conditional 849 850 self.end_function(function_name) 851 852 def generate_guard(self, name): 853 854 """ 855 Get the accessor details for 'name', found in the current namespace, and 856 generate any guards defined for it. 857 """ 858 859 # Obtain the location, keeping track of assignment versions. 860 861 location = self.get_accessor_location(name) 862 test = self.deducer.accessor_guard_tests.get(location) 863 864 # Generate any guard from the deduced information. 865 866 if test: 867 guard, guard_type = test 868 869 if guard == "specific": 870 ref = first(self.deducer.accessor_all_types[location]) 871 argstr = "&%s" % encode_path(ref.get_origin()) 872 elif guard == "common": 873 ref = first(self.deducer.accessor_all_general_types[location]) 874 typeattr = encode_type_attribute(ref.get_origin()) 875 argstr = "%s, %s" % (encode_symbol("pos", typeattr), encode_symbol("code", typeattr)) 876 else: 877 return 878 879 # Produce an appropriate access to an attribute's value. 880 881 parameters = self.importer.function_parameters.get(self.get_namespace_path()) 882 if parameters and name in parameters: 883 name_to_value = "%s->value" % name 884 else: 885 name_to_value = "%s.value" % name 886 887 # Write a test that raises a TypeError upon failure. 888 889 self.writestmt("if (!__test_%s_%s(%s, %s)) __raise_type_error();" % ( 890 guard, guard_type, name_to_value, argstr)) 891 892 def process_function_node(self, n): 893 894 """ 895 Process the given function, lambda, if expression or list comprehension 896 node 'n', generating any initialisation statements. 897 """ 898 899 # Where a function is declared conditionally, use a separate name for 900 # the definition, and assign the definition to the stated name. 901 902 original_name = n.name 903 904 if self.in_conditional or self.in_function: 905 name = self.get_lambda_name() 906 else: 907 name = n.name 908 909 objpath = self.get_object_path(name) 910 911 # Obtain details of the defaults. 912 913 defaults = self.process_function_defaults(n, name, objpath) 914 if defaults: 915 for default in defaults: 916 self.writeline("%s;" % default) 917 918 # Where a function is set conditionally or where the name may refer to 919 # different values, assign the name. 920 921 ref = self.importer.identify(objpath) 922 923 if self.in_conditional or self.in_function: 924 self.process_assignment_for_function(original_name, compiler.ast.Name(name)) 925 elif not ref.static(): 926 context = self.is_method(objpath) 927 928 self.process_assignment_for_function(original_name, 929 make_expression("((__attr) {%s, &%s})" % ( 930 context and "&%s" % encode_path(context) or "0", 931 encode_path(objpath)))) 932 933 def process_function_defaults(self, n, name, objpath, instance_name=None): 934 935 """ 936 Process the given function or lambda node 'n', initialising defaults 937 that are dynamically set. The given 'name' indicates the name of the 938 function. The given 'objpath' indicates the origin of the function. 939 The given 'instance_name' indicates the name of any separate instance 940 of the function created to hold the defaults. 941 942 Return a list of operations setting defaults on a function instance. 943 """ 944 945 function_name = self.get_object_path(name) 946 function_defaults = self.importer.function_defaults.get(function_name) 947 if not function_defaults: 948 return None 949 950 # Determine whether any unidentified defaults are involved. 951 952 for argname, default in function_defaults: 953 if not default.static(): 954 break 955 else: 956 return None 957 958 # Handle bound methods. 959 960 if not instance_name: 961 if self.is_method(objpath): 962 instance_name = "&%s" % encode_bound_reference(objpath) 963 else: 964 instance_name = "&%s" % encode_path(objpath) 965 966 # Where defaults are involved but cannot be identified, obtain a new 967 # instance of the lambda and populate the defaults. 968 969 defaults = [] 970 971 # Join the original defaults with the inspected defaults. 972 973 original_defaults = [(argname, default) for (argname, default) in compiler.ast.get_defaults(n) if default] 974 975 for i, (original, inspected) in enumerate(map(None, original_defaults, function_defaults)): 976 977 # Obtain any reference for the default. 978 979 if original: 980 argname, default = original 981 name_ref = self.process_structure_node(default) 982 elif inspected: 983 argname, default = inspected 984 name_ref = TrResolvedNameRef(argname, default) 985 else: 986 continue 987 988 if name_ref: 989 defaults.append("__SETDEFAULT(%s, %s, %s)" % (instance_name, i, name_ref)) 990 991 return defaults 992 993 def process_if_node(self, n): 994 995 """ 996 Process the given "if" node 'n'. 997 """ 998 999 first = True 1000 for test, body in n.tests: 1001 test_ref = self.process_structure_node(test) 1002 self.start_if(first, test_ref) 1003 1004 in_conditional = self.in_conditional 1005 self.in_conditional = True 1006 self.process_structure_node(body) 1007 self.in_conditional = in_conditional 1008 1009 self.end_if() 1010 first = False 1011 1012 if n.else_: 1013 self.start_else() 1014 self.process_structure_node(n.else_) 1015 self.end_else() 1016 1017 def process_invocation_node(self, n): 1018 1019 "Process the given invocation node 'n'." 1020 1021 expr = self.process_structure_node(n.node) 1022 objpath = expr.get_origin() 1023 target = None 1024 function = None 1025 literal_instantiation = False 1026 context_required = True 1027 1028 # Obtain details of the callable. 1029 1030 # Literals may be instantiated specially. 1031 1032 if expr.is_name() and expr.name.startswith("$L") and objpath: 1033 literal_instantiation = True 1034 parameters = None 1035 target = encode_literal_instantiator(objpath) 1036 context_required = False 1037 1038 # Identified targets employ function pointers directly. 1039 1040 elif objpath: 1041 parameters = self.importer.function_parameters.get(objpath) 1042 1043 # Class invocation involves instantiators. 1044 1045 if expr.has_kind("<class>"): 1046 target = encode_instantiator_pointer(objpath) 1047 target_structure = "&%s" % encode_bound_reference("%s.__init__" % objpath) 1048 context_required = False 1049 1050 # Only plain functions and bound methods employ function pointers. 1051 1052 elif expr.has_kind("<function>"): 1053 function = objpath 1054 1055 # Test for functions and methods. 1056 1057 method_class = self.is_method(objpath) 1058 accessor_kinds = expr.get_accessor_kinds() 1059 instance_accessor = accessor_kinds and \ 1060 len(accessor_kinds) == 1 and \ 1061 first(accessor_kinds) == "<instance>" 1062 1063 if not method_class or instance_accessor: 1064 target = encode_function_pointer(objpath) 1065 target_structure = self.is_method(objpath) and \ 1066 encode_bound_reference(objpath) or \ 1067 "&%s" % encode_path(objpath) 1068 1069 if not method_class: 1070 context_required = False 1071 1072 # Other targets are retrieved at run-time. 1073 1074 else: 1075 parameters = None 1076 1077 # Arguments are presented in a temporary frame array with any context 1078 # always being the first argument. Where it would be unused, it may be 1079 # set to null. 1080 1081 if context_required: 1082 args = ["__CONTEXT_AS_VALUE(__tmp_targets[%d])" % self.function_target] 1083 else: 1084 args = ["(__attr) {0, 0}"] 1085 1086 args += [None] * (not parameters and len(n.args) or parameters and len(parameters) or 0) 1087 kwcodes = [] 1088 kwargs = [] 1089 1090 # Any invocations in the arguments will store target details in a 1091 # different location. 1092 1093 self.function_target += 1 1094 1095 for i, arg in enumerate(n.args): 1096 argexpr = self.process_structure_node(arg) 1097 1098 # Store a keyword argument, either in the argument list or 1099 # in a separate keyword argument list for subsequent lookup. 1100 1101 if isinstance(arg, compiler.ast.Keyword): 1102 1103 # With knowledge of the target, store the keyword 1104 # argument directly. 1105 1106 if parameters: 1107 argnum = parameters.index(arg.name) 1108 args[argnum+1] = str(argexpr) 1109 1110 # Otherwise, store the details in a separate collection. 1111 1112 else: 1113 kwargs.append(str(argexpr)) 1114 kwcodes.append("{%s, %s}" % ( 1115 encode_symbol("ppos", arg.name), 1116 encode_symbol("pcode", arg.name))) 1117 1118 # Store non-keyword arguments in the argument list, rejecting 1119 # superfluous arguments. 1120 1121 else: 1122 try: 1123 args[i+1] = str(argexpr) 1124 except IndexError: 1125 raise TranslateError("Too many arguments specified.", 1126 self.get_namespace_path(), n) 1127 1128 # Reference the current target again. 1129 1130 self.function_target -= 1 1131 1132 # Defaults are added to the frame where arguments are missing. 1133 1134 if parameters: 1135 function_defaults = self.importer.function_defaults.get(objpath) 1136 if function_defaults: 1137 1138 # Visit each default and set any missing arguments. 1139 # Use the target structure to obtain defaults, as opposed to the 1140 # actual function involved. 1141 1142 for i, (argname, default) in enumerate(function_defaults): 1143 argnum = parameters.index(argname) 1144 if not args[argnum+1]: 1145 args[argnum+1] = "__GETDEFAULT(%s, %d)" % (target_structure, i) 1146 1147 # Test for missing arguments. 1148 1149 if None in args: 1150 raise TranslateError("Not all arguments supplied.", 1151 self.get_namespace_path(), n) 1152 1153 # Encode the arguments. 1154 1155 argstr = "__ARGS(%s)" % ", ".join(args) 1156 kwargstr = kwargs and ("__ARGS(%s)" % ", ".join(kwargs)) or "0" 1157 kwcodestr = kwcodes and ("__KWARGS(%s)" % ", ".join(kwcodes)) or "0" 1158 1159 # Where literal instantiation is occurring, add an argument indicating 1160 # the number of values. 1161 1162 if literal_instantiation: 1163 argstr += ", %d" % (len(args) - 1) 1164 1165 # First, the invocation expression is presented. 1166 1167 stages = [] 1168 1169 # Without a known specific callable, the expression provides the target. 1170 1171 if not target or context_required: 1172 stages.append("__tmp_targets[%d] = %s" % (self.function_target, expr)) 1173 1174 # Any specific callable is then obtained. 1175 1176 if target: 1177 stages.append(target) 1178 elif function: 1179 stages.append("__load_via_object(__tmp_targets[%d].value, %s).fn" % ( 1180 self.function_target, encode_symbol("pos", "__fn__"))) 1181 1182 # With a known target, the function is obtained directly and called. 1183 1184 if target or function: 1185 output = "(\n%s\n)(%s)" % (",\n".join(stages), argstr) 1186 1187 # With unknown targets, the generic invocation function is applied to 1188 # the callable and argument collections. 1189 1190 else: 1191 output = "(%s, __invoke(\n__tmp_targets[%d],\n%d, %d, %s, %s,\n%d, %s\n))" % ( 1192 ",\n".join(stages), 1193 self.function_target, 1194 self.always_callable and 1 or 0, 1195 len(kwargs), kwcodestr, kwargstr, 1196 len(args), argstr) 1197 1198 return make_expression(output) 1199 1200 def always_callable(self, refs): 1201 1202 "Determine whether all 'refs' are callable." 1203 1204 for ref in refs: 1205 if not ref.static(): 1206 return False 1207 else: 1208 origin = ref.final() 1209 if not self.importer.get_attribute(origin, "__fn__"): 1210 return False 1211 return True 1212 1213 def need_default_arguments(self, objpath, nargs): 1214 1215 """ 1216 Return whether any default arguments are needed when invoking the object 1217 given by 'objpath'. 1218 """ 1219 1220 parameters = self.importer.function_parameters.get(objpath) 1221 return nargs < len(parameters) 1222 1223 def process_lambda_node(self, n): 1224 1225 "Process the given lambda node 'n'." 1226 1227 name = self.get_lambda_name() 1228 function_name = self.get_object_path(name) 1229 1230 defaults = self.process_function_defaults(n, name, function_name, "__tmp_value") 1231 1232 # Without defaults, produce an attribute referring to the function. 1233 1234 if not defaults: 1235 return make_expression("((__attr) {0, &%s})" % encode_path(function_name)) 1236 1237 # With defaults, copy the function structure and set the defaults on the 1238 # copy. 1239 1240 else: 1241 return make_expression("(__tmp_value = __COPY(&%s, sizeof(%s)), %s, (__attr) {0, __tmp_value})" % ( 1242 encode_path(function_name), 1243 encode_symbol("obj", function_name), 1244 ", ".join(defaults))) 1245 1246 def process_logical_node(self, n): 1247 1248 """ 1249 Process the given operator node 'n'. 1250 1251 Convert ... to ... 1252 1253 <a> and <b> 1254 (__tmp_result = <a>, !__BOOL(__tmp_result)) ? __tmp_result : <b> 1255 1256 <a> or <b> 1257 (__tmp_result = <a>, __BOOL(__tmp_result)) ? __tmp_result : <b> 1258 """ 1259 1260 if isinstance(n, compiler.ast.And): 1261 op = "!" 1262 else: 1263 op = "" 1264 1265 results = [] 1266 1267 for node in n.nodes[:-1]: 1268 expr = self.process_structure_node(node) 1269 results.append("(__tmp_result = %s, %s__BOOL(__tmp_result)) ? __tmp_result : " % (expr, op)) 1270 1271 expr = self.process_structure_node(n.nodes[-1]) 1272 results.append(str(expr)) 1273 1274 return make_expression("(%s)" % "".join(results)) 1275 1276 def process_name_node(self, n, expr=None): 1277 1278 "Process the given name node 'n' with the optional assignment 'expr'." 1279 1280 # Determine whether the name refers to a static external entity. 1281 1282 if n.name in predefined_constants: 1283 return PredefinedConstantRef(n.name) 1284 1285 # Convert literal references, operator function names, and print 1286 # function names to references. 1287 1288 elif n.name.startswith("$L") or n.name.startswith("$op") or \ 1289 n.name.startswith("$print"): 1290 ref = self.importer.get_module(self.name).special.get(n.name) 1291 return TrResolvedNameRef(n.name, ref) 1292 1293 # Get the appropriate name for the name reference, using the same method 1294 # as in the inspector. 1295 1296 path = self.get_namespace_path() 1297 objpath = self.get_object_path(n.name) 1298 1299 # Determine any assigned globals. 1300 1301 globals = self.importer.get_module(self.name).scope_globals.get(path) 1302 if globals and n.name in globals: 1303 objpath = self.get_global_path(n.name) 1304 1305 # Get the static identity of the name. 1306 1307 ref = self.importer.identify(objpath) 1308 if ref and not ref.get_name(): 1309 ref = ref.alias(objpath) 1310 1311 # Obtain any resolved names for non-assignment names. 1312 1313 if not expr and not ref and self.in_function: 1314 locals = self.importer.function_locals.get(path) 1315 ref = locals and locals.get(n.name) 1316 1317 # Determine whether the name refers to a parameter. The generation of 1318 # parameter references is different from other names. 1319 1320 parameters = self.importer.function_parameters.get(path) 1321 parameter = n.name == "self" and self.in_method() or \ 1322 parameters and n.name in parameters 1323 1324 # Qualified names are used for resolved static references or for 1325 # static namespace members. The reference should be configured to return 1326 # such names. 1327 1328 return TrResolvedNameRef(n.name, ref, expr=expr, parameter=parameter) 1329 1330 def process_not_node(self, n): 1331 1332 "Process the given operator node 'n'." 1333 1334 return make_expression("(__BOOL(%s) ? %s : %s)" % 1335 (self.process_structure_node(n.expr), PredefinedConstantRef("False"), 1336 PredefinedConstantRef("True"))) 1337 1338 def process_raise_node(self, n): 1339 1340 "Process the given raise node 'n'." 1341 1342 # NOTE: Determine which raise statement variants should be permitted. 1343 1344 if n.expr1: 1345 self.writestmt("__Raise(%s);" % self.process_structure_node(n.expr1)) 1346 else: 1347 self.writestmt("__Complete;") 1348 1349 def process_return_node(self, n): 1350 1351 "Process the given return node 'n'." 1352 1353 expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") 1354 if self.in_try_finally or self.in_try_except: 1355 self.writestmt("__Return(%s);" % expr) 1356 else: 1357 self.writestmt("return %s;" % expr) 1358 1359 return ReturnRef() 1360 1361 def process_try_node(self, n): 1362 1363 """ 1364 Process the given "try...except" node 'n'. 1365 """ 1366 1367 in_try_except = self.in_try_except 1368 self.in_try_except = True 1369 1370 # Use macros to implement exception handling. 1371 1372 self.writestmt("__Try") 1373 self.writeline("{") 1374 self.indent += 1 1375 self.process_structure_node(n.body) 1376 1377 # Put the else statement in another try block that handles any raised 1378 # exceptions and converts them to exceptions that will not be handled by 1379 # the main handling block. 1380 1381 if n.else_: 1382 self.writestmt("__Try") 1383 self.writeline("{") 1384 self.indent += 1 1385 self.process_structure_node(n.else_) 1386 self.indent -= 1 1387 self.writeline("}") 1388 self.writeline("__Catch (__tmp_exc)") 1389 self.writeline("{") 1390 self.indent += 1 1391 self.writeline("if (__tmp_exc.raising) __RaiseElse(__tmp_exc.arg);") 1392 self.writeline("else if (__tmp_exc.completing) __Throw(__tmp_exc);") 1393 self.indent -= 1 1394 self.writeline("}") 1395 1396 # Complete the try block and enter the finally block, if appropriate. 1397 1398 if self.in_try_finally: 1399 self.writestmt("__Complete;") 1400 1401 self.indent -= 1 1402 self.writeline("}") 1403 1404 self.in_try_except = in_try_except 1405 1406 # Handlers are tests within a common handler block. 1407 1408 self.writeline("__Catch (__tmp_exc)") 1409 self.writeline("{") 1410 self.indent += 1 1411 1412 # Introduce an if statement to handle the completion of a try block. 1413 1414 self.process_try_completion() 1415 1416 # Handle exceptions in else blocks converted to __RaiseElse, converting 1417 # them back to normal exceptions. 1418 1419 if n.else_: 1420 self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") 1421 1422 # Exception handling. 1423 1424 for name, var, handler in n.handlers: 1425 1426 # Test for specific exceptions. 1427 1428 if name is not None: 1429 name_ref = self.process_structure_node(name) 1430 self.writeline("else if (__BOOL(__fn_native__isinstance((__attr[]) {{0, 0}, __tmp_exc.arg, %s})))" % name_ref) 1431 else: 1432 self.writeline("else if (1)") 1433 1434 self.writeline("{") 1435 self.indent += 1 1436 1437 # Establish the local for the handler. 1438 1439 if var is not None: 1440 self.writestmt("%s;" % self.process_name_node(var, make_expression("__tmp_exc.arg"))) 1441 1442 if handler is not None: 1443 self.process_structure_node(handler) 1444 1445 self.indent -= 1 1446 self.writeline("}") 1447 1448 # Re-raise unhandled exceptions. 1449 1450 self.writeline("else __Throw(__tmp_exc);") 1451 1452 # End the handler block. 1453 1454 self.indent -= 1 1455 self.writeline("}") 1456 1457 def process_try_finally_node(self, n): 1458 1459 """ 1460 Process the given "try...finally" node 'n'. 1461 """ 1462 1463 in_try_finally = self.in_try_finally 1464 self.in_try_finally = True 1465 1466 # Use macros to implement exception handling. 1467 1468 self.writestmt("__Try") 1469 self.writeline("{") 1470 self.indent += 1 1471 self.process_structure_node(n.body) 1472 self.indent -= 1 1473 self.writeline("}") 1474 1475 self.in_try_finally = in_try_finally 1476 1477 # Finally clauses handle special exceptions. 1478 1479 self.writeline("__Catch (__tmp_exc)") 1480 self.writeline("{") 1481 self.indent += 1 1482 self.process_structure_node(n.final) 1483 1484 # Introduce an if statement to handle the completion of a try block. 1485 1486 self.process_try_completion() 1487 self.writeline("else __Throw(__tmp_exc);") 1488 1489 self.indent -= 1 1490 self.writeline("}") 1491 1492 def process_try_completion(self): 1493 1494 "Generate a test for the completion of a try block." 1495 1496 self.writestmt("if (__tmp_exc.completing)") 1497 self.writeline("{") 1498 self.indent += 1 1499 1500 # Only use the normal return statement if no surrounding try blocks 1501 # apply. 1502 1503 if not self.in_try_finally and not self.in_try_except: 1504 self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") 1505 else: 1506 self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") 1507 1508 self.indent -= 1 1509 self.writeline("}") 1510 1511 def process_while_node(self, n): 1512 1513 "Process the given while node 'n'." 1514 1515 self.writeline("while (1)") 1516 self.writeline("{") 1517 self.indent += 1 1518 test = self.process_structure_node(n.test) 1519 1520 # Emit the loop termination condition unless "while <true value>" is 1521 # indicated. 1522 1523 if not (isinstance(test, PredefinedConstantRef) and test.value): 1524 1525 # NOTE: This needs to evaluate whether the operand is true or false 1526 # NOTE: according to Python rules. 1527 1528 self.writeline("if (!__BOOL(%s))" % test) 1529 self.writeline("{") 1530 self.indent += 1 1531 if n.else_: 1532 self.process_structure_node(n.else_) 1533 self.writestmt("break;") 1534 self.indent -= 1 1535 self.writeline("}") 1536 1537 in_conditional = self.in_conditional 1538 self.in_conditional = True 1539 self.process_structure_node(n.body) 1540 self.in_conditional = in_conditional 1541 1542 self.indent -= 1 1543 self.writeline("}") 1544 1545 # Output generation. 1546 1547 def start_output(self): 1548 1549 "Write the declarations at the top of each source file." 1550 1551 print >>self.out, """\ 1552 #include "types.h" 1553 #include "exceptions.h" 1554 #include "ops.h" 1555 #include "progconsts.h" 1556 #include "progops.h" 1557 #include "progtypes.h" 1558 #include "main.h" 1559 """ 1560 1561 def start_module(self): 1562 1563 "Write the start of each module's main function." 1564 1565 print >>self.out, "void __main_%s()" % encode_path(self.name) 1566 print >>self.out, "{" 1567 self.indent += 1 1568 self.write_temporaries(self.importer.function_targets.get(self.name)) 1569 1570 def end_module(self): 1571 1572 "End each module by closing its main function." 1573 1574 self.indent -= 1 1575 print >>self.out, "}" 1576 1577 def start_function(self, name): 1578 1579 "Start the function having the given 'name'." 1580 1581 print >>self.out, "__attr %s(__attr __args[])" % encode_function_pointer(name) 1582 print >>self.out, "{" 1583 self.indent += 1 1584 self.write_temporaries(self.importer.function_targets.get(name)) 1585 1586 # Obtain local names from parameters. 1587 1588 parameters = self.importer.function_parameters[name] 1589 locals = self.importer.function_locals[name].keys() 1590 names = [] 1591 1592 for n in locals: 1593 1594 # Filter out special names and parameters. Note that self is a local 1595 # regardless of whether it originally appeared in the parameters or 1596 # not. 1597 1598 if n.startswith("$l") or n in parameters or n == "self": 1599 continue 1600 names.append(encode_path(n)) 1601 1602 # Emit required local names. 1603 1604 if names: 1605 names.sort() 1606 self.writeline("__attr %s;" % ", ".join(names)) 1607 1608 self.write_parameters(name) 1609 1610 def end_function(self, name): 1611 1612 "End the function having the given 'name'." 1613 1614 self.indent -= 1 1615 print >>self.out, "}" 1616 print >>self.out 1617 1618 def write_temporaries(self, targets): 1619 1620 """ 1621 Write temporary storage employed by functions, providing space for the 1622 given number of 'targets'. 1623 """ 1624 1625 targets = targets is not None and "__tmp_targets[%d], " % targets or "" 1626 1627 self.writeline("__ref __tmp_context, __tmp_value;") 1628 self.writeline("__attr %s__tmp_result;" % targets) 1629 self.writeline("__exc __tmp_exc;") 1630 1631 def write_parameters(self, name): 1632 1633 """ 1634 For the function having the given 'name', write definitions of 1635 parameters found in the arguments array. 1636 """ 1637 1638 parameters = self.importer.function_parameters[name] 1639 1640 # Generate any self reference. 1641 1642 if self.is_method(name): 1643 self.writeline("__attr * const self = &__args[0];") 1644 1645 # Generate aliases for the parameters. 1646 1647 for i, parameter in enumerate(parameters): 1648 self.writeline("__attr * const %s = &__args[%d];" % (encode_path(parameter), i+1)) 1649 1650 def start_if(self, first, test_ref): 1651 self.writestmt("%sif (__BOOL(%s))" % (not first and "else " or "", test_ref)) 1652 self.writeline("{") 1653 self.indent += 1 1654 1655 def end_if(self): 1656 self.indent -= 1 1657 self.writeline("}") 1658 1659 def start_else(self): 1660 self.writeline("else") 1661 self.writeline("{") 1662 self.indent += 1 1663 1664 def end_else(self): 1665 self.indent -= 1 1666 self.writeline("}") 1667 1668 def statement(self, expr): 1669 # NOTE: Should never be None. 1670 if not expr: 1671 self.writestmt("...;") 1672 s = str(expr) 1673 if s: 1674 self.writestmt("%s;" % s) 1675 1676 def statements(self, results): 1677 for result in results: 1678 self.statement(result) 1679 1680 def writeline(self, s): 1681 print >>self.out, "%s%s" % (self.pad(), self.indenttext(s, self.indent + 1)) 1682 1683 def writestmt(self, s): 1684 print >>self.out 1685 self.writeline(s) 1686 1687 def write_comment(self, s): 1688 self.writestmt("/* %s */" % s) 1689 1690 def pad(self, extra=0): 1691 return (self.indent + extra) * self.tabstop 1692 1693 def indenttext(self, s, levels): 1694 lines = s.split("\n") 1695 out = [lines[0]] 1696 for line in lines[1:]: 1697 out.append(levels * self.tabstop + line) 1698 if line.endswith("("): 1699 levels += 1 1700 elif line.startswith(")"): 1701 levels -= 1 1702 return "\n".join(out) 1703 1704 # vim: tabstop=4 expandtab shiftwidth=4