1.1 --- a/generator.py Tue Oct 25 23:06:37 2016 +0200
1.2 +++ b/generator.py Tue Oct 25 23:10:29 2016 +0200
1.3 @@ -21,7 +21,11 @@
1.4
1.5 from common import CommonOutput
1.6 from encoders import encode_bound_reference, encode_function_pointer, \
1.7 - encode_instantiator_pointer, encode_path, encode_symbol, \
1.8 + encode_instantiator_pointer, \
1.9 + encode_literal_constant, encode_literal_constant_member, \
1.10 + encode_literal_constant_value, encode_literal_reference, \
1.11 + encode_path, \
1.12 + encode_predefined_reference, encode_symbol, \
1.13 encode_type_attribute
1.14 from os import listdir
1.15 from os.path import isdir, join, split
1.16 @@ -59,6 +63,13 @@
1.17 "<instance>" : "i"
1.18 }
1.19
1.20 + predefined_constant_members = (
1.21 + ("__builtins__.bool", "False"),
1.22 + ("__builtins__.bool", "True"),
1.23 + ("__builtins__.none", "None"),
1.24 + ("__builtins__.notimplemented", "NotImplemented"),
1.25 + )
1.26 +
1.27 def __init__(self, importer, optimiser, output):
1.28 self.importer = importer
1.29 self.optimiser = optimiser
1.30 @@ -212,7 +223,12 @@
1.31 self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin())
1.32
1.33 self.populate_structure(Reference(kind, path), attrs, kind, structure)
1.34 - self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure)
1.35 +
1.36 + if kind == "<class>":
1.37 + self.write_instance_structure(f_decls, path, structure_size)
1.38 +
1.39 + self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure,
1.40 + kind == "<class>" and path)
1.41
1.42 # Record function instance details for function generation below.
1.43
1.44 @@ -261,8 +277,7 @@
1.45 # A bound version of a method.
1.46
1.47 structure = self.populate_function(path, function_instance_attrs, False)
1.48 - self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure,
1.49 - encode_bound_reference(path))
1.50 + self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure_size, structure)
1.51
1.52 # An unbound version of a method.
1.53
1.54 @@ -284,6 +299,16 @@
1.55
1.56 self.make_parameter_table(f_decls, f_defs, path, path)
1.57
1.58 + # Generate predefined constants.
1.59 +
1.60 + for path, name in self.predefined_constant_members:
1.61 + self.make_predefined_constant(f_decls, f_defs, path, name)
1.62 +
1.63 + # Generate literal constants.
1.64 +
1.65 + for value, n in self.optimiser.constants.items():
1.66 + self.make_literal_constant(f_decls, f_defs, n, value)
1.67 +
1.68 # Output more boilerplate.
1.69
1.70 print >>f_consts, """\
1.71 @@ -311,6 +336,76 @@
1.72 f_signatures.close()
1.73 f_code.close()
1.74
1.75 + def make_literal_constant(self, f_decls, f_defs, n, value):
1.76 +
1.77 + """
1.78 + Write literal constant details to 'f_decls' (to declare a structure) and
1.79 + to 'f_defs' (to define the contents) for the constant with the number
1.80 + 'n' with the given literal 'value'.
1.81 + """
1.82 +
1.83 + const_path = encode_literal_constant(n)
1.84 + structure_name = encode_literal_reference(n)
1.85 +
1.86 + # NOTE: This makes assumptions about the __builtins__ structure.
1.87 +
1.88 + typename = value.__class__.__name__
1.89 + ref = Reference("<instance>", "__builtins__.%s.%s" % (typename, typename))
1.90 +
1.91 + self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value)
1.92 +
1.93 + def make_predefined_constant(self, f_decls, f_defs, path, name):
1.94 +
1.95 + """
1.96 + Write predefined constant details to 'f_decls' (to declare a structure)
1.97 + and to 'f_defs' (to define the contents) for the constant located in
1.98 + 'path' with the given 'name'.
1.99 + """
1.100 +
1.101 + # Determine the details of the constant.
1.102 +
1.103 + attr_path = "%s.%s" % (path, name)
1.104 + structure_name = encode_predefined_reference(attr_path)
1.105 + ref = self.importer.get_object(attr_path)
1.106 +
1.107 + self.make_constant(f_decls, f_defs, ref, attr_path, structure_name)
1.108 +
1.109 + def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None):
1.110 +
1.111 + """
1.112 + Write constant details to 'f_decls' (to declare a structure) and to
1.113 + 'f_defs' (to define the contents) for the constant described by 'ref'
1.114 + having the given 'path' and 'structure_name' (for the constant structure
1.115 + itself).
1.116 + """
1.117 +
1.118 + # Obtain the attributes.
1.119 +
1.120 + cls = ref.get_origin()
1.121 + indexes = self.optimiser.attr_table[ref]
1.122 + attrnames = self.get_attribute_names(indexes)
1.123 + attrs = self.get_instance_attributes(cls, attrnames)
1.124 +
1.125 + # Set the data, if provided.
1.126 +
1.127 + if data is not None:
1.128 + attrs["__data__"] = data
1.129 +
1.130 + # Define the structure details. An object is created for the constant,
1.131 + # but an attribute is provided, referring to the object, for access to
1.132 + # the constant in the program.
1.133 +
1.134 + structure = []
1.135 + table_name = encode_tablename("Instance", cls)
1.136 + structure_size = encode_size(self.structure_size_prefixes["<instance>"], cls)
1.137 + self.populate_structure(ref, attrs, ref.get_kind(), structure)
1.138 + self.write_structure(f_decls, f_defs, structure_name, table_name, structure_size, structure)
1.139 +
1.140 + # Define a macro for the constant.
1.141 +
1.142 + attr_name = encode_path(const_path)
1.143 + print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name)
1.144 +
1.145 def make_parameter_table(self, f_decls, f_defs, path, function_path):
1.146
1.147 """
1.148 @@ -405,17 +500,13 @@
1.149 table_name, structure_size,
1.150 ",\n ".join([("{%s, %s}" % t) for t in table]))
1.151
1.152 - def write_structure(self, f_decls, f_defs, path, table_name, structure_size, structure, copy=None):
1.153 + def write_instance_structure(self, f_decls, path, structure_size):
1.154
1.155 """
1.156 - Write the declarations to 'f_decls' and definitions to 'f_defs' for
1.157 - the object having the given 'path', the given 'table_name', and the
1.158 - given 'structure_size', with 'structure' details used to populate the
1.159 - definition.
1.160 + Write a declaration to 'f_decls' for the object having the given 'path'
1.161 + and the given 'structure_size'.
1.162 """
1.163
1.164 - print >>f_decls, "extern __obj %s;\n" % encode_path(path)
1.165 -
1.166 # Write an instance-specific type definition for instances of classes.
1.167 # See: templates/types.h
1.168
1.169 @@ -425,11 +516,21 @@
1.170 unsigned int pos;
1.171 __attr attrs[%s];
1.172 } %s;
1.173 -""" % (structure_size, encode_symbol("obj", copy or path))
1.174 +""" % (structure_size, encode_symbol("obj", path))
1.175 +
1.176 + def write_structure(self, f_decls, f_defs, structure_name, table_name, structure_size, structure, path=None):
1.177
1.178 - # Write the corresponding definition.
1.179 + """
1.180 + Write the declarations to 'f_decls' and definitions to 'f_defs' for
1.181 + the object having the given 'structure_name', the given 'table_name',
1.182 + and the given 'structure_size', with 'structure' details used to
1.183 + populate the definition.
1.184 + """
1.185
1.186 - is_class = self.importer.get_object(path).has_kind("<class>")
1.187 + if f_decls:
1.188 + print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name)
1.189 +
1.190 + is_class = path and self.importer.get_object(path).has_kind("<class>")
1.191 pos = is_class and encode_symbol("pos", encode_type_attribute(path)) or "0"
1.192
1.193 print >>f_defs, """\
1.194 @@ -440,7 +541,7 @@
1.195 %s
1.196 }};
1.197 """ % (
1.198 - encode_path(copy or path), table_name, pos,
1.199 + encode_path(structure_name), table_name, pos,
1.200 ",\n ".join(structure))
1.201
1.202 def get_argument_limits(self, path):
1.203 @@ -595,6 +696,8 @@
1.204 else:
1.205 attr = attrs[attrname]
1.206
1.207 + # Special function pointer member.
1.208 +
1.209 if attrname == "__fn__":
1.210
1.211 # Provide bound method references and the unbound function
1.212 @@ -622,10 +725,19 @@
1.213 structure.append("{%s, .fn=%s}" % (bound_attr and ".b=&%s" % bound_attr or "0", attr))
1.214 continue
1.215
1.216 + # Special argument specification member.
1.217 +
1.218 elif attrname == "__args__":
1.219 structure.append("{.min=%s, .ptable=&%s}" % (attr, encode_tablename("Function", origin)))
1.220 continue
1.221
1.222 + # Special internal data member.
1.223 +
1.224 + elif attrname == "__data__":
1.225 + structure.append("{0, .%s=%s}" % (encode_literal_constant_member(attr),
1.226 + encode_literal_constant_value(attr)))
1.227 + continue
1.228 +
1.229 structure.append(self.encode_member(origin, attrname, attr, kind))
1.230
1.231 def encode_member(self, path, name, ref, structure_type):
1.232 @@ -650,6 +762,12 @@
1.233 constant_value = "const%d" % constant_number
1.234 return "{&%s, &%s} /* %s */" % (constant_value, constant_value, name)
1.235
1.236 + # Predefined constant references.
1.237 +
1.238 + if (path, name) in self.predefined_constant_members:
1.239 + attr_path = encode_predefined_reference("%s.%s" % (path, name))
1.240 + return "{&%s, &%s} /* %s */" % (attr_path, attr_path, name)
1.241 +
1.242 # General undetermined members.
1.243
1.244 if kind in ("<var>", "<instance>"):