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

Last change on this file since 4619 was 4619, checked in by nmedfort, 4 years ago

Corrected bug in generated UCD code that prevented including the predefined UnicodeSets? in more than one file and removed quad_count.

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