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 else: 501 print >>f_options, "CFLAGS = -O2" 502 503 if gc_sections: 504 print >>f_options, "include gc_sections.mk" 505 506 finally: 507 f_options.close() 508 509 # Native and module definitions divide the program modules into native 510 # and generated code. 511 512 f_native = open(join(self.output, "native.mk"), "w") 513 f_modules = open(join(self.output, "modules.mk"), "w") 514 try: 515 # Identify modules used by the program. 516 517 native_modules = [join("native", "common.c")] 518 modules = [] 519 520 for name in self.importer.modules.keys(): 521 parts = name.split(".", 1) 522 523 # Identify source files to be built. 524 525 if parts[0] == "native": 526 native_modules.append(join("native", "%s.c" % parts[1])) 527 else: 528 modules.append(join("src", "%s.c" % name)) 529 530 print >>f_native, "SRC =", " ".join(native_modules) 531 print >>f_modules, "SRC +=", " ".join(modules) 532 533 finally: 534 f_native.close() 535 f_modules.close() 536 537 # Instance position configuration uses the position of the ubiquitous 538 # __class__ attribute as a means of indicating that an object is an 539 # instance. Classes employ special identifying attributes that are 540 # positioned elsewhere and thus cannot be in the same location as the 541 # __class__ attribute. 542 543 f_instancepos = open(join(self.output, "instancepos.h"), "w") 544 try: 545 print >>f_instancepos, """\ 546 #ifndef __INSTANCEPOS 547 #define __INSTANCEPOS %d 548 #endif 549 """ % self.instancepos 550 finally: 551 f_instancepos.close() 552 553 def make_literal_constant(self, f_decls, f_defs, n, constant): 554 555 """ 556 Write literal constant details to 'f_decls' (to declare a structure) and 557 to 'f_defs' (to define the contents) for the constant with the number 558 'n' with the given 'constant'. 559 """ 560 561 value, value_type, encoding = constant 562 563 const_path = encode_literal_constant(n) 564 structure_name = encode_literal_reference(n) 565 566 ref = Reference("<instance>", value_type) 567 self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value, encoding) 568 569 def make_predefined_constant(self, f_decls, f_defs, path, name): 570 571 """ 572 Write predefined constant details to 'f_decls' (to declare a structure) 573 and to 'f_defs' (to define the contents) for the constant located in 574 'path' with the given 'name'. 575 """ 576 577 # Determine the details of the constant. 578 579 attr_path = "%s.%s" % (path, name) 580 structure_name = encode_predefined_reference(attr_path) 581 ref = self.importer.get_object(attr_path) 582 583 self.make_constant(f_decls, f_defs, ref, attr_path, structure_name) 584 585 def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None, encoding=None): 586 587 """ 588 Write constant details to 'f_decls' (to declare a structure) and to 589 'f_defs' (to define the contents) for the constant described by 'ref' 590 having the given 'path' and 'structure_name' (for the constant structure 591 itself). 592 593 The additional 'data' and 'encoding' are used to describe specific 594 values. 595 """ 596 597 # Obtain the attributes. 598 599 cls = ref.get_origin() 600 indexes = self.optimiser.attr_table[ref] 601 attrnames = self.get_attribute_names(indexes) 602 attrs = self.get_instance_attributes(cls, attrnames) 603 604 # Set the data, if provided. 605 606 if data is not None: 607 attrs["__data__"] = data 608 609 # Also set a key for dynamic attribute lookup, if a string. 610 611 if attrs.has_key("__key__"): 612 if data in self.optimiser.all_attrnames: 613 attrs["__key__"] = data 614 else: 615 attrs["__key__"] = None 616 617 # Initialise the size, if a string. 618 619 if attrs.has_key("__size__"): 620 attrs["__size__"] = len(data) 621 622 # Define Unicode constant encoding details. 623 624 if cls == self.unicode_type: 625 626 # Reference the encoding's own constant value. 627 628 if encoding: 629 n = self.optimiser.constants[(encoding, self.string_type, None)] 630 631 # Employ a special alias that will be tested specifically in 632 # encode_member. 633 634 encoding_ref = Reference("<instance>", self.string_type, "$c%s" % n) 635 636 # Use None where no encoding was indicated. 637 638 else: 639 encoding_ref = Reference("<instance>", self.none_type) 640 641 attrs["encoding"] = encoding_ref 642 643 # Define the structure details. An object is created for the constant, 644 # but an attribute is provided, referring to the object, for access to 645 # the constant in the program. 646 647 structure = [] 648 table_name = encode_tablename("<instance>", cls) 649 self.populate_structure(ref, attrs, ref.get_kind(), structure) 650 self.write_structure(f_decls, f_defs, structure_name, table_name, structure) 651 652 # Define a macro for the constant. 653 654 attr_name = encode_path(const_path) 655 print >>f_decls, "#define %s __ATTRVALUE(&%s)" % (attr_name, structure_name) 656 657 def make_parameter_table(self, f_decls, f_defs, argmin, parameters): 658 659 """ 660 Write parameter table details to 'f_decls' (to declare a table) and to 661 'f_defs' (to define the contents) for the given 'argmin' and 662 'parameters'. 663 """ 664 665 # Use a signature for the table name instead of a separate name for each 666 # function. 667 668 signature = self.get_parameter_signature(argmin, parameters) 669 table_name = encode_tablename("<function>", signature) 670 min_parameters = encode_size("pmin", signature) 671 max_parameters = encode_size("pmax", signature) 672 structure_size = encode_size("psize", signature) 673 674 table = [] 675 self.populate_parameter_table(parameters, table) 676 self.write_parameter_table(f_decls, f_defs, table_name, min_parameters, max_parameters, structure_size, table) 677 678 def get_parameter_signature(self, argmin, parameters): 679 680 "Return a signature for the given 'argmin' and 'parameters'." 681 682 l = [str(argmin)] 683 for parameter in parameters: 684 if parameter is None: 685 l.append("") 686 else: 687 name, pos = parameter 688 l.append("%s_%s" % (name, pos)) 689 return l and "__".join(l) or "__void" 690 691 def get_signature_for_callable(self, path): 692 693 "Return the signature for the callable with the given 'path'." 694 695 function_path = self.callables[path] 696 argmin, argmax = self.get_argument_limits(function_path) 697 parameters = self.optimiser.parameters[function_path] 698 return self.get_parameter_signature(argmin, parameters) 699 700 def write_size_constants(self, f_consts, size_prefix, sizes, padding): 701 702 """ 703 Write size constants to 'f_consts' for the given 'size_prefix', using 704 the 'sizes' dictionary to populate the definition, adding the given 705 'padding' to the basic sizes. 706 """ 707 708 print >>f_consts, "enum %s {" % encode_size(size_prefix) 709 first = True 710 for path, size in sizes.items(): 711 if not first: 712 print >>f_consts, "," 713 else: 714 first = False 715 f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding)) 716 print >>f_consts, "\n };" 717 718 def write_code_constants(self, f_consts, attrnames, locations, code_prefix, 719 pos_prefix, code_encoder, pos_encoder): 720 721 """ 722 Write code constants to 'f_consts' for the given 'attrnames' and 723 attribute 'locations'. 724 """ 725 726 print >>f_consts, "enum %s {" % encode_symbol(code_prefix) 727 first = True 728 for i, attrname in enumerate(attrnames): 729 if not first: 730 print >>f_consts, "," 731 else: 732 first = False 733 f_consts.write(" %s = %d" % (code_encoder(attrname), i)) 734 print >>f_consts, "\n };" 735 736 print >>f_consts, "enum %s {" % encode_symbol(pos_prefix) 737 first = True 738 for i, attrnames in enumerate(locations): 739 for attrname in attrnames: 740 if not first: 741 print >>f_consts, "," 742 else: 743 first = False 744 f_consts.write(" %s = %d" % (pos_encoder(attrname), i)) 745 print >>f_consts, "\n };" 746 747 def write_table(self, f_decls, f_defs, table_name, structure_size, table): 748 749 """ 750 Write the declarations to 'f_decls' and definitions to 'f_defs' for 751 the object having the given 'table_name' and the given 'structure_size', 752 with 'table' details used to populate the definition. 753 """ 754 755 print >>f_decls, "extern const __table %s;\n" % table_name 756 757 # Write the corresponding definition. 758 759 print >>f_defs, """\ 760 const __table %s = { 761 %s, 762 { 763 %s 764 } 765 }; 766 """ % (table_name, structure_size, 767 ",\n ".join(table)) 768 769 def write_parameter_table(self, f_decls, f_defs, table_name, min_parameters, 770 max_parameters, structure_size, table): 771 772 """ 773 Write the declarations to 'f_decls' and definitions to 'f_defs' for 774 the object having the given 'table_name' and the given 'min_parameters', 775 'max_parameters' and 'structure_size', with 'table' details used to 776 populate the definition. 777 """ 778 779 members = [] 780 for t in table: 781 members.append("{.code=%s, .pos=%s}" % t) 782 783 print >>f_decls, "extern const __ptable %s;\n" % table_name 784 785 # Write the corresponding definition. 786 787 print >>f_defs, """\ 788 const __ptable %s = { 789 .min=%s, 790 .max=%s, 791 .size=%s, 792 { 793 %s 794 } 795 }; 796 """ % (table_name, min_parameters, max_parameters, structure_size, 797 ",\n ".join(members)) 798 799 def write_instance_structure(self, f_decls, path, structure_size): 800 801 """ 802 Write a declaration to 'f_decls' for the object having the given 'path' 803 and the given 'structure_size'. 804 """ 805 806 # Write an instance-specific type definition for instances of classes. 807 # See: templates/types.h 808 809 print >>f_decls, """\ 810 typedef struct { 811 const __table * table; 812 __pos pos; 813 __attr attrs[%s]; 814 } %s; 815 """ % (structure_size, encode_symbol("obj", path)) 816 817 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None): 818 819 """ 820 Write the declarations to 'f_decls' and definitions to 'f_defs' for 821 the object having the given 'structure_name', the given 'table_name', 822 and the given 'structure' details used to populate the definition. 823 """ 824 825 if f_decls: 826 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 827 828 is_class = path and self.importer.get_object(path).has_kind("<class>") 829 pos = is_class and encode_pos(encode_type_attribute(path)) or str(self.instancepos) 830 831 print >>f_defs, """\ 832 __obj %s = { 833 &%s, 834 %s, 835 { 836 %s 837 }}; 838 """ % ( 839 encode_path(structure_name), table_name, pos, 840 ",\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(self, name, attrnames): 902 903 """ 904 Return a mapping of attribute names to references for attributes 905 belonging to instances of the class with the given 'name', where the 906 given 'attrnames' are supported. 907 """ 908 909 consts = self.importer.all_instance_attr_constants[name] 910 attrs = {} 911 for attrname in attrnames: 912 if attrname is None: 913 continue 914 const = consts.get(attrname) 915 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 916 return attrs 917 918 def populate_table(self, path, table): 919 920 """ 921 Traverse the attributes in the determined order for the structure having 922 the given 'path', adding entries to the attribute 'table'. 923 """ 924 925 for attrname in self.optimiser.structures[path]: 926 927 # Handle gaps in the structure. 928 929 if attrname is None: 930 table.append("0") 931 else: 932 table.append(encode_code(attrname)) 933 934 def populate_parameter_table(self, parameters, table): 935 936 """ 937 Traverse the 'parameters' in the determined order, adding entries to the 938 attribute 'table'. 939 """ 940 941 for value in parameters: 942 943 # Handle gaps in the structure. 944 945 if value is None: 946 table.append(("0", "0")) 947 else: 948 name, pos = value 949 table.append((encode_symbol("pcode", name), pos)) 950 951 def populate_function(self, path, function_instance_attrs): 952 953 """ 954 Populate a structure for the function with the given 'path'. The given 955 'attrs' provide the instance attributes. 956 """ 957 958 structure = [] 959 self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure) 960 961 # Append default members. 962 963 self.append_defaults(path, structure) 964 return structure 965 966 def populate_structure(self, ref, attrs, kind, structure): 967 968 """ 969 Traverse the attributes in the determined order for the structure having 970 the given 'ref' whose members are provided by the 'attrs' mapping, in a 971 structure of the given 'kind', adding entries to the object 'structure'. 972 """ 973 974 # Populate function instance structures for functions. 975 976 if ref.has_kind("<function>"): 977 origin = self.function_type 978 structure_ref = Reference("<instance>", self.function_type) 979 980 # Otherwise, just populate the appropriate structures. 981 982 else: 983 origin = ref.get_origin() 984 structure_ref = ref 985 986 for attrname in self.optimiser.structures[structure_ref]: 987 988 # Handle gaps in the structure. 989 990 if attrname is None: 991 structure.append("__NULL") 992 993 # Handle non-constant and constant members. 994 995 else: 996 attr = attrs[attrname] 997 998 # Special function pointer member. 999 1000 if attrname == "__fn__": 1001 1002 # Classes offer instantiators which can be called without a 1003 # context. 1004 1005 if kind == "<class>": 1006 attr = encode_instantiator_pointer(attr) 1007 else: 1008 attr = encode_function_pointer(attr) 1009 1010 structure.append("{.fn=%s}" % attr) 1011 continue 1012 1013 # Special argument specification member. 1014 1015 elif attrname == "__args__": 1016 signature = self.get_signature_for_callable(ref.get_origin()) 1017 ptable = encode_tablename("<function>", signature) 1018 1019 structure.append("{.ptable=&%s}" % ptable) 1020 continue 1021 1022 # Special internal data member. 1023 1024 elif attrname == "__data__": 1025 structure.append("{.%s=%s}" % ( 1026 encode_literal_constant_member(attr), 1027 encode_literal_constant_value(attr))) 1028 continue 1029 1030 # Special internal size member. 1031 1032 elif attrname == "__size__": 1033 structure.append("{.intvalue=%d}" % attr) 1034 continue 1035 1036 # Special internal key member. 1037 1038 elif attrname == "__key__": 1039 structure.append("{.code=%s, .pos=%s}" % (attr and encode_code(attr) or "0", 1040 attr and encode_pos(attr) or "0")) 1041 continue 1042 1043 # Special cases. 1044 1045 elif attrname in ("__file__", "__name__"): 1046 path = ref.get_origin() 1047 value_type = self.string_type 1048 1049 # Provide constant values. These must match the values 1050 # originally recorded during inspection. 1051 1052 if attrname == "__file__": 1053 module = self.importer.get_module(path) 1054 value = module.filename 1055 1056 # Function and class names are leafnames. 1057 1058 elif attrname == "__name__" and not ref.has_kind("<module>"): 1059 value = path.rsplit(".", 1)[-1] 1060 1061 # All other names just use the object path information. 1062 1063 else: 1064 value = path 1065 1066 encoding = None 1067 1068 local_number = self.importer.all_constants[path][(value, value_type, encoding)] 1069 constant_name = "$c%d" % local_number 1070 attr_path = "%s.%s" % (path, constant_name) 1071 constant_number = self.optimiser.constant_numbers[attr_path] 1072 constant_value = "__const%s" % constant_number 1073 structure.append("%s /* %s */" % (constant_value, attrname)) 1074 continue 1075 1076 elif attrname == "__parent__": 1077 path = ref.get_origin() 1078 1079 # Parents of classes and functions are derived from their 1080 # object paths. 1081 1082 value = path.rsplit(".", 1)[0] 1083 structure.append("{.value=&%s}" % encode_path(value)) 1084 continue 1085 1086 # Special context member. 1087 # Set the context depending on the kind of attribute. 1088 # For methods: <parent> 1089 # For other attributes: __NULL 1090 1091 elif attrname == "__context__": 1092 path = ref.get_origin() 1093 1094 # Contexts of methods are derived from their object paths. 1095 1096 context = "0" 1097 1098 if ref.get_kind() == "<function>": 1099 parent = path.rsplit(".", 1)[0] 1100 if self.importer.classes.has_key(parent): 1101 context = "&%s" % encode_path(parent) 1102 1103 structure.append("{.value=%s}" % context) 1104 continue 1105 1106 # Special class relationship attributes. 1107 1108 elif is_type_attribute(attrname): 1109 structure.append("{.value=&%s}" % encode_path(decode_type_attribute(attrname))) 1110 continue 1111 1112 # All other kinds of members. 1113 1114 structure.append(self.encode_member(origin, attrname, attr, kind)) 1115 1116 def encode_member(self, path, name, ref, structure_type): 1117 1118 """ 1119 Encode within the structure provided by 'path', the member whose 'name' 1120 provides 'ref', within the given 'structure_type'. 1121 """ 1122 1123 kind = ref.get_kind() 1124 origin = ref.get_origin() 1125 1126 # References to constant literals. 1127 1128 if kind == "<instance>" and ref.is_constant_alias(): 1129 alias = ref.get_name() 1130 1131 # Use the alias directly if appropriate. 1132 1133 if alias.startswith("$c"): 1134 constant_value = encode_literal_constant(alias[2:]) 1135 return "%s /* %s */" % (constant_value, name) 1136 1137 # Obtain a constant value directly assigned to the attribute. 1138 1139 if self.optimiser.constant_numbers.has_key(alias): 1140 constant_number = self.optimiser.constant_numbers[alias] 1141 constant_value = encode_literal_constant(constant_number) 1142 return "%s /* %s */" % (constant_value, name) 1143 1144 # Usage of predefined constants, currently only None supported. 1145 1146 if kind == "<instance>" and origin == self.none_type: 1147 attr_path = encode_predefined_reference(self.none_value) 1148 return "{.value=&%s} /* %s */" % (attr_path, name) 1149 1150 # Predefined constant members. 1151 1152 if (path, name) in self.predefined_constant_members: 1153 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 1154 return "{.value=&%s} /* %s */" % (attr_path, name) 1155 1156 # General undetermined members. 1157 1158 if kind in ("<var>", "<instance>"): 1159 attr_path = encode_predefined_reference(self.none_value) 1160 return "{.value=&%s} /* %s */" % (attr_path, name) 1161 1162 else: 1163 return "{.value=&%s}" % encode_path(origin) 1164 1165 def append_defaults(self, path, structure): 1166 1167 """ 1168 For the given 'path', append default parameter members to the given 1169 'structure'. 1170 """ 1171 1172 for name, default in self.importer.function_defaults.get(path): 1173 structure.append(self.encode_member(path, name, default, "<instance>")) 1174 1175 def write_instantiator(self, f_code, f_signatures, path, init_ref): 1176 1177 """ 1178 Write an instantiator to 'f_code', with a signature to 'f_signatures', 1179 for instances of the class with the given 'path', with 'init_ref' as the 1180 initialiser function reference. 1181 1182 NOTE: This also needs to initialise any __fn__ and __args__ members 1183 NOTE: where __call__ is provided by the class. 1184 """ 1185 1186 initialiser = init_ref.get_origin() 1187 parameters = self.importer.function_parameters[initialiser] 1188 argmin, argmax = self.get_argument_limits(initialiser) 1189 1190 l = [] 1191 for name in parameters: 1192 l.append("__attr %s" % name) 1193 1194 print >>f_code, """\ 1195 __attr %s(__attr __self%s) 1196 { 1197 return %s(__NEWINSTANCE(%s)%s); 1198 } 1199 """ % ( 1200 encode_instantiator_pointer(path), 1201 l and ", %s" % ",".join(l) or "", 1202 encode_function_pointer(initialiser), 1203 encode_path(path), 1204 parameters and ", %s" % ", ".join(parameters) or "" 1205 ) 1206 1207 # Signature: __new_typename(__attr __self, ...) 1208 1209 print >>f_signatures, "__attr %s(__attr __self%s);" % ( 1210 encode_instantiator_pointer(path), 1211 l and ", %s" % ", ".join(l) or "" 1212 ) 1213 1214 print >>f_signatures, "#define __HAVE_%s" % encode_path(path) 1215 1216 # Write additional literal instantiators. These do not call the 1217 # initialisers but instead populate the structures directly. 1218 1219 # Signature: __newliteral_sequence(ARGS, NUM) 1220 1221 if path in self.literal_instantiator_types: 1222 if path in self.literal_mapping_types: 1223 style = "mapping" 1224 else: 1225 style = "sequence" 1226 1227 print >>f_signatures, "#define %s(ARGS, NUM) (%s(__NEWINSTANCE(%s), ARGS, NUM))" % ( 1228 encode_literal_instantiator(path), 1229 encode_literal_data_initialiser(style), 1230 encode_path(path) 1231 ) 1232 1233 def write_main_program(self, f_code, f_signatures): 1234 1235 """ 1236 Write the main program to 'f_code', invoking the program's modules. Also 1237 write declarations for module main functions to 'f_signatures'. 1238 """ 1239 1240 print >>f_code, """\ 1241 int main(int argc, char *argv[]) 1242 { 1243 __exc __tmp_exc; 1244 1245 GC_INIT(); 1246 1247 __Try 1248 {""" 1249 1250 for name in self.importer.order_modules(): 1251 function_name = "__main_%s" % encode_path(name) 1252 print >>f_signatures, "void %s();" % function_name 1253 1254 # Omit the native modules. 1255 1256 parts = name.split(".") 1257 1258 if parts[0] != "native": 1259 print >>f_code, """\ 1260 %s();""" % function_name 1261 1262 print >>f_code, """\ 1263 } 1264 __Catch(__tmp_exc) 1265 { 1266 if (__ISINSTANCE(__tmp_exc.arg, __ATTRVALUE(&__builtins___exception_system_SystemExit))) 1267 return __load_via_object( 1268 __load_via_object(__tmp_exc.arg.value, __data__).value, 1269 value).intvalue; 1270 1271 fprintf(stderr, "Program terminated due to exception: %%s.\\n", 1272 __load_via_object( 1273 %s(__NULL, __tmp_exc.arg).value, 1274 __data__).strvalue); 1275 return 1; 1276 } 1277 1278 return 0; 1279 } 1280 """ % encode_function_pointer("__builtins__.str.str") 1281 1282 # vim: tabstop=4 expandtab shiftwidth=4