source: icGREP/icgrep-devel/icgrep/resolve_properties.cpp @ 4631

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

Fix for SCX and updated property objects.

File size: 14.2 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
7#include <string>
8#include <re/re_re.h>
9#include <re/re_alt.h>
10#include <re/re_any.h>
11#include <re/re_cc.h>
12#include <re/re_seq.h>
13#include <re/re_rep.h>
14#include <re/re_name.h>
15#include <re/re_diff.h>
16#include <re/re_intersect.h>
17#include <re/re_assertion.h>
18#include <re/re_start.h>
19#include <re/re_end.h>
20#include <cc/cc_namemap.hpp>
21#include "UCD/PropertyAliases.h"
22#include "UCD/PropertyObjects.h"
23#include "UCD/PropertyObjectTable.h"
24#include "UCD/PropertyValueAliases.h"
25#include <boost/algorithm/string/case_conv.hpp>
26#include "resolve_properties.h"
27
28using namespace UCD;
29using namespace re;
30
31class UnicodePropertyExpressionError : public std::exception {
32public:
33    UnicodePropertyExpressionError(const std::string && msg) noexcept : _msg(msg) {}
34    const char* what() const noexcept { return _msg.c_str();}
35private:
36    inline UnicodePropertyExpressionError() noexcept {}
37    const std::string _msg;
38};
39
40inline std::string lowercase(const std::string & name) {
41    std::locale loc;
42    return boost::algorithm::to_lower_copy(name, loc);
43}
44
45inline int GetPropertyValueEnumCode(const UCD::property_t type, const std::string & value) {
46    return property_object_table[type]->GetPropertyValueEnumCode(value);
47}
48
49void resolveProperties(RE * re) {
50    if (Alt * alt = dyn_cast<Alt>(re)) {
51        for (auto item : *alt) {
52            resolveProperties(item);
53        }
54    }
55    else if (Seq * seq = dyn_cast<Seq>(re)) {
56        for (auto item : *seq) {
57            resolveProperties(item);
58        }
59    }
60    else if (Rep * rep = dyn_cast<Rep>(re)) {
61        resolveProperties(rep->getRE());
62    }
63    else if (Assertion * a = dyn_cast<Assertion>(re)) {
64        resolveProperties(a->getAsserted());
65    }
66    else if (Diff * diff = dyn_cast<Diff>(re)) {
67        resolveProperties(diff->getRH());
68        resolveProperties(diff->getLH());
69    }
70    else if (Intersect * e = dyn_cast<Intersect>(re)) {
71        resolveProperties(e->getRH());
72        resolveProperties(e->getLH());
73    }
74    else if (Name * name = dyn_cast<Name>(re)) {
75        if (name->getType() == Name::Type::UnicodeProperty) {
76            const std::string prop = canonicalize_value_name(name->getNamespace());
77            const std::string value = canonicalize_value_name(name->getName());
78            if (prop.length() != 0) {
79                auto propit = alias_map.find(prop);
80                if (propit == alias_map.end()) {
81                    throw UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
82                }
83                auto theprop = propit->second;
84                if (theprop == gc) {
85                    // General Category
86                    int valcode = GetPropertyValueEnumCode(gc, value);
87                    if (valcode < 0) {
88                        throw UnicodePropertyExpressionError("Erroneous property value for general_category property");
89                    }                   
90                    name->setName("__get_gc_" + GC_ns::enum_names[valcode]);
91                }
92                else if (theprop == sc) {
93                    // Script property identified
94                    int valcode = GetPropertyValueEnumCode(sc, value);
95                    if (valcode < 0) {
96                        throw UnicodePropertyExpressionError("Erroneous property value for script property");
97                    }
98                    name->setName("__get_sc_" + SC_ns::enum_names[valcode]);
99                }
100                else if (theprop == scx) {
101                    // Script extension property identified
102                    int valcode = GetPropertyValueEnumCode(sc, value);
103                    if (valcode < 0) {
104                        throw UnicodePropertyExpressionError("Erroneous property value for script_extension property");
105                    }
106                    name->setName("__get_scx_" + SC_ns::enum_names[valcode]);
107                }
108                else if (theprop == blk) {
109                    // Block property identified
110                    int valcode = GetPropertyValueEnumCode(blk, value);
111                    if (valcode < 0) {
112                         throw UnicodePropertyExpressionError("Erroneous property value for block property");
113                    }
114                    name->setName("__get_blk_" + BLK_ns::enum_names[valcode]);
115                }
116                else if (isa<BinaryPropertyObject>(property_object_table[theprop])){
117                    auto valit = Binary_ns::aliases_only_map.find(value);
118                    if (valit == Binary_ns::aliases_only_map.end()) {
119                        throw UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
120                    }
121                    if (valit->second == Binary_ns::Y) {
122                        name->setName("__get_" + lowercase(property_enum_name[theprop]) + "_Y");
123                        return;
124                    }
125                    else {
126                        Name * binprop = makeName("__get_" + lowercase(property_enum_name[theprop]) + "_Y", Name::Type::UnicodeProperty);
127                        name->setDefinition(makeDiff(makeAny(), binprop));
128                        return;
129                    }
130                }
131                else {
132                    throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized, but not supported in icgrep 1.0");
133                }
134            }
135            else {
136                // No namespace (property) name.   Try as a general category.
137                int valcode = GetPropertyValueEnumCode(gc, value);
138                if (valcode >= 0) {
139                    name->setName("__get_gc_" + GC_ns::enum_names[valcode]);
140                    return;
141                }
142                valcode = GetPropertyValueEnumCode(sc, value);
143                if (valcode >= 0) {
144                    name->setName("__get_sc_" + SC_ns::enum_names[valcode]);
145                    return;
146                }
147                // Try as a binary property.
148                auto propit = alias_map.find(value);
149                if (propit != alias_map.end()) {
150                    auto theprop = propit->second;
151                    if (isa<BinaryPropertyObject>(property_object_table[theprop])) {
152                        name->setName("__get_" + lowercase(property_enum_name[theprop]) + "_Y");
153                        return;
154                    }
155                    else {
156                        throw UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
157                    }
158                }
159                // Now try special cases of Unicode TR #18
160                else if (value == "any") {
161                    name->setDefinition(makeAny());
162                    return;
163                }
164                else if (value == "assigned") {
165                    Name * Cn = makeName("Cn", Name::Type::UnicodeProperty);
166                    resolveProperties(Cn);
167                    name->setDefinition(makeDiff(makeAny(), Cn));
168                    return;
169                }
170                else if (value == "ascii") {
171                    name->setName("__get_blk_ASCII");
172                    return;
173                }
174                // Now compatibility properties of UTR #18 Annex C
175                else if (value == "xdigit") {
176                    Name * Nd = makeName("Nd", Name::Type::UnicodeProperty);
177                    resolveProperties(Nd);
178                    Name * hexdigit = makeName("Hex_digit", Name::Type::UnicodeProperty);
179                    resolveProperties(hexdigit);
180                    name->setDefinition(makeAlt({Nd, hexdigit}));
181                    return;
182                }
183                else if (value == "alnum") {
184                    Name * digit = makeName("Nd", Name::Type::UnicodeProperty);
185                    resolveProperties(digit);
186                    Name * alpha = makeName("alphabetic", Name::Type::UnicodeProperty);
187                    resolveProperties(alpha);
188                    name->setDefinition(makeAlt({digit, alpha}));
189                    return;
190                }
191                else if (value == "blank") {
192                    Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
193                    resolveProperties(space_sep);
194                    CC * tab = makeCC(0x09);
195                    name->setDefinition(makeAlt({space_sep, tab}));
196                    return;
197                }
198                else if (value == "graph") {
199                    Name * space = makeName("space", Name::Type::UnicodeProperty);
200                    resolveProperties(space);
201                    Name * ctrl = makeName("control", Name::Type::UnicodeProperty);
202                    resolveProperties(ctrl);
203                    Name * surr = makeName("surrogate", Name::Type::UnicodeProperty);
204                    resolveProperties(surr);
205                    Name * unassigned = makeName("Cn", Name::Type::UnicodeProperty);
206                    resolveProperties(unassigned);
207                    Name * nongraph = makeName("[^graph]", Name::Type::UnicodeProperty);
208                    nongraph->setDefinition(makeAlt({space, ctrl, surr, unassigned}));
209                    name->setDefinition(makeDiff(makeAny(), nongraph));
210                    return;
211                }
212                else if (value == "print") {
213                    Name * graph = makeName("graph", Name::Type::UnicodeProperty);
214                    resolveProperties(graph);
215                    Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
216                    resolveProperties(space_sep);
217                    std::vector<RE *> alts = {graph, space_sep};
218                    name->setDefinition(makeAlt(alts.begin(), alts.end()));
219                    return;
220                }
221                else if (value == "word") {
222                    Name * alnum = makeName("alnum", Name::Type::UnicodeProperty);
223                    resolveProperties(alnum);
224                    Name * mark = makeName("mark", Name::Type::UnicodeProperty);
225                    resolveProperties(mark);
226                    Name * conn = makeName("Connector_Punctuation", Name::Type::UnicodeProperty);
227                    resolveProperties(conn);
228                    Name * join = makeName("Join_Control", Name::Type::UnicodeProperty);
229                    resolveProperties(join);
230                    name->setDefinition(makeAlt({alnum, mark, conn, join}));
231                    return;
232                }
233                else {
234                    throw UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
235                }
236            }
237
238            //name->setCompiled(compileCC(cast<CC>(d), mCG));
239        }
240    }
241    else if (!isa<CC>(re) && !isa<Start>(re) && !isa<End>(re) && !isa<Any>(re)) {
242        throw UnicodePropertyExpressionError("Unknown RE type in resolveProperties.");
243    }
244}
245
246UnicodeSet resolveUnicodeSet(Name * const name) {
247
248    if (name->getType() == Name::Type::UnicodeProperty) {
249        std::string prop = name->getNamespace();
250        std::string value = canonicalize_value_name(name->getName());
251        if (prop.length() > 0) {
252            prop = canonicalize_value_name(prop);
253            auto propit = alias_map.find(prop);
254            if (propit == alias_map.end()) {
255                throw UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
256            }
257            auto theprop = propit->second;
258            if (theprop == gc) {
259                // General Category
260                return cast<EnumeratedPropertyObject>(property_object_table[gc])->GetCodepointSet(value);
261            }
262            else if (theprop == sc) {
263                // Script property identified
264                return cast<EnumeratedPropertyObject>(property_object_table[sc])->GetCodepointSet(value);
265            }
266            else if (theprop == scx) {
267                // Script extension property identified
268                return cast<EnumeratedPropertyObject>(property_object_table[scx])->GetCodepointSet(value);
269            }
270            else if (theprop == blk) {
271                // Block property identified
272                return cast<EnumeratedPropertyObject>(property_object_table[blk])->GetCodepointSet(value);
273            }
274            else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])){
275                auto valit = Binary_ns::aliases_only_map.find(value);
276                if (valit == Binary_ns::aliases_only_map.end()) {
277                    throw UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
278                }
279                return p->GetCodepointSet(value);
280            }           
281            throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
282        }
283        else {
284            // No namespace (property) name.   Try as a general category.
285            int valcode = GetPropertyValueEnumCode(gc, value);
286            if (valcode >= 0) {
287                return cast<EnumeratedPropertyObject>(property_object_table[gc])->GetCodepointSet(valcode);
288            }
289            valcode = GetPropertyValueEnumCode(sc, value);
290            if (valcode >= 0) {
291                return cast<EnumeratedPropertyObject>(property_object_table[sc])->GetCodepointSet(valcode);
292            }
293            // Try as a binary property.
294            auto propit = alias_map.find(value);
295            if (propit != alias_map.end()) {
296                auto theprop = propit->second;
297                if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
298                    return p->GetCodepointSet(Binary_ns::Y);
299                }
300                else {
301                    throw UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
302                }
303            }
304        }
305    }
306    throw UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
307}
Note: See TracBrowser for help on using the repository browser.