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

Last change on this file since 4442 was 4435, checked in by cameron, 5 years ago

Switch to dyn_cast system for PropertyObjects?

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