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