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

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

Moved 'resolveProperties' into CC_NameMap as a single call for each unique Name.

File size: 11.3 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_re.h>
8#include <re/re_alt.h>
9#include <re/re_any.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#include <boost/algorithm/string/case_conv.hpp>
25#include <string>
26#include <iostream>
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 resolveProperty(Name * name) {
50    const std::string prop = canonicalize_value_name(name->getNamespace());
51    const std::string value = canonicalize_value_name(name->getName());
52    if (prop.length() != 0) {
53        auto propit = alias_map.find(prop);
54        if (propit == alias_map.end()) {
55            throw UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
56        }
57        auto theprop = propit->second;
58        if (theprop == gc) {
59            // General Category
60            int valcode = GetPropertyValueEnumCode(gc, value);
61            if (valcode < 0) {
62                throw UnicodePropertyExpressionError("Erroneous property value for general_category property");
63            }
64            name->setFunctionName("__get_gc_" + GC_ns::enum_names[valcode]);
65        }
66        else if (theprop == sc) {
67            // Script property identified
68            int valcode = GetPropertyValueEnumCode(sc, value);
69            if (valcode < 0) {
70                throw UnicodePropertyExpressionError("Erroneous property value for script property");
71            }
72            name->setFunctionName("__get_sc_" + SC_ns::enum_names[valcode]);
73        }
74        else if (theprop == scx) {
75            // Script extension property identified
76            int valcode = GetPropertyValueEnumCode(sc, value);
77            if (valcode < 0) {
78                throw UnicodePropertyExpressionError("Erroneous property value for script_extension property");
79            }
80            name->setFunctionName("__get_scx_" + SC_ns::enum_names[valcode]);
81        }
82        else if (theprop == blk) {
83            // Block property identified
84            int valcode = GetPropertyValueEnumCode(blk, value);
85            if (valcode < 0) {
86                 throw UnicodePropertyExpressionError("Erroneous property value for block property");
87            }
88            name->setFunctionName("__get_blk_" + BLK_ns::enum_names[valcode]);
89        }
90        else if (isa<BinaryPropertyObject>(property_object_table[theprop])){
91            auto valit = Binary_ns::aliases_only_map.find(value);
92            if (valit == Binary_ns::aliases_only_map.end()) {
93                throw UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
94            }
95            if (valit->second == Binary_ns::Y) {
96                name->setFunctionName("__get_" + lowercase(property_enum_name[theprop]) + "_Y");
97                return;
98            }
99            else {
100                Name * binprop = makeName("__get_" + lowercase(property_enum_name[theprop]) + "_Y", Name::Type::UnicodeProperty);
101                name->setDefinition(makeDiff(makeAny(), binprop));
102                return;
103            }
104        }
105        else {
106            throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized, but not supported in icgrep 1.0");
107        }
108    }
109    else {
110
111        // No namespace (property) name.   Try as a general category.
112        int valcode = GetPropertyValueEnumCode(gc, value);
113        if (valcode >= 0) {
114            name->setFunctionName("__get_gc_" + GC_ns::enum_names[valcode]);
115            return;
116        }
117        valcode = GetPropertyValueEnumCode(sc, value);
118        if (valcode >= 0) {
119            name->setFunctionName("__get_sc_" + SC_ns::enum_names[valcode]);
120            return;
121        }
122        // Try as a binary property.
123        auto propit = alias_map.find(value);
124        if (propit != alias_map.end()) {
125            auto theprop = propit->second;
126            if (isa<BinaryPropertyObject>(property_object_table[theprop])) {
127                name->setFunctionName("__get_" + lowercase(property_enum_name[theprop]) + "_Y");
128                return;
129            }
130            else {
131                throw UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
132            }
133        }
134        // Now try special cases of Unicode TR #18
135        else if (value == "any") {
136            name->setDefinition(makeAny());
137            return;
138        }
139        else if (value == "assigned") {
140            Name * Cn = makeName("Cn", Name::Type::UnicodeProperty);
141            name->setDefinition(makeDiff(makeAny(), Cn));
142            return;
143        }
144        else if (value == "ascii") {
145            name->setFunctionName("__get_blk_ASCII");
146            return;
147        }
148        // Now compatibility properties of UTR #18 Annex C
149        else if (value == "xdigit") {
150            Name * Nd = makeName("Nd", Name::Type::UnicodeProperty);
151            Name * hexdigit = makeName("Hex_digit", Name::Type::UnicodeProperty);
152            name->setDefinition(makeAlt({Nd, hexdigit}));
153            return;
154        }
155        else if (value == "alnum") {
156            Name * digit = makeName("Nd", Name::Type::UnicodeProperty);
157            Name * alpha = makeName("alphabetic", Name::Type::UnicodeProperty);
158            name->setDefinition(makeAlt({digit, alpha}));
159            return;
160        }
161        else if (value == "blank") {
162            Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
163            CC * tab = makeCC(0x09);
164            name->setDefinition(makeAlt({space_sep, tab}));
165            return;
166        }
167        else if (value == "graph") {
168            Name * space = makeName("space", Name::Type::UnicodeProperty);
169            Name * ctrl = makeName("control", Name::Type::UnicodeProperty);
170            Name * surr = makeName("surrogate", Name::Type::UnicodeProperty);
171            Name * unassigned = makeName("Cn", Name::Type::UnicodeProperty);
172            Name * nongraph = makeName("[^graph]", Name::Type::UnicodeProperty);
173            nongraph->setDefinition(makeAlt({space, ctrl, surr, unassigned}));
174            name->setDefinition(makeDiff(makeAny(), nongraph));
175            return;
176        }
177        else if (value == "print") {
178            Name * graph = makeName("graph", Name::Type::UnicodeProperty);
179            Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
180            name->setDefinition(makeAlt({graph, space_sep}));
181            return;
182        }
183        else if (value == "word") {
184            Name * alnum = makeName("alnum", Name::Type::UnicodeProperty);
185            Name * mark = makeName("mark", Name::Type::UnicodeProperty);
186            Name * conn = makeName("Connector_Punctuation", Name::Type::UnicodeProperty);
187            Name * join = makeName("Join_Control", Name::Type::UnicodeProperty);
188            name->setDefinition(makeAlt({alnum, mark, conn, join}));
189            return;
190        }
191        else {
192            throw UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
193        }
194    }
195}
196
197UnicodeSet resolveUnicodeSet(Name * const name) {
198    if (name->getType() == Name::Type::UnicodeProperty) {
199        std::string prop = name->getNamespace();
200        std::string value = canonicalize_value_name(name->getName());
201        if (prop.length() > 0) {
202            prop = canonicalize_value_name(prop);
203            auto propit = alias_map.find(prop);
204            if (propit == alias_map.end()) {
205                throw UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
206            }
207            auto theprop = propit->second;
208            if (theprop == gc) {
209                // General Category
210                return cast<EnumeratedPropertyObject>(property_object_table[gc])->GetCodepointSet(value);
211            }
212            else if (theprop == sc) {
213                // Script property identified
214                return cast<EnumeratedPropertyObject>(property_object_table[sc])->GetCodepointSet(value);
215            }
216            else if (theprop == scx) {
217                // Script extension property identified
218                return cast<ExtensionPropertyObject>(property_object_table[scx])->GetCodepointSet(value);
219            }
220            else if (theprop == blk) {
221                // Block property identified
222                return cast<EnumeratedPropertyObject>(property_object_table[blk])->GetCodepointSet(value);
223            }
224            else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])){
225                auto valit = Binary_ns::aliases_only_map.find(value);
226                if (valit == Binary_ns::aliases_only_map.end()) {
227                    throw UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
228                }
229                return p->GetCodepointSet(value);
230            }           
231            throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
232        }
233        else {
234            // No namespace (property) name.   Try as a general category.
235            int valcode = GetPropertyValueEnumCode(gc, value);
236            if (valcode >= 0) {
237                return cast<EnumeratedPropertyObject>(property_object_table[gc])->GetCodepointSet(valcode);
238            }
239            valcode = GetPropertyValueEnumCode(sc, value);
240            if (valcode >= 0) {
241                return cast<EnumeratedPropertyObject>(property_object_table[sc])->GetCodepointSet(valcode);
242            }
243            // Try as a binary property.
244            auto propit = alias_map.find(value);
245            if (propit != alias_map.end()) {
246                auto theprop = propit->second;
247                if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
248                    return p->GetCodepointSet(Binary_ns::Y);
249                }
250                else {
251                    throw UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
252                }
253            }
254        }
255    }
256    throw UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
257}
Note: See TracBrowser for help on using the repository browser.