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