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