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

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

Moved resolveProperty responsibilities out of RE_Parser but kept expansion of Name objects with definitions in it.

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