Lichen

generator.py

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