Lichen

generator.py

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