1 #!/usr/bin/env python 2 3 """ 4 Generate C code from object layouts and other deduced information. 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 CommonOutput 23 from encoders import encode_bound_reference, encode_function_pointer, \ 24 encode_instantiator_pointer, \ 25 encode_literal_constant, encode_literal_constant_member, \ 26 encode_literal_constant_value, \ 27 encode_literal_data_initialiser, \ 28 encode_literal_instantiator, encode_literal_reference, \ 29 encode_path, \ 30 encode_predefined_reference, encode_size, \ 31 encode_symbol, encode_tablename, \ 32 encode_type_attribute, decode_type_attribute, \ 33 is_type_attribute 34 from os import listdir, mkdir 35 from os.path import exists, isdir, join, split 36 from referencing import Reference 37 38 def copy(source, target): 39 40 "Copy a text file from 'source' to 'target'." 41 42 if isdir(target): 43 target = join(target, split(source)[-1]) 44 infile = open(source) 45 outfile = open(target, "w") 46 try: 47 outfile.write(infile.read()) 48 finally: 49 outfile.close() 50 infile.close() 51 52 class Generator(CommonOutput): 53 54 "A code generator." 55 56 # NOTE: These must be synchronised with the library. 57 58 function_type = "__builtins__.core.function" 59 type_type = "__builtins__.core.type" 60 61 predefined_constant_members = ( 62 ("__builtins__.boolean", "False"), 63 ("__builtins__.boolean", "True"), 64 ("__builtins__.none", "None"), 65 ("__builtins__.notimplemented", "NotImplemented"), 66 ) 67 68 literal_mapping_types = ( 69 "__builtins__.dict.dict", 70 ) 71 72 literal_sequence_types = ( 73 "__builtins__.list.list", 74 "__builtins__.tuple.tuple", 75 ) 76 77 literal_instantiator_types = literal_mapping_types + literal_sequence_types 78 79 def __init__(self, importer, optimiser, output): 80 81 """ 82 Initialise the generator with the given 'importer', 'optimiser' and 83 'output' directory. 84 """ 85 86 self.importer = importer 87 self.optimiser = optimiser 88 self.output = output 89 90 def to_output(self, debug=False): 91 92 "Write the generated code." 93 94 self.check_output() 95 self.write_structures() 96 self.copy_templates(debug) 97 98 def copy_templates(self, debug=False): 99 100 "Copy template files to the generated output directory." 101 102 templates = join(split(__file__)[0], "templates") 103 104 for filename in listdir(templates): 105 target = self.output 106 107 # Handle debug resources. 108 109 if filename.endswith("-debug"): 110 if debug: 111 target = join(self.output, filename[:-len("-debug")]) 112 else: 113 continue 114 115 # Handle non-debug resources. 116 117 if debug and exists(join(templates, "%s-debug" % filename)): 118 continue 119 120 pathname = join(templates, filename) 121 122 # Copy files into the target directory. 123 124 if not isdir(pathname): 125 copy(pathname, target) 126 127 # Copy directories (such as the native code directory). 128 129 else: 130 target = join(self.output, filename) 131 132 if not exists(target): 133 mkdir(target) 134 135 for filename in listdir(pathname): 136 copy(join(pathname, filename), target) 137 138 def write_structures(self): 139 140 "Write structures used by the program." 141 142 f_consts = open(join(self.output, "progconsts.h"), "w") 143 f_defs = open(join(self.output, "progtypes.c"), "w") 144 f_decls = open(join(self.output, "progtypes.h"), "w") 145 f_signatures = open(join(self.output, "main.h"), "w") 146 f_code = open(join(self.output, "main.c"), "w") 147 148 try: 149 # Output boilerplate. 150 151 print >>f_consts, """\ 152 #ifndef __PROGCONSTS_H__ 153 #define __PROGCONSTS_H__ 154 """ 155 print >>f_decls, """\ 156 #ifndef __PROGTYPES_H__ 157 #define __PROGTYPES_H__ 158 159 #include "progconsts.h" 160 #include "types.h" 161 """ 162 print >>f_defs, """\ 163 #include "progtypes.h" 164 #include "progops.h" 165 #include "main.h" 166 """ 167 print >>f_signatures, """\ 168 #ifndef __MAIN_H__ 169 #define __MAIN_H__ 170 171 #include "types.h" 172 """ 173 print >>f_code, """\ 174 #include <string.h> 175 #include <stdio.h> 176 #include "types.h" 177 #include "exceptions.h" 178 #include "ops.h" 179 #include "progconsts.h" 180 #include "progtypes.h" 181 #include "progops.h" 182 #include "main.h" 183 """ 184 185 # Generate table and structure data. 186 187 function_instance_attrs = None 188 objects = self.optimiser.attr_table.items() 189 objects.sort() 190 191 self.callables = {} 192 193 for ref, indexes in objects: 194 attrnames = self.get_attribute_names(indexes) 195 196 kind = ref.get_kind() 197 path = ref.get_origin() 198 table_name = encode_tablename(kind, path) 199 structure_size = encode_size(kind, path) 200 201 # Generate structures for classes and modules. 202 203 if kind != "<instance>": 204 structure = [] 205 attrs = self.get_static_attributes(kind, path, attrnames) 206 207 # Set a special instantiator on the class. 208 209 if kind == "<class>": 210 211 # Write instantiator declarations based on the 212 # applicable initialiser. 213 214 init_ref = attrs["__init__"] 215 216 # Write instantiator definitions. 217 218 self.write_instantiator(f_code, f_signatures, path, init_ref) 219 220 # Record the callable for parameter table generation. 221 222 self.callables[path] = init_ref.get_origin() 223 224 # Define special attributes. 225 226 signature = self.get_signature_for_callable(path) 227 attrs["__fn__"] = path 228 attrs["__args__"] = encode_size("pmin", signature) 229 230 self.populate_structure(Reference(kind, path), attrs, kind, structure) 231 232 if kind == "<class>": 233 self.write_instance_structure(f_decls, path, structure_size) 234 235 self.write_structure(f_decls, f_defs, path, table_name, structure, 236 kind == "<class>" and path) 237 238 # Record function instance details for function generation below. 239 240 else: 241 attrs = self.get_instance_attributes(path, attrnames) 242 if path == self.function_type: 243 function_instance_attrs = attrs 244 245 # Record the callable for parameter table generation. 246 247 self.callables[path] = path 248 249 # Write a table for all objects. 250 251 table = [] 252 self.populate_table(Reference(kind, path), table) 253 self.write_table(f_decls, f_defs, table_name, structure_size, table) 254 255 # Generate function instances. 256 257 functions = self.importer.function_parameters.keys() 258 functions.sort() 259 extra_function_instances = [] 260 261 for path in functions: 262 263 # Instantiators are generated above. 264 265 if self.importer.classes.has_key(path) or not self.importer.get_object(path): 266 continue 267 268 # Record the callable for parameter table generation. 269 270 self.callables[path] = path 271 272 # Define the structure details. 273 274 cls = self.function_type 275 table_name = encode_tablename("<instance>", cls) 276 structure_size = encode_size("<instance>", path) 277 278 # Set a special callable attribute on the instance. 279 280 signature = self.get_signature_for_callable(path) 281 function_instance_attrs["__fn__"] = path 282 function_instance_attrs["__args__"] = encode_size("pmin", signature) 283 284 # Produce two structures where a method is involved. 285 286 parent, name = path.rsplit(".", 1) 287 parent_ref = self.importer.get_object(parent) 288 parent_kind = parent_ref and parent_ref.get_kind() 289 290 # Populate and write each structure. 291 292 if parent_kind == "<class>": 293 294 # A bound version of a method. 295 296 structure = self.populate_function(path, function_instance_attrs, False) 297 self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure) 298 299 # An unbound version of a method. 300 301 structure = self.populate_function(path, function_instance_attrs, True) 302 self.write_structure(f_decls, f_defs, path, table_name, structure) 303 304 else: 305 # A normal function. 306 307 structure = self.populate_function(path, function_instance_attrs, False) 308 self.write_structure(f_decls, f_defs, path, table_name, structure) 309 310 # Functions with defaults need to declare instance structures. 311 312 if self.importer.function_defaults.get(path): 313 self.write_instance_structure(f_decls, path, structure_size) 314 extra_function_instances.append(path) 315 316 # Write function declarations. 317 # Signature: __attr <name>(__attr[]); 318 319 print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path) 320 321 # Consolidate parameter tables for instantiators and functions. 322 323 parameter_tables = set() 324 325 for path, function_path in self.callables.items(): 326 parameters = self.optimiser.parameters[function_path] 327 if not parameters: 328 parameters = () 329 else: 330 parameters = tuple(parameters) 331 parameter_tables.add(parameters) 332 333 # Generate parameter tables for distinct function signatures. 334 335 for parameters in parameter_tables: 336 self.make_parameter_table(f_decls, f_defs, parameters) 337 338 # Generate predefined constants. 339 340 for path, name in self.predefined_constant_members: 341 self.make_predefined_constant(f_decls, f_defs, path, name) 342 343 # Generate literal constants. 344 345 for value, n in self.optimiser.constants.items(): 346 self.make_literal_constant(f_decls, f_defs, n, value) 347 348 # Finish the main source file. 349 350 self.write_main_program(f_code, f_signatures) 351 352 # Record size information for certain function instances as well as 353 # for classes, modules and other instances. 354 355 size_tables = {} 356 357 for kind in ["<class>", "<module>", "<instance>"]: 358 size_tables[kind] = {} 359 360 # Generate structure size data. 361 362 for ref, structure in self.optimiser.structures.items(): 363 size_tables[ref.get_kind()][ref.get_origin()] = len(structure) 364 365 for path in extra_function_instances: 366 defaults = self.importer.function_defaults[path] 367 size_tables["<instance>"][path] = size_tables["<instance>"][self.function_type] + len(defaults) 368 369 size_tables = size_tables.items() 370 size_tables.sort() 371 372 for kind, sizes in size_tables: 373 self.write_size_constants(f_consts, kind, sizes, 0) 374 375 # Generate parameter table size data. 376 377 min_sizes = {} 378 max_sizes = {} 379 380 for path, parameters in self.optimiser.parameters.items(): 381 argmin, argmax = self.get_argument_limits(path) 382 383 # Use the parameter signature in the constant names. 384 385 signature = self.get_parameter_signature(parameters) 386 min_sizes[signature] = argmin 387 max_sizes[signature] = argmax 388 389 # Record instantiator limits. 390 391 if path.endswith(".__init__"): 392 path = path[:-len(".__init__")] 393 394 self.write_size_constants(f_consts, "pmin", min_sizes, 0) 395 self.write_size_constants(f_consts, "pmax", max_sizes, 0) 396 397 # Generate parameter codes. 398 399 self.write_code_constants(f_consts, self.optimiser.all_paramnames, self.optimiser.arg_locations, "pcode", "ppos") 400 401 # Generate attribute codes. 402 403 self.write_code_constants(f_consts, self.optimiser.all_attrnames, self.optimiser.locations, "code", "pos") 404 405 # Output more boilerplate. 406 407 print >>f_consts, """\ 408 409 #endif /* __PROGCONSTS_H__ */""" 410 411 print >>f_decls, """\ 412 413 #define __FUNCTION_TYPE %s 414 #define __FUNCTION_INSTANCE_SIZE %s 415 #define __TYPE_CLASS_TYPE %s 416 #define __TYPE_CLASS_POS %s 417 #define __TYPE_CLASS_CODE %s 418 419 #endif /* __PROGTYPES_H__ */""" % ( 420 encode_path(self.function_type), 421 encode_size("<instance>", self.function_type), 422 encode_path(self.type_type), 423 encode_symbol("pos", encode_type_attribute(self.type_type)), 424 encode_symbol("code", encode_type_attribute(self.type_type)), 425 ) 426 427 print >>f_signatures, """\ 428 429 #endif /* __MAIN_H__ */""" 430 431 finally: 432 f_consts.close() 433 f_defs.close() 434 f_decls.close() 435 f_signatures.close() 436 f_code.close() 437 438 def make_literal_constant(self, f_decls, f_defs, n, value): 439 440 """ 441 Write literal constant details to 'f_decls' (to declare a structure) and 442 to 'f_defs' (to define the contents) for the constant with the number 443 'n' with the given literal 'value'. 444 """ 445 446 const_path = encode_literal_constant(n) 447 structure_name = encode_literal_reference(n) 448 449 # NOTE: This makes assumptions about the __builtins__ structure. 450 451 modname = value.__class__.__name__ 452 typename = modname == "str" and "string" or modname 453 ref = Reference("<instance>", "__builtins__.%s.%s" % (modname, typename)) 454 455 self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value) 456 457 def make_predefined_constant(self, f_decls, f_defs, path, name): 458 459 """ 460 Write predefined constant details to 'f_decls' (to declare a structure) 461 and to 'f_defs' (to define the contents) for the constant located in 462 'path' with the given 'name'. 463 """ 464 465 # Determine the details of the constant. 466 467 attr_path = "%s.%s" % (path, name) 468 structure_name = encode_predefined_reference(attr_path) 469 ref = self.importer.get_object(attr_path) 470 471 self.make_constant(f_decls, f_defs, ref, attr_path, structure_name) 472 473 def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None): 474 475 """ 476 Write constant details to 'f_decls' (to declare a structure) and to 477 'f_defs' (to define the contents) for the constant described by 'ref' 478 having the given 'path' and 'structure_name' (for the constant structure 479 itself). 480 """ 481 482 # Obtain the attributes. 483 484 cls = ref.get_origin() 485 indexes = self.optimiser.attr_table[ref] 486 attrnames = self.get_attribute_names(indexes) 487 attrs = self.get_instance_attributes(cls, attrnames) 488 489 # Set the data, if provided. 490 491 if data is not None: 492 attrs["__data__"] = data 493 494 # Define the structure details. An object is created for the constant, 495 # but an attribute is provided, referring to the object, for access to 496 # the constant in the program. 497 498 structure = [] 499 table_name = encode_tablename("<instance>", cls) 500 self.populate_structure(ref, attrs, ref.get_kind(), structure) 501 self.write_structure(f_decls, f_defs, structure_name, table_name, structure) 502 503 # Define a macro for the constant. 504 505 attr_name = encode_path(const_path) 506 print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name) 507 508 def make_parameter_table(self, f_decls, f_defs, parameters): 509 510 """ 511 Write parameter table details to 'f_decls' (to declare a table) and to 512 'f_defs' (to define the contents) for the given 'parameters'. 513 """ 514 515 # Use a signature for the table name instead of a separate name for each 516 # function. 517 518 signature = self.get_parameter_signature(parameters) 519 table_name = encode_tablename("<function>", signature) 520 structure_size = encode_size("pmax", signature) 521 522 table = [] 523 self.populate_parameter_table(parameters, table) 524 self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table) 525 526 def get_parameter_signature(self, parameters): 527 528 "Return a signature for the given 'parameters'." 529 530 l = [] 531 for parameter in parameters: 532 if parameter is None: 533 l.append("") 534 else: 535 name, pos = parameter 536 l.append(name) 537 return l and "__".join(l) or "__void" 538 539 def get_signature_for_callable(self, path): 540 541 "Return the signature for the callable with the given 'path'." 542 543 function_path = self.callables[path] 544 parameters = self.optimiser.parameters[function_path] 545 return self.get_parameter_signature(parameters) 546 547 def write_size_constants(self, f_consts, size_prefix, sizes, padding): 548 549 """ 550 Write size constants to 'f_consts' for the given 'size_prefix', using 551 the 'sizes' dictionary to populate the definition, adding the given 552 'padding' to the basic sizes. 553 """ 554 555 print >>f_consts, "enum %s {" % encode_size(size_prefix) 556 first = True 557 for path, size in sizes.items(): 558 if not first: 559 print >>f_consts, "," 560 else: 561 first = False 562 f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding)) 563 print >>f_consts, "\n };" 564 565 def write_code_constants(self, f_consts, attrnames, locations, code_prefix, pos_prefix): 566 567 """ 568 Write code constants to 'f_consts' for the given 'attrnames' and 569 attribute 'locations'. 570 """ 571 572 print >>f_consts, "enum %s {" % encode_symbol(code_prefix) 573 first = True 574 for i, attrname in enumerate(attrnames): 575 if not first: 576 print >>f_consts, "," 577 else: 578 first = False 579 f_consts.write(" %s = %d" % (encode_symbol(code_prefix, attrname), i)) 580 print >>f_consts, "\n };" 581 582 print >>f_consts, "enum %s {" % encode_symbol(pos_prefix) 583 first = True 584 for i, attrnames in enumerate(locations): 585 for attrname in attrnames: 586 if not first: 587 print >>f_consts, "," 588 else: 589 first = False 590 f_consts.write(" %s = %d" % (encode_symbol(pos_prefix, attrname), i)) 591 print >>f_consts, "\n };" 592 593 def write_table(self, f_decls, f_defs, table_name, structure_size, table): 594 595 """ 596 Write the declarations to 'f_decls' and definitions to 'f_defs' for 597 the object having the given 'table_name' and the given 'structure_size', 598 with 'table' details used to populate the definition. 599 """ 600 601 print >>f_decls, "extern const __table %s;\n" % table_name 602 603 # Write the corresponding definition. 604 605 print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % ( 606 table_name, structure_size, 607 ",\n ".join(table)) 608 609 def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table): 610 611 """ 612 Write the declarations to 'f_decls' and definitions to 'f_defs' for 613 the object having the given 'table_name' and the given 'structure_size', 614 with 'table' details used to populate the definition. 615 """ 616 617 print >>f_decls, "extern const __ptable %s;\n" % table_name 618 619 # Write the corresponding definition. 620 621 print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % ( 622 table_name, structure_size, 623 ",\n ".join([("{%s, %s}" % t) for t in table])) 624 625 def write_instance_structure(self, f_decls, path, structure_size): 626 627 """ 628 Write a declaration to 'f_decls' for the object having the given 'path' 629 and the given 'structure_size'. 630 """ 631 632 # Write an instance-specific type definition for instances of classes. 633 # See: templates/types.h 634 635 print >>f_decls, """\ 636 typedef struct { 637 const __table * table; 638 unsigned int pos; 639 __attr attrs[%s]; 640 } %s; 641 """ % (structure_size, encode_symbol("obj", path)) 642 643 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None): 644 645 """ 646 Write the declarations to 'f_decls' and definitions to 'f_defs' for 647 the object having the given 'structure_name', the given 'table_name', 648 and the given 'structure' details used to populate the definition. 649 """ 650 651 if f_decls: 652 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 653 654 is_class = path and self.importer.get_object(path).has_kind("<class>") 655 pos = is_class and encode_symbol("pos", encode_type_attribute(path)) or "0" 656 657 print >>f_defs, """\ 658 __obj %s = { 659 &%s, 660 %s, 661 { 662 %s 663 }}; 664 """ % ( 665 encode_path(structure_name), table_name, pos, 666 ",\n ".join(structure)) 667 668 def get_argument_limits(self, path): 669 670 """ 671 Return the argument minimum and maximum for the callable at 'path', 672 adding an argument position for a universal context. 673 """ 674 675 parameters = self.importer.function_parameters[path] 676 defaults = self.importer.function_defaults.get(path) 677 num_parameters = len(parameters) + 1 678 return num_parameters - (defaults and len(defaults) or 0), num_parameters 679 680 def get_attribute_names(self, indexes): 681 682 """ 683 Given a list of attribute table 'indexes', return a list of attribute 684 names. 685 """ 686 687 all_attrnames = self.optimiser.all_attrnames 688 attrnames = [] 689 for i in indexes: 690 if i is None: 691 attrnames.append(None) 692 else: 693 attrnames.append(all_attrnames[i]) 694 return attrnames 695 696 def get_static_attributes(self, kind, name, attrnames): 697 698 """ 699 Return a mapping of attribute names to paths for attributes belonging 700 to objects of the given 'kind' (being "<class>" or "<module>") with 701 the given 'name' and supporting the given 'attrnames'. 702 """ 703 704 attrs = {} 705 706 for attrname in attrnames: 707 if attrname is None: 708 continue 709 if kind == "<class>": 710 path = self.importer.all_class_attrs[name][attrname] 711 elif kind == "<module>": 712 path = "%s.%s" % (name, attrname) 713 else: 714 continue 715 716 # The module may be hidden. 717 718 attr = self.importer.get_object(path) 719 if not attr: 720 module = self.importer.hidden.get(path) 721 if module: 722 attr = Reference(module.name, "<module>") 723 attrs[attrname] = attr 724 725 return attrs 726 727 def get_instance_attributes(self, name, attrnames): 728 729 """ 730 Return a mapping of attribute names to references for attributes 731 belonging to instances of the class with the given 'name', where the 732 given 'attrnames' are supported. 733 """ 734 735 consts = self.importer.all_instance_attr_constants[name] 736 attrs = {} 737 for attrname in attrnames: 738 if attrname is None: 739 continue 740 const = consts.get(attrname) 741 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 742 return attrs 743 744 def populate_table(self, path, table): 745 746 """ 747 Traverse the attributes in the determined order for the structure having 748 the given 'path', adding entries to the attribute 'table'. 749 """ 750 751 for attrname in self.optimiser.structures[path]: 752 753 # Handle gaps in the structure. 754 755 if attrname is None: 756 table.append("0") 757 else: 758 table.append(encode_symbol("code", attrname)) 759 760 def populate_parameter_table(self, parameters, table): 761 762 """ 763 Traverse the 'parameters' in the determined order, adding entries to the 764 attribute 'table'. 765 """ 766 767 for value in parameters: 768 769 # Handle gaps in the structure. 770 771 if value is None: 772 table.append(("0", "0")) 773 else: 774 name, pos = value 775 table.append((encode_symbol("pcode", name), pos)) 776 777 def populate_function(self, path, function_instance_attrs, unbound=False): 778 779 """ 780 Populate a structure for the function with the given 'path'. The given 781 'attrs' provide the instance attributes, and if 'unbound' is set to a 782 true value, an unbound method structure is produced (as opposed to a 783 callable bound method structure). 784 """ 785 786 structure = [] 787 self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure, unbound) 788 789 # Append default members. 790 791 self.append_defaults(path, structure) 792 return structure 793 794 def populate_structure(self, ref, attrs, kind, structure, unbound=False): 795 796 """ 797 Traverse the attributes in the determined order for the structure having 798 the given 'ref' whose members are provided by the 'attrs' mapping, in a 799 structure of the given 'kind', adding entries to the object 'structure'. 800 If 'unbound' is set to a true value, an unbound method function pointer 801 will be employed, with a reference to the bound method incorporated into 802 the special __fn__ attribute. 803 """ 804 805 # Populate function instance structures for functions. 806 807 if ref.has_kind("<function>"): 808 origin = self.function_type 809 structure_ref = Reference("<instance>", self.function_type) 810 811 # Otherwise, just populate the appropriate structures. 812 813 else: 814 origin = ref.get_origin() 815 structure_ref = ref 816 817 for attrname in self.optimiser.structures[structure_ref]: 818 819 # Handle gaps in the structure. 820 821 if attrname is None: 822 structure.append("{0, 0}") 823 824 # Handle non-constant and constant members. 825 826 else: 827 attr = attrs[attrname] 828 829 # Special function pointer member. 830 831 if attrname == "__fn__": 832 833 # Provide bound method references and the unbound function 834 # pointer if populating methods in a class. 835 836 bound_attr = None 837 838 # Classes offer instantiators. 839 840 if kind == "<class>": 841 attr = encode_instantiator_pointer(attr) 842 843 # Methods offers references to bound versions and an unbound 844 # method function. 845 846 elif unbound: 847 bound_attr = encode_bound_reference(attr) 848 attr = "__unbound_method" 849 850 # Other functions just offer function pointers. 851 852 else: 853 attr = encode_function_pointer(attr) 854 855 structure.append("{%s, .fn=%s}" % (bound_attr and ".b=&%s" % bound_attr or "0", attr)) 856 continue 857 858 # Special argument specification member. 859 860 elif attrname == "__args__": 861 signature = self.get_signature_for_callable(ref.get_origin()) 862 ptable = encode_tablename("<function>", signature) 863 864 structure.append("{.min=%s, .ptable=&%s}" % (attr, ptable)) 865 continue 866 867 # Special internal data member. 868 869 elif attrname == "__data__": 870 structure.append("{0, .%s=%s}" % (encode_literal_constant_member(attr), 871 encode_literal_constant_value(attr))) 872 continue 873 874 # Special cases. 875 876 elif attrname in ("__file__", "__fname__", "__mname__", "__name__"): 877 path = ref.get_origin() 878 879 if attrname == "__file__": 880 module = self.importer.get_module(path) 881 value = module.filename 882 else: 883 value = path 884 885 local_number = self.importer.all_constants[path][value] 886 constant_name = "$c%d" % local_number 887 attr_path = "%s.%s" % (path, constant_name) 888 constant_number = self.optimiser.constant_numbers[attr_path] 889 constant_value = "__const%d" % constant_number 890 structure.append("%s /* %s */" % (constant_value, attrname)) 891 continue 892 893 # Special class relationship attributes. 894 895 elif is_type_attribute(attrname): 896 structure.append("{0, &%s}" % encode_path(decode_type_attribute(attrname))) 897 continue 898 899 structure.append(self.encode_member(origin, attrname, attr, kind)) 900 901 def encode_member(self, path, name, ref, structure_type): 902 903 """ 904 Encode within the structure provided by 'path', the member whose 'name' 905 provides 'ref', within the given 'structure_type'. 906 """ 907 908 kind = ref.get_kind() 909 origin = ref.get_origin() 910 911 # References to constant literals. 912 913 if kind == "<instance>" and ref.is_constant_alias(): 914 alias = ref.get_name() 915 916 # Obtain a constant value directly assigned to the attribute. 917 918 if self.optimiser.constant_numbers.has_key(alias): 919 constant_number = self.optimiser.constant_numbers[alias] 920 constant_value = "__const%d" % constant_number 921 return "%s /* %s */" % (constant_value, name) 922 923 # Predefined constant references. 924 925 if (path, name) in self.predefined_constant_members: 926 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 927 return "{&%s, &%s} /* %s */" % (attr_path, attr_path, name) 928 929 # General undetermined members. 930 931 if kind in ("<var>", "<instance>"): 932 return "{0, 0} /* %s */" % name 933 934 # Set the context depending on the kind of attribute. 935 # For methods: {&<parent>, &<attr>} 936 # For other attributes: {&<attr>, &<attr>} 937 938 else: 939 if kind == "<function>" and structure_type == "<class>": 940 parent = origin.rsplit(".", 1)[0] 941 context = "&%s" % encode_path(parent) 942 elif kind == "<instance>": 943 context = "&%s" % encode_path(origin) 944 else: 945 context = "0" 946 return "{%s, &%s}" % (context, encode_path(origin)) 947 948 def append_defaults(self, path, structure): 949 950 """ 951 For the given 'path', append default parameter members to the given 952 'structure'. 953 """ 954 955 for name, default in self.importer.function_defaults.get(path): 956 structure.append(self.encode_member(path, name, default, "<instance>")) 957 958 def write_instantiator(self, f_code, f_signatures, path, init_ref): 959 960 """ 961 Write an instantiator to 'f_code', with a signature to 'f_signatures', 962 for instances of the class with the given 'path', with 'init_ref' as the 963 initialiser function reference. 964 965 NOTE: This also needs to initialise any __fn__ and __args__ members 966 NOTE: where __call__ is provided by the class. 967 """ 968 969 parameters = self.importer.function_parameters[init_ref.get_origin()] 970 971 print >>f_code, """\ 972 __attr %s(__attr __args[]) 973 { 974 /* Allocate the structure. */ 975 __args[0] = __new(&%s, &%s, sizeof(%s)); 976 977 /* Call the initialiser. */ 978 %s(__args); 979 980 /* Return the allocated object details. */ 981 return __args[0]; 982 } 983 """ % ( 984 encode_instantiator_pointer(path), 985 encode_tablename("<instance>", path), 986 encode_path(path), 987 encode_symbol("obj", path), 988 encode_function_pointer(init_ref.get_origin()) 989 ) 990 991 print >>f_signatures, "#define __HAVE_%s" % encode_path(path) 992 print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path) 993 994 # Write additional literal instantiators. These do not call the 995 # initialisers but instead populate the structures directly. 996 997 if path in self.literal_instantiator_types: 998 if path in self.literal_mapping_types: 999 style = "mapping" 1000 else: 1001 style = "sequence" 1002 1003 print >>f_code, """\ 1004 __attr %s(__attr __args[], unsigned int number) 1005 { 1006 /* Allocate the structure. */ 1007 __args[0] = __new(&%s, &%s, sizeof(%s)); 1008 1009 /* Allocate a structure for the data and set it on the __data__ attribute. */ 1010 %s(__args, number); 1011 1012 /* Return the allocated object details. */ 1013 return __args[0]; 1014 } 1015 """ % ( 1016 encode_literal_instantiator(path), 1017 encode_tablename("<instance>", path), 1018 encode_path(path), 1019 encode_symbol("obj", path), 1020 encode_literal_data_initialiser(style) 1021 ) 1022 1023 print >>f_signatures, "__attr %s(__attr[], unsigned int);" % encode_literal_instantiator(path) 1024 1025 def write_main_program(self, f_code, f_signatures): 1026 1027 """ 1028 Write the main program to 'f_code', invoking the program's modules. Also 1029 write declarations for module main functions to 'f_signatures'. 1030 """ 1031 1032 print >>f_code, """\ 1033 int main(int argc, char *argv[]) 1034 { 1035 __exc __tmp_exc; 1036 1037 __Try 1038 {""" 1039 1040 for name in self.importer.order_modules(): 1041 function_name = "__main_%s" % encode_path(name) 1042 print >>f_signatures, "void %s();" % function_name 1043 1044 # Omit the native modules. 1045 1046 parts = name.split(".") 1047 1048 if parts[0] != "native": 1049 print >>f_code, """\ 1050 %s();""" % function_name 1051 1052 print >>f_code, """\ 1053 return 0; 1054 } 1055 __Catch(__tmp_exc) 1056 { 1057 fprintf(stderr, "Program terminated due to exception: %%s.\\n", 1058 __load_via_object( 1059 %s((__attr[]) {{0, 0}, __tmp_exc.arg}).value, 1060 %s).strvalue); 1061 return 1; 1062 } 1063 } 1064 """ % ( 1065 encode_function_pointer("__builtins__.str.str"), 1066 encode_symbol("pos", "__data__") 1067 ) 1068 1069 # vim: tabstop=4 expandtab shiftwidth=4