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

Last change on this file since 4736 was 4735, checked in by cameron, 4 years ago

Support for Grapheme, Sentence, Word break properties

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