source: icGREP/icgrep-devel/icgrep/UCD/resolve_properties.cpp @ 5656

Last change on this file since 5656 was 5545, checked in by cameron, 2 years ago

Fixing :graph:? :print:?

File size: 13.7 KB
Line 
1/*
2 *  Copyright (c) 2015 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6#include "resolve_properties.h"
7#include <re/re_alt.h>
8#include <re/re_any.h>
9#include <re/re_name.h>
10#include <re/re_diff.h>
11#include <re/re_start.h>
12#include <re/re_end.h>
13#include <re/re_cc.h>
14#include <re/re_seq.h>
15#include <re/re_assertion.h>
16#include "UCD/PropertyAliases.h"
17#include "UCD/PropertyObjects.h"
18#include "UCD/PropertyObjectTable.h"
19#include "UCD/PropertyValueAliases.h"
20#include <llvm/Support/ErrorHandling.h>
21
22using namespace UCD;
23using namespace re;
24using namespace llvm;
25
26inline int GetPropertyValueEnumCode(const UCD::property_t type, const std::string & value) {
27    return property_object_table[type]->GetPropertyValueEnumCode(value);
28}
29
30namespace UCD {
31   
32void UnicodePropertyExpressionError(std::string errmsg) {
33    llvm::report_fatal_error(errmsg);
34
35}
36
37
38void generateGraphemeClusterBoundaryRule(Name * const &property) {
39    // 3.1.1 Grapheme Cluster Boundary Rules
40#define Behind(x) makeLookBehindAssertion(x)
41#define Ahead(x) makeLookAheadAssertion(x)
42
43//    RE * GCB_Control = makeName("gcb", "cn", Name::Type::UnicodeProperty);
44    RE * GCB_CR = makeName("gcb", "cr", Name::Type::UnicodeProperty);
45    RE * GCB_LF = makeName("gcb", "lf", Name::Type::UnicodeProperty);
46    RE * GCB_Control_CR_LF = makeAlt({GCB_CR, GCB_LF});
47
48    // Break at the start and end of text.
49    RE * GCB_1 = makeStart();
50    RE * GCB_2 = makeEnd();
51    // Do not break between a CR and LF.
52    RE * GCB_3 = makeSeq({Behind(GCB_CR), Ahead(GCB_LF)});
53    // Otherwise, break before and after controls.
54    RE * GCB_4 = Behind(GCB_Control_CR_LF);
55    RE * GCB_5 = Ahead(GCB_Control_CR_LF);
56    RE * GCB_1_5 = makeAlt({GCB_1, GCB_2, makeDiff(makeAlt({GCB_4, GCB_5}), GCB_3)});
57
58    RE * GCB_L = makeName("gcb", "l", Name::Type::UnicodeProperty);
59    RE * GCB_V = makeName("gcb", "v", Name::Type::UnicodeProperty);
60    RE * GCB_LV = makeName("gcb", "lv", Name::Type::UnicodeProperty);
61    RE * GCB_LVT = makeName("gcb", "lvt", Name::Type::UnicodeProperty);
62    RE * GCB_T = makeName("gcb", "t", Name::Type::UnicodeProperty);
63    RE * GCB_RI = makeName("gcb", "ri", Name::Type::UnicodeProperty);
64    // Do not break Hangul syllable sequences.
65    RE * GCB_6 = makeSeq({Behind(GCB_L), Ahead(makeAlt({GCB_L, GCB_V, GCB_LV, GCB_LVT}))});
66    RE * GCB_7 = makeSeq({Behind(makeAlt({GCB_LV, GCB_V})), Ahead(makeAlt({GCB_V, GCB_T}))});
67    RE * GCB_8 = makeSeq({Behind(makeAlt({GCB_LVT, GCB_T})), Ahead(GCB_T)});
68    // Do not break between regional indicator symbols.
69    RE * GCB_8a = makeSeq({Behind(GCB_RI), Ahead(GCB_RI)});
70    // Do not break before extending characters.
71    RE * GCB_9 = Ahead(makeName("gcb", "ex", Name::Type::UnicodeProperty));
72    // Do not break before SpacingMarks, or after Prepend characters.
73    RE * GCB_9a = Ahead(makeName("gcb", "sm", Name::Type::UnicodeProperty));
74    RE * GCB_9b = Behind(makeName("gcb", "pp", Name::Type::UnicodeProperty));
75    RE * GCB_6_9b = makeAlt({GCB_6, GCB_7, GCB_8, GCB_8a, GCB_9, GCB_9a, GCB_9b});
76    // Otherwise, break everywhere.
77    RE * GCB_10 = makeSeq({Behind(makeAny()), Ahead(makeAny())});
78
79    //Name * gcb = makeName("gcb", Name::Type::UnicodeProperty);
80    property->setDefinition(makeAlt({GCB_1_5, makeDiff(GCB_10, GCB_6_9b)}));
81}
82
83bool resolvePropertyDefinition(Name * const property) {
84    if (property->hasNamespace()) {
85        auto propit = alias_map.find(property->getNamespace());
86        if (propit == alias_map.end()) {
87            UnicodePropertyExpressionError("Expected a property name but '" + property->getNamespace() + "' was found instead");
88        }
89        auto theprop = propit->second;
90        if (isa<BinaryPropertyObject>(property_object_table[theprop])){
91            auto valit = Binary_ns::aliases_only_map.find(property->getName());
92            if (valit != Binary_ns::aliases_only_map.end()) {
93                if (valit->second == Binary_ns::N) {
94                    Name * binprop = makeName(property_enum_name[theprop], Name::Type::UnicodeProperty);
95                    property->setDefinition(makeDiff(makeAny(), binprop));
96                    return true;
97                }
98            }
99        }
100    } else {
101        const std::string value = property->getName();
102        // Try special cases of Unicode TR #18
103        if (value == "any") {
104            property->setDefinition(makeAny());
105            return true;
106        } else if (value == "ascii") {
107            property->setDefinition(makeName("blk", "ascii", Name::Type::UnicodeProperty));
108            return true;
109        } else if (value == "assigned") {
110            Name * unassigned = makeName("cn", Name::Type::UnicodeProperty);
111            property->setDefinition(makeDiff(makeAny(), unassigned));
112            return true;
113        } else if (value == "GCB" || value == "NonGCB"){
114            generateGraphemeClusterBoundaryRule(property);
115            return true;
116        }
117    }
118    return false;
119}
120
121std::string resolvePropertyFunction(Name * const property) {
122    const std::string value = property->getName();
123    std::string functionName;
124    if (property->hasNamespace()) {
125        auto propit = alias_map.find(property->getNamespace());
126        if (propit == alias_map.end()) {
127            UnicodePropertyExpressionError("Expected a property name but '" + property->getNamespace() + "' was found instead");
128        }
129        auto theprop = propit->second;
130        if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
131            int valcode = p->GetPropertyValueEnumCode(value);
132            if (valcode < 0) {
133                UnicodePropertyExpressionError("Erroneous property value '" + value + "' for " + property_full_name[theprop] + " property");
134            }
135            functionName = "__get_" + property_enum_name[theprop] + "_" + p->GetValueEnumName(valcode);
136        }
137        else if (theprop == scx) {
138            // Script extension property identified
139            int valcode = GetPropertyValueEnumCode(sc, value);
140            if (valcode < 0) {
141                UnicodePropertyExpressionError("Erroneous property value for script_extension property");
142            }
143            functionName = "__get_scx_" + SC_ns::enum_names[valcode];
144        }
145        else if (isa<BinaryPropertyObject>(property_object_table[theprop])){
146            auto valit = Binary_ns::aliases_only_map.find(value);
147            if (valit == Binary_ns::aliases_only_map.end()) {
148                UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
149            }
150            if (valit->second == Binary_ns::Y) {
151                functionName = "__get_" + property_enum_name[theprop] + "_Y";
152            } else {
153                UnicodePropertyExpressionError("Unexpected property value for binary property " + property_full_name[theprop]);
154            }
155        }
156        else {
157            UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
158        }
159    } else { // No namespace (property) name.
160        // Try as a general category, script or binary property.
161        int valcode;
162        if ((valcode = GetPropertyValueEnumCode(gc, value)) >= 0) {
163            functionName = "__get_gc_" + GC_ns::enum_names[valcode];
164        }
165        else if ((valcode = GetPropertyValueEnumCode(sc, value)) >= 0) {
166            functionName = "__get_sc_" + SC_ns::enum_names[valcode];
167        }
168        else { // Try as a binary property.
169            auto propit = alias_map.find(value);
170            if (propit != alias_map.end()) {
171                auto theprop = propit->second;
172                if (isa<BinaryPropertyObject>(property_object_table[theprop])) {
173                    functionName = "__get_" + property_enum_name[theprop] + "_Y";
174                }
175                else {
176                    UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
177                }
178            }
179            else {
180                UnicodePropertyExpressionError("Expected a general category, script or binary property name but '" + value + "' was found instead");
181            }
182        }
183    }
184    assert (functionName.length() > 0);
185    return functionName;
186}
187
188const std::string & getPropertyValueGrepString(const std::string & prop) {
189    auto propit = alias_map.find(canonicalize_value_name(prop));
190    if (propit == alias_map.end()) {
191        UnicodePropertyExpressionError("Expected a property name, but '" + prop + "' found instead");
192    }
193    auto theprop = propit->second;
194    if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
195        return p->GetPropertyValueGrepString();
196    } else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
197        return p->GetPropertyValueGrepString();
198    }
199
200    UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
201}
202
203UnicodeSet resolveUnicodeSet(Name * const name) {
204    if (name->getType() == Name::Type::UnicodeProperty) {
205        std::string prop = name->getNamespace();
206        std::string value = canonicalize_value_name(name->getName());
207        if (prop.length() > 0) {
208            prop = canonicalize_value_name(prop);
209            auto propit = alias_map.find(prop);
210            if (propit == alias_map.end()) {
211                UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
212            }
213            auto theprop = propit->second;
214            if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
215                return p->GetCodepointSet(value);
216            }
217            else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])){
218                auto valit = Binary_ns::aliases_only_map.find(value);
219                if (valit == Binary_ns::aliases_only_map.end()) {
220                    UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
221                }
222                return p->GetCodepointSet(value);
223            }           
224            UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
225        }
226        else {
227            // No namespace (property) name.   Try as a general category.
228            int valcode = GetPropertyValueEnumCode(gc, value);
229            if (valcode >= 0) {
230                return cast<EnumeratedPropertyObject>(property_object_table[gc])->GetCodepointSet(valcode);
231            }
232            valcode = GetPropertyValueEnumCode(sc, value);
233            if (valcode >= 0) {
234                return cast<EnumeratedPropertyObject>(property_object_table[sc])->GetCodepointSet(valcode);
235            }
236            // Try as a binary property.
237            auto propit = alias_map.find(value);
238            if (propit != alias_map.end()) {
239                auto theprop = propit->second;
240                if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
241                    return p->GetCodepointSet(Binary_ns::Y);
242                }
243                else {
244                    UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
245                }
246            }
247            // Try special cases of Unicode TR #18
248            // Now compatibility properties of UTR #18 Annex C
249                   
250            else if (value == "alnum") {
251                Name * digit = makeName("nd", Name::Type::UnicodeProperty);
252                Name * alpha = makeName("alphabetic", Name::Type::UnicodeProperty);
253                return resolveUnicodeSet(digit) + resolveUnicodeSet(alpha);
254            } else if (value == "xdigit") {
255                Name * digit = makeName("nd", Name::Type::UnicodeProperty);
256                Name * hexdigit = makeName("hexdigit", Name::Type::UnicodeProperty);
257                return resolveUnicodeSet(digit) + resolveUnicodeSet(hexdigit);
258            } else if (value == "blank") {
259                Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
260                return resolveUnicodeSet(space_sep) + UnicodeSet(0x09) /* tab */;
261            } else if (value == "print") {
262                Name * graph = makeName("graph", Name::Type::UnicodeProperty);
263                Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
264                return resolveUnicodeSet(graph) + resolveUnicodeSet(space_sep);
265            } else if (value == "word") {
266                Name * alnum = makeName("alnum", Name::Type::UnicodeProperty);
267                Name * mark = makeName("mark", Name::Type::UnicodeProperty);
268                Name * conn = makeName("connectorpunctuation", Name::Type::UnicodeProperty);
269                Name * join = makeName("joincontrol", Name::Type::UnicodeProperty);
270                return resolveUnicodeSet(alnum) + resolveUnicodeSet(mark) + resolveUnicodeSet(conn) + resolveUnicodeSet(join);
271            } else if (value == "graph") {
272                Name * space = makeName("space", Name::Type::UnicodeProperty);
273                Name * ctrl = makeName("control", Name::Type::UnicodeProperty);
274                Name * surr = makeName("surrogate", Name::Type::UnicodeProperty);
275                Name * unassigned = makeName("cn", Name::Type::UnicodeProperty);
276                return ~(resolveUnicodeSet(space) + resolveUnicodeSet(ctrl) + resolveUnicodeSet(surr) + resolveUnicodeSet(unassigned));
277            }
278
279
280        }
281    }
282    UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
283}
284
285}
Note: See TracBrowser for help on using the repository browser.