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