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