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