Lichen

Change of generator.py

357:b8b6d8de775f
generator.py
     1.1 --- a/generator.py	Fri Dec 09 17:27:30 2016 +0100
     1.2 +++ b/generator.py	Fri Dec 09 19:42:33 2016 +0100
     1.3 @@ -77,6 +77,12 @@
     1.4      literal_instantiator_types = literal_mapping_types + literal_sequence_types
     1.5  
     1.6      def __init__(self, importer, optimiser, output):
     1.7 +
     1.8 +        """
     1.9 +        Initialise the generator with the given 'importer', 'optimiser' and
    1.10 +        'output' directory.
    1.11 +        """
    1.12 +
    1.13          self.importer = importer
    1.14          self.optimiser = optimiser
    1.15          self.output = output
    1.16 @@ -182,6 +188,8 @@
    1.17              objects = self.optimiser.attr_table.items()
    1.18              objects.sort()
    1.19  
    1.20 +            self.callables = {}
    1.21 +
    1.22              for ref, indexes in objects:
    1.23                  attrnames = self.get_attribute_names(indexes)
    1.24  
    1.25 @@ -199,8 +207,6 @@
    1.26                      # Set a special instantiator on the class.
    1.27  
    1.28                      if kind == "<class>":
    1.29 -                        attrs["__fn__"] = path
    1.30 -                        attrs["__args__"] = encode_size("pmin", path)
    1.31  
    1.32                          # Write instantiator declarations based on the
    1.33                          # applicable initialiser.
    1.34 @@ -211,9 +217,15 @@
    1.35  
    1.36                          self.write_instantiator(f_code, f_signatures, path, init_ref)
    1.37  
    1.38 -                        # Write parameter table.
    1.39 +                        # Record the callable for parameter table generation.
    1.40 +
    1.41 +                        self.callables[path] = init_ref.get_origin()
    1.42  
    1.43 -                        self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin())
    1.44 +                        # Define special attributes.
    1.45 +
    1.46 +                        signature = self.get_signature_for_callable(path)
    1.47 +                        attrs["__fn__"] = path
    1.48 +                        attrs["__args__"] = encode_size("pmin", signature)
    1.49  
    1.50                      self.populate_structure(Reference(kind, path), attrs, kind, structure)
    1.51  
    1.52 @@ -230,6 +242,10 @@
    1.53                      if path == self.function_type:
    1.54                          function_instance_attrs = attrs
    1.55  
    1.56 +                        # Record the callable for parameter table generation.
    1.57 +
    1.58 +                        self.callables[path] = path
    1.59 +
    1.60                  # Write a table for all objects.
    1.61  
    1.62                  table = []
    1.63 @@ -249,14 +265,21 @@
    1.64                  if self.importer.classes.has_key(path) or not self.importer.get_object(path):
    1.65                      continue
    1.66  
    1.67 +                # Record the callable for parameter table generation.
    1.68 +
    1.69 +                self.callables[path] = path
    1.70 +
    1.71 +                # Define the structure details.
    1.72 +
    1.73                  cls = self.function_type
    1.74                  table_name = encode_tablename("<instance>", cls)
    1.75                  structure_size = encode_size("<instance>", path)
    1.76  
    1.77                  # Set a special callable attribute on the instance.
    1.78  
    1.79 +                signature = self.get_signature_for_callable(path)
    1.80                  function_instance_attrs["__fn__"] = path
    1.81 -                function_instance_attrs["__args__"] = encode_size("pmin", path)
    1.82 +                function_instance_attrs["__args__"] = encode_size("pmin", signature)
    1.83  
    1.84                  # Produce two structures where a method is involved.
    1.85  
    1.86 @@ -295,9 +318,22 @@
    1.87  
    1.88                  print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path)
    1.89  
    1.90 -                # Write parameter table.
    1.91 +            # Consolidate parameter tables for instantiators and functions.
    1.92 +
    1.93 +            parameter_tables = set()
    1.94  
    1.95 -                self.make_parameter_table(f_decls, f_defs, path, path)
    1.96 +            for path, function_path in self.callables.items():
    1.97 +                parameters = self.optimiser.parameters[function_path]
    1.98 +                if not parameters:
    1.99 +                    parameters = ()
   1.100 +                else:
   1.101 +                    parameters = tuple(parameters)
   1.102 +                parameter_tables.add(parameters)
   1.103 +
   1.104 +            # Generate parameter tables for distinct function signatures.
   1.105 +
   1.106 +            for parameters in parameter_tables:
   1.107 +                self.make_parameter_table(f_decls, f_defs, parameters)
   1.108  
   1.109              # Generate predefined constants.
   1.110  
   1.111 @@ -343,8 +379,12 @@
   1.112  
   1.113              for path, parameters in self.optimiser.parameters.items():
   1.114                  argmin, argmax = self.get_argument_limits(path)
   1.115 -                min_sizes[path] = argmin
   1.116 -                max_sizes[path] = argmax
   1.117 +
   1.118 +                # Use the parameter signature in the constant names.
   1.119 +
   1.120 +                signature = self.get_parameter_signature(parameters)
   1.121 +                min_sizes[signature] = argmin
   1.122 +                max_sizes[signature] = argmax
   1.123  
   1.124                  # Record instantiator limits.
   1.125  
   1.126 @@ -465,22 +505,45 @@
   1.127          attr_name = encode_path(const_path)
   1.128          print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name)
   1.129  
   1.130 -    def make_parameter_table(self, f_decls, f_defs, path, function_path):
   1.131 +    def make_parameter_table(self, f_decls, f_defs, parameters):
   1.132  
   1.133          """
   1.134          Write parameter table details to 'f_decls' (to declare a table) and to
   1.135 -        'f_defs' (to define the contents) for the function with the given
   1.136 -        'path', using 'function_path' to obtain the parameter details. The
   1.137 -        latter two arguments may differ when describing an instantiator using
   1.138 -        the details of an initialiser.
   1.139 +        'f_defs' (to define the contents) for the given 'parameters'.
   1.140          """
   1.141  
   1.142 +        # Use a signature for the table name instead of a separate name for each
   1.143 +        # function.
   1.144 +
   1.145 +        signature = self.get_parameter_signature(parameters)
   1.146 +        table_name = encode_tablename("<function>", signature)
   1.147 +        structure_size = encode_size("pmax", signature)
   1.148 +
   1.149          table = []
   1.150 -        table_name = encode_tablename("<function>", path)
   1.151 -        structure_size = encode_size("pmax", path)
   1.152 -        self.populate_parameter_table(function_path, table)
   1.153 +        self.populate_parameter_table(parameters, table)
   1.154          self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table)
   1.155  
   1.156 +    def get_parameter_signature(self, parameters):
   1.157 +
   1.158 +        "Return a signature for the given 'parameters'."
   1.159 +
   1.160 +        l = []
   1.161 +        for parameter in parameters:
   1.162 +            if parameter is None:
   1.163 +                l.append("")
   1.164 +            else:
   1.165 +                name, pos = parameter
   1.166 +                l.append(name)
   1.167 +        return l and "__".join(l) or "__void"
   1.168 +
   1.169 +    def get_signature_for_callable(self, path):
   1.170 +
   1.171 +        "Return the signature for the callable with the given 'path'."
   1.172 +
   1.173 +        function_path = self.callables[path]
   1.174 +        parameters = self.optimiser.parameters[function_path]
   1.175 +        return self.get_parameter_signature(parameters)
   1.176 +
   1.177      def write_size_constants(self, f_consts, size_prefix, sizes, padding):
   1.178  
   1.179          """
   1.180 @@ -678,14 +741,14 @@
   1.181              attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname))
   1.182          return attrs
   1.183  
   1.184 -    def populate_table(self, key, table):
   1.185 +    def populate_table(self, path, table):
   1.186  
   1.187          """
   1.188          Traverse the attributes in the determined order for the structure having
   1.189 -        the given 'key', adding entries to the attribute 'table'.
   1.190 +        the given 'path', adding entries to the attribute 'table'.
   1.191          """
   1.192  
   1.193 -        for attrname in self.optimiser.structures[key]:
   1.194 +        for attrname in self.optimiser.structures[path]:
   1.195  
   1.196              # Handle gaps in the structure.
   1.197  
   1.198 @@ -694,14 +757,14 @@
   1.199              else:
   1.200                  table.append(encode_symbol("code", attrname))
   1.201  
   1.202 -    def populate_parameter_table(self, key, table):
   1.203 +    def populate_parameter_table(self, parameters, table):
   1.204  
   1.205          """
   1.206 -        Traverse the parameters in the determined order for the structure having
   1.207 -        the given 'key', adding entries to the attribute 'table'.
   1.208 +        Traverse the 'parameters' in the determined order, adding entries to the
   1.209 +        attribute 'table'.
   1.210          """
   1.211  
   1.212 -        for value in self.optimiser.parameters[key]:
   1.213 +        for value in parameters:
   1.214  
   1.215              # Handle gaps in the structure.
   1.216  
   1.217 @@ -751,11 +814,6 @@
   1.218              origin = ref.get_origin()
   1.219              structure_ref = ref
   1.220  
   1.221 -        # Refer to instantiator function tables for classes, specific function
   1.222 -        # tables for individual functions.
   1.223 -
   1.224 -        ptable = encode_tablename("<function>", ref.get_origin())
   1.225 -
   1.226          for attrname in self.optimiser.structures[structure_ref]:
   1.227  
   1.228              # Handle gaps in the structure.
   1.229 @@ -800,6 +858,9 @@
   1.230                  # Special argument specification member.
   1.231  
   1.232                  elif attrname == "__args__":
   1.233 +                    signature = self.get_signature_for_callable(ref.get_origin())
   1.234 +                    ptable = encode_tablename("<function>", signature)
   1.235 +
   1.236                      structure.append("{.min=%s, .ptable=&%s}" % (attr, ptable))
   1.237                      continue
   1.238