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