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