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

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

Case folding property objects

File size: 11.5 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 addDataRecord(self, cp_lo, cp_hi, v):
35        pass
36    def finalizeProperty(self):
37        pass
38    def getPropertyCode(self):
39        return self.property_code
40    def getPropertyFullName(self):
41        return self.full_name
42    def getAliases(self):
43        return self.aliases
44    def getFileSource(self):
45        return self.source_file
46    def getAllCanonicalNames(self):
47        return [canonicalize(self.property_code), canonicalize(self.full_name)] + [canonicalize(x) for x in self.aliases]
48
49class EnumeratedPropertyObject(PropertyObject):
50    def __init__(self):
51        PropertyObject.__init__(self)
52        self.property_value_list = []
53        self.property_value_enum_integer = {}
54        self.property_value_full_name_map = {}
55        self.property_value_lookup_map = {}
56        self.enum_integer = 0
57        self.value_map = {}
58        self.default_value = None
59        self.name_list_order = []
60        self.independent_prop_values = 0
61
62    def getPropertyKind(self): return "Enumerated"
63
64    def addPropertyValue(self, value_enum, value_preferred_full_name, aliases):
65        if value_enum in self.property_value_list: raise Exception("Duplicate entry " + value_enum)
66        self.property_value_list.append(value_enum)
67        if self.property_code == "ccc":
68            self.property_value_enum_integer[value_enum] = int(aliases[0])
69        else:
70            self.property_value_enum_integer[value_enum] = self.enum_integer
71            self.enum_integer += 1
72        self.property_value_full_name_map[value_enum] = value_preferred_full_name
73        for name in [value_enum, value_preferred_full_name] + aliases:
74            self.property_value_lookup_map[name] = value_enum
75            self.property_value_lookup_map[canonicalize(name)] = value_enum
76        self.value_map[value_enum] = empty_uset()
77
78    def setDefaultValue(self, default):
79        if not default in self.property_value_lookup_map: 
80            raise Exception("Erroneous default value %s for property %s" % (default, self.full_name))
81        dflt = self.property_value_lookup_map[default]
82        if not dflt in self.name_list_order: self.name_list_order = [dflt] + self.name_list_order
83        PropertyObject.setDefaultValue(self, dflt)
84
85    def finalizeProperty(self):
86        explicitly_defined_cps = empty_uset()
87        for k in self.value_map.keys(): 
88            explicitly_defined_cps = uset_union(explicitly_defined_cps, self.value_map[k])
89        need_default_value = uset_complement(explicitly_defined_cps)
90        dflt = self.default_value
91        if not dflt == None:
92            if dflt in self.value_map:
93                self.value_map[dflt] = uset_union(self.value_map[dflt], need_default_value)
94            else: 
95                self.value_map[dflt] = need_default_value
96        self.independent_prop_values = len(self.name_list_order)
97        for v in self.property_value_list:
98            if not v in self.name_list_order:
99                self.name_list_order.append(v)
100        self.property_value_list = self.name_list_order
101        if self.property_code == 'gc':
102            # special logic for derived categories
103            self.value_map['LC'] = union_of_all([self.value_map[v] for v in ['Lu', 'Ll', 'Lt']])
104            self.value_map['L'] = union_of_all([self.value_map[v] for v in ['Lu', 'Ll', 'Lt', 'Lm', 'Lo']])
105            self.value_map['M'] = union_of_all([self.value_map[v] for v in ['Mn', 'Mc', 'Me']])
106            self.value_map['N'] = union_of_all([self.value_map[v] for v in ['Nd', 'Nl', 'No']])
107            self.value_map['P'] = union_of_all([self.value_map[v] for v in ['Pc', 'Pd', 'Ps', 'Pe', 'Pi', 'Pf', 'Po']])
108            self.value_map['S'] = union_of_all([self.value_map[v] for v in ['Sm', 'Sc', 'Sk', 'So']])
109            self.value_map['Z'] = union_of_all([self.value_map[v] for v in ['Zs', 'Zl', 'Zp']])
110            self.value_map['C'] = union_of_all([self.value_map[v] for v in ['Cc', 'Cf', 'Cs', 'Co', 'Cn']])
111
112
113
114    def addDataRecord(self, cp_lo, cp_hi, v):
115        canon = canonicalize(v)
116        if not canon in self.property_value_lookup_map: 
117            raise Exception("Unknown enumeration value for %s: %s" % (self.full_name, v))
118        enum_code = self.property_value_lookup_map[canon]
119        self.value_map[enum_code] = uset_union(self.value_map[enum_code], range_uset(cp_lo, cp_hi))
120        if not enum_code in self.name_list_order: self.name_list_order.append(enum_code)
121
122class BinaryPropertyObject(PropertyObject):
123    def __init__(self):
124        PropertyObject.__init__(self)
125        self.empty_regexp = re.compile("\s+")
126        self.property_value_full_name_map = {"N" : "No", "Y" : "Yes"}
127        self.name_list_order = ['N', 'Y']
128        self.property_value_lookup_map = {"n" : "N", "N" : "N", "no" : "N", "f" : "N", "false" : "N",
129        "y" : "Y", "Y" : "Y", "yes" : "Y", "t" : "Y", "true" : "Y"}
130        self.default_value = "N"
131        self.value_map = {"N" : empty_uset(), "Y" : empty_uset()}
132
133    def getPropertyKind(self): return "Binary"
134
135    def addDataRecord(self, cp_lo, cp_hi, v):
136        if v==None or v in self.property_value_lookup_map[v] == 'Y':
137            self.value_map['Y'] = uset_union(self.value_map['Y'], range_uset(cp_lo, cp_hi))
138        else: 
139            self.value_map['Y'] = uset_difference(self.value_map['Y'], range_uset(cp_lo, cp_hi))
140
141
142
143class NumericPropertyObject(PropertyObject):
144    def __init__(self):
145        PropertyObject.__init__(self)
146        self.cp_value_map = {}
147        self.NaN_set = empty_uset()
148
149    def getPropertyKind(self): return "Numeric"
150
151    def addDataRecord(self, cp_lo, cp_hi, stringValue):
152        if stringValue == '':
153            self.NaN_set = uset_union(self.NaN_set, range_uset(cp_lo, cp_hi))
154        else:
155            for cp in range(cp_lo, cp_hi+1):
156                self.cp_value_map[cp] = stringValue
157
158    def finalizeProperty(self):
159        explicitly_defined_cps = empty_uset()
160        for cp in self.cp_value_map.keys():
161            explicitly_defined_cps = uset_union(explicitly_defined_cps, singleton_uset(cp))
162        # set NaN default
163        self.NaN_set = uset_union(self.NaN_set, uset_complement(explicitly_defined_cps))
164
165
166class ExtensionPropertyObject(PropertyObject):
167    def __init__(self):
168        PropertyObject.__init__(self)
169        self.value_map = {}
170
171    def setBaseProperty(self, property_obj):
172        self.base_property = property_obj
173        for p in property_obj.property_value_list:
174            self.value_map[p] = empty_uset()
175
176    def getPropertyKind(self): return "Extension"
177
178    def addDataRecord(self, cp_lo, cp_hi, base_item_list):
179        newset = range_uset(cp_lo, cp_hi)
180        base_items = base_item_list.split()
181        for e in base_items:
182            self.value_map[e] = uset_union(self.value_map[e], newset)
183   
184    def finalizeProperty(self):
185        explicitly_defined_cps = empty_uset()
186        for k in self.value_map.keys(): 
187            explicitly_defined_cps = uset_union(explicitly_defined_cps, self.value_map[k])
188        # set <script> default
189        for k in self.base_property.value_map.keys():
190            base_set = self.base_property.value_map[k]
191            if k in ['Zzzz', 'Zyyy', 'Zinh']: # Unknown, Common, Inherited not included if the set is explicitly defined UAX #24
192                self.value_map[k] = uset_union(self.value_map[k], uset_difference(base_set, explicitly_defined_cps))
193            else:
194                self.value_map[k] = uset_union(self.value_map[k], base_set)
195
196codepoint_String_regexp = re.compile("^[A-F0-9]{4,6}(?: [A-F0-9]{4,6})*$")
197class StringPropertyObject(PropertyObject):
198    def __init__(self):
199        PropertyObject.__init__(self)
200        self.cp_value_map = {}
201        self.null_str_set = empty_uset()
202        self.reflexive_set = empty_uset()
203       
204    def getPropertyKind(self): 
205        return "String"
206
207    def addDataRecord(self, cp_lo, cp_hi, stringValue):
208        if stringValue == '':
209            self.null_str_set = uset_union(self.null_str_set, range_uset(cp_lo, cp_hi))
210        else:
211            if codepoint_String_regexp.match(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                if len(stringValue) == 1 and ord(stringValue[0]) == cp:
218                    print("Found reflexive entry for %s: %s" % (self.property_code, stringValue))
219                    self.reflexive_set = uset_union(self.reflexive_set, singleton_uset(ord(stringValue[0])))
220                else:
221                    self.cp_value_map[cp] = stringValue
222
223    def finalizeProperty(self):
224        explicitly_defined_cps = empty_uset()
225        for cp in self.cp_value_map.keys():
226            explicitly_defined_cps = uset_union(explicitly_defined_cps, singleton_uset(cp))
227        # set <script> default
228        if self.default_value == "<code point>":
229            self.reflexive_set = uset_union(self.reflexive_set, uset_complement(uset_union(explicitly_defined_cps, self.null_str_set)))
230        else:
231            self.null_str_set = uset_union(self.null_str_set, uset_complement(uset_union(explicitly_defined_cps, self.reflexive_set)))
232
233class StringOverridePropertyObject(PropertyObject):
234    def __init__(self, overridden_code):
235        PropertyObject.__init__(self)
236        self.cp_value_map = {}
237        self.overridden_code = overridden_code
238        self.overridden_set = empty_uset()
239       
240    def getPropertyKind(self): 
241        return "StringOverride"
242
243    def addDataRecord(self, cp_lo, cp_hi, stringValue):
244        if codepoint_String_regexp.match(stringValue):
245            s = ""
246            for cp in [int(x, 16) for x in stringValue.split(' ')]:
247                s += chr(cp)
248            stringValue = s
249        else: 
250            raise Exception("Expecting codepoint string, but got " + stringValue)
251        for cp in range(cp_lo, cp_hi+1): self.cp_value_map[cp] = stringValue
252
253    def finalizeProperty(self):
254        explicitly_defined_cps = empty_uset()
255        for cp in self.cp_value_map.keys():
256            explicitly_defined_cps = uset_union(explicitly_defined_cps, singleton_uset(cp))
257        self.overridden_set = explicitly_defined_cps
258
259class ObsoletePropertyObject(PropertyObject):
260    def __init__(self):
261        PropertyObject.__init__(self)
262
263    def getPropertyKind(self): return "Obsolete"
264
265
266def getPropertyLookupMap(property_object_map):
267    property_lookup_map = {}
268    for k in property_object_map.keys():
269        po = property_object_map[k]
270        names = po.getAllCanonicalNames()
271        for n in names:
272            property_lookup_map[n] = k
273    return property_lookup_map
274
Note: See TracBrowser for help on using the repository browser.