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, """\ 654 const __table %s = { 655 %s, 656 { 657 %s 658 } 659 }; 660 """ % (table_name, structure_size, ",\n ".join(table)) 661 662 def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table): 663 664 """ 665 Write the declarations to 'f_decls' and definitions to 'f_defs' for 666 the object having the given 'table_name' and the given 'structure_size', 667 with 'table' details used to populate the definition. 668 """ 669 670 members = [] 671 for t in table: 672 members.append("{%s, %s}" % t) 673 674 print >>f_decls, "extern const __ptable %s;\n" % table_name 675 676 # Write the corresponding definition. 677 678 print >>f_defs, """\ 679 const __ptable %s = { 680 %s, 681 { 682 %s 683 } 684 }; 685 """ % (table_name, structure_size, ",\n ".join(members)) 686 687 def write_instance_structure(self, f_decls, path, structure_size): 688 689 """ 690 Write a declaration to 'f_decls' for the object having the given 'path' 691 and the given 'structure_size'. 692 """ 693 694 # Write an instance-specific type definition for instances of classes. 695 # See: templates/types.h 696 697 print >>f_decls, """\ 698 typedef struct { 699 const __table * table; 700 __pos pos; 701 __attr attrs[%s]; 702 } %s; 703 """ % (structure_size, encode_symbol("obj", path)) 704 705 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure, path=None): 706 707 """ 708 Write the declarations to 'f_decls' and definitions to 'f_defs' for 709 the object having the given 'structure_name', the given 'table_name', 710 and the given 'structure' details used to populate the definition. 711 """ 712 713 if f_decls: 714 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 715 716 is_class = path and self.importer.get_object(path).has_kind("<class>") 717 pos = is_class and encode_symbol("pos", encode_type_attribute(path)) or "0" 718 719 print >>f_defs, """\ 720 __obj %s = { 721 &%s, 722 %s, 723 { 724 %s 725 }}; 726 """ % ( 727 encode_path(structure_name), table_name, pos, 728 ",\n ".join(structure)) 729 730 def get_argument_limits(self, path): 731 732 """ 733 Return the argument minimum and maximum for the callable at 'path', 734 adding an argument position for a universal context. 735 """ 736 737 parameters = self.importer.function_parameters[path] 738 defaults = self.importer.function_defaults.get(path) 739 num_parameters = len(parameters) + 1 740 return num_parameters - (defaults and len(defaults) or 0), num_parameters 741 742 def get_attribute_names(self, indexes): 743 744 """ 745 Given a list of attribute table 'indexes', return a list of attribute 746 names. 747 """ 748 749 all_attrnames = self.optimiser.all_attrnames 750 attrnames = [] 751 for i in indexes: 752 if i is None: 753 attrnames.append(None) 754 else: 755 attrnames.append(all_attrnames[i]) 756 return attrnames 757 758 def get_static_attributes(self, kind, name, attrnames): 759 760 """ 761 Return a mapping of attribute names to paths for attributes belonging 762 to objects of the given 'kind' (being "<class>" or "<module>") with 763 the given 'name' and supporting the given 'attrnames'. 764 """ 765 766 attrs = {} 767 768 for attrname in attrnames: 769 if attrname is None: 770 continue 771 if kind == "<class>": 772 path = self.importer.all_class_attrs[name][attrname] 773 elif kind == "<module>": 774 path = "%s.%s" % (name, attrname) 775 else: 776 continue 777 778 # The module may be hidden. 779 780 attr = self.importer.get_object(path) 781 if not attr: 782 module = self.importer.hidden.get(path) 783 if module: 784 attr = Reference(module.name, "<module>") 785 attrs[attrname] = attr 786 787 return attrs 788 789 def get_instance_attributes(self, name, attrnames): 790 791 """ 792 Return a mapping of attribute names to references for attributes 793 belonging to instances of the class with the given 'name', where the 794 given 'attrnames' are supported. 795 """ 796 797 consts = self.importer.all_instance_attr_constants[name] 798 attrs = {} 799 for attrname in attrnames: 800 if attrname is None: 801 continue 802 const = consts.get(attrname) 803 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 804 return attrs 805 806 def populate_table(self, path, table): 807 808 """ 809 Traverse the attributes in the determined order for the structure having 810 the given 'path', adding entries to the attribute 'table'. 811 """ 812 813 for attrname in self.optimiser.structures[path]: 814 815 # Handle gaps in the structure. 816 817 if attrname is None: 818 table.append("0") 819 else: 820 table.append(encode_symbol("code", attrname)) 821 822 def populate_parameter_table(self, parameters, table): 823 824 """ 825 Traverse the 'parameters' in the determined order, adding entries to the 826 attribute 'table'. 827 """ 828 829 for value in parameters: 830 831 # Handle gaps in the structure. 832 833 if value is None: 834 table.append(("0", "0")) 835 else: 836 name, pos = value 837 table.append((encode_symbol("pcode", name), pos)) 838 839 def populate_function(self, path, function_instance_attrs): 840 841 """ 842 Populate a structure for the function with the given 'path'. The given 843 'attrs' provide the instance attributes. 844 """ 845 846 structure = [] 847 self.populate_structure(Reference("<function>", path), function_instance_attrs, "<instance>", structure) 848 849 # Append default members. 850 851 self.append_defaults(path, structure) 852 return structure 853 854 def populate_structure(self, ref, attrs, kind, structure): 855 856 """ 857 Traverse the attributes in the determined order for the structure having 858 the given 'ref' whose members are provided by the 'attrs' mapping, in a 859 structure of the given 'kind', adding entries to the object 'structure'. 860 """ 861 862 # Populate function instance structures for functions. 863 864 if ref.has_kind("<function>"): 865 origin = self.function_type 866 structure_ref = Reference("<instance>", self.function_type) 867 868 # Otherwise, just populate the appropriate structures. 869 870 else: 871 origin = ref.get_origin() 872 structure_ref = ref 873 874 for attrname in self.optimiser.structures[structure_ref]: 875 876 # Handle gaps in the structure. 877 878 if attrname is None: 879 structure.append("__NULL") 880 881 # Handle non-constant and constant members. 882 883 else: 884 attr = attrs[attrname] 885 886 # Special function pointer member. 887 888 if attrname == "__fn__": 889 890 # Classes offer instantiators which can be called without a 891 # context. 892 893 if kind == "<class>": 894 attr = encode_instantiator_pointer(attr) 895 unbound_attr = attr 896 897 # Provide bound method and unbound function pointers if 898 # populating methods in a class. 899 900 else: 901 attr = encode_function_pointer(attr) 902 unbound_attr = "__unbound_method" 903 904 structure.append("{{.inv=%s, .fn=%s}}" % (unbound_attr, attr)) 905 continue 906 907 # Special argument specification member. 908 909 elif attrname == "__args__": 910 signature = self.get_signature_for_callable(ref.get_origin()) 911 ptable = encode_tablename("<function>", signature) 912 913 structure.append("{{.min=%s, .ptable=&%s}}" % (attr, ptable)) 914 continue 915 916 # Special internal data member. 917 918 elif attrname == "__data__": 919 structure.append("{.%s=%s}" % ( 920 encode_literal_constant_member(attr), 921 encode_literal_constant_value(attr))) 922 continue 923 924 # Special internal key member. 925 926 elif attrname == "__key__": 927 structure.append("{{.code=%s, .pos=%s}}" % (attr and encode_symbol("code", attr) or "0", 928 attr and encode_symbol("pos", attr) or "0")) 929 continue 930 931 # Special cases. 932 933 elif attrname in ("__file__", "__name__"): 934 path = ref.get_origin() 935 value_type = self.string_type 936 937 # Provide constant values. These must match the values 938 # originally recorded during inspection. 939 940 if attrname == "__file__": 941 module = self.importer.get_module(path) 942 value = module.filename 943 944 # Function and class names are leafnames. 945 946 elif attrname == "__name__" and not ref.has_kind("<module>"): 947 value = path.rsplit(".", 1)[-1] 948 949 # All other names just use the object path information. 950 951 else: 952 value = path 953 954 encoding = None 955 956 local_number = self.importer.all_constants[path][(value, value_type, encoding)] 957 constant_name = "$c%d" % local_number 958 attr_path = "%s.%s" % (path, constant_name) 959 constant_number = self.optimiser.constant_numbers[attr_path] 960 constant_value = "__const%d" % constant_number 961 structure.append("%s /* %s */" % (constant_value, attrname)) 962 continue 963 964 elif attrname == "__parent__": 965 path = ref.get_origin() 966 967 # Parents of classes and functions are derived from their 968 # object paths. 969 970 value = path.rsplit(".", 1)[0] 971 structure.append("{{.context=0, .value=&%s}}" % encode_path(value)) 972 continue 973 974 # Special class relationship attributes. 975 976 elif is_type_attribute(attrname): 977 structure.append("{{.context=0, .value=&%s}}" % encode_path(decode_type_attribute(attrname))) 978 continue 979 980 # All other kinds of members. 981 982 structure.append(self.encode_member(origin, attrname, attr, kind)) 983 984 def encode_member(self, path, name, ref, structure_type): 985 986 """ 987 Encode within the structure provided by 'path', the member whose 'name' 988 provides 'ref', within the given 'structure_type'. 989 """ 990 991 kind = ref.get_kind() 992 origin = ref.get_origin() 993 994 # References to constant literals. 995 996 if kind == "<instance>" and ref.is_constant_alias(): 997 alias = ref.get_name() 998 999 # Use the alias directly if appropriate. 1000 1001 if alias.startswith("$c"): 1002 constant_value = encode_literal_constant(int(alias[2:])) 1003 return "%s /* %s */" % (constant_value, name) 1004 1005 # Obtain a constant value directly assigned to the attribute. 1006 1007 if self.optimiser.constant_numbers.has_key(alias): 1008 constant_number = self.optimiser.constant_numbers[alias] 1009 constant_value = encode_literal_constant(constant_number) 1010 return "%s /* %s */" % (constant_value, name) 1011 1012 # Usage of predefined constants, currently only None supported. 1013 1014 if kind == "<instance>" and origin == self.none_type: 1015 attr_path = encode_predefined_reference(self.none_value) 1016 return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name) 1017 1018 # Predefined constant members. 1019 1020 if (path, name) in self.predefined_constant_members: 1021 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 1022 return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name) 1023 1024 # General undetermined members. 1025 1026 if kind in ("<var>", "<instance>"): 1027 attr_path = encode_predefined_reference(self.none_value) 1028 return "{{.context=&%s, .value=&%s}} /* %s */" % (attr_path, attr_path, name) 1029 1030 # Set the context depending on the kind of attribute. 1031 # For methods: {&<parent>, &<attr>} 1032 # For other attributes: {&<attr>, &<attr>} 1033 1034 else: 1035 if kind == "<function>" and structure_type == "<class>": 1036 parent = origin.rsplit(".", 1)[0] 1037 context = "&%s" % encode_path(parent) 1038 elif kind == "<instance>": 1039 context = "&%s" % encode_path(origin) 1040 else: 1041 context = "0" 1042 return "{{.context=%s, .value=&%s}}" % (context, encode_path(origin)) 1043 1044 def append_defaults(self, path, structure): 1045 1046 """ 1047 For the given 'path', append default parameter members to the given 1048 'structure'. 1049 """ 1050 1051 for name, default in self.importer.function_defaults.get(path): 1052 structure.append(self.encode_member(path, name, default, "<instance>")) 1053 1054 def write_instantiator(self, f_code, f_signatures, path, init_ref): 1055 1056 """ 1057 Write an instantiator to 'f_code', with a signature to 'f_signatures', 1058 for instances of the class with the given 'path', with 'init_ref' as the 1059 initialiser function reference. 1060 1061 NOTE: This also needs to initialise any __fn__ and __args__ members 1062 NOTE: where __call__ is provided by the class. 1063 """ 1064 1065 parameters = self.importer.function_parameters[init_ref.get_origin()] 1066 1067 print >>f_code, """\ 1068 __attr %s(__attr __args[]) 1069 { 1070 /* Allocate the structure. */ 1071 __args[0] = __new(&%s, &%s, sizeof(%s)); 1072 1073 /* Call the initialiser. */ 1074 %s(__args); 1075 1076 /* Return the allocated object details. */ 1077 return __args[0]; 1078 } 1079 """ % ( 1080 encode_instantiator_pointer(path), 1081 encode_tablename("<instance>", path), 1082 encode_path(path), 1083 encode_symbol("obj", path), 1084 encode_function_pointer(init_ref.get_origin()) 1085 ) 1086 1087 print >>f_signatures, "#define __HAVE_%s" % encode_path(path) 1088 print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path) 1089 1090 # Write additional literal instantiators. These do not call the 1091 # initialisers but instead populate the structures directly. 1092 1093 if path in self.literal_instantiator_types: 1094 if path in self.literal_mapping_types: 1095 style = "mapping" 1096 else: 1097 style = "sequence" 1098 1099 print >>f_code, """\ 1100 __attr %s(__attr __args[], __pos number) 1101 { 1102 /* Allocate the structure. */ 1103 __args[0] = __new(&%s, &%s, sizeof(%s)); 1104 1105 /* Allocate a structure for the data and set it on the __data__ attribute. */ 1106 %s(__args, number); 1107 1108 /* Return the allocated object details. */ 1109 return __args[0]; 1110 } 1111 """ % ( 1112 encode_literal_instantiator(path), 1113 encode_tablename("<instance>", path), 1114 encode_path(path), 1115 encode_symbol("obj", path), 1116 encode_literal_data_initialiser(style) 1117 ) 1118 1119 print >>f_signatures, "__attr %s(__attr[], __pos);" % encode_literal_instantiator(path) 1120 1121 def write_main_program(self, f_code, f_signatures): 1122 1123 """ 1124 Write the main program to 'f_code', invoking the program's modules. Also 1125 write declarations for module main functions to 'f_signatures'. 1126 """ 1127 1128 print >>f_code, """\ 1129 int main(int argc, char *argv[]) 1130 { 1131 __exc __tmp_exc; 1132 1133 GC_INIT(); 1134 1135 __Try 1136 {""" 1137 1138 for name in self.importer.order_modules(): 1139 function_name = "__main_%s" % encode_path(name) 1140 print >>f_signatures, "void %s();" % function_name 1141 1142 # Omit the native modules. 1143 1144 parts = name.split(".") 1145 1146 if parts[0] != "native": 1147 print >>f_code, """\ 1148 %s();""" % function_name 1149 1150 print >>f_code, """\ 1151 } 1152 __Catch(__tmp_exc) 1153 { 1154 if (__ISINSTANCE(__tmp_exc.arg, ((__attr) {{.context=0, .value=&__builtins___exception_system_SystemExit}}))) 1155 return __load_via_object( 1156 __load_via_object(__tmp_exc.arg.value, %s).value, 1157 %s).intvalue; 1158 1159 fprintf(stderr, "Program terminated due to exception: %%s.\\n", 1160 __load_via_object( 1161 %s((__attr[]) {__NULL, __tmp_exc.arg}).value, 1162 %s).strvalue); 1163 return 1; 1164 } 1165 1166 return 0; 1167 } 1168 """ % ( 1169 encode_symbol("pos", "value"), 1170 encode_symbol("pos", "__data__"), 1171 encode_function_pointer("__builtins__.str.str"), 1172 encode_symbol("pos", "__data__") 1173 ) 1174 1175 # vim: tabstop=4 expandtab shiftwidth=4