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