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