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