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