source: proto/charsetcompiler/UCD/UCD_properties.py @ 4389

Last change on this file since 4389 was 4389, checked in by cameron, 5 years ago

Generating binary properties, reformatting

File size: 11.7 KB
RevLine 
[4146]1#
[4147]2# UCD_properties.py - parsing Unicode Character Database (UCD) files
3# and generating C headers for property data using a compact bitset
4# representation.
5#
6# Robert D. Cameron
[4389]7# January 2, 2015
[4147]8#
[4146]9# Licensed under Open Software License 3.0.
[4147]10#
11#
[4183]12import re, string, os.path, cformat
[4146]13from unicode_set import *
[4367]14from UCD_parser import *
[4146]15
16UCD_dir = "7.0.0"
[4150]17
18PropertyAliases_template = r"""
19namespace UCD {
[4153]20  enum property_t {
[4155]21%s
[4150]22  };
[4389]23  const std::vector<std::string> property_enum_name = {
24%s
25  };
[4186]26  const std::vector<std::string> property_full_name = {
[4155]27%s
[4154]28  };
[4172]29  const std::unordered_map<std::string, property_t> alias_map = {
[4155]30%s
[4154]31  };
[4150]32}
33"""
34
[4155]35PropertyValueAliases_template = r"""
36namespace UCD {
[4181]37  enum binary_value_t {N, Y};
[4155]38%s
[4181]39
40  const std::vector<std::string> value_name[] = {
41%s};
42
43  const std::unordered_map<std::string, int> property_value_alias_map[] = {
44%s};
45
[4155]46}
47"""
[4154]48
[4185]49EnumeratedProperty_template = r"""
[4381]50  namespace %s_ns {
[4185]51    enum value_t {
[4186]52      %s};
[4381]53    const std::vector<std::string> enum_names = {
54      %s};
[4186]55    const std::vector<std::string> value_names = {
56      %s};
[4387]57    const std::unordered_map<std::string, int> aliases_only_map = std::unordered_map<std::string, int> {
[4186]58      %s};
[4185]59  }
60"""
[4179]61
62   
[4185]63CodepointProperties = ['scf', 'slc', 'suc', 'stc']
64
[4186]65class UCD_generator():
[4367]66    def __init__(self):
[4389]67        self.supported_props = []
68        self.property_data_headers = []
69        self.missing_specs = {}
[4146]70
[4367]71    def load_property_name_info(self):
[4389]72        (self.property_enum_name_list, self.full_name_map, self.property_lookup_map, self.property_kind_map) = parse_PropertyAlias_txt()
[4186]73
[4363]74    def generate_PropertyAliases_h(self):
[4389]75        f = cformat.open_header_file_for_write('PropertyAliases')
76        cformat.write_imports(f, ["<string>", "<vector>", "<unordered_map>"])
77        enum_text = cformat.multiline_fill(self.property_enum_name_list, ',')
78        enum_text2 = cformat.multiline_fill(['"%s"' % e for e in self.property_enum_name_list], ',')
79        full_name_text = cformat.multiline_fill(['"%s"' % self.full_name_map[e] for e in self.property_enum_name_list], ',')
80        map_text = cformat.multiline_fill(['{"%s", %s}' % (k, self.property_lookup_map[k]) for k in sorted(self.property_lookup_map.keys())], ',')
81        f.write(PropertyAliases_template % (enum_text, enum_text2, full_name_text, map_text))
82        cformat.close_header_file(f)
[4186]83
[4367]84    def load_property_value_info(self):
[4389]85        (self.property_value_list, self.property_value_enum_integer, self.property_value_full_name_map, self.property_value_lookup_map, self.missing_specs) = parse_PropertyValueAlias_txt(self.property_lookup_map)
[4186]86
87
[4363]88    def generate_PropertyValueAliases_h(self):
[4389]89        f = cformat.open_header_file_for_write('PropertyValueAliases')
90        cformat.write_imports(f, ["<string>", "<unordered_map>", '"PropertyAliases.h"'])
91        f.write("namespace UCD {\n")
92        #  Generate the aliases for all Binary properties.
93        enum_text = cformat.multiline_fill(['N', 'Y'], ',', 6)
94        enum_names = cformat.multiline_fill(['"N"', '"Y"'], ',', 6)
95        full_name_text = cformat.multiline_fill(['"No"', '"Yes"'], ',', 6)
96        binary_map_text = cformat.multiline_fill(['{"n", N}', '{"y", Y}', '{"no", N}', '{"yes", Y}', '{"f", N}', '{"t", Y}', '{"false", N}', '{"true", Y}'], ',', 6)
97        f.write(EnumeratedProperty_template % ('Binary', enum_text, enum_names, full_name_text, binary_map_text))
98        #
99        for p in self.property_enum_name_list:
100           if self.property_value_list.has_key(p):
101              if not self.property_kind_map[p] == 'Binary':
102                  enum_text = cformat.multiline_fill(self.property_value_list[p], ',', 6)
103                  enum_names = cformat.multiline_fill(['"%s"' % s for s in self.property_value_list[p]], ',', 6)
104                  if p == 'ccc': # Special case: add numeric value information for ccc.
105                      enum_text += r"""
[4363]106        };
107        const uint8_t enum_val[] = {
108    """
[4389]109                      enum_text += "      " + cformat.multiline_fill(["%s" % (self.property_value_enum_integer[p][e]) for e in self.property_value_list['ccc']], ',', 6)
110                  full_names = [self.property_value_full_name_map[p][e] for e in self.property_value_list[p]]
111                  full_name_text = cformat.multiline_fill(['"%s"' % name for name in full_names], ',', 6)
112                  canon_full_names = [canonicalize(name) for name in full_names]
113                  canon_enums = [canonicalize(e) for e in self.property_value_list[p]]
114                  canon_keys = [canonicalize(k) for k in self.property_value_lookup_map[p].keys()]
115                  aliases_only = [k for k in canon_keys if not k in canon_enums + canon_full_names]
116                  map_text = cformat.multiline_fill(['{"%s", %s_ns::%s}' % (k, p.upper(), self.property_value_lookup_map[p][k]) for k in sorted(aliases_only)], ',', 6)
117                  f.write(EnumeratedProperty_template % (p.upper(), enum_text, enum_names, full_name_text, map_text))
118        f.write("}\n")
119        cformat.close_header_file(f)
[4186]120
[4363]121 
[4365]122    def generate_property_value_file(self, filename_root, property_code, default_value = None):
[4389]123        vlist = self.property_value_list[property_code]
124        canon_map = self.property_value_lookup_map[property_code]
125        (prop_values, value_map) = parse_UCD_enumerated_property_map(property_code, vlist, canon_map, filename_root + '.txt', default_value)
126        basename = os.path.basename(filename_root)
127        f = cformat.open_header_file_for_write(os.path.basename(filename_root))
128        cformat.write_imports(f, ["<vector>", '"unicode_set.h"', '"PropertyAliases.h"', '"PropertyValueAliases.h"'])
129        f.write("\nnamespace UCD {\n")
130        f.write("  namespace %s_ns {\n" % property_code.upper())
131        for v in self.property_value_list[property_code]:
132            f.write("    const UnicodeSet %s_Set \n" % v.lower())
133            f.write(value_map[v].showC(6) + ";\n")
134        print "%s: %s bytes" % (basename, sum([value_map[v].bytes() for v in value_map.keys()]))
135        set_list = ['%s_Set' % v.lower() for v in self.property_value_list[property_code]]
136        f.write("    EnumeratedPropertyObject property_object\n")
137        f.write("      {%s,\n" % property_code)
138        f.write("       %s_ns::enum_names,\n" % property_code.upper())
139        f.write("       %s_ns::value_names,\n" % property_code.upper())
140        f.write("       %s_ns::aliases_only_map,\n" % property_code.upper())
141        f.write("       {")
142        f.write(cformat.multiline_fill(set_list, ',', 8))
143        f.write("\n       }};\n  }\n}\n")
144        cformat.close_header_file(f)
145        self.supported_props.append(property_code)
146        self.property_data_headers.append(basename)
[4186]147
[4363]148    def generate_ScriptExtensions_h(self):
[4389]149        filename_root = 'ScriptExtensions'
150        property_code = 'scx'
151        (prop_values, value_map) = parse_ScriptExtensions_txt(self.property_value_list['sc'], self.property_value_lookup_map['sc'])
152        basename = os.path.basename(filename_root)
153        f = cformat.open_header_file_for_write(basename)
154        cformat.write_imports(f, ["<vector>", '"PropertyAliases.h"', '"PropertyValueAliases.h"', '"unicode_set.h"'])
155        f.write("\nnamespace UCD {\n")
156        f.write("  namespace SCX_ns {\n")
157        for v in self.property_value_list['sc']:
158            f.write("    const UnicodeSet %s_Ext \n" % v.lower())
159            f.write(value_map[v].showC(6) + ";\n")
160        print "%s: %s bytes" % (basename, sum([value_map[v].bytes() for v in value_map.keys()]))
161        set_list = ['%s_Ext' % v.lower() for v in self.property_value_list['sc']]
162        f.write("    EnumeratedPropertyObject property_object\n")
163        f.write("      {%s,\n" % property_code)
164        f.write("       SC_ns::enum_names,\n")
165        f.write("       SC_ns::value_names,\n")
166        f.write("       SC_ns::aliases_only_map,\n")
167        f.write("       {")
168        f.write(cformat.multiline_fill(set_list, ',', 8))
169        f.write("\n       }};\n  }\n}\n")
170        cformat.close_header_file(f)
171        self.supported_props.append('property_code')
172        self.property_data_headers.append(basename)
[4186]173
174
[4363]175    def generate_binary_properties_file(self, filename_root):
[4389]176        (props, prop_map) = parse_UCD_codepoint_name_map(filename_root + '.txt', self.property_lookup_map)
177        basename = os.path.basename(filename_root)
178        f = cformat.open_header_file_for_write(basename)
179        cformat.write_imports(f, ["<vector>", '"unicode_set.h"', '"PropertyAliases.h"'])
180        f.write("\nnamespace UCD {\n")
181        print "%s: %s bytes" % (basename, sum([prop_map[p].bytes() for p in prop_map.keys()]))
182        for p in sorted(props):
183            f.write("  namespace %s_ns {\n    const UnicodeSet codepoint_set \n" % p.upper())
184            f.write(prop_map[p].showC(6) + ";\n")
185            f.write("    BinaryPropertyObject property_object{%s, codepoint_set};\n  }\n" % p)
186        f.write("}\n\n")
187        cformat.close_header_file(f)
188        self.supported_props += props
189        self.property_data_headers.append(basename)
[4186]190
[4363]191    def generate_PropertyObjectTable_h(self):
[4389]192        f = cformat.open_header_file_for_write('PropertyObjectTable')
193        cformat.write_imports(f, ['"PropertyObjects.h"', '"PropertyAliases.h"'])
194        cformat.write_imports(f, ['"%s.h"' % fname for fname in self.property_data_headers])
195        f.write("\nnamespace UCD {\n")
196        objlist = []
197        for p in self.property_enum_name_list:
198            k = self.property_kind_map[p]
199            if (k == 'Enumerated' or k == 'Catalog') and p in self.supported_props:
200                objlist.append("&%s_ns::property_object" % p.upper())
201            elif k == 'String':
202                if p in CodepointProperties:
203                    objlist.append("new UnsupportedPropertyObject(%s, CodepointProperty)" % p)
204                else:
205                    objlist.append("new UnsupportedPropertyObject(%s, StringProperty)" % p)
206            elif k == 'Binary' and p in self.supported_props:
207                objlist.append("&%s_ns::property_object" % p.upper())
[4363]208            else:
[4389]209                objlist.append("new UnsupportedPropertyObject(%s, %sProperty)" % (p, k))
210        f.write("\n  PropertyObject* property_object_table[] = {\n    ")
211        f.write(",\n    ".join(objlist) + '  };\n}\n')
212        cformat.close_header_file(f)
[4186]213
[4363]214
215
[4179]216def UCD_main():
[4389]217    ucd = UCD_generator()
[4186]218
[4389]219    # First parse all property names and their aliases
220    ucd.load_property_name_info()
221    #
222    # Generate the PropertyAliases.h file to define all the Unicode property_t enum
223    # and the basic property information.
224    ucd.generate_PropertyAliases_h()
225    #
226    # Next parse all property value names and their aliases.  Generate the data.
227    ucd.load_property_value_info()
228    ucd.generate_PropertyValueAliases_h()
229    #
230    # The Block property
231    ucd.generate_property_value_file('Blocks', 'blk')
232    #
233    # Scripts
234    ucd.generate_property_value_file('Scripts', 'sc')
235    #
236    # Script Extensions
237    ucd.generate_ScriptExtensions_h()
238    #
239    # General Category
240    ucd.generate_property_value_file('extracted/DerivedGeneralCategory', 'gc')
241    #
242    # Binary properties from PropList.txt
243    ucd.generate_binary_properties_file('PropList')
244    #
245    # Binary properties from DerivedCoreProperties.txt
246    ucd.generate_binary_properties_file('DerivedCoreProperties')
247    #
248    #
249    # LineBreak types
250    ucd.generate_property_value_file('LineBreak', 'lb')
251    #
252    # East Asian Width
253    ucd.generate_property_value_file('EastAsianWidth', 'ea')
254    #
255    # Hangul Syllable Type
256    ucd.generate_property_value_file('HangulSyllableType', 'hst')
257    #
258    # Jamo Short Name - AAARGH - property value for 110B is an empty string!!!!!  - Not in PropertyValueAliases.txt
259    # ucd.generate_property_value_file('Jamo', 'jsn')
260    #
261    # Stubs
262    #
263    ucd.generate_PropertyObjectTable_h()
[4179]264
[4180]265if __name__ == "__main__":
266  UCD_main()
Note: See TracBrowser for help on using the repository browser.