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