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

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

Updated generator files for new predefined property support

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