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

Last change on this file since 5976 was 5749, checked in by nmedfort, 22 months ago

updated UCD python scripts

File size: 11.4 KB
Line 
1from unicode_set import *
2trivial_name_char_re = re.compile('[-_\s]')
3def canonicalize(property_string):
4    return trivial_name_char_re.sub('', property_string.lower())
5
6#
7#  Union of a list of sets
8#
9def union_of_all(uset_list):
10    if uset_list == []: return empty_uset()
11    else:
12        accum_set = uset_list[0]
13        for s in uset_list[1:]:
14            accum_set = uset_union(accum_set, s)
15        return accum_set
16
17
18class PropertyObject():
19    def __init__(self):
20        self.default_value = None
21    def setID(self, prop_code, long_name):
22        self.property_code = prop_code
23        self.full_name = long_name
24    def setAliases(self, aliases):
25        self.aliases = aliases
26    def setSource(self, file_root):
27        self.source_file = file_root
28    def setDefaultValue(self, default):
29        if self.default_value != None and self.default_value != default:
30            raise Exception("Conflicting default specification")
31        self.default_value = default
32    def addDataRecord(self, cp_lo, cp_hi, v):
33        pass
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
120class BinaryPropertyObject(PropertyObject):
121    def __init__(self):
122        PropertyObject.__init__(self)
123        self.empty_regexp = re.compile("\s+")
124        self.property_value_full_name_map = {"N" : "No", "Y" : "Yes"}
125        self.name_list_order = ['N', 'Y']
126        self.property_value_lookup_map = {"n" : "N", "N" : "N", "no" : "N", "f" : "N", "false" : "N",
127        "y" : "Y", "Y" : "Y", "yes" : "Y", "t" : "Y", "true" : "Y"}
128        self.default_value = "N"
129        self.value_map = {"N" : empty_uset(), "Y" : empty_uset()}
130
131    def getPropertyKind(self): return "Binary"
132
133    def addDataRecord(self, cp_lo, cp_hi, v):
134        if v==None or v in self.property_value_lookup_map[v] == 'Y':
135            self.value_map['Y'] = uset_union(self.value_map['Y'], range_uset(cp_lo, cp_hi))
136        else: 
137            self.value_map['Y'] = uset_difference(self.value_map['Y'], range_uset(cp_lo, cp_hi))
138
139
140
141class NumericPropertyObject(PropertyObject):
142    def __init__(self):
143        PropertyObject.__init__(self)
144        self.cp_value_map = {}
145        self.NaN_set = empty_uset()
146
147    def getPropertyKind(self): return "Numeric"
148
149    def addDataRecord(self, cp_lo, cp_hi, stringValue):
150        if stringValue == '':
151            self.NaN_set = uset_union(self.NaN_set, range_uset(cp_lo, cp_hi))
152        else:
153            for cp in range(cp_lo, cp_hi+1):
154                self.cp_value_map[cp] = stringValue
155
156    def finalizeProperty(self):
157        explicitly_defined_cps = empty_uset()
158        for cp in self.cp_value_map.keys():
159            explicitly_defined_cps = uset_union(explicitly_defined_cps, singleton_uset(cp))
160        # set NaN default
161        self.NaN_set = uset_union(self.NaN_set, uset_complement(explicitly_defined_cps))
162
163
164class ExtensionPropertyObject(PropertyObject):
165    def __init__(self):
166        PropertyObject.__init__(self)
167        self.value_map = {}
168
169    def setBaseProperty(self, property_obj):
170        self.base_property = property_obj
171        for p in property_obj.property_value_list:
172            self.value_map[p] = empty_uset()
173
174    def getPropertyKind(self): return "Extension"
175
176    def addDataRecord(self, cp_lo, cp_hi, base_item_list):
177        newset = range_uset(cp_lo, cp_hi)
178        base_items = base_item_list.split()
179        for e in base_items:
180            self.value_map[e] = uset_union(self.value_map[e], newset)
181   
182    def finalizeProperty(self):
183        explicitly_defined_cps = empty_uset()
184        for k in self.value_map.keys(): 
185            explicitly_defined_cps = uset_union(explicitly_defined_cps, self.value_map[k])
186        # set <script> default
187        for k in self.base_property.value_map.keys():
188            base_set = self.base_property.value_map[k]
189            if k in ['Zzzz', 'Zyyy', 'Zinh']: # Unknown, Common, Inherited not included if the set is explicitly defined UAX #24
190                self.value_map[k] = uset_union(self.value_map[k], uset_difference(base_set, explicitly_defined_cps))
191            else:
192                self.value_map[k] = uset_union(self.value_map[k], base_set)
193
194codepoint_String_regexp = re.compile("^[A-F0-9]{4,6}(?: [A-F0-9]{4,6})*$")
195class StringPropertyObject(PropertyObject):
196    def __init__(self):
197        PropertyObject.__init__(self)
198        self.cp_value_map = {}
199        self.null_str_set = empty_uset()
200        self.reflexive_set = empty_uset()
201       
202    def getPropertyKind(self): 
203        return "String"
204
205    def addDataRecord(self, cp_lo, cp_hi, stringValue):
206        if stringValue == '':
207            self.null_str_set = uset_union(self.null_str_set, range_uset(cp_lo, cp_hi))
208        else:
209            if codepoint_String_regexp.match(stringValue):
210                s = ""
211                for cp in [int(x, 16) for x in stringValue.split(' ')]:
212                    s += chr(cp)
213                stringValue = s
214            for cp in range(cp_lo, cp_hi+1):
215                if len(stringValue) == 1 and ord(stringValue[0]) == cp:
216                    print("Found reflexive entry for %s: %s" % (self.property_code, stringValue))
217                    self.reflexive_set = uset_union(self.reflexive_set, singleton_uset(ord(stringValue[0])))
218                else:
219                    self.cp_value_map[cp] = stringValue
220
221    def finalizeProperty(self):
222        explicitly_defined_cps = empty_uset()
223        for cp in self.cp_value_map.keys():
224            explicitly_defined_cps = uset_union(explicitly_defined_cps, singleton_uset(cp))
225        # set <script> default
226        if self.default_value == "<code point>":
227            self.reflexive_set = uset_union(self.reflexive_set, uset_complement(uset_union(explicitly_defined_cps, self.null_str_set)))
228        else:
229            self.null_str_set = uset_union(self.null_str_set, uset_complement(uset_union(explicitly_defined_cps, self.reflexive_set)))
230
231class StringOverridePropertyObject(PropertyObject):
232    def __init__(self, overridden_code):
233        PropertyObject.__init__(self)
234        self.cp_value_map = {}
235        self.overridden_code = overridden_code
236        self.overridden_set = empty_uset()
237       
238    def getPropertyKind(self): 
239        return "StringOverride"
240
241    def addDataRecord(self, cp_lo, cp_hi, stringValue):
242        if codepoint_String_regexp.match(stringValue):
243            s = ""
244            for cp in [int(x, 16) for x in stringValue.split(' ')]:
245                s += chr(cp)
246            stringValue = s
247        else: 
248            raise Exception("Expecting codepoint string, but got " + stringValue)
249        for cp in range(cp_lo, cp_hi+1): self.cp_value_map[cp] = stringValue
250
251    def finalizeProperty(self):
252        explicitly_defined_cps = empty_uset()
253        for cp in self.cp_value_map.keys():
254            explicitly_defined_cps = uset_union(explicitly_defined_cps, singleton_uset(cp))
255        self.overridden_set = explicitly_defined_cps
256
257class ObsoletePropertyObject(PropertyObject):
258    def __init__(self):
259        PropertyObject.__init__(self)
260
261    def getPropertyKind(self): return "Obsolete"
262
263
264def getPropertyLookupMap(property_object_map):
265    property_lookup_map = {}
266    for k in property_object_map.keys():
267        po = property_object_map[k]
268        names = po.getAllCanonicalNames()
269        for n in names:
270            property_lookup_map[n] = k
271    return property_lookup_map
272
Note: See TracBrowser for help on using the repository browser.