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

Last change on this file since 4375 was 4375, checked in by cameron, 4 years ago

Update to UCD 7.0.0, have UCD parsers return totally-defined value maps

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