source: icGREP/icgrep-devel/UCD-scripts/UCD_properties.py @ 5735

Last change on this file since 5735 was 5686, checked in by cameron, 19 months ago

Update to UCD 10.0.0

File size: 29.1 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# January 2, 2015
8#
9# Licensed under Open Software License 3.0.
10#
11#
12import re, string, os.path, cformat, UCD_config
13from unicode_set import *
14from UCD_parser import *
15from UCD_property_objects import *
16
17PropertyAliases_template = r"""
18namespace UCD {
19    enum property_t {
20        %s};
21    const static std::vector<std::string> property_enum_name = {
22        %s};
23    const static std::vector<std::string> property_full_name = {
24        %s};
25    static std::unordered_map<std::string, int> alias_map {{
26        %s}};
27}
28"""
29
30EnumeratedProperty_template = r"""
31    namespace %s_ns {
32        enum value_t {
33            %s};
34        const static std::vector<std::string> enum_names = {
35            %s};
36        const static std::vector<std::string> value_names = {
37            %s};
38        static std::unordered_map<std::string, int> aliases_only_map {{
39            %s}};
40    }
41"""
42
43def emit_string_property(f, property_code, null_set, reflexive_set, cp_value_map):
44    s = string.Template(r"""    namespace ${prop_enum_up}_ns {
45        /** Code Point Ranges for ${prop_enum} mapping to <none>
46        ${null_set_ranges}**/
47
48        const UnicodeSet null_codepoint_set
49        ${null_set_value};
50
51        /** Code Point Ranges for ${prop_enum} mapping to <codepoint>
52        ${reflexive_set_ranges}**/
53        const UnicodeSet reflexive_set
54        ${reflexive_set_value};
55
56        const unsigned buffer_length = ${buffer_length};
57        const static char __attribute__ ((aligned (32))) string_buffer[${allocation_length}] = u8R"__(${string_buffer})__";
58
59        const static std::vector<codepoint_t> defined_cps = {
60        ${explicitly_defined_cps}};
61        static StringPropertyObject property_object(${prop_enum},
62                                                    null_codepoint_set,
63                                                    reflexive_set,
64                                                    static_cast<const char *>(string_buffer),
65                                                    buffer_length,
66                                                    defined_cps);
67    }
68""")
69    cps = sorted(cp_value_map.keys())
70    string_buffer = ""
71    for cp in cps: 
72        string_buffer += cp_value_map[cp] + "\n"
73    buffer_length = len(string_buffer.encode("utf-8"))
74    f.write(s.substitute(prop_enum = property_code,
75    prop_enum_up = property_code.upper(),
76    string_buffer = string_buffer,
77    buffer_length = buffer_length,
78    allocation_length = (buffer_length + 255) & -256,
79    null_set_ranges = cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(null_set)], ',', 8),
80    null_set_value = null_set.showC(12),
81    reflexive_set_ranges = cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(reflexive_set)], ',', 8),
82    reflexive_set_value = reflexive_set.showC(12),
83    explicitly_defined_cp_count = len(cps),
84    explicitly_defined_cps = cformat.multiline_fill(['0x%04x' % cp for cp in cps], ',', 8)
85    ))
86
87def emit_string_override_property(f, property_code, overridden_code, override_set, cp_value_map):
88    s = string.Template(r"""    namespace ${prop_enum_up}_ns {
89        /** Code Point Ranges for ${prop_enum} (possibly overriding values from ${overridden})
90        ${overridden_set_ranges}**/
91
92        const UnicodeSet explicitly_defined_set
93        ${overridden_set_value};
94
95        const unsigned buffer_length = ${buffer_length};
96        const static char __attribute__ ((aligned (32))) string_buffer[${allocation_length}] = u8R"__(${string_buffer})__";
97
98        const static std::vector<codepoint_t> defined_cps = {
99        ${explicitly_defined_cps}};
100        static StringOverridePropertyObject property_object(${prop_enum},
101                                                    ${overridden}_ns::property_object,
102                                                    explicitly_defined_set,
103                                                    static_cast<const char *>(string_buffer),
104                                                    buffer_length,
105                                                    defined_cps);
106    }
107""")
108    cps = sorted(cp_value_map.keys())
109    string_buffer = ""
110    for cp in cps: 
111        string_buffer += cp_value_map[cp] + "\n"
112    buffer_length = len(string_buffer.encode("utf-8"))
113    f.write(s.substitute(prop_enum = property_code,
114    prop_enum_up = property_code.upper(),
115    overridden = overridden_code.upper(),
116    string_buffer = string_buffer,
117    buffer_length = buffer_length,
118    allocation_length = (buffer_length + 255) & -256,
119    overridden_set_ranges = cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(override_set)], ',', 8),
120    overridden_set_value = override_set.showC(12),
121    explicitly_defined_cp_count = len(cps),
122    explicitly_defined_cps = cformat.multiline_fill(['0x%04x' % cp for cp in cps], ',', 8)
123    ))
124
125def emit_numeric_property(f, property_code, NaN_set, cp_value_map):
126    s = string.Template(r"""    namespace ${prop_enum_up}_ns {
127        /** Code Point Ranges for ${prop_enum} mapping to NaN
128        ${NaN_set_ranges}**/
129
130        const UnicodeSet NaN_set
131        ${NaN_set_value};
132
133       const unsigned buffer_length = ${buffer_length};
134        const static char __attribute__ ((aligned (32))) string_buffer[${allocation_length}] = u8R"__(${string_buffer})__";
135
136        const static std::vector<codepoint_t> defined_cps = {
137        ${explicitly_defined_cps}};
138        static NumericPropertyObject property_object(${prop_enum},
139                                                    NaN_set,
140                                                    static_cast<const char *>(string_buffer),
141                                                    buffer_length,
142                                                    defined_cps);
143    }
144""")
145    cps = sorted(cp_value_map.keys())
146    string_buffer = ""
147    for cp in cps: 
148        string_buffer += cp_value_map[cp] + "\n"
149    string_buffer += "NaN\n"  # This inserts the standard default value for strings as the last entry
150    buffer_length = len(string_buffer.encode("utf-8"))
151    f.write(s.substitute(prop_enum = property_code,
152    prop_enum_up = property_code.upper(),
153    string_buffer = string_buffer,
154    buffer_length = buffer_length,
155    allocation_length = (buffer_length + 255) & -256,
156    NaN_set_ranges = cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(NaN_set)], ',', 8),
157    NaN_set_value = NaN_set.showC(12),
158    explicitly_defined_cp_count = len(cps),
159    explicitly_defined_cps = cformat.multiline_fill(['0x%04x' % cp for cp in cps], ',', 8)
160    ))
161
162
163def emit_binary_property(f, property_code, property_set):
164    f.write("    namespace %s_ns {\n" % property_code.upper())
165    f.write("        /** Code Point Ranges for %s\n        " % property_code)
166    f.write(cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(property_set)], ',', 8))
167    f.write("**/\n")
168    f.write("        const UnicodeSet codepoint_set \n")
169    f.write(property_set.showC(12) + ";\n")
170    f.write("        static BinaryPropertyObject property_object{%s, codepoint_set};\n    }\n" % property_code)
171
172def emit_enumerated_property(f, property_code, independent_prop_values, prop_values, value_map):
173    f.write("  namespace %s_ns {\n" % property_code.upper())
174    f.write("    const unsigned independent_prop_values = %s;\n" % independent_prop_values)
175    for v in prop_values:
176        f.write("    /** Code Point Ranges for %s\n    " % v)
177        f.write(cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(value_map[v])], ',', 4))
178        f.write("**/\n")
179        f.write("    const UnicodeSet %s_Set \n" % v.lower())
180        f.write(value_map[v].showC(8) + ";\n")
181    set_list = ['&%s_Set' % v.lower() for v in prop_values]
182    f.write("    static EnumeratedPropertyObject property_object\n")
183    f.write("        {%s,\n" % property_code)
184    f.write("         %s_ns::independent_prop_values,\n" % property_code.upper())
185    f.write("         %s_ns::enum_names,\n" % property_code.upper())
186    f.write("         %s_ns::value_names,\n" % property_code.upper())
187    f.write("         %s_ns::aliases_only_map,\n" % property_code.upper())
188    f.write("         {")
189    f.write(cformat.multiline_fill(set_list, ',', 8))
190    f.write("\n         }};\n    }\n")
191
192def emit_Obsolete_property(f, property_code):
193    s = string.Template(r"""    namespace ${prop_enum_up}_ns {
194        static ObsoletePropertyObject property_object(${prop_enum});
195    }
196""")
197    f.write(s.substitute(prop_enum = property_code, prop_enum_up = property_code.upper()))
198
199
200def simple_CaseClosure_map(fold_data):
201   simpleFoldMap = {}
202   for k in fold_data['S'].keys(): simpleFoldMap[k] = int(fold_data['S'][k], 16)
203   for k in fold_data['C'].keys(): simpleFoldMap[k] = int(fold_data['C'][k], 16)
204   cl_map = {}
205   for k in simpleFoldMap.keys():
206      v = simpleFoldMap[k]
207      if not v in cl_map: cl_map[v] = [k]
208      else: cl_map[v].append(k)
209      if not k in cl_map: cl_map[k] = [v]
210      else: cl_map[k].append(v)
211   newEntries = True
212   while newEntries:
213      newEntries = False
214      for k in cl_map.keys():
215         vlist = cl_map[k]
216         for v in vlist:
217            for w in cl_map[v]:
218               if k != w and not k in cl_map[w]:
219                  cl_map[w].append(k)
220                  newEntries = True
221   return cl_map
222
223#
224# Simple case fold map.     
225# The simple case fold map is an ordered list of fold entries each of
226# the form (lo_codepoint, hicodepoint, offset).  Each entry describes
227# the case fold that applies for the consecutive entries in the given
228# codepoint range, according to the following equations. 
229# casefold(x) = x + offset, if ((x - low_codepoint) div offset) mod 2 = 0
230#             = x - offset, if ((x - low_codepoint) div offset) mod 2 = 1
231#
232#
233def caseFoldRangeMap(casemap):
234   foldable = sorted(casemap.keys())
235   entries = []
236   cp = foldable[0]
237   open_entries = [(cp, f - cp) for f in casemap[cp]]
238   last_cp = cp
239   for cp in foldable[1:]:
240      if cp != last_cp + 1:
241         # Close the pending range entries
242         for (cp0, offset) in open_entries:
243            entries.append((cp0, last_cp, offset))
244         open_entries = [(cp, f - cp) for f in casemap[cp]]
245      else:
246         new_open = []
247         projected = []
248         for (cp0, offset) in open_entries:
249            even_odd_offset_group = int(abs(cp - cp0)/ abs(offset)) & 1
250            if even_odd_offset_group == 0: 
251               projected_foldcp = cp + offset
252            else: projected_foldcp = cp - offset
253            if not projected_foldcp in casemap[cp]:
254               entries.append((cp0, last_cp, offset))
255            else:
256               new_open.append((cp0, offset))
257               projected.append(projected_foldcp)
258         open_entries = new_open
259         for f in casemap[cp]:
260            if not f in projected:
261               open_entries.append((cp, f-cp))
262      last_cp = cp
263   # Close the final entries.
264   for (cp0, offset) in open_entries:
265      entries.append((cp0, last_cp, offset))
266   return entries
267
268
269
270def genFoldEntryData(casemap):
271   rMap = caseFoldRangeMap(casemap)
272   individuals = [(m[0],m[0]+m[2]) for m in rMap if m[0] == m[1]]
273   ranges = [m for m in rMap if m[0] != m[1]]
274   last_hi = -1
275   generated = "const FoldEntry foldTable[foldTableSize] = {\n"
276   foldTableSize = 0
277   for (lo, hi, offset) in ranges:
278      if lo != last_hi + 1:
279         pairs = ["{0x%x, 0x%x}" % (m[0], m[1]) for m in individuals if m[0]>last_hi and m[0]< lo]
280         generated += "  {0x%x, 0, {" % (last_hi + 1) + cformat.multiline_fill(pairs) + "}},\n"
281         foldTableSize += 1
282      last_hi = hi
283      pairs = ["{0x%x, 0x%x}" % (m[0], m[1]) for m in individuals if m[0]>=lo and m[0]<= hi]
284      generated += "  {0x%x, %i, {" % (lo, offset) + cformat.multiline_fill(pairs) + "}},\n"
285      foldTableSize += 1
286   if last_hi != 0x10FFFF:
287      pairs = ["{0x%x, 0x%x}" % (m[0], m[1]) for m in individuals if m[0]>last_hi]
288      generated += "  {0x%x, 0, {" % (last_hi + 1) + cformat.multiline_fill(pairs) + "}},\n"
289      foldTableSize += 1
290   generated += "  {0x110000, 0, {}}};"
291   foldTableSize += 1
292   generated = "\nconst int foldTableSize = %s;\n\n" % foldTableSize  + generated
293   return generated
294
295foldDeclarations = r"""
296typedef unsigned codepoint_t;
297
298struct FoldEntry {
299    re::codepoint_t range_lo;
300    int fold_offset;
301    std::vector<re::interval_t> fold_pairs;
302};
303
304
305void caseInsensitiveInsertRange(re::CC * cc, const re::codepoint_t lo, const re::codepoint_t hi);
306
307inline void caseInsensitiveInsert(re::CC * cc, const re::codepoint_t cp) {
308    caseInsensitiveInsertRange(cc, cp, cp);
309}
310"""
311
312
313class UCD_generator():
314    def __init__(self):
315        self.supported_props = []
316        self.property_data_headers = []
317        self.missing_specs = {}
318        self.binary_properties = {}
319
320    def load_property_name_info(self):
321        (self.property_enum_name_list, self.property_object_map) = parse_PropertyAlias_txt()
322        self.property_lookup_map = getPropertyLookupMap(self.property_object_map)
323        self.full_name_map = {}
324        for p in self.property_enum_name_list:
325            self.full_name_map[p] = self.property_object_map[p].getPropertyFullName()
326
327
328    def generate_PropertyAliases_h(self):
329        f = cformat.open_header_file_for_write('PropertyAliases')
330        cformat.write_imports(f, ["<string>", "<unordered_map>", "<vector>"])
331        enum_text = cformat.multiline_fill(self.property_enum_name_list, ',', 8)
332        enum_text2 = cformat.multiline_fill(['"%s"' % e for e in self.property_enum_name_list], ',', 8)
333        full_name_text = cformat.multiline_fill(['"%s"' % self.full_name_map[e] for e in self.property_enum_name_list], ',', 8)
334        map_text = cformat.multiline_fill(['{"%s", %s}' % (k, self.property_lookup_map[k]) for k in sorted(self.property_lookup_map.keys())], ',', 8)
335        f.write(PropertyAliases_template % (enum_text, enum_text2, full_name_text, map_text))
336        cformat.close_header_file(f)
337
338    def load_property_value_info(self):
339        initializePropertyValues(self.property_object_map, self.property_lookup_map)
340
341    def generate_PropertyValueAliases_h(self):
342        f = cformat.open_header_file_for_write('PropertyValueAliases')
343        cformat.write_imports(f, ['"PropertyAliases.h"', "<vector>", "<unordered_map>", "<string>"])
344        f.write("namespace UCD {\n")
345        #  Generate the aliases for all Binary properties.
346        enum_text = cformat.multiline_fill(['N', 'Y'], ',', 12)
347        enum_names = cformat.multiline_fill(['"N"', '"Y"'], ',', 12)
348        full_name_text = cformat.multiline_fill(['"No"', '"Yes"'], ',', 12)
349        binary_properties = ['{"n", N}', '{"y", Y}', '{"no", N}', '{"yes", Y}', '{"f", N}', '{"t", Y}', '{"false", N}', '{"true", Y}']
350        binary_map_text = cformat.multiline_fill(binary_properties, ',', 12)
351        f.write(EnumeratedProperty_template % ('Binary', enum_text, enum_names, full_name_text, binary_map_text))
352        #
353        for p in self.property_enum_name_list:
354            po = self.property_object_map[p]
355            if isinstance(po, EnumeratedPropertyObject):
356                ordered_enum_list = po.property_value_list
357                enum_text = cformat.multiline_fill(ordered_enum_list, ',', 12)
358                enum_names = cformat.multiline_fill(['"%s"' % s for s in ordered_enum_list], ',', 12)
359                if p == 'ccc': # Special case: add numeric value information for ccc.
360                    enum_text += r"""
361        };
362        const uint16_t enum_val[] = {
363        """
364                    enum_text += "      " + cformat.multiline_fill(["%s" % (po.property_value_enum_integer[e]) for e in ordered_enum_list], ',', 12)
365                full_names = [po.property_value_full_name_map[e] for e in ordered_enum_list]
366                full_name_text = cformat.multiline_fill(['"%s"' % name for name in full_names], ',', 12)
367                canon_full_names = [canonicalize(name) for name in full_names]
368                canon_enums = [canonicalize(e) for e in ordered_enum_list]
369                canon_keys = [canonicalize(k) for k in po.property_value_lookup_map.keys()]
370                aliases_only = []
371                for k in canon_keys:
372                    if k in canon_enums: continue
373                    if k in canon_full_names: continue
374                    if k in aliases_only: continue
375                    aliases_only.append(k)
376                map_text = cformat.multiline_fill(['{"%s", %s_ns::%s}' % (k, p.upper(), po.property_value_lookup_map[k]) for k in sorted(aliases_only)], ',', 12)
377                f.write(EnumeratedProperty_template % (p.upper(), enum_text, enum_names, full_name_text, map_text))
378        f.write("}\n")
379        cformat.close_header_file(f)
380
381    def emit_property(self, f, property_code):
382        property_object = self.property_object_map[property_code]
383        if isinstance(property_object, BinaryPropertyObject):
384            emit_binary_property(f, property_code, property_object.value_map['Y'])
385            print("%s: %s bytes" % (property_object.getPropertyFullName(), property_object.value_map['Y'].bytes()))
386        elif isinstance(property_object, EnumeratedPropertyObject):
387            prop_values = property_object.name_list_order
388            independent_prop_values = property_object.independent_prop_values
389            emit_enumerated_property(f, property_code, independent_prop_values, prop_values, property_object.value_map)
390            print("%s: %s bytes" % (property_object.getPropertyFullName(), sum([property_object.value_map[v].bytes() for v in property_object.value_map.keys()])))
391        elif isinstance(property_object, StringPropertyObject):
392            emit_string_property(f, property_code, property_object.null_str_set, property_object.reflexive_set, property_object.cp_value_map)
393        elif isinstance(property_object, StringOverridePropertyObject):
394            emit_string_override_property(f, property_code, property_object.overridden_code, property_object.overridden_set, property_object.cp_value_map)
395        elif isinstance(property_object, NumericPropertyObject):
396            emit_numeric_property(f, property_code, property_object.NaN_set, property_object.cp_value_map)
397        elif isinstance(property_object, ObsoletePropertyObject):
398            emit_Obsolete_property(f, property_code)
399        else: 
400            print("%s: unsupported property.")
401            return
402        self.supported_props.append(property_code)
403
404    def generate_property_value_file(self, filename_root, property_code):
405        property_object = self.property_object_map[property_code]
406        parse_property_data(self.property_object_map[property_code], filename_root + '.txt')
407        basename = os.path.basename(filename_root)
408        f = cformat.open_header_file_for_write(basename)
409        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"unicode_set.h"'])
410        f.write("\nnamespace UCD {\n")
411        self.emit_property(f, property_code)
412        f.write("}\n")
413        cformat.close_header_file(f)
414        self.property_data_headers.append(basename)
415
416    def generate_multisection_properties_file(self, filename_root):
417        props = parse_multisection_property_data(filename_root + '.txt', self.property_object_map, self.property_lookup_map)
418        #(props, prop_map) = parse_UCD_codepoint_name_map(filename_root + '.txt', self.property_lookup_map)
419        basename = os.path.basename(filename_root)
420        f = cformat.open_header_file_for_write(basename)
421        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"unicode_set.h"'])
422        f.write("\nnamespace UCD {\n")
423        for p in sorted(props):
424            self.emit_property(f, p)
425            property_object = self.property_object_map[p]
426        f.write("}\n\n")
427        cformat.close_header_file(f)
428        self.property_data_headers.append(basename)
429
430    def generate_multicolumn_properties_file(self, filename_root, prop_code_list):
431        props = parse_multicolumn_property_data(filename_root + '.txt', self.property_object_map, self.property_lookup_map, prop_code_list)
432        #(props, prop_map) = parse_UCD_codepoint_name_map(filename_root + '.txt', self.property_lookup_map)
433        basename = os.path.basename(filename_root)
434        f = cformat.open_header_file_for_write(basename)
435        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"unicode_set.h"'])
436        f.write("\nnamespace UCD {\n")
437        for p in prop_code_list:
438            if p in self.property_object_map: self.emit_property(f, p)
439        f.write("}\n\n")
440        cformat.close_header_file(f)
441        self.property_data_headers.append(basename)
442
443    def generate_UnicodeData_h(self):
444        basename = 'UnicodeData'
445        parse_UnicodeData_txt(self.property_object_map)
446        f = cformat.open_header_file_for_write(basename)
447        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"unicode_set.h"'])
448        prop_code_list = ['na', 'dm', 'suc', 'slc', 'stc', 'na1', 'isc', 'nv']
449        f.write("\nnamespace UCD {\n")
450        for p in prop_code_list:
451            self.emit_property(f, p)
452            property_object = self.property_object_map[p]
453        f.write("}\n\n")
454        cformat.close_header_file(f)
455        self.property_data_headers.append(basename)
456
457    def generate_SpecialCasing_h(self):
458        basename = 'SpecialCasing'
459        parse_SpecialCasing_txt(self.property_object_map)
460        f = cformat.open_header_file_for_write(basename)
461        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"UnicodeData.h"', '"unicode_set.h"'])
462        f.write("\nnamespace UCD {\n")
463        for p in ['lc', 'uc', 'tc']:
464            self.emit_property(f, p)
465            property_object = self.property_object_map[p]
466        f.write("}\n\n")
467        cformat.close_header_file(f)
468        self.property_data_headers.append(basename)
469
470    def generate_ScriptExtensions_h(self):
471        filename_root = 'ScriptExtensions'
472        property_code = 'scx'
473        extension_object = self.property_object_map['scx']
474        extension_object.setBaseProperty(self.property_object_map['sc'])
475        parse_property_data(extension_object, filename_root+'.txt')
476        basename = os.path.basename(filename_root)
477        f = cformat.open_header_file_for_write(basename)
478        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"unicode_set.h"'])
479        prop_list = self.property_object_map['sc'].name_list_order
480        value_map = extension_object.value_map
481        f.write("\nnamespace UCD {\n")
482        f.write("    namespace SCX_ns {\n")
483        for v in prop_list:
484            f.write("        /** Code Point Ranges for %s\n        " % v)
485            f.write(cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(value_map[v])], ',', 8))
486            f.write("**/\n")
487            f.write("        const UnicodeSet %s_Ext \n" % v.lower())
488            f.write(value_map[v].showC(12) + ";\n")
489        set_list = ['&%s_Ext' % v.lower() for v in prop_list]
490        f.write("        static ExtensionPropertyObject property_object\n")
491        f.write("       {%s,\n" % property_code)
492        f.write("        UCD::sc,\n")
493        f.write("       {")
494        f.write(cformat.multiline_fill(set_list, ',', 8))
495        f.write("\n        }};\n    }\n}\n")
496        cformat.close_header_file(f)
497        print("%s: %s bytes" % (basename, sum([value_map[v].bytes() for v in value_map.keys()])))
498        self.supported_props.append(property_code)
499        self.property_data_headers.append(basename)
500
501    def generate_PropertyObjectTable_h(self):
502        f = cformat.open_header_file_for_write('PropertyObjectTable')
503        cformat.write_imports(f, ['"PropertyObjects.h"', '"PropertyAliases.h"', '<array>'])
504        cformat.write_imports(f, ['"%s.h"' % fname for fname in self.property_data_headers])
505        f.write("\nnamespace UCD {\n")
506        objlist = []
507        for p in self.property_enum_name_list:
508            k = self.property_object_map[p].getPropertyKind()
509            if p in self.supported_props:
510                objlist.append("&%s_ns::property_object" % p.upper())
511            else:
512                objlist.append("new UnsupportedPropertyObject(%s, PropertyObject::ClassTypeId::%sProperty)" % (p, k))
513        f.write("\n  const std::array<PropertyObject *, %i> property_object_table = {{\n    " % len(objlist))
514        f.write(",\n    ".join(objlist) + '  }};\n}\n')
515        cformat.close_header_file(f)
516
517    def generate_UCD_Config_h(self):
518        setVersionfromReadMe_txt()
519        f = cformat.open_header_file_for_write('UCD_Config')
520        f.write("\nnamespace UCD {\n")
521        f.write("   const std::string UnicodeVersion = \"%s\";\n" % UCD_config.version)
522        f.write("}\n")
523        cformat.close_header_file(f)
524
525
526    def genCaseFolding_h(self):
527        basename = 'CaseFolding'
528        fold_data = parse_CaseFolding_txt(self.property_object_map)
529        cm = simple_CaseClosure_map(fold_data)
530        f = cformat.open_header_file_for_write(basename, 'casefold.py')
531        cformat.write_imports(f, ['"PropertyAliases.h"', '"PropertyObjects.h"', '"PropertyValueAliases.h"', '"unicode_set.h"', "<vector>", '"re/re_cc.h"'])
532        f.write(foldDeclarations)
533        f.write(genFoldEntryData(cm))
534        f.write("\nnamespace UCD {\n")
535        self.emit_property(f, 'scf')
536        self.emit_property(f, 'cf')
537        f.write("}\n")
538        cformat.close_header_file(f)
539        self.supported_props.append(['scf', 'cf'])
540        self.property_data_headers.append(basename)
541
542
543
544def UCD_main():
545    ucd = UCD_generator()
546
547    # First parse all property names and their aliases
548    ucd.load_property_name_info()
549    #
550    # Generate the PropertyAliases.h file to define all the Unicode property_t enum
551    # and the basic property information.
552    ucd.generate_PropertyAliases_h()
553    #
554    # Next parse all property value names and their aliases.  Generate the data.
555    ucd.load_property_value_info()
556
557    ucd.generate_UnicodeData_h()
558   
559    ucd.generate_SpecialCasing_h()
560   
561    ucd.genCaseFolding_h()
562   
563    ucd.generate_multicolumn_properties_file('NameAliases', ['Name_Alias', 'Alias_Kind'])
564
565    #
566    # The Age property
567    ucd.generate_property_value_file('DerivedAge', 'age')
568    #
569    # The Block property
570    ucd.generate_property_value_file('Blocks', 'blk')
571   
572    # Scripts
573    ucd.generate_property_value_file('Scripts', 'sc')
574    #
575    # # Script Extensions
576    ucd.generate_ScriptExtensions_h()
577    # #
578    # General Category
579    ucd.generate_property_value_file('extracted/DerivedGeneralCategory', 'gc')
580   
581    # Binary properties from PropList.txt
582    ucd.generate_multisection_properties_file('PropList')
583   
584    # Binary properties from DerivedCoreProperties.txt
585    ucd.generate_multisection_properties_file('DerivedCoreProperties')
586    #
587    #
588    # LineBreak types
589    #ucd.generate_property_value_file('extracted/DerivedLineBreak', 'lb')
590    ucd.generate_property_value_file('LineBreak', 'lb')
591    #
592    # Grapheme Cluster Break property
593    ucd.generate_property_value_file('auxiliary/GraphemeBreakProperty', 'GCB')
594    #
595    # Sentence Break property
596    ucd.generate_property_value_file('auxiliary/SentenceBreakProperty', 'SB')
597    #
598    # Word Break property
599    ucd.generate_property_value_file('auxiliary/WordBreakProperty', 'WB')
600    #
601    # Vertical orientation property
602    ucd.generate_property_value_file('VerticalOrientation', 'vo')
603
604    # East Asian Width - can use either source
605    ucd.generate_property_value_file('EastAsianWidth', 'ea')
606    #ucd.generate_property_value_file('extracted/DerivedEastAsianWidth', 'ea')
607    #
608    # Hangul Syllable Type
609    ucd.generate_property_value_file('HangulSyllableType', 'hst')
610    #
611    ucd.generate_multisection_properties_file('extracted/DerivedBinaryProperties')
612    # #
613    # # Canonical_Combining_Class
614    ucd.generate_property_value_file('extracted/DerivedCombiningClass', 'ccc')
615    #
616    # Decomposition Type
617    ucd.generate_property_value_file('extracted/DerivedDecompositionType', 'dt')
618    #
619    # Joining Group and Type
620    ucd.generate_property_value_file('extracted/DerivedJoiningGroup', 'jg')
621    ucd.generate_property_value_file('extracted/DerivedJoiningType', 'jt')
622    #
623    # Numeric Type and Value
624    ucd.generate_property_value_file('extracted/DerivedNumericType', 'nt')
625    #ucd.generate_property_value_file('extracted/DerivedNumericValue', 'nv')
626    #
627    # Normalization properties.
628    ucd.generate_multisection_properties_file('DerivedNormalizationProps')
629    #
630    # Bidirectional properties
631    ucd.generate_property_value_file('extracted/DerivedBidiClass', 'bc')
632    ucd.generate_multicolumn_properties_file('BidiBrackets', ['bpb', 'bpt'])
633    ucd.generate_property_value_file('BidiMirroring', 'bmg')
634
635    # Indic properties
636    ucd.generate_property_value_file('IndicPositionalCategory', 'InPC')
637    ucd.generate_property_value_file('IndicSyllabicCategory', 'InSC')
638
639    ucd.generate_property_value_file('CompositionExclusions', 'CE')
640    #
641    ucd.generate_property_value_file('Jamo', 'JSN')
642    #
643    #
644    #
645    ucd.generate_PropertyValueAliases_h()
646
647    ucd.generate_PropertyObjectTable_h()
648
649    ucd.generate_UCD_Config_h()
650
651if __name__ == "__main__":
652  UCD_main()
Note: See TracBrowser for help on using the repository browser.