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

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

More modifications to UnicodeSet? class.

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