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