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