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

Last change on this file since 5751 was 5751, checked in by cameron, 22 months ago

LLVM_ALIGNAS placement, eliminate std::move of temp objects to allow copy elision

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