source: icGREP/icgrep-devel/UCD-scripts/UCD_property_objects.py @ 5659

Last change on this file since 5659 was 5659, checked in by cameron, 21 months ago

UCD generator restructuring and improvements

File size: 9.8 KB
Line 
1import re, string, os.path
2import UCD_config
3from unicode_set import *
4trivial_name_char_re = re.compile('[-_\s]')
5def canonicalize(property_string):
6    return trivial_name_char_re.sub('', property_string.lower())
7
8#
9#  Union of a list of sets
10#
11def union_of_all(uset_list):
12    if uset_list == []: return empty_uset()
13    else:
14        accum_set = uset_list[0]
15        for s in uset_list[1:]:
16            accum_set = uset_union(accum_set, s)
17        return accum_set
18
19
20class PropertyObject():
21    def __init__(self):
22        self.default_value = None
23    def setID(self, prop_code, long_name):
24        self.property_code = prop_code
25        self.full_name = long_name
26    def setAliases(self, aliases):
27        self.aliases = aliases
28    def setSource(self, file_root):
29        self.source_file = file_root
30    def setDefaultValue(self, default):
31        if self.default_value != None and self.default_value != default:
32            raise Exception("Conflicting default specification")
33        self.default_value = default
34    def finalizeProperty(self):
35        pass
36    def getPropertyCode(self):
37        return self.property_code
38    def getPropertyFullName(self):
39        return self.full_name
40    def getAliases(self):
41        return self.aliases
42    def getFileSource(self):
43        return self.source_file
44    def getAllCanonicalNames(self):
45        return [canonicalize(self.property_code), canonicalize(self.full_name)] + [canonicalize(x) for x in self.aliases]
46
47class EnumeratedPropertyObject(PropertyObject):
48    def __init__(self):
49        PropertyObject.__init__(self)
50        self.property_value_list = []
51        self.property_value_enum_integer = {}
52        self.property_value_full_name_map = {}
53        self.property_value_lookup_map = {}
54        self.enum_integer = 0
55        self.value_map = {}
56        self.default_value = None
57        self.name_list_order = []
58        self.independent_prop_values = 0
59
60    def getPropertyKind(self): return "Enumerated"
61
62    def addPropertyValue(self, value_enum, value_preferred_full_name, aliases):
63        if value_enum in self.property_value_list: raise Exception("Duplicate entry " + value_enum)
64        self.property_value_list.append(value_enum)
65        if self.property_code == "ccc":
66            self.property_value_enum_integer[value_enum] = int(aliases[0])
67        else:
68            self.property_value_enum_integer[value_enum] = self.enum_integer
69            self.enum_integer += 1
70        self.property_value_full_name_map[value_enum] = value_preferred_full_name
71        for name in [value_enum, value_preferred_full_name] + aliases:
72            self.property_value_lookup_map[name] = value_enum
73            self.property_value_lookup_map[canonicalize(name)] = value_enum
74        self.value_map[value_enum] = empty_uset()
75
76    def setDefaultValue(self, default):
77        if not default in self.property_value_lookup_map: 
78            raise Exception("Erroneous default value %s for property %s" % (default, self.full_name))
79        dflt = self.property_value_lookup_map[default]
80        if not dflt in self.name_list_order: self.name_list_order = [dflt] + self.name_list_order
81        PropertyObject.setDefaultValue(self, dflt)
82
83    def finalizeProperty(self):
84        explicitly_defined_cps = empty_uset()
85        for k in self.value_map.keys(): 
86            explicitly_defined_cps = uset_union(explicitly_defined_cps, self.value_map[k])
87        need_default_value = uset_complement(explicitly_defined_cps)
88        dflt = self.default_value
89        if not dflt == None:
90            if dflt in self.value_map:
91                self.value_map[dflt] = uset_union(self.value_map[dflt], need_default_value)
92            else: 
93                self.value_map[dflt] = need_default_value
94        self.independent_prop_values = len(self.name_list_order)
95        for v in self.property_value_list:
96            if not v in self.name_list_order:
97                self.name_list_order.append(v)
98        self.property_value_list = self.name_list_order
99        if self.property_code == 'gc':
100            # special logic for derived categories
101            self.value_map['LC'] = union_of_all([self.value_map[v] for v in ['Lu', 'Ll', 'Lt']])
102            self.value_map['L'] = union_of_all([self.value_map[v] for v in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo']])
103            self.value_map['M'] = union_of_all([self.value_map[v] for v in ['Mn', 'Mc', 'Me']])
104            self.value_map['N'] = union_of_all([self.value_map[v] for v in ['Nd', 'Nl', 'No']])
105            self.value_map['P'] = union_of_all([self.value_map[v] for v in ['Pc', 'Pd', 'Ps', 'Pe', 'Pi', 'Pf', 'Po']])
106            self.value_map['S'] = union_of_all([self.value_map[v] for v in ['Sm', 'Sc', 'Sk', 'So']])
107            self.value_map['Z'] = union_of_all([self.value_map[v] for v in ['Zs', 'Zl', 'Zp']])
108            self.value_map['C'] = union_of_all([self.value_map[v] for v in ['Cc', 'Cf', 'Cs', 'Co', 'Cn']])
109
110
111
112    def addDataRecord(self, cp_lo, cp_hi, v):
113        canon = canonicalize(v)
114        if not canon in self.property_value_lookup_map: 
115            raise Exception("Unknown enumeration value for %s: %s" % (self.full_name, v))
116        enum_code = self.property_value_lookup_map[canon]
117        self.value_map[enum_code] = uset_union(self.value_map[enum_code], range_uset(cp_lo, cp_hi))
118        if not enum_code in self.name_list_order: self.name_list_order.append(enum_code)
119
120    def emit():
121        f.write("\nnamespace UCD {\n")
122        f.write("  namespace %s_ns {\n" % self.property_code.upper())
123        #f.write("    const unsigned independent_prop_values = %s;\n" % self.independent_prop_values)
124        for v in self.property_values:
125            f.write("    /** Code Point Ranges for %s\n    " % v)
126            f.write(cformat.multiline_fill(['[%04x, %04x]' % (lo, hi) for (lo, hi) in uset_to_range_list(value_map[v])], ',', 4))
127            f.write("**/\n")
128            f.write("    const UnicodeSet %s_Set \n" % v.lower())
129            f.write(self.value_map[v].showC(8) + ";\n")
130        print("%s: %s bytes" % (basename, sum([self.value_map[v].bytes() for v in self.value_map.keys()])))
131        set_list = ['&%s_Set' % v.lower() for v in self.property_values]
132        f.write("    static EnumeratedPropertyObject property_object\n")
133        f.write("        {%s,\n" % self.property_code)
134        f.write("         %s_ns::independent_prop_values,\n" % self.property_code.upper())
135        f.write("         %s_ns::enum_names,\n" % self.property_code.upper())
136        f.write("         %s_ns::value_names,\n" % self.property_code.upper())
137        f.write("         %s_ns::aliases_only_map,\n" % self.property_code.upper())
138        f.write("         {")
139        f.write(cformat.multiline_fill(set_list, ',', 8))
140        f.write("\n         }};\n    }\n}\n")
141
142class BinaryPropertyObject(PropertyObject):
143    def __init__(self):
144        PropertyObject.__init__(self)
145        self.empty_regexp = re.compile("\s+")
146        self.property_value_full_name_map = {"N" : "No", "Y" : "Yes"}
147        self.name_list_order = ['N', 'Y']
148        self.property_value_lookup_map = {"n" : "N", "N" : "N", "no" : "N", "f" : "N", "false" : "N",
149        "y" : "Y", "Y" : "Y", "yes" : "Y", "t" : "Y", "true" : "Y"}
150        self.default_value = "N"
151        self.value_map = {"N" : empty_uset(), "Y" : empty_uset()}
152
153    def getPropertyKind(self): return "Binary"
154
155    def setID(self, prop_code, long_name):
156        PropertyObject.setID(self, prop_code, long_name)
157
158    def addDataRecord(self, cp_lo, cp_hi):
159        self.value_map['Y'] = uset_union(self.value_map['Y'], range_uset(cp_lo, cp_hi))
160
161
162
163class NumericPropertyObject(PropertyObject):
164    def __init__(self):
165        PropertyObject.__init__(self)
166
167    def getPropertyKind(self): return "Numeric"
168
169class ExtensionPropertyObject(PropertyObject):
170    def __init__(self):
171        PropertyObject.__init__(self)
172        self.value_map = {}
173
174    def setBaseProperty(self, property_obj):
175        self.base_property = property_obj
176        for p in property_obj.property_value_list:
177            self.value_map[p] = empty_uset()
178
179    def getPropertyKind(self): return "Extension"
180
181    def addDataRecord(self, cp_lo, cp_hi, base_item_list):
182        newset = range_uset(cp_lo, cp_hi)
183        base_items = base_item_list.split()
184        for e in base_items:
185            self.value_map[e] = uset_union(self.value_map[e], newset)
186   
187    def finalizeProperty(self):
188        explicitly_defined_cps = empty_uset()
189        for k in self.value_map.keys(): 
190            explicitly_defined_cps = uset_union(explicitly_defined_cps, self.value_map[k])
191        # set <script> default
192        for k in self.base_property.value_map.keys():
193            base_set = self.base_property.value_map[k]
194            if k in ['Zzzz', 'Zyyy', 'Zinh']: # Unknown, Common, Inherited not included if the set is explicitly defined UAX #24
195                self.value_map[k] = uset_union(self.value_map[k], uset_difference(base_set, explicitly_defined_cps))
196            else:
197                self.value_map[k] = uset_union(self.value_map[k], base_set)
198
199class StringPropertyObject(PropertyObject):
200    def __init__(self):
201        PropertyObject.__init__(self)
202        self.str_value_map = {}
203
204    def getPropertyKind(self): 
205        if self.property_code in ['scf', 'slc', 'suc', 'stc']: 
206            return "Codepoint"
207        else: 
208            return "String"
209
210    def addDataRecord(self, cp_lo, cp_hi, stringValue):
211        if not self.property_code in ['na', 'JSN', 'na1', 'isc'] and stringValue != '':
212            s = ""
213            for cp in [int(x, 16) for x in stringValue.split(' ')]: 
214                s+= chr(cp)
215            stringValue = s
216        for cp in range(cp_lo, cp_hi+1):
217            self.str_value_map[cp] = stringValue
218
219def getPropertyLookupMap(property_object_map):
220    property_lookup_map = {}
221    for k in property_object_map.keys():
222        po = property_object_map[k]
223        names = po.getAllCanonicalNames()
224        for n in names:
225            property_lookup_map[n] = k
226    return property_lookup_map
227
Note: See TracBrowser for help on using the repository browser.